来自 fft 结果的功率谱密度 c#

power spectral density from fft result c#

我有一个 Complex[](来自 CsCore),这是我的 FFT 的结果。

Complex 有一个 float real 和一个 float imaginary.

由此我计算出以下

如有错误请指正

据我了解,这是频域信息,它让我可以看到哪些频率在我的样本中最常见。现在我想查看随时间变化的功率密度。 Matlab documentation 显示了示例,但是我不了解它,因为我不会 Matlab。有人可以解释有关此主题的 Matlab 文档或帮助我实现 C# 吗?

编辑:
This answer 建议简单地平方振幅。对吗?

确实,正如我在 this other answer you could obtain a power spectrum density (PSD) estimate by squaring the amplitudes of the FFT results. This is essentially what the following line from the Matlab documentation 中所述,您引用了状态(达到比例因子,这对于大多数只需要比较不同频率分量的相对强度的应用程序来说并不重要):

psdx = (1/(Fs*N)) * abs(xdft).^2;

正如我在其他答案中也提到的,并且在 Matlab 文档中也有描述,您可以通过在进行 FFT 之前将信号乘以 window function 并对平方进行平均来获得更好的 PSD 估计 -多个 FFT 结果的幅度。

注意: 对于阶段,您最好使用 Math.Atan2(imaginary, real)(请参阅仅涵盖 [-pi/2,pi/2]Math.Atan2 on MSDN) which covers the enter [-pi,pi] range (instead of Math.Atan())。

首先 Math.Sqrt(Math.Pow(real, 2) + Math.Pow(imaginary, 2)); 已经实现为 Complex.Magnitude property. Or you can use the Complex.Abs method

除了SleuthEye说的,我还对功能实现做了一些测量。

因为我不信任我实现的Math.Pow(x,2)功能:

private static double Square(double value)
{
    return value * value;
}

不过,事实证明C#已经优化了Math.Pow(x,2),所以它足够快了。但无论如何:接下来我比较了三个实现

  1. Square(testData[idx].Real) + Square(testData[idx].Imaginary);
  2. Square(testData[idx].Magnitude);
  3. Square(Complex.Abs(testData[idx]));

我的(平均)结果是(对于 10,000,000 个复杂元素):

  1. 45 毫秒
  2. 220 毫秒
  3. 211 毫秒

所以看起来 Magnitude 属性 和 Abs 方法在内部使用平方根,这需要很多周期来处理。但是对于 PSD 你不需要那个。