如何从fft结果中获取频率?

2022-09-01 10:40:21

我在Android手机上记录了一个来自麦克风的数据数组[1024],并通过真实数据的1D转发DFT传递(将1024位进一步设置为0)。我将数组保存到文本文件中,并重复了8次。

我得到了16384个结果。我在Excel中打开文本文件并制作了一个图表以查看它的外观(x=数组索引,y=返回的数字大小)。在110,232左右的震级上有一些巨大的峰值(正的和负的),小的峰值以这种方式持续到1817年和1941年左右,其中峰值再次变大,然后再次下降。

我的问题是,无论我在哪里寻求有关该主题的帮助,它都提到了实数和虚数,我只有一个1D数组,我从Piotr Wendykier的类中使用的方法中得到了它:

DoubleFFT_1D.realForwardFull(audioDataArray); // from the library JTransforms.

我的问题是:我需要对这些数据做些什么才能返回频率?录制的声音是我在吉他的底部弦(第5个音符)上演奏“A”(大约440Hz)。


答案 1

复数数据是交错的,实分量在偶数指数处,虚分量在奇数指数处,即实分量在索引处,虚分量在索引处。2*i2*i+1

要获得索引 i 处的频谱大小,您需要:

re = fft[2*i];
im = fft[2*i+1];
magnitude[i] = sqrt(re*re+im*im);

然后,您可以绘制i = 0到N / 2的幅度[i]以获得功率谱。根据音频输入的性质,您应该会在频谱中看到一个或多个峰值。

要获得任何给定峰值的近似频率,您可以按如下方式转换峰值的索引:

freq = i * Fs / N;

哪里:

freq = frequency in Hz
i = index of peak
Fs = sample rate in Hz (e.g. 44100 Hz, or whatever you are using)
N = size of FFT (e.g. 1024 in your case)

注意:如果您以前没有对时域输入数据应用合适的窗口函数,那么您将获得一定量的频谱泄漏,并且功率谱看起来相当“模糊”。


为了进一步扩展这一点,这里有一个完整的示例的伪代码,我们获取音频数据并识别最大峰值的频率:

N = 1024          // size of FFT and sample window
Fs = 44100        // sample rate = 44.1 kHz
data[N]           // input PCM data buffer
fft[N * 2]        // FFT complex buffer (interleaved real/imag)
magnitude[N / 2]  // power spectrum

// capture audio in data[] buffer
// ...

// apply window function to data[]
// ...

// copy real input data to complex FFT buffer
for i = 0 to N - 1
  fft[2*i] = data[i]
  fft[2*i+1] = 0

// perform in-place complex-to-complex FFT on fft[] buffer
// ...

// calculate power spectrum (magnitude) values from fft[]
for i = 0 to N / 2 - 1
  re = fft[2*i]
  im = fft[2*i+1]
  magnitude[i] = sqrt(re*re+im*im)

// find largest peak in power spectrum
max_magnitude = -INF
max_index = -1
for i = 0 to N / 2 - 1
  if magnitude[i] > max_magnitude
    max_magnitude = magnitude[i]
    max_index = i

// convert index of largest peak to frequency
freq = max_index * Fs / N

答案 2

推荐