如何解释这些 FFT 结果?

信息处理 fft
2022-01-29 16:01:10

我最近开始使用MathNet.Numerics,我的需求之一是对肌电信号进行 FFT 分析。

我做的第一个测试是在 2kHz 下获得大约 15 秒的信号,它是这样绘制的:

在此处输入图像描述

我有一个前段时间写的 Python 脚本,生成的 FFT 谱如下:

lenfft = len(signal)/2.
nyq = 2000/2.
freq_axis = numpy.linspace(0, nyq, lenfft+1)
spectrum = numpy.abs(numpy.fft.rfft(signal))
plt.plot(freq_axis, spectrum)
plt.show()

在此处输入图像描述

问题是,当我使用 MathNet.Numerics 时,我得到了一个奇怪的结果(下面的代码和图像):

Complex[] signal = ArrayOfDoublesFromFile()
                        .Select(val => new Complex(val, 0))
                        .ToArray();

Fourier.Forward(signal, FourierOptions.Default); // inplace

SaveToFile(signal);

在此处输入图像描述

我知道如果输入是纯实数,输出应该是对称的或类似的东西,但由于Fourier.Forward()需要一个MatNet.Numerics.Complex[]数组,我正在创建一个虚部设置为零的数组,并且只使用结果的实部进行绘图,那是对的吗?

所以,问题是: 生成的输出的含义是什么,MathNet.Numerics.Fourier.Forward()如果我想要一个最常与 FFT 相关的视觉形式的结果,即中间图,我应该做什么?

3个回答

请注意第三个图中的对称性。这告诉我 MathNet.Numerics FFT 正在计算全频 FFT(正频率和负频率),并绘制 FFT 结果,其中零赫兹应该是水平轴的中心。然而,问题#1,由于某种原因,水平轴的标签在中心没有零赫兹。我无法解释。问题#2,第三个图中的“平顶”光谱形状存在很大问题。问题#3,在我看来,您的第三个图应该具有幅度为 10 的 15 次方的频谱分量。(看看你的第一个图,我希望你的光谱幅度结果大约是 10 的 7 次方。)用技术术语来说,你的第三个图是“真正的 FUBAR”。

heltonbiker 的答案是让您准确、非常详细地确定在您的 MathNet.Numerics FFT 和绘图例程中正在发生什么处理。祝你好运。

通常对于频谱分析,幅度是绘制 fft 输出的图。因此,在您的示例 python 代码中采用 fft 输出的绝对值。fft 背后的数学期望输入很复杂,但我们通常只输入实数值,但这没关系。通过仅输出实数,您只需查看包含信号的余弦波中的能量估计值,而忽略正弦波。幅度是平方根、总和、平方(实部和虚部)的平方根。

对于那些在 math.net 上遇到同样问题的人。在将来

1) 在你得到你的傅立叶结果/输出之后,而不是这个:

var nth_Val = signal[i].real  ;  // this is wrong 

用这个:

var nth_Val = signal[i].Magnitude          ; // real amplitude  

即使您使用虚部 0.0 值发送输入。输出包含您需要 square_root(real^2 + imaginary^2) 或使用相同的 maqnitude 的虚数部分。


如果第一个选项不起作用,请执行以下操作:

2) 向前给出了均匀的电平幅度。所以我用了逆。这给了我更好的音频峰值幅度结果。

 Fourier.Inverse( fftData, FourierOptions.Matlab );

我的完整片段

  var fftData = new  Complex[  44100 ];  //(int) Math.Pow( 2,16)
  for (int i = 0; i < fftData.Length ; ++i)
  {
     // Fill the complex data
     fftData[i] = new Complex( data[ 1300 + i ] , 0 ) ; 
  }

  // FFT the time domain data to get frequency domain data
  Fourier.Inverse( fftData, FourierOptions.Matlab );

  //fftData now has results. but it contains "result+result_mirror"
  // so we take the first half of fftData
  var result = fftData
                  .Select( x => x.Magnitude )
                  .Take(fftData.Length / 2).ToArray();