Second-Order Allpass Filter

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.

phase response of fred harris 2nd order allpass, f=2500, bw=1000

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);
    }
}

swept band pass filter using above code. narrow band width: 1/10th the frequency

Leave a Reply

Your email address will not be published.