Fast IIR filtering on ARM Cortex-M with CMSIS-DSP and GNU Octave

Written by matteo-scordino | Published 2020/04/12
Tech Story Tags: embedded | dsp | arm-architecture | cmsis | gnu-octave | firmware | signal-processing | c-language

TLDR Fast IIR filtering on ARM Cortex-M with CMSIS-DSP and GNU Octave and GCC Octave. iir-designer-cmsis-dsp is available with examples on GitHub. The code is mostly boilerplate, and you just need to provide an input array of floats (pSrc) and a buffer for the filtered signal (pDst) and their length (blockSize) to run the code. Let us know if you find it useful, we would love to know what people are using it for!via the TL;DR App

Signal filtering is the bread and butter of digital signal processing, and ARM Cortex-M cores provide a very efficient way to implement IIR filters, especially for cores that come with an FPU.
ARM maintains the CMSIS-DSP library as a collection of useful DSP functionality, including IIR filters implemented using a Direct Form II transposed structure. Big words, right?
In fact, the maths needed to go from filter specification to running code are not necessarily straightforward to do on paper. The process is complex and error prone, plus there is not a lot of value in doing it yourself for every minimal parameter variation.
That's why at Elimo Engineering we created a collection of scripts to harness the power of GNU Octave to design IIR filters and automatically get "ready-to-run" C code for our applications.
Being very creative people, we called it iir-designer-cmsis-dsp and, in the spirit of open source, we made it available with examples on GitHub.
The repo includes a file with example inputs like the following for a DC blocking filter:
%///////////////////////////////////////////////////////////////
	% Example 1
% 2nd order DC blocker, 20 Hz, sampling frequency = 44.1kHz
% Plots the filter response and sample signals 
%///////////////////////////////////////////////////////////////
pkg load signal
order=2
f1=20
fs=44100
plot_results=true
	

design_iir_highpass_cmsis_butter(order,f1,fs,plot_results);
which will give you the following output:
coeffs =

   0.99799
  -1.99597
   0.99799
   1.99597
  -0.99598
That array of coefficients can be directly used in ARM code like the following:
#define IIR_ORDER     2
#define IIR_NUMSTAGES (IIR_ORDER/2)

static float32_t m_biquad_state[IIR_ORDER];
static float32_t m_biquad_coeffs[5*IIR_NUMSTAGES] =
{
   0.99799,
  -1.99597,
   0.99799,
   1.99597,
  -0.99598
};

arm_biquad_cascade_df2T_instance_f32 const iir_inst = 
{
  IIR_ORDER/2,
  m_biquad_state,
  m_biquad_coeffs
};

extern float32_t* pSrc;
extern float32_t* pDst;
extern uint16_t blockSize;

arm_biquad_cascade_df2T_f32(&iir_inst, pSrc, pDst, blockSize);
Note that this code is mostly boilerplate, and you just need to provide an input array of floats (pSrc in our example), a buffer for the filtered signal (pDst) and their length (blockSize)
Let us know if you find it useful, we would love to know what people are using it for!

Written by matteo-scordino | I started my adventures in computing with a CBM64 in my childhood bedroom and never looked back
Published by HackerNoon on 2020/04/12