# Trouble with fixed-point arithmetic 2nd order IIR implementation in c

DSP newcomer here!

I am tinkering around with a TI DSP and am trying to implement a second order IIR filter in C. Input is 16 bit 2's complement, as is the output, the accumulator is 32 bit wide. I have tried several structures: Direct form I, Transposed direct form II, Gold & Rader structure. However, I can't seem to get anything to work and I am not sure whether it is a typo in the code of all of my filter implementations or whether it is because of me misunderstanding the principle of fixed-point arithmetic. I assume - or better: hope - that it's the same mistake that is affecting all implementations.

Here's my code for the transposed df II implementation:

// state variables
int w = {0};

short filter_dfii(short value) {
w = ((value * sos_filter_coeffs_b + w) >> 15 ) & 0xffff;
w = value * sos_filter_coeffs_b
- w * sos_filter_coeffs_a
+ w;
w = value * sos_filter_coeffs_b
- w * sos_filter_coeffs_a;

return (short) w;
}


My df I implementation looks like this:

int last_value = {0};

short filter_dfi(short value) {
w =
((value * sos_filter_coeffs_b
+ last_value * sos_filter_coeffs_b
+ last_value * sos_filter_coeffs_b
- w * sos_filter_coeffs_a
- w * sos_filter_coeffs_a)
>> 15) & 0xffff;
last_value = last_value;
last_value = value;
w = w;
w = w;
return (short) w;
}


The filter coefficients are:

int sos_filter_coefficients_a = {32767, -51150, 21015};
int sos_filter_coefficients_b = {658, 1316, 658};


How did I get those coefficients? I utilized the Matlab 'butter' function and specified a 2nd order Butterworth lowpass with a cutoff frequency of 0.05*fs or 2400 kHz in my specific case. Then I multiplied each coefficient with 32767 and rounded it to an integer value. If I call Matlab freqz function with those quantized coefficients, I get a bode plot with the expected result, so I believe quantization error is not the issue here.

However, the result is not a lowpass but just garbage. Unfortunately, I lack the proper testing equipment to describe the result scientifically, but it sounds like digital oscillation that is slightly modulated by the actual input signal and is present even when there's no input at all.

So, in my opinion, this can't be an unstable filter since the poles are well within the unit circle. It can't be overflow limit cycle either because then it shouldn't be happening when there's only low input level or no input at all.. right?

If I alter the coefficients to

int sos_filter_coefficients_a = {32767, 0, 0};
int sos_filter_coefficients_b = {32767, 0, 0};


input gets returned basically unprocessed as expected, so my issues most likely aren't caused by any external factors - there must be something wrong with my coefficients, with the function itself, or both.

Any help is much appreciated!

• why is w[current_filter] a two-dimensional array but w and w are one-dimensional? and you are returning short w. is w[ ] one-dimensional or two-dimensional? i can't see how that code compiles. – robert bristow-johnson May 15 '17 at 2:14
• Thank you for pointing that out, Robert! My original code is designed for handling multiple filters and channels, but when writing this question I left that part part out for simplicity's sake. Seems like I was sloppy with the editing. – UnbescholtenerBuerger May 15 '17 at 7:42
• why isn't there something like w = w; w = w; in your DF2 code? – robert bristow-johnson May 15 '17 at 16:50
• It's actually transposed df2. – UnbescholtenerBuerger May 15 '17 at 17:54

• Removing the & 0xffff statement indeed helped a bit. Now audio gets passed through, although the actual filter doesn't behave as specified at all, so I need to do further investigation. Regarding your DF1 suggestion - I don't see how that would be beneficial. Before multiplying the variables with the coefficients, I would need to right-shift them anyways to avoid overflow, wouldn't I? – UnbescholtenerBuerger May 15 '17 at 13:37
• Yes, my int definitely holds 32 bit. Nevertheless , scaling my coefficients to 2^14 to have them fit into short sounds like an interesting idea. However, my a0 coefficient wouldn't be 1.0 (or 32767 respectively) any more. Can I just right-shift my output by 14 instead of 15 bits and everything's just fine or do I need to make any additional adjustments? – UnbescholtenerBuerger May 15 '17 at 13:31