【问题标题】:power spectral density from fft result c#来自fft结果的功率谱密度c#
【发布时间】:2017-08-06 00:33:48
【问题描述】:

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

Complex 有一个float real 和一个float imaginary

据此我计算了以下

  • 频率:(double)index * sampleRate / FftSize;
  • 幅度/幅度:Math.Sqrt(Math.Pow(real, 2) + Math.Pow(imaginary, 2));
  • 阶段:Math.Atan(imaginary / real);

如有错误请指正。

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

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

【问题讨论】:

标签: c# matlab signal-processing fft spectral-density


【解决方案1】:

确实,正如我在this other answer 中所述,您可以通过平方 FFT 结果的幅度来获得功率谱密度 (PSD) 估计值。这基本上是您引用的Matlab documentation 中的以下行的状态(达到比例因子,这对于大多数只需要比较不同频率分量的相对强度的应用来说并不重要):

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

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

注意: 对于包含输入 [-pi,pi] 范围的 Math.Atan2(imaginary, real)(请参阅 Math.Atan2 on MSDN),您会得到更好的服务(而不是仅覆盖 [-pi/2,pi/2]Math.Atan() )。

【讨论】:

  • 我不太确定如何使用窗口。我了解 hann(0.50f * (1 - (float)Math.Cos((2 * Math.PI * n) / N - 1))) 的公式,但我必须在我的 wave 上使用 fft 之前的窗口?
  • 如果你只使用Complex.Phase property它已经使用Math.Atan2(b, a)作为复数a + bi
  • @GertKommer 是的,如果您的波形中有 N 个样本,您可以将元素乘以窗口函数,然后对结果进行 FFT。
  • 我有一个float[] buffer1,其中包含 10 毫秒的数据。我只需要创建一个新的float[] buffer2 来保存buffer1 * window 的值。所以如果buffer1[0] == 5和窗口函数的输出是2而不是buffer2[0] = 10等等
【解决方案2】:

首先Math.Sqrt(Math.Pow(real, 2) + Math.Pow(imaginary, 2)); 已经实现为Complex.Magnitude property。或者您可以使用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,你不需要那个。

【讨论】:

  • 我使用的不是标准的Complex类,而是CsCore的Complex类。可悲的是,没有幅度和相位。至于你的其余答案,我真的不知道该怎么办。
  • 有时值得将一种类型转换为另一种类型以便能够使用更多功能;)但我想说的是:首先确定绝对/幅度(我看到:在 CsCore 中它被称为Complex.Value) - 有一个平方根 - 然后对结果进行平方是非常低效的。
  • 我很惭愧我没有看到Complex.Value。对于 PSD,我确实必须对幅度进行平方,然后 Complex.Value 或我自己的 writen 函数比 Sys 数字更快?
  • Math.Pow(a[i].Real, 2) + Math.Pow(a[i].Imaginary, 2)Math.Pow(a[i].Value, 2) 快。自己写一个比较测试是一个很好的练习:)
  • 好吧,a[i].Value 也有一个 sqrt 而另一个没有,所以它更快并不是一个惊喜。关于自己比较不同方法的好建议。老实说,我没有这样做,因为我对实现的工作方式更感兴趣,在以后的阶段我会担心性能并开始优化。但仍然感谢提示:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-17
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多