Downsampling and applying a lowpass filter to digital audio

后端 未结 10 835
北恋
北恋 2021-02-02 17:41

I\'ve got a 44Khz audio stream from a CD, represented as an array of 16 bit PCM samples. I\'d like to cut it down to an 11KHz stream. How do I do that? From my days of engine

相关标签:
10条回答
  • 2021-02-02 18:20

    You need to apply a lowpass filter before you downsample the signal to avoid "aliasing". The cutoff frequency of the lowpass filter should be less than the nyquist frequency, which is half the sample frequency.

    0 讨论(0)
  • 2021-02-02 18:21

    Read on FIR and IIR filters. These are the filters that use a coefficent array.

    If you do a google search on "FIR or IIR filter designer" you will find lots of software and online-applets that does the hard job (getting the coefficients) for you.

    EDIT:

    This page here ( http://www-users.cs.york.ac.uk/~fisher/mkfilter/ ) lets you enter the parameters of your filter and will spit out ready to use C-Code...

    0 讨论(0)
  • 2021-02-02 18:22

    The process you're after called "Decimation". There are 2 steps:

    1. Applying Low Pass Filter on the data (In your case LPF with Cut Off at Pi / 4).
    2. Downsampling (In you case taking 1 out of 4 samples).

    There are many methods to design and apply the Low Pass Filter.

    You may start here:

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

    0 讨论(0)
  • 2021-02-02 18:23

    The "best" solution possible is indeed a DFT, discarding the top 3/4 of the frequencies, and performing an inverse DFT, with the domain restricted to the bottom 1/4th. Discarding the top 3/4ths is a low-pass filter in this case. Padding to a power of 2 number of samples will probably give you a speed benefit. Be aware of how your FFT package stores samples though. If it's a complex FFT (which is much easier to analyze, and generally has nicer properties), the frequencies will either go from -22 to 22, or 0 to 44. In the first case, you want the middle 1/4th. In the latter, the outermost 1/4th.

    You can do an adequate job by averaging sample values together. The naïve way of grabbing samples four by four and doing an equal weighted average works, but isn't too great. Instead you'll want to use a "kernel" function that averages them together in a non-intuitive way.

    Mathwise, discarding everything outside the low-frequency band is multiplication by a box function in frequency space. The (inverse) Fourier transform turns pointwise multiplication into a convolution of the (inverse) Fourier transforms of the functions, and vice-versa. So, if we want to work in the time domain, we need to perform a convolution with the (inverse) Fourier transform of box function. This turns out to be proportional to the "sinc" function (sin at)/at, where a is the width of the box in the frequency space. So at every 4th location (since you're downsampling by a factor of 4) you can add up the points near it, multiplied by sin (a dt) / a dt, where dt is the distance in time to that location. How nearby? Well, that depends on how good you want it to sound. It's common to ignore everything outside the first zero, for instance, or just take the number of points to be the ratio by which you're downsampling.

    Finally there's the piss-poor (but fast) way of just discarding the majority of the samples, keeping just the zeroth, the fourth, and so on.

    Honestly, if it fits in memory, I'd recommend just going the DFT route. If it doesn't use one of the software filter packages that others have recommended to construct the filter for you.

    0 讨论(0)
提交回复
热议问题