Jump to content

Programming Reference:IIRFilterBase Class

From BCI2000 Wiki

Location

BCI2000/src/shared/modules/signalprocessing

Synopsis

The IIRFilter class is a base class for BCI2000 filters that implement digital filters. Classes derived from IIRFilter are supposed to implement IIRFilter::DesignFilter(), specifying filter behavior by providing a transfer function. Differently from typical IIR filter implementations, which expect the transfer function in terms of filter coefficients, the BCI2000 IIRFilter class expects the transfer function in terms of its numerator's roots ("zeros") and denominator roots ("poles"); this approach reduces numerical instability at higher filter orders.

FilterDesign Library

While any method may be used to determine the transfer function, the FilterDesign library provides a convenient way to compute a transfer function from desired filter properties. It is located at BCI2000/src/extlib/math/FilterDesign, and was written for BCI2000 based on public-domain code by A.J. Fisher, and provides a number of classes that correspond to classic filter design methods. To use such a class, instantiate it, use its member functions to configure its parameters, and obtain its TransferFunction property (see the example section below).

FilterDesign::Butterworth

Order(integer)

Set the filter order to the specified value.

Lowpass(corner frequency)

Design a low pass with the specified corner frequency, i.e. suppress signals above the given frequency. Frequencies are specified in terms of the sampling rate, and expected to be below 0.5 (the Nyquist frequency).

Highpass(corner frequency)

Design a high pass with the specified corner frequency, i.e. suppress signals below the given frequency.

Bandpass(low corner, high corner)

Design a bandpass with the specified corner frequencies, i.e. suppress signals outside the given frequency range.

Bandstop(low corner, high corner)

Design a bandstop with specified corner frequencies, i.e. suppress signals inside the given frequency range.

rational polynomial TransferFunction

Returns a transfer function as a rational polynomial with complex roots as declared in BCI2000/src/extlib/math/Polynomials.h. From the Ratpoly object returned, numerator and denominator polynomials may be extracted using Ratpoly::Numerator() and Ratpoly::Denominator(), respectively. Both functions return a polynomial, from which roots or coefficients may be obtained using Polynomial::Roots() or Polynomial::Coefficients().

FilterDesign::Chebychev

The Chebychev class provides the same functions as the Butterworth class, and a single additional function.

Ripple_dB(amplitude)

Set the amplitude of the filter's passband ripples in dB.

FilterDesign::Resonator

Rather than through corner frequencies, the Resonator class is parameterized using its resonant frequency in conjunction with its quality factor (which is inversely proportional to the resonance peak's width).

QFactor

Set the resonator's quality factor to the specified value.

Bandpass(center frequency)

Design a bandpass around the specified center frequency.

Bandstop(center frequency)

Design a bandstop around the specified center frequency.

Allpass(center frequency)

Design a filter with a constant frequency response but altering phase at the center frequency.

Example

To implement a 2nd order Butterworth low pass filter, you might derive a class ButterworthLP from IIRFilter, with its declaration being

class ButterworthLP : public IIRFilter
{
  public:
    ButterworthLP();
    virtual ~ButterworthLP() {}
  private:
    virtual void DesignFilter( IIRFilter::Real gain, 
                                                 IIRFilter::ComplexVector& zeros, 
                                                 IIRFilter::ComplexVector& poles ) const;
};

The filter's corner frequency is specified in a parameter "ButterworthLPCorner":

ButterworthLP::ButterworthLP()
{
  BEGIN_PARAMETER_DEFINITIONS
    "Filtering float ButterworthLPCorner= 30Hz % % % // Low pass corner frequency",
  END_PARAMETER_DEFINITIONS
}

In the DesignFilter method, we use the FilterDesign library to obtain poles and zeros from our parameters:

 void
 ButterwortLP::ButterworthLP( IIRFilter::Real outGain, IIRFilter::ComplexVector& outZeros, IIRFilter::ComplexVector& outPoles ) const
 {
   float corner = MeasurementUnits::ReadAsFreq( Parameter( "ButterworthLPCorner" ) );
   if( corner < 0.0 || corner > 0.5 )
     bcierr << "ButterworthLPCorner exceeds range" << endl;

   Ratpoly<FilterDesign::Complex>  TransferFunction tf = FilterDesign::Butterworth()
       .Order( 2 )
       .Lowpass( corner )
       .TransferFunction();

   outGain = 1.0 / abs( tf.Evaluate( 1.0 ) ); // LF gain
   outZeros = tf.Numerator().Roots();
   outPoles = tf.Denominator().Roots();
 }

For an example that combines a notch filter with a high pass filter, please see the SourceFilter's source code.

See also

Programming Reference:TextToSpeech Class, Programming Reference:MidiPlayer Class