Introduction
In the section on phase shifters, 2 first order allpass filters are cascaded to obtain a phase shift of -π in the middle of the frequency range. The -π phase shift makes it possible to implement a band reject filter by adding the input to the phase shifted allpass output or a band pass by subtracting the allpass output from the input.
There are many ways to formulate a second order allpass, but in this section we will be using a filter developed by professor fred harris at SDSU for an efficient parametric equalizer used in an early hybrid guitar amp.
y[n] = -c(x[n]) + (d - dc)x[n-1] + x[n-2] - (d - dc)(y[n-1]) + c(y[n-2])Above is the difference equation for this allpass. The coefficients are c and d. The input parameters used are frequency and bandwidth. Frequency is the -π phase shift point and bandwidth is the frequency distance between the -π/2 and -3π/2 points.
The coefficients are calculated from frequency (f) and bandwidth (bw) by:
\begin{aligned}& d = -cos\bigg(2\pi \frac{f}{sr} \bigg) \\ & tf = tan\bigg(\pi \frac{bw}{sr} \bigg) \\ & c = \frac{tf-1}{tf+1} \end{aligned}Notice the d is completely dependent on f and c is completely dependent on bw. The decoupling of coefficients will allow easy optimization of this filter.
The plot above shows that this filter reaches -π/2 at 2000Hz, -π at 2500Hz and -3π/2 at 3000Hz. The C implementation is straightforward and can be derived directly from the difference equation above.
#define SAMPLERATE 44100.0 #define PI 3.141592653589793 double x0 = 0.0; // input double x1 = 0.0; // delayed input double x2 = 0.0; // delayed input double y1 = 0.0; // delayed output double y2 = 0.0; // delayed output soap(float *input, float *output, long samples, float cutoff, float bw) { double d = -cos(2.0 * PI * (cutoff/SAMPLERATE)); double tf = tan(PI * (bw/SAMPLERATE)); // tangent bandwidth double c = (tf - 1.0)/(tf + 1.0); // coefficient for(int i = 0; i < samples; i++) { x0 = *(input+i); *(output+i) = -c*x0 + (d - d*c)*x1 + x2 - (d - d*c)y1 + c*y2; // move samples in delay for next sample x2 = x1; x1 = x0; y2 = y1; y1 = *(output+i); } }