When dealing with data samples collected over time, or in the time-domain, one of the most basic operations is to “filter” the data. It is important to understand common ways that data can be digitally filtered to achieve the best results and free up a CPU to perform other tasks, especially when it comes to embedded microcontrollers.
In this article, learn about the widely used methods for filtering and processing data samples in the time domain. Also, take a closer look at the Dual Biquad IIR engine of the PowerQuad unit in the LPC55S69 MCU — a versatile DSP building block useful in many filtering use-cases.
Common Filters for Continuously Sampled Data
When sampling data in the time-domain, data are continuously collected at a known, fixed rate. Time-domain filters accept this data as an input and output a new signal that is modified in some way. The output of a filter is just another time domain signal, which can either be processed further or transferred to a digital to analog converter (DAC).
We commonly approach filters in terms of how they respond to sine waves. If we consider an input signal to be a simple sine wave, the filter can adjust the amplitude of the input as well as adjust its phase. When applying a complex signal to the filter, it will adjust the amplitude and phase of the signal’s sinusoidal components. How the filter behaves over a range of frequencies is called its frequency response.
A standard operation in the time domain is performed by the so-called Finite Impulse Response (FIR) filters, which mix the most recent data sample with the previously collected elements to obtain the next output sample.
Figure 1. Sample by sample filter processing using a history of the input.
One way of implementing such a filter is to store previous samples in an array and combine them using a straightforward equation:
x[n] // The most recent input
x[n-1], x[n-2] // The two previous input samples <br />
y[n] // The next output sample <br />
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2]
This particular pseudo-code snippet combines the most recent sample with the two previous data samples. It multiplies each data sample with a separate constant-coefficient before summing up the results to obtain the next output sample. In summary, this represents a simple multiply and accumulate operation, where the constant coefficients and the length of the history control the frequency response of the filter.
By choosing appropriate values for the coefficients, it’s possible to construct various types of filters. If the filter attenuates high frequencies, it acts as a low-pass filter. By attenuating low frequencies, the resulting filter will perform as a high-pass filter. It’s also possible to combine the two approaches, which will result in a band-pass filter.
FIR filters are conceptually simple but can require quite a few previous data samples to achieve precise control over its frequency response. While this filter is easy to understand and implement, executing it on a conventional CPU might be cumbersome, especially with a moderately sized history. This is because every sample requires many multiply and add operations to determine the output.
One method to reduce the amount of history required is to use the previously determined filter outputs when calculating the next output sample. This is the root of another class of digital filters called Infinite Impulse Response filters (IIR):
// This examples uses the previously established naming conventions<br />
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a1 * y[n-2]
The example above is a special case of the IIR filter known as a biquad filter — a common building block that can be cascaded to construct larger filters. This approach requires fewer coefficients compared to an FIR filter to achieve the desired frequency response. There are special tradeoffs to consider when using this approach. The use of feedback can cause filters to oscillate if the coefficients are not picked correctly.
Figure 2. One of the many tools that automatically generate coefficients.
Using the PowerQuad IIR Biquad Engines
The LPC55S69 PowerQuad unit incorporates dedicated hardware for computing IIR biquad filters. Employing the PowerQuad for filtering the collected data-samples will leave the CPU free to perform other tasks.
As discussed above, the filter algorithms aren’t complicated to implement, but they can chew up a lot of CPU time. The PowerQuad unit of the LPC55S69 MCU contains dedicated hardware optimized for many filtering and complex mathematical operations. It’s connected through the AHB bus and the Arm® Cortex®-M33 coprocessor interface.
The standard development environment for the LPC55S69 is the free eclipse-based IDE MCUXpresso. The LPC55S69 SDK contains many useful examples, some of which are PowerQuad example applications.
Figure 3. Selecting the PowerQuad digital filter example.
The ‘powerquad_filter’ example project contains a few examples of different filter configurations. The ‘powerquad_filter.c’ file has several functions that demonstrate basic filter setups.
Earlier, the article discussed a filter that uses ‘Direct Form I,’ which is the most straightforward implementation. However, the PowerQuad re-arranges the flow of multiply and add operations without changing the result, leading to ‘Direct Form II,’ which doesn’t require the history of both inputs and outputs to be stored. Instead, an intermediate history v[n] is stored, also referred to as a filter state.
A handful of registers on the AHB bus are used for storing the state and coefficients to set up the PowerQuad for IIR filter operations. In the SDK examples, the state of the filter is initialized in the PQ_BiquadRestoreInternalState function.
Once that is completed, the filter is ready to process data samples. This is done in the PQ_VectorBiquadDf2F32 function in fsl_powerquad_filter.c:
Figure 4. Vectorized IIR Filter Implementation
This function is designed to process blocks of input samples in multiples of eight. Data can be transferred from a register of the LPC55S69’s main processing core to an attached co-processor, which is the PowerQuad in this case, with the help of the MCR instruction.
The PowerQuad will then do the filtering work — a much more efficient way of performing many multiply and add operations than it would have been on either of the LPC55S69’s Cortex-M33 cores. Once the PowerQuad is done, the result can be accessed with MCR instruction, which moves data from a co-processor back to an internal CPU register.
The Dual Biquad IIR Engine for Digital Filtering
The LPC55S69 MCU comes with a PowerQuad unit (which contains two separate biquad engines) that can help accelerate filtering and complex mathematical operations. AHB bus registers are used to configure PowerQuad IIR functions, and the data is exchanged between the PowerQuad and Cortex-M33 cores over the coprocessor interface.
The LPC55S69 SDK in MCUXpresso is a good starting point. The code, however, isn’t optimized as it is meant to be easy to understand. Keep in mind that while the PowerQuad can significantly speed up filtering applications, the CPU must still transfer data from and to the PowerQuad co-processor.
NXP has a helpful IIR Biquad Filter Design & Visualization Tool to assist in configuring software. NXP’s community page also offers an in-depth look at the LPC55S69 MCU’s PowerQuad unit and its capabilities.
Industry Articles are a form of content that allows industry partners to share useful news, messages, and technology with All About Circuits readers in a way editorial content is not well suited to. All Industry Articles are subject to strict editorial guidelines with the intention of offering readers useful news, technical expertise, or stories. The viewpoints and opinions expressed in Industry Articles are those of the partner and not necessarily those of All About Circuits or its writers.