2
$\begingroup$

How do you reconcile Scipy.signal's IIR design with CMSIS-DISP's API? Scipy.signal outputs in one of 3 forms:

  • Numerator/denominator
  • Pole Zero
  • Second-Order-Sections.

CMSIS requires an array of length a multiple of five. Each 5 values are coefficients b0, b1, b2, a1, and a2 for a filter state: "Coefficients b0, b1 and b2 multiply the input signal x[n] and are referred to as the feedforward coefficients. Coefficients a1 and a2 multiply the output signal y[n] and are referred to as the feedback coefficients. Pay careful attention to the sign of the feedback coefficients. Some design tools use the difference equation"

Scipy's formats seem incompatible: Numerator/Denominator uses "b" and "a" terminology, but returns 2 arrays: A numerator array of lengh 6, and denominator array of len 6. SOS format also returns arrays of length 6.

This is in contrast to FIR, where there's a 1-to-1 mapping. Ie both use an array of coefficients corresponding to a convolution kernel. IIR seems more diverse by comparison.

scipy.signal.iirdesign

CMSIS-DSP Biquad Cascade

$\endgroup$
1
  • 2
    $\begingroup$ CMIS uses a standard normalized second order sections. They just assume that $a_0=1$ and you don't specifically pass it into the function, so you pass in 5 coefficients instead of 6. $\endgroup$
    – Hilmar
    Nov 8, 2021 at 12:08

1 Answer 1

5
$\begingroup$

scipy.signal returns a sos matrix when you set output='sos', which is cascaded second-order sections and has a shape of (n_sections, 6).

Each row corresponds to a second-order section, and you have [b0, b1, b2, a0, a1, a2] in order. Normalize these coefficients to make sure that a0=1, and then remove a0 from the array -- CMSIS assumes that a=1 so you only need 5 coefficients.

One thing to mention is that the sign of the denominators are different in scipy and CMSIS. The difference equation defined in CMSIS is given by

$$ y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] - a_1 y[n-1] - a_2 y[n-2] $$

However it is defined in scipy/MATLAB by $$ y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] + a_1 y[n-1] + a_2 y[n-2] $$

So you have to change the signs of all the denominators. And finally, cascade coefficients of all sections and you get array of length n_sections * 5:

$$ [b_0^1, b_1^1, b_2^1, -a_1^1, -a_2^1, b_0^2, b_1^2, b_2^2, -a_1^2, -a_2^2,\ldots, b_0^N, b_1^N, b_2^N, -a_1^N, -a_2^N] $$ where $N$ is the number of biquad sections, which is defined as numStages in CMSIS.

$\endgroup$
3
  • $\begingroup$ This was exactly what I was looking for (how to run a scipy-generated filter in CMSIS), thanks! Stuff like this should be in the CMSIS documentation $\endgroup$
    – BjornW
    Mar 18 at 9:45
  • $\begingroup$ However, something might have changed, because the difference equation specified in CMSIS now is y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] (with positive a1 and a2), see keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html $\endgroup$
    – BjornW
    Mar 18 at 12:48
  • $\begingroup$ I think the scipy convention is -a1, -a2, so the end result is correct that you need to negate them, but for the opposite reasons as in the answer :) $\endgroup$
    – BjornW
    Mar 18 at 13:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.