3 Infinite Impulse Response (IIR) Filters

Principle

Infinite Impulse Response (IIR) filters are feedback-based filters, i.e., the previous output plays a role in the current output. Due to the feedback principle, these filters lose the phase information and might be unstable, so they are not always the first choice for audio applications. But for sensor readings, they can be a great tool.

For this application note, a simple and flexible implementation of IIR was chosen, with emphasis on ease of use.

An IIR filter can be described by the differential equation:

y[n]=Σk=0M1bkx[nk]Σk=1N1aky[nk]  
The implementation we have is an example of a third-order IIR filter.

In the initialization phase, the b02 and a02 are set based on the type of filter, e.g., Low-Pass Filter. When running the filter, xnk and ynk values are updated continuously by the current signal, while ak and bk are constants.

Note: The notation in the code differs from the notation used in the general equations.
Table 3-1. Variable Explanation for Code
Variable in CodeVariable in Equation
a0b0a0
a1b1a0
a2b2a0
a3a1a0
a4a2a0
/* Computes a BiQuad filter on a sample */
smp_type BiQuad(const smp_type sample, biquad* const b)
{
  smp_type result;

  /* compute result */
  result = b->a0 * sample + b->a1 * b->x1 + b->a2 * b->x2 -
    b->a3 * b->y1 - b->a4 * b->y2;

  /* shift x1 to x2, sample to x1 */
  b->x2 = b->x1;
  b->x1 = sample;

  /* shift y1 to y2, result to y1 */
  b->y2 = b->y1;
  b->y1 = result;

  return result;
}             // Bandwidth in Octaves
When using the normalization factor a0, the equation becomes: y[3]=Σk=031bkx[nk]Σk=131aky[nk]  (b0a0×signal+b1a0×x1+b2a0×x2)(a1a0×y1+a2a0×y2)

For further reading, we refer to the IIR filtering sections from the music department at the University of California - San Diego: musicweb.ucsd.edu/%7Etrsmyth/filters/Biquad_Section.html.

Even if the IIR filter implementation we have used has support for multiple filters, we will only cover Low-Pass and Band-Pass. The complete list of supported filters is:
  • Low-Pass Filter
  • High-Pass Filter
  • Band-Pass Filter
  • Notch Filter
  • Peaking Band EQ Filter
  • Low Shelf Filter
  • High Shelf Filter

Examples

In this section we will examine the implementation in the example code.

Note: The implementation uses floating-point arithmetic, which can slow down the speed of the filter compared to an integer implementation.

In main.c, we create a hard-coded signal to illustrate the filter.

const uint8_t  sinewave[] = {147, ..., 135};

The signal passes the filter. To handle the the filtered results, the library creates a bq struct, which is made by setting the sample rate, frequency, bandwidth and gain. (Gain is used only by the Low Shelf and High Shelf filters.)

    
biquad *bq = BiQuad_new(FILTER_TYPE, dbGain,    /* gain of filter */
                          freq,                 /* center frequency */
                          srate,                /* sampling rate */
                          bandwidth);           /* Bandwidth in Octaves */
To filter, send one value to biquad with the initialized bq struct.
Note: Further down in the application note, it says that it is possible to switch data type. The input value will be implicitly cast to that data type.
filtered = BiQuad(sinevalue, bq);

Example: Low-Pass Filter

A low-pass filter is a filter that passes the signals lower than a given frequency threshold freq and attenuates/rejects the signal outside that range. Often, for filters with high/low discrimination, the term "bandwidth" denotes that frequency threshold (think of a low-pass filter as a "band-pass from zero to bandwidth" and a high-pass filter as a "band-pass from bandwidth to infinity"). Here, the variable bandwidth determines the shape of the transition between high/low areas. The variable srate helps to determine the phase Ω between samples.

    smp_type freq = 8.0;                    // Frequency in Hertz
    smp_type srate = 255.0;                 // Samples per second
    smp_type bandwidth = 5;                 // Bandwidth in Octaves
To Use the Data Visualizer, click Load Workspace → Choose data_visualizer.json
Figure 3-1. Input Signal and Low-Pass Filter Output

The green is the filtered signal, and the blue is the original signal. Using the MPLAB® Data Visualizer to compare the two signals sent over the Universal Synchronous and Asynchronous Receiver and Transmitter - USART, it is clear that the Low-Pass signal has removed high-frequency components.

Example: Band-Pass Filter

A band-pass filter is a filter that rejects or attenuates signals outside of a given frequency range and accepts those inside.

Ideally, a band-pass filter does not attenuate or amplify signals inside the range and completely remove the signal outside the frequency range. The center frequency of the band-pass filter is determined by bandwidth.

    smp_type freq = 3.0;                    // Frequency in Hertz
    smp_type srate = 255.0;                 // Samples per second
    smp_type bandwidth = 1;                 // Bandwidth in Octaves
Note: A calculator for bandwidth in octaves can be found at www.sengpielaudio.com/calculator-bandwidth.htm.
Figure 3-2. Low-Pass Filter Output Before and After Band-Pass Filter

Using the MPLAB® Data Visualizer to compare the two signals sent over the Universal Synchronous and Asynchronous Receiver and Transmitter - USART, the filter effect is visible: The Band-Pass filter has removed noise outside of a set frequency using the parameters for the IIR filter, and the result is the green filtered signal. To Use the Data Visualizer, click Load Workspace → Choose data_visualizer.json.

Notice that the signal is centered around 0 because the DC offset of the input signal (blue) is equivalent to a frequency of 0 Hz. This is below the pass-band of the filter and hence, removed, meaning that the band-pass filter output (green) has no DC offset and is centered around 0.

Performance and Properties

The IIR filter can use either double or float for the filters, which has a minor impact on how fast the filter will be.

To measure the time/cycles, set ONLY_SEND_USART to ‘0’ in main.c. This allows to measure the time between ticks on PORT B on PIN 2. Connect the PIN to a logic analyzer, and, by knowing the speed of the device, it is possible to time the filter.

Table 3-2. Cycle Times - IIR filter
Data TypeCycles
float1280

Some combinations of compiler and device architecture support changing the size of double, e.g., from 32-bit to 64-bit. An increase improves the precision, but with a cost of a slower run-time. Integers will not work with this implementation.

Use the type definition typedef float smp_type; in biquad.h to change the data type in the filter implementation. The compiler may require additional arguments, such as -fno-short-double. See the compiler’s documentation for details.

Conclusion and Use Cases

We have demonstrated how to use a biquadratic IIR filter on AVR devices. In addition, we have introduced how to time the filter in the code.

The IIR, as applied here, offers several filtering options. In combination with a low CPU load, IIR is a valuable tool for digital signal processing, especially on an 8-bit microcontroller. Depending on the application, IIR can be used to reject noise or offset variations, which helps to isolate the desired signal component. Thanks to its rather low CPU load, the IIR can easily fit into load- or timing-sensitive applications.