Programming a low-pass filter

[亡魂溺海] 提交于 2019-12-04 05:03:00

EDIT: I have included a filter implementation below that answers your question as asked. However, implementing a high order filter with a signal at such a high sample rate is going to consume many, many millions of operations per second. It might be best if you do a spectrum analysis of the output of the chip first. If there is no sound energy above a few kHz then the anti-aliasing filter is a waste of processing resources. Even if there is energy up to moderately high frequencies, it may be worth decimating the signal first, then filtering before applying the second stage decimation. As a side note, you might also want to decimate down to a much lower rate than 44.1 kHz. You'd probably be fine with an 8- or 10-kHz sample rate for a master system emulator (we're not talking hi-fi here). But anyway, to answer your question about how to implement a low-pass filter with the sampling rate and cutoff that you specify . . .

Ok, firstly to design a lowpass filter. The matlab decimate function sounds good to my ears so we will copy that approach for this example. The documentation says the following

The decimated vector y is r times shorter in length than the input vector x. By default, decimate employs an eighth-order lowpass Chebyshev Type I filter with a cutoff frequency of 0.8*(Fs/2)/r. It filters the input sequence in both the forward and reverse directions to remove all phase distortion, effectively doubling the filter order.

Cheby filters are a good choice as they have a steeper rejection than Butterworth designs at the expense of a little passband ripple. We cannot do IIR filtering in both directions in a real time system, but this should be ok for your purposes. We can make the filter coefficients using the following Matlab code . . . .

sr = 221e3;
srDesired = 44.1e3;
order = 8;
passBandRipple = 1; %//dB

Wp = 0.8 * (srDesired/2) / (sr/2);

[b,a] = cheby1 (order, passBandRipple, Wp, 'low');

freqz(b,a,[],sr, 'half');

sos = tf2sos(b,a)

This gives us an 8th order IIR filter with a response like the following. This looks like what we want. The phase response is unimportant for this application. The cutoff is 0.8* 22.050 kHz as you want the signal near to the Nyquist limit to be well attenuated before decimation.

The tf2sos command at the end converts the filter that we have just created into second order sections that you can realise using a cascade of biquad filter sections. The output of this command is as follows . . .

SECTION A

b=1.98795003258633e-07, 3.97711540624783e-07, 1.98854354149782e-07,
a=1 -1.81843900641769, 0.835282840946310

SECTION B

b=1, 2.02501937393162, 1.02534004997240,
a=1, -1.77945624664044, 0.860871442492022

SECTION C

b=1, 1.99938921206706, 0.999702296645625,
a=1, -1.73415546937221, 0.907015729252152

SECTION D

b=1, 1.97498006006623, 0.975285456788754,
a=1, -1.72600279649390, 0.966884508765457

Now, you can use these filter coefficients for each biquad stage in the filter cascade. You can realise this filter using code like the that in the following example. It is C code, but you should be able to convert it to java pretty easily. Note that there is no a0 coefficient in the code below. The second order sections above are correctly normalised so that a0 always equals 1. Just leave it out.

//Make the following vars private members of your filter class
// b0, b1, b2, a1, a2 calculated above
// m1, m2 are the memory locations
// dn is the de-denormal coeff (=1.0e-20f) 

void processBiquad(const float* in, float* out, unsigned length)
{
    for(unsigned i = 0; i < length; ++i)
    {
        register float w = in[i] - a1*m1 - a2*m2 + dn;
        out[i] = b1*m1 + b2*m2 + b0*w;
        m2 = m1; m1 = w;
    }
    dn = -dn;
}

You should make a class for this filter and then instantiate 4 separate classes (1 for each filter), setting the a, and b values to those specified above. Next, hook the input of one stage to the ouput of the next to give you your cascade.

http://en.wikipedia.org/wiki/Butterworth_filter

C code generator: http://www-users.cs.york.ac.uk/~fisher/mkfilter/ (should be translatable to Java easily enough)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!