用快速傅里叶变换分析音频

我正在尝试用 python 创建一个图形频谱分析仪。

我目前正在阅读1024字节的16位双通道44,100赫兹采样率音频流和平均振幅的2个通道在一起。现在我有一个256个签名短裤的数组。现在我想用 numpy 这样的模块在这个数组上预先形成一个 fft,然后用结果创建图形频谱分析仪,开始只有32个小节。

我已经阅读了维基百科关于快速傅里叶变换和离散傅里叶变换的文章,但我仍然不清楚最终的数组代表着什么。下面是我使用 numpy 在数组上预先生成 fft 之后数组的样子:

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
-2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
-1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
-4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
-2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
-2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
-1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
-1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
-2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

我想知道这些数字到底代表什么,以及如何将这些数字转换为32个酒吧的每一个高度的百分比。还有,我是不是应该把两个频道平均在一起?

62061 次浏览

what you have is a sample whose length in time is 256/44100 = 0.00580499 seconds. This means that your frequency resolution is 1 / 0.00580499 = 172 Hz. The 256 values you get out from Python correspond to the frequencies, basically, from 86 Hz to 255*172+86 Hz = 43946 Hz. The numbers you get out are complex numbers (hence the "j" at the end of every second number).

EDITED: FIXED WRONG INFORMATION

You need to convert the complex numbers into amplitude by calculating the sqrt(i2 + j2) where i and j are the real and imaginary parts, resp.

If you want to have 32 bars, you should as far as I understand take the average of four successive amplitudes, getting 256 / 4 = 32 bars as you want.

The array you are showing is the Fourier Transform coefficients of the audio signal. These coefficients can be used to get the frequency content of the audio. The FFT is defined for complex valued input functions, so the coefficients you get out will be imaginary numbers even though your input is all real values. In order to get the amount of power in each frequency, you need to calculate the magnitude of the FFT coefficient for each frequency. This is not just the real component of the coefficient, you need to calculate the square root of the sum of the square of its real and imaginary components. That is, if your coefficient is a + b*j, then its magnitude is sqrt(a^2 + b^2).

Once you have calculated the magnitude of each FFT coefficient, you need to figure out which audio frequency each FFT coefficient belongs to. An N point FFT will give you the frequency content of your signal at N equally spaced frequencies, starting at 0. Because your sampling frequency is 44100 samples / sec. and the number of points in your FFT is 256, your frequency spacing is 44100 / 256 = 172 Hz (approximately)

The first coefficient in your array will be the 0 frequency coefficient. That is basically the average power level for all frequencies. The rest of your coefficients will count up from 0 in multiples of 172 Hz until you get to 128. In an FFT, you only can measure frequencies up to half your sample points. Read these links on the Nyquist Frequency and Nyquist-Shannon Sampling Theorem if you are a glutton for punishment and need to know why, but the basic result is that your lower frequencies are going to be replicated or aliased in the higher frequency buckets. So the frequencies will start from 0, increase by 172 Hz for each coefficient up to the N/2 coefficient, then decrease by 172 Hz until the N - 1 coefficient.

That should be enough information to get you started. If you would like a much more approachable introduction to FFTs than is given on Wikipedia, you could try Understanding Digital Signal Processing: 2nd Ed.. It was very helpful for me.

So that is what those numbers represent. Converting to a percentage of height could be done by scaling each frequency component magnitude by the sum of all component magnitudes. Although, that would only give you a representation of the relative frequency distribution, and not the actual power for each frequency. You could try scaling by the maximum magnitude possible for a frequency component, but I'm not sure that that would display very well. The quickest way to find a workable scaling factor would be to experiment on loud and soft audio signals to find the right setting.

Finally, you should be averaging the two channels together if you want to show the frequency content of the entire audio signal as a whole. You are mixing the stereo audio into mono audio and showing the combined frequencies. If you want two separate displays for right and left frequencies, then you will need to perform the Fourier Transform on each channel separately.

Although this thread is years old, I found it very helpful. I just wanted to give my input to anyone who finds this and are trying to create something similar.

As for the division into bars this should not be done as antti suggest, by dividing the data equally based on the number of bars. The most useful would be to divide the data into octave parts, each octave being double the frequency of the previous. (ie. 100hz is one octave above 50hz, which is one octave above 25hz).

Depending on how many bars you want, you divide the whole range into 1/X octave ranges. Based on a given center frequency of A on the bar, you get the upper and lower limits of the bar from:

upper limit = A * 2 ^ ( 1 / 2X )
lower limit = A / 2 ^ ( 1 / 2X )

To calculate the next adjoining center frequency you use a similar calculation:

next lower =  A / 2 ^ ( 1 / X )
next higher = A * 2 ^ ( 1 / X )

You then average the data that fits into these ranges to get the amplitude for each bar.

For example: We want to divide into 1/3 octaves ranges and we start with a center frequency of 1khz.

Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9

Given 44100hz and 1024 samples (43hz between each data point) we should average out values 21 through 26. ( 890.9 / 43 = 20.72 ~ 21 and 1122.5 / 43 = 26.10 ~ 26 )

(1/3 octave bars would get you around 30 bars between ~40hz and ~20khz). As you can figure out by now, as we go higher we will average a larger range of numbers. Low bars typically only include 1 or a small number of data points. While the higher bars can be the average of hundreds of points. The reason being that 86hz is an octave above 43hz... while 10086hz sounds almost the same as 10043hz.

FFT return N complex values which of you can compute the module=sqrt(real_part^2+imaginary_part^2). To get the value for each band you have to sum the modules about all harmonics inside the band. Below you can see an example about a 10 bars spectrum analyzer. The c code has to be wrapped to get a pyd python module.

float *samples_vett;
float *out_filters_vett;
int Nsamples;
float band_power = 0.0;
float harmonic_amplitude=0.0;
int i, out_index;


out_index=0;




for (i = 0; i < Nsamples / 2 + 1; i++)
{
if (i == 1 || i == 2 || i == 4 || i == 8 || i == 17 || i == 33 || i == 66 || i == 132 || i == 264 || i == 511)
{
out_filters_vett[out_index] = band_power;
band_power = 0;
out_index++;
}


harmonic_amplitude = sqrt(pow(ttfr_out_vett[i].r, 2) + pow(ttfr_out_vett[i].i, 2));
band_power += harmonic_amplitude;


}

I designed and made a whole 10 led bar spectrum analyzer by Python. Instead to use the nunmpy library (too big and useless to get just the FFT) a python pyd module (just 27KB) to get the FFT and to split the entire audio spectrum to bands was created.

In addition, to read the output audio a loopback WASapi portaudio pyd module was created. You can see the project (block diagram) in the image 10BarsSpectrumAnalyzerWithWASapi.jpg

Just added a tutorial video on my YouTube channel: how to design and make a very smart Python Spectrum Analyzer 10 Led Bar