如何使用FFT计算数据频率?

时间:2010-11-19 13:29:39

标签: algorithm c#-3.0 signal-processing fft

我想知道数据的频率。我有点想到它可以使用FFT完成,但我不知道该怎么做。一旦我将整个数据传递给FFT,它就会给我2个峰值,但我怎样才能获得频率?

提前多多感谢。

6 个答案:

答案 0 :(得分:10)

假设x[n] = cos(2*pi*f0*n/fs)其中f0是赫兹的正弦波频率,n=0:N-1fs是每秒样本中x的采样率

X = fft(x)xX都有N的长度。假设Xn0N-n0处有两个峰值。

然后正弦波频率f0 = fs*n0/N赫兹。

示例fs =每秒8000个样本,N = 16000个样本。因此,x持续两秒钟。

假设X = fft(x)在2000和14000(= 16000-2000)处有峰值。因此,f0 = 8000 * 2000/16000 = 1000 Hz。

答案 1 :(得分:8)

以下是您可能正在寻找的内容:

当你谈到计算信号的频率时,你可能对组件正弦波不太感兴趣。这就是FFT给你的。例如,如果你总和sin(2 * pi * 10x)+ sin(2 * pi * 15x)+ sin(2 * pi * 20x)+ sin(2 * pi * 25x),你可能想要检测“频率” “为5(看看这个功能的图表)。但是,该信号的FFT将检测频率为5的 0 的幅度。

您可能更感兴趣的是信号的周期性。也就是说,信号变得最像自己的间隔。所以你最想要的是 autocorrelation 。仔细看看。这基本上可以衡量信号在被移位一定量后自身与自身相似的程度。因此,如果您在自相关中找到一个峰值,那么这表明信号在移动超过该量时与自身匹配良好。它背后有很多很酷的数学,如果你有兴趣可以查阅,但如果你只想让它工作,那就这样做:

  1. 使用平滑窗口(余弦将会这样做)窗口信号。窗口应该至少是您想要检测的最大周期的两倍。大3倍会产生更好的结果)。 (如果您感到困惑,请参阅http://zone.ni.com/devzone/cda/tut/p/id/4844)。

  2. 采用FFT(但是,确保FFT大小是窗口的两倍,后半部分用零填充。如果FFT大小只是窗口的大小,你将有效地采取循环自相关,这不是你想要的。见https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Circular_convolution_theorem_and_cross-correlation_theorem

  3. 用其平方值(real ^ 2 + imag ^ 2)替换FFT的所有系数。这实际上是在进行自相关。

  4. 参加iFFT

  5. 找到iFFT中最大的峰值。这是波形的最强周期。实际上你可以更聪明地选择哪个峰值,但对于大多数用途来说,这应该足够了。要查找频率,只需f = 1 / T.

答案 2 :(得分:6)

如果您有一个频率的信号(例如:

y = sin(2 pi f t)

使用:

  • y time signal
  • f中心频率
  • t time

然后你会得到两个峰值,一个频率对应于f,另一个频率对应-f。

因此,要达到一个频率,可以丢弃负频率部分。它位于正频率部分之后。此外,数组中的第一个元素是直流偏移,因此频率为0.(请注意,此偏移量通常远大于0,因此其他频率成分可能会相形见绌。)

在代码中:(我在python中编写它,但在c#中应该同样简单):

import numpy as np
from pylab import * 
x = np.random.rand(100) # create 100 random numbers of which we want the fourier transform
x = x - mean(x) # make sure the average is zero, so we don't get a huge DC offset.
dt = 0.1 #[s] 1/the sampling rate
fftx = np.fft.fft(x) # the frequency transformed part
# now discard anything  that we do not need..
fftx = fftx[range(int(len(fftx)/2))]
# now create the frequency axis: it runs from 0 to the sampling rate /2
freq_fftx = np.linspace(0,2/dt,len(fftx))
# and plot a power spectrum
plot(freq_fftx,abs(fftx)**2)
show()

现在频率位于最大峰值。

答案 3 :(得分:4)

如果您正在查看最常用类型的FFT的幅度结果,那么实际数据的强正弦频率分量将显示在两个位置,一个位于下半部分,加上其复共轭镜像上半部分。这两个峰值都代表相同的光谱峰值和相同的频率(对于严格的实际数据)。如果FFT结果bin编号从0(零)开始,则FFT结果的下半部分中由bin表示的正弦分量的频率最有可能。

Frequency_of_Peak = Data_Sample_Rate * Bin_number_of_Peak / Length_of_FFT ;

确保在上述等式中找出合适的单位(获得每秒周期单位,每两周,每千克等)。

请注意,除非数据的波长是FFT长度的精确整数的约数,否则实际峰值将在二进制位之间,从而在多个附近的FFT结果二进制位之间分配能量。因此,您可能需要进行插值以更好地估计频率峰值。寻找更精确的频率估计的常见插值方法是3点抛物线和Sinc卷积(这与使用零填充更长的FFT几乎相同)。

答案 4 :(得分:1)

假设您使用离散傅里叶变换来查看频率,那么您必须注意如何将归一化频率解释为物理频率(即Hz)。

根据FFTW tutorial关于如何计算信号的功率谱:

#include <rfftw.h>
...
{
     fftw_real in[N], out[N], power_spectrum[N/2+1];
     rfftw_plan p;
     int k;
     ...
     p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
     ...
     rfftw_one(p, in, out);
     power_spectrum[0] = out[0]*out[0];  /* DC component */
     for (k = 1; k < (N+1)/2; ++k)  /* (k < N/2 rounded up) */
          power_spectrum[k] = out[k]*out[k] + out[N-k]*out[N-k];
     if (N % 2 == 0) /* N is even */
          power_spectrum[N/2] = out[N/2]*out[N/2];  /* Nyquist freq. */
     ...
     rfftw_destroy_plan(p);
}

请注意,它处理的数据长度不均匀。请注意,如果给出数据长度,FFTW将为您提供与奈奎斯特频率相对应的“bin”(采样率除以2)。否则,你没有得到它(即最后一个箱子就在Nyquist之下)。

MATLAB example类似,但他们选择的长度为1000(偶数):

N = length(x);
xdft = fft(x);
xdft = xdft(1:N/2+1);
psdx = (1/(Fs*N)).*abs(xdft).^2;
psdx(2:end-1) = 2*psdx(2:end-1);
freq = 0:Fs/length(x):Fs/2;

通常,它可以是(DFT)的实现依赖。您应该以已知频率创建测试纯正弦波,然后确保计算得到相同的数字。

答案 5 :(得分:-7)

频率=速度/波长。

波长是两个峰值之间的距离。