The subject of digital filtering is vast but the basics can be understood easily. Digital filters process signals in the frequency domain and are commonly used to process sampled analog sensor data, images, video, audio and IF signals in the fields of audio, speech, image and video processing, radar, sonar, ultra-sound, communications, modulation and demodulation, sensors, motor control, power management, sensor arrays, medical, automotive, aviation, aero-space, hi-fi, cell-phones, audio effects, appliances and more.
Digital Filters are usually one component in a larger system, and you will find them in almost every device that you use. Your phone will use them to process incoming and outgoing audio signals; process the pictures and video that you take; modulate and demodulate the radio IF signals, process data from the accelerometer, light and other sensors. Your Bluetooth headset will use them on the radio side and to compensate for the speaker and microphone characteristics. Your mouse may use them to process the optical image data or de-bounce the noisy button and wheel signals as some examples. You will usually find them anywhere that signals are processed by computer. Traditionally, their development has been associated with complex math, thick books filled with equations, and long, iterative development cycles, electrical engineers, mathematicians and assembly language programmers. Now, software is available that can automate the whole design and coding process in a few mouse clicks, allowing developers to focus less on the problems and more on the solution.
Traditionally, digital filters have been implemented on specialized Digital Signal Processors or FPGAs, but Arm-based CPUs such as the Cortex-M4 have instruction sets and architectures that can competitively run these types of computations. Handling the signal processing on a CPU such as a Cortex-M4 instead of using a separate Digital Signal Processor has the obvious advantage that a second processor is not required. This means lower cost, less board area, lower power consumption, less external bus traffic and lower interfacing costs. Everything can be combined into one build process and binary and you don't have to debug over multiple processors from different vendors. Keeping everything on one processor eases the pain and cost of development and choosing Arm as the processor is an obvious one. You have full support of all the resources behind Arm, including forums, libraries, development tools and you can use an architecture that has become a standard within the Embedded Systems community.
The following graph shows the frequency response of a band-pass filter, showing gain, or how much an input signal is amplified (or reduced) vs the frequency of the signal. Signals in the central frequency band are allowed to pass while signals at the other frequencies are removed:
Low pass, High pass and Band stop filters are also commonly used. Arbitrary frequency responses as in the FIR filter at the bottom-right, can also be easily achieved:
Here's some example code, illustrating how you might read from an Analog to Digital Converter, filter it then write it to a Digital to Analog Converter. The code to implement the filter was generated in MicroModeler DSP (See below), and copied and pasted into filter1.c/.h
filter1.c/.h
#include "filter1.h" // Generated in MicroModeler DSP. filter1.c also needs to be added to the project const int inputBufferSize = 32; // Length of the input buffer const int outputBufferSize = 32; // Length of the output buffer void ADC1_read( short *pOutput, int nOutput ); // User supplied function that reads nOutput 16-bit samples from an ADC into buffer pOutput. (Blocks until complete) void DAC1_write( short *pInput, int nInput ); // User supplied function that writes nInput 16-bit samples from buffer pInput to a DAC. (Blocks until complete) short inputBuffer[inputBufferSize], outputBuffer[outputBufferSize]; // Allocate an input and output buffer int main( void ) { int nProcessedSamples; // The number of samples output by the filter. For multi-rate filters this will be different from the number of input samples filter1Type *filter = filter1_create(); // Create an instance of the filter. while( 1 ) // Loop infinitely, transferring data from the ADC, to the filter, to the DAC { ADC1_read( inputBuffer, inputBufferSize ); // Read inputBuffer from the ADC (User-supplied) nProcessedSamples = filter1_filterBlock( filter, inputBuffer, outputBuffer, inputBufferSize ); // Read from inputBuffer, filter the data and write to outputBuffer DAC1_write( outputBuffer, nOutputSamples ); // Write outputBuffer to the DAC } filter1_destroy( filter ); // Destroy the filter (if we ever get here!) return 0; }
The above example serves to illustrate its use and in practice, the ADC and DAC would most likely be interrupt-driven and double-buffered for performance. It's faster to process multiple samples at once than one at a time, so they are typically "batched" into a buffer of a few samples then processed in one go. The longer the buffer, the better the performance but the higher the latency (delay).
Digital Filters are usually Finite Impulse Response (FIR) or Infinite Impulse Response (IIR). IIR filters use feedback to recycle the signal, resulting in a longer (i.e. Infinite) response to an impulse. FIR filters are more stable but have higher computation cost and lower frequency "resolution" than IIR filters. IIR filters suffer from phase distortion, where signals at different frequencies cross the filter at different speeds (Similar to wave dispersion). FIR filters can usually be designed without phase distortion. IIR filters also have both "poles" and "zeros" whereas FIR filters have only "zeros".
Digital filters often process a high speed stream of data. They are subject to time critical constraints, tend to be computationally intensive and make heavy use of multiply-accumulate operations. Cortex-M4 microcontrollers have a very advanced set of multiply-accumulate instructions that can perform up to two integer multiply-accumulates in a single clock cycle (e.g. SMLAD), which makes them excellent for digital signal processing.
An easy way to build a digital filter is to use MicroModeler DSP, which provides a browser-based, self-contained filter design environment. Drag a filter to the application and visually configure the filter's frequency response. When you're ready, copy and paste the automatically generated code into a .c and a .h file and add to your project. All of the filters produced by MicroModeler DSP use the same interface, so it's easy to switch to a different filter without changing your application code. You can choose to generate code that uses C, the CMSIS DSP libraries or mixed C and Arm Assembly depending on your preference.
The above MicroModeler DSP filter design package is a great way to visually learn about filter design and signal processing. The software is fully web-based and runs in your browser with no software to install.
If you'd like to discover more, tutorials and videos on filter design are also available on the MicroModeler website.
Hope you've enjoyed this short introduction.