I'm trying to create a LPF, using language JAVA. My first aim is to understand how filters design is working and the second one is to create a "home made" equalizer with "home made" filters.
To help me, I'm using EarLevel website for the formulas and to check my calculations results for the feedforward / feedback coefficients ; and
the introduction to digital filters by Julius O. Smith.
My input have is sampled at 44100 Hz and my Q=0.7071 (an approximation of 1/sqrt(2)) and I'm using the general formula :
$$y(n) = f_0 x(n) + f_1 x(n-1) + f_2 x(n-2) - b_1 y(n-1) - b_2 y(n-2)$$
with $f_0$ being the zeroth feed-forward coefficient, and so on, and $b_1$ being the first feed-back coefficient.
Edit : The coefficients are stored in a type "double".
In a first time, I set the center frequency at 10 000 Hz and it seems working. Then, I tried to lower the center frequency. When I reached around 7000 Hz, my output signal started to diverge after less than 30 "computations".
Here are my feedforward / feedback coefficients calculated for a 44100 Hz sampling signal with a central frenquency at 2000 Hz and Q = 0.7071 :
\begin{align} f_0 &= 0.016819123361395717\\ f_1 &= 0.033638246722791434\\ f_2 &= 0.016819123361395717\\ b_1 &= -1.601089848140876\\ b_2 &= 0.668366341586459 \end{align}
There are the same values thand those given by the site calculator so, I suppose they are correct.
But here is the input / output result after 20 signals sent to the filter :
Edit : The input datas are integers, representing the 16 bits input audio signal (from -32000 to +32000). The audio format used is a PCM_signed signal, sampled at 44100 Hz, 16 bits, 2 channels. I made test by comparison to check if the transformation PCM coded => integer => PCM coded was ok and, yes, it is ; so, the problem don't seems to come from there.
The output datas are stored in a double to keep the precision after the unit digit. Of course, I round them to an integer before sending them to the sound card.
id = 20 - input = -2997 output= -4511.426234017688
id = 21 - input = -3022 output= 97.52810634470279
id = 22 - input = -3506 output= -6592.151428768328
id = 23 - input = -3176 output= 2949.256088740449
id = 24 - input = -3272 output= -10840.64632338293
id = 25 - input = -3287 output= 8909.22977931816
id = 26 - input = -2555 output= -19536.606226891832
id = 27 - input = -3123 output= 21316.24417688955
id = 28 - input = -1890 output= -37414.30445881503
id = 29 - input = -2821 output= 47023.28302742664
id = 30 - input = -1497 output= -74302.58304596202
id = 31 - input = -2557 output= 100154.15317482647
(...)
id = 45 - input = -3401 output= 1.6528078507359352E7
id = 46 - input = -2367 output= -2.3763232415918328E7
id = 47 - input = -3865 output= 3.415084117779622E7
(...)
id = 2047 - input = 1971 output= Infinity
id = 2048 - input = 4435 output= -Infinity
id = 2049 - input = 2648 output= Infinity
What's wrong ? Why does that signal diverge ? And why around 7000 Hz ? A LPF should work for much lower frequencies if I want to redirect it to a subwoofer for example, isn't it ?
Thank you for your help...
Edit2 : Here are the methods I'm using to find the coefficients and the method I'm using to calculate the output.
protected int centerFrequency, samplingFrequency;
protected double settingFactor;
protected double feedforward0, feedforward1, feedforward2, feedback1, feedback2;
protected double normalized, coefK;
private int test=0;
public LowPassFilter(int samplingFrequency, int centerFrequency, double qualityFactor) {
super(samplingFrequency, centerFrequency, qualityFactor);
coefK=Math.tan(Math.PI*centerFrequency/samplingFrequency);
computeGains(settingFactor);
}
@Override
protected void computeGains(double qualityFactor) {
normalized= 1 / (1 + coefK / qualityFactor + coefK * coefK);
feedforward0 = coefK * coefK * normalized;
feedforward1 = 2 * feedforward0;
feedforward2 = feedforward0;
feedback1 = 2 * (coefK * coefK - 1) * normalized;
feedback2 = (1 - coefK / qualityFactor + coefK * coefK) * normalized;
System.out.println("LPF.computeGains : "+feedforward0+" ; "+feedforward1+" ; "+feedforward2+" ; "+feedback1+" ; "+feedback2);
}
And here is the routine :
protected LinkedList<Integer> inputValues2 = new LinkedList<Integer>();
protected LinkedList<Double> outputValues2 = new LinkedList<Double>();
public double process(int inputValue) {
// On renseigne la valeur d'entrée dans le tableau des valeurs d'entrées
inputValues2.removeFirst();
inputValues2.add(inputValue);
double outputValue= feedforward0*inputValues2.get(2) + feedforward1*inputValues2.get(1) + feedforward2*inputValues2.get(0) - feedback1*outputValues2.get(1) - feedback2*outputValues2.get(0);
outputValues2.removeFirst();
outputValues2.add(outputValue);
if ((test>0 && test<100) || (test>2030 && test<2050)) {
System.out.println("BiquadFilter.process - id = "+test+" - input = "+inputValues2.get(0)+" output= "+outputValues2.get(0) );
}
test++;
return outputValue;
}