# Why my low pass digital filter amplifies in the passband?

I'm trying to implement a 10th-order Butterworth Low Pass digital filter on my MCU.

To find the coefficients I used Matlab's Filter Design & Analisys Tool. So I create two little scripts: in the first of them I used the Filter Object created by the tool and it seems to works perfectly, but in the second one I tryed to implement the general code based to the Biquad Direct-Form-II using only the coefficients generated by the tool and, in this case, the filter works good except for a signal amplification of about 5E+7!

My code in matlab is the following:

input = AmplitudeF8.';

delayline_lp = [0,0,0,0,0,0,0,0,0,0];
coeff_lp = [-1.7582972612745587, 0.89109671836321969, 2, 1, -1.5932765493727838, 0.71361243648860972, 2, 1, -1.4754804435926461, 0.58691950806119031, 2, 1, -1.4002643388507841, 0.50602253348347193, 2, 1, -1.3637162169443289, 0.46671403035270148, 2, 1];

for k=1:length(output1)
y = output1(k);

for j=1:5 %the biquad sections (order 10 = num_sections = 5)
w = y;
for i=1:2
w = w - (coeff_lp(((j - 1) * 4) + i) * delayline_lp(((j - 1) * 2) + i));
end

y = w;
for i=1:2
y = y + (coeff_lp(((j - 1) * 4) + i + 2) * delayline_lp(((j - 1) * 2) + i));
end

delayline_lp(j * 2) = delayline_lp((j * 2) - 1);
delayline_lp((j * 2) - 1) = w;
end

output2(k) = y;
end


Consider that in the coeff_lp array there are a1,a2,b1,b2,.... since a0=b0=1 for every biquad section.

Why in this case the filtered signal is amplified by a 5E+7 factor? Where I'm wrong?

• wrong polarity of terms? not sure,... so you ended up with positive feedback gain – Tony Stewart Sunnyskyguy EE75 May 24 '17 at 15:26
• @TonyStewart.EEsince'75 The polatity is ok. Thanks for your interest, but I found the mistake. Now I answer to myself. – thoraz May 24 '17 at 16:16

I found the mistake in my code:

when the Matlab's Filter Design & Analisys Tool generates the cofficients, there are even the Gains for the every biquad section. Before the value goes out from one section, it must be multiplied with this gain.

So the right code is the following:

input = AmplitudeF8.';

delayline_lp = [0,0,0,0,0,0,0,0,0,0];
scale_values = [0.033199864272165251, 0.030083971778956442, 0.027859766117136031, 0.026439548658171989, 0.025749453352093145];
coeff_lp = [-1.7582972612745587, 0.89109671836321969, 2, 1, -1.5932765493727838, 0.71361243648860972, 2, 1, -1.4754804435926461, 0.58691950806119031, 2, 1, -1.4002643388507841, 0.50602253348347193, 2, 1, -1.3637162169443289, 0.46671403035270148, 2, 1];

for k=1:length(input)
y = input(k);

w = y;
for i=1:2
w = w - (coeff_lp(((j - 1) * 4) + i) * delayline_lp(((j - 1) * 2) + i));
end

y = w;
for i=1:2
y = y + (coeff_lp(((j - 1) * 4) + i + 2) * delayline_lp(((j - 1) * 2) + i));
end

y = y * scale_values(j);

delayline_lp(j * 2) = delayline_lp((j * 2) - 1);
delayline_lp((j * 2) - 1) = w;
end

output2(k) = y;
end


Then the C-Code for my MCU is (maybe is usefull for someone):

double Filter_IIR_Biquad_Sec( double signal, double *coeffs, double *scaleValues, double *delayLine, uint32_t nSections )
{
uint32_t i, j;
double y = signal;
double w = 0.0;

for ( j = 0; j < nSections; j++ )
{
// The denominator
w = y;
for ( i = 0; i < 2; i++ )
w -= coeffs[ ( j << 2 ) + i ] * delayLine[ ( j << 1 ) + i ];

// The numerator
y = w;
for ( i = 0; i < 2; i++ )
y += coeffs[ ( j << 2 ) + i + 2 ] * delayLine[ ( j << 1 ) + i ];

y *= scaleValues[ j ];

// Shift the register values
delayLine[ ( j << 1 ) + 1 ] = delayLine[ j << 1 ];
delayLine[ j << 1 ] = w;
}

return y;
}


and now it works very well.

• You were the best person to be answering your question, as you are current with the tools you are applying. I love it when the author does discover the problem and posts the solution. Makes total sense given the added context. Thanks! – jonk May 24 '17 at 17:25