I need to design a lowpass FIR filter to downsample an audio stream that is oversampled at 250Khz. The goal is to write a real-time audio player of an audio stream on an embedded system which is severely resource-constrained.
On this system, I don't have a DSP or FPGA available, it is a very slow CPU (MIPS 200Mhz) but with floating point instructions available. I'm familiar with code optimization, assembly and everything required to make sure the implementation is efficient, but I know almost nothing about filter design.
The output sampling rate for the stream should be 22050Hz (but anything in the range 20k-25k would do, because I am in control of the DAC clock so I can configure it to any value up to 48Khz -- but I'd rather stay in the 20-25K range of output sampling rate anyway unless this proves to be complex from a filter design standpoint).
I would also note that I don't need this system to produce high-fidelity audio like a CD; I would say that something that sounds like a low bitrate MP3 is OK. Just to give another reference point, I have already attempted to decimate my stream with factor M=11 by simply averaging each window of 11 consecutive samples, and I do get some aliasing as expected but it's not that bad -- it's not acceptable yet, but I was personally expecting much worse results for this very simple downsampling, while in reality it's actually pretty similar to the result I am looking for (though the aliasing is sometimes not acceptable).
By using an offline audio conversion tool on PC, I also verified that it's possible to downsample this audio stream to 22Khz and obtain audio quality that is good enough for my goals, and without aliasing -- I just need to understand how to do this in realtime on my embedded system, if possible.
The FIR filter must be very efficient because I'm doing real-time processing, so hopefully the number of taps should be quite small. I do not know right now what would be a target here: the fastest the best, because the system needs to do other processing in background. I was personally hoping something in the range of 10-20 taps, but honestly I have not benchmarked this yet. I would like to understand the compromises I get into and maybe running some experiments with different filters, to find a good balance between audio quality and performance.
I have close to zero understanding of the theory of signal processing, though I know something about the programming side of it (eg: if you give me the coefficients, I know how write a FIR filter).
Reading this page: https://dspguru.com/dsp/faqs/multirate/decimation/ I understand that I need to design this FIR filter first, and then decimate my stream.
I am thus attempting to create a decimation filter with M=11 (250000/11 ~= 22727, which is near to my desired output sampling rate). I've read other resources that tell me that it's better to use multistage cascading filters, but I would like to keep it simple for now, at least to get a basic understanding first.
The part that I cannot follow of that page is this:
The passband lower frequency is zero; the passband upper frequency is whatever information bandwidth you want to preserve after decimating. The passband ripple is whatever your application can tolerate.
The stopband lower frequency is half the output rate minus the passband upper frequency. The stopband attenuation is set according to whatever aliasing your application can stand. (Note that there will always be aliasing in a decimator, but you just reduce it to a negligible value with the decimating filter.)
As with any FIR, the number of taps is whatever is required to meet the passband and stopband specifications.
I have no clue how to convert these insights into a coefficient list I can use for the filter. I tried playing a bit with this simple online tool:
but I am not sure what numbers to input. This is where I got:
- Sampling freq: this is my input sampling freq, which is 250Khz.
- In the passband filter, I put "0 hz" in "From", but I don't know what to put in "To". The page linked above says "the passband upper frequency is whatever information bandwidth you want to preserve after decimating". Should this be 22050 Hz? I guess not, but I don't know.
- Passband ripple: the page says "whatever your application can tolerate". Since I don't have any background on this, I can't understand what it is a good valute for this.
- Stopband lower frequency: the page advises me to input half of the output rate minus the passband upper frequency. I can calculate this once I know what the passband upper frequency should be.
- Stopband upper frequency: the page speaks about "stopband attenuation", it doesn't mention "upper frequency". So I don't know what to input here.
- Stopband ripple: no explicit mention in the page, at least that I can understand.
Thank you in advance for any insights you can give me.
EDIT: as requested, I'm attaching a picture of the spectrum of an example stream: