I've implemented a very simple first order recursive low pass filter in c using the algorithm:
double a, b, prevOutput;
double lowPassFilter(double input)
{
double output = a * input + b * prevOutput;
prevOutput = output;
return output;
}
where:
a = 1.0 - b
According to The Scientist and Engineer's Guide to Digital Signal Processing, the cutoff frequency of the filter is defined by the relation:
$$b = e^{-2πf_c}$$
$f_c$ is the -3db cutoff frequency as a fraction of the sampling frequency. Using $f_c = 0.25$, I calculated that $b = 0.20788$ (approximately) and plugged it into my filter. I wanted to verify my filter, so I passed an impulse function through it and recorded the output:
double result[128];
for (int i = 0; i < 128; ++i)
{
if (0 == i) result[i] = lowPassFilter(1.0);
else result[i] = lowPassFilter(0.0);
}
I then performed FFT on the result to find the frequency response:
complex_t fftResult* = fft(result);
for (int i = 0; i < 65; ++i)
{
double amplitude = fftResult[i].real * fftResult[i].real;
amplitude += fftResult[i].img * fftResult[i].img;
amplitude = sqrt(magnitude);
printf("f = %.3f: %f\n", i / 128.0, amplitude );
}
The result I saw was somewhat expected but also not exactly what I expected. In the DC bin ($f = 0$) I saw a amplitude very close to one and I saw the amplitude attenuate as it approached 0.5. However, I also expected that at $f = 0.25$ the amplitude should have been around $0.70795$ (i.e. -3db). but instead the amplitude was around $0.775$:
...
f = 0.242: 0.782501
f = 0.250: 0.774971
f = 0.258: 0.767380
...
Aside from the inefficient code, is there something wrong with the method I am using to obtain the frequency response or am I interpreting the cut-off frequency relation incorrectly or something else?
Answer
That formula for the cut-off frequency is a very inaccurate approximation. In this answer I derived the exact relation between the coefficient of a first order recursive averaging filter and its 3-dB cut-off frequency. Note that in the quoted answer I used the constant $\alpha=1-b$. From formula $(3)$ in that answer we get for the coefficient $b$
$$b = 2-\cos(\omega_c)-\sqrt{(2-\cos(\omega_c))^2-1)}\tag{1}$$
With $\omega_c=2\pi f_c$ we get for $f_c=0.25$ a value $b=0.26795$.
The frequency response of the filter is given by
$$H(e^{j\omega})=\frac{1-b}{1-be^{-j\omega}}\tag{2}$$
The figure below shows the magnitude response $|H(e^{j\omega})|$, and it shows that the desired cut-off frequency is achieved with the chosen value of $b$:
Note that the 'EDIT' part of the answer quoted above also explains where the inaccurate formula for the cut-off frequency comes from. The following figure shows the resulting cut-off frequency of the filter as a function of the desired cut-off frequency when the exact formula $(1)$ is used and when the approximation is used:
Clearly, the approximation is quite bad and it only kind of works for very small cut-off frequencies. I see no reason why it should be used at all.
No comments:
Post a Comment