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:
The implementation we have is an example of a third-order IIR filter.In the initialization phase, the and are set based on the type of filter, e.g., Low-Pass Filter. When running the filter, and values are updated continuously by the current signal, while and are constants.
Variable in Code | Variable in Equation |
---|---|
/* 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 , the equation becomes: 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.
- 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.
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 */
bq
struct. 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 OctavesTo Use the Data Visualizer, click Load Workspace → Choose data_visualizer.json
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
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.
Data Type | Cycles |
---|---|
float | 1280 |
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.