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.
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);
with
y_n = (short) a[k][0] * ((s1[k][1] + b[k][0] * x_n) >> 15);
but this heavily distorts the signal.