I am struggling to find the proper algorithms for generating the coefficients for low pass filters. I wrote the following taking the butterworthLowPass code from another SO question:
class Filter {
float fs;
float a1, a2, b0, b1, b2;
float v1, v2;
public:
Filter(float fs) : fs(fs) {}
float compute(float x)
{
float v0 = x - a1 * v1 - a2 * v2;
float y = b0 * v0 + b1 * v1 + b2 * v2;
v2 = v1;
v1 = v0;
return y;
}
void butterworthLowPass(float fc)
{
const float ita = 1.0 / tan(M_PI * fc / fs);
const float q = sqrt(2.0);
b0 = 1.0 / (1.0 + q * ita + ita * ita);
b1 = 2 * b0;
b2 = b0;
a1 = 2.0 * (ita * ita - 1.0) * b0;
a2 = -(1.0 - q * ita + ita * ita) * b0;
}
void chebyshevLowPass(float f, float ripple)
{
// TODO: implement
}
void ellipticLowPass(float f, float ripple, float stopband)
{
// TODO: implement
}
void displayCoefficients()
{
fprintf(stderr, "a = [ %f, %f, %f ]\n", 1.f, a1, a2);
fprintf(stderr, "b = [ %f, %f, %f ]\n", b0, b1, b2);
}
};
Here the main:
int main()
{
const float fs = 10000;
Filter biquad(fs);
biquad.butterworthLowPass(1000);
biquad.displayCoefficients();
}
When taking the computed coefficients and using Matlab to display the filter response, I get a -15dB gain which is not what I expect.
a = [ 1.000000, 1.142980, -0.412802 ];
b = [ 0.067455, 0.134911, 0.067455 ];
[mag, phase, wout] = bode(tf(b,a,1/(fs/2)));
subplot(2,1,1);
semilogx(wout(:,1)/(2*pi), 20*log10(squeeze(mag)), '-b'); zoom on; grid on;
axis tight
ylim([-40 0])
title('magnitude'); xlabel('Frequency (Hz)'); ylabel('Magnitude (dB)');
subplot(2,1,2);
semilogx(wout(:,1)/(2*pi), squeeze(phase), '-r'); zoom on; grid on;
axis tight
Matlab gives me something very different:
>> fs = 10000;
>> fc = 1000;
>> [b, a] = butter(2, 1000/10000)
b =
0.0201 0.0402 0.0201
a =
1.0000 -1.5610 0.6414
Further experiments
I tried to clone ruohoruotsi/Butterworth-Filter-Design.git and test with:
#include "Butterworth.h"
using namespace std;
int main() {
float fs = 20000;
float fc = 500;
int order = 2;
vector<Biquad> coeffs; // second-order sections (sos)
Butterworth butterworth;
bool designedCorrectly = butterworth.loPass(fs, fc, 0, order, coeffs, 1.0f);
std::cout << "Designed correctly? " << designedCorrectly << std::endl;
std::cout << "a = [" << 1.f << ", " << coeffs[0].a1 << ", " << coeffs[0].a2
<< "]" << std::endl;
std::cout << "b = [" << coeffs[0].b0 << ", " << coeffs[0].b1 << ", "
<< coeffs[0].b2 << "]" << std::endl;
}
It gives me:
a = [1, 1.77863, -0.800803]
b = [1, 2, 1]
Which again doesn't really fit.




I dont have access to Matlab, but on python
butter(2,.2) = [0.06745527, 0.13491055, 0.06745527], [ 1., -1.1429805, 0.4128016]and
butter(2,.1) = [0.02008337, 0.04016673, 0.02008337],[ 1. , -1.56101808, 0.64135154]So your values from Matlab are off by a factor of "2" on FF (I once made same mistake and posted a comment in Calculate Coefficients of 2nd Order Butterworth Low Pass Filter)
The "Butterworth.h" code has normalized the "b" values by multiplying by
(1.0 + q*ita + ita*ita). Your "a" values have minus signs compared to what Matlab, Scipy, and the original SO post use, I didnt check how that contributes too.