I have designed an IIR filter in Matlab that comprises the following biquads

0.244   0.002   0.244   1   -1.432  0.543
0.244   -0.345  0.244   1   -1.555  0.777
0.244   -0.388  0.244   1   -1.652  0.943

I want to implement this filter in a 16-bit DSP. Before converting the coefficients to short int, I therefore normalize them by dividing all coefficients by the largest magnitude present in the matrix (in this case 1.652). This results in

b0      b1      b2      a0       a1     a2
0.147   0.001   0.147   0.605   -0.866  0.328
0.147   -0.208  0.147   0.605   -0.941  0.470
0.147   -0.235  0.147   0.605   -1      0.570

I then convert these coefficients to 16-bit values ranging from +32767 to -32768. I implemented the filter using the Transposed Direct Form II.

enter image description here

The I realized that the gain is very low although the filter shows 0 dB in the passband when testing it in Matlab. The algorithm is as follows. It iterates through all biquads and reintroduces their ouputs to the next one as necessary.

for (k = 0; k < N_sos; k++) {

    y_n = (short) ((s1[k][1] + b[k][0] * x_n) >> 15);

    s1[k][0] = s2[k][1] + b[k][1] * x_n - a[k][1] * y_n;

    s2[k][0] = b[k][2] * x_n - a[k][2] * y_n;

    s1[k][1] = s1[k][0];

    s2[k][1] = s2[k][0];

    x_n = y_n;

IIR_out = y_n;

Notice that I have not taken the a0 coefficient into account. Since it usually is 1, it does not matter. But I wonder if the missing gain is caused by this missing coefficient. I tried multiplying y_n with it by exchanging

y_n = (short) ((s1[k][1] + b[k][0] * x_n) >> 15);


y_n = (short) a[k][0] * ((s1[k][1] + b[k][0] * x_n) >> 15);

but this heavily distorts the signal.

  • $\begingroup$ you should divide ((s1[k][1] + b[k][0] * x_n) >> 15) by a[k][0] $\endgroup$
    – Ben
    Feb 23 at 16:04
  • $\begingroup$ That doesn't make sense. It reduces the gain even more. $\endgroup$
    – neolith
    Feb 23 at 16:12
  • $\begingroup$ a[0] is less than 1, so it will increase the gain! $\endgroup$
    – Ben
    Feb 23 at 16:13
  • $\begingroup$ I know and I just tried it. Now I have no output anymore, when I do that $\endgroup$
    – neolith
    Feb 23 at 16:22
  • 1
    $\begingroup$ Well simply adapt your fixed-point arithmetic to that reality... Mulitply the coefficients by 16384, not 32768. No one said that fixed-point coefficients must be smaller than 1. $\endgroup$
    – Ben
    Feb 23 at 16:40

The OP should first implement the filter using floating point to confirm all specifications and structure. Once confirmed there is no "optimal" since the solution is a trade between precision required and accuracy needed in the result but typically the design approach is to use 2 more bits of precision for the coefficients over what is used in the datapath; scale all coefficients accordingly, let the filter grow the signal with an extended precision accumulator (such that no clipping occurs with input set to the maximum possible signal) and then scale the output back to the datapath precision.

See my further details on this at this answer recently posted:

What is the correct gain of an RRC Filter?


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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