Bandpass and Bandreject Derived from Allpass Filter

As in the phase shifter, bandreject and bandpass filters can be simply constructed from a second order allpass filter, taking advantage of the phase inversion (-π) at the frequency of the allpass. The input signal will be out of phase with the allpass output at this frequency. Furthermore, the input signal is in phase with the allpass output at frequencies near 0, as well as near the nyquist. Here is the allpass phase response again.

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

Implementation

Because of this, a band reject filter can be obtained by adding the output of the allpass to the input signal and multiplying the sum by 1/2. This will cancel the signal at the -π frequency and pass it at 0 and nyquist. Note that at the -π/2 (and -3π/2) frequency the sum of a the input (0 phase) and allpass output (-π/2 phase) will be the hypotenuse of the two magnitudes as they are 90 degree apart. The hypotenuse is \sqrt{(1.0^2 + 1.0^2)} = 1.4142135... This sum will be multiplied by 1/2 as well, giving 0.707106… or -3.0103… dB at the bandwidth frequencies.

It follows that band pass filter can be obtained by subtracting the output of the allpass from the input signal and multiplying the sum by 1/2. We can combine these by multiplying the allpass output by a gain factor that varies from -1.0 to 1.0. This will give a filter that can go from bandpass to bandreject smoothly. Here is the C implementation, a simple modification of the second order allpass code.

#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 y0 = 0.0; // allpass output
double y1 = 0.0; // delayed output
double y2 = 0.0; // delayed output

sobpo(float *input, float *output, long samples, float cutoff, float bw) 
{   
    double d = -cos(2.0 * PI * (f/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);   
        y0 = -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 = y0;
        *(output+i) = (x0 + y0 * factor) * 0.5;
    }
}

Leave a Reply

Your email address will not be published.