功率谱密度估计 (PSD)

信息处理 fft stft 功率谱密度
2022-02-08 14:30:41

我正在尝试了解 PSD,以及它的功能。

到目前为止,我已经执行了以下操作:

  • NFFT = 256用和分割信号hop_size = 128
  • 对这些段中的每一个进行窗口化(汉明)
  • 每个窗口的 DFT
  • 取结果矩阵的前半部分(n/2+1)

从我目前所阅读的内容来看,该算法可以最好地描述如下:

我们取 LENGTH 的平方大小NFFT,我们通过以下方式计算mag = (bin.re * bin.re + bin.im * bin.im)这给出了 DFT bin 中每个点的大小。

Q1:这些是“平均”形成Pxx Pxx的,是我假设存储平均值的大小的 bin NFFT/2+1,但是,这些存储每个 bin 的平均值吗?因为不太明白:

如果我有一个包含值的二维矩阵:

a = [[1, 2, 3, 4, 5, 6, 9, 8],
     [2, 5, 8, 9, 7, 8, 9, 7],
     [4, 5, 6, 4, 7, 8, 9, 8]

然后我取这些的“平均值”.. 即 (1+2 ....., n)/NFFT/2+1。对于每个垃圾箱,这只会给出一个值?

好的,现在进入缩放。因此,我们可以扩展到频率吗?如果是这样,我们是否按比例缩放Fs * window_size

编辑:

我认为我的最后一个问题没有那么有意义..

到目前为止,我有一个包含146x128..

block1 = [1, 2, 3, ...... n] (where `n` is 128) 

block2 = [0, 5, 6, ...... n] 

.....

block146 = [1, 4, 5, .... n]

现在,如果我计算每个块的平均幅度,即sum(sqrt(re*re+im*im))/128这将为我提供每个块的平均值(包含 146 个样本的向量)。

对于我的每个样本,blocks我是否因此将每个样本除以该特定块的平均幅度?IE

block1 = [0, 1, 2, ...... n]
average = (0+1+2)/128 = 0.58 (for example)

result = [0/0.58, 1/0.58, 2/0.58.... n]

因此,我得到的向量仍然是二维向量。

这有意义吗?

编辑:

1 - 你想处理什么类型的信号?即:它是什么类型的应用程序?它是一维信号吗,例如以 44.1Khz 采样的音频?还是像图像或视频这样的多维信号?

我正在尝试处理音频信号。

到目前为止我所做的是:

采用一维输入向量,然后将该向量拆分为块(大小256与此重叠/跳跃128给我总共 146 个块,每个块包含 128 个样本。这些样本已乘以汉明窗,然后 DFT 有被通过了。

这些块包含窗口化和 DFT 发生后的结果值。

2 - 你在哪里进行这些计算?Matlab、Octave、python 还是其他?

我正在使用 C++ 执行这些计算

3 - 当您说 2D 向量(称其为矩阵可能会更容易混淆)时,里面的数字是什么意思?什么是列,什么是行?

列和行包含每个块的汉宁窗的 DFT 结果256/2 = 128

本质上,我试图做的是创建一个频谱图。目前,我可以用值的幅度绘制频谱图,即(re*re+im*im),我想绘制整体功率谱(PSD),而不是绘制幅度,以便我可以确定功率主要在信号内的位置。

如果我这样做,matplotlib我可以得到以下结果:

在此处输入图像描述

所以理论上,magnitudes我不想显示我目前正在做的事情,而是想显示 PSD(如图所示)。我查看了 matplotlib 源代码,这是给出的:

result, windowVals = apply_window(result, window, axis=0,
                                  return_window=True)
result = np.fft.fft(result, n=pad_to, axis=0)[:numFreqs, :]

result = np.conjugate(result) * result

# for PSD
result /= (np.abs(windowVals)**2).sum()

result[1:-1] *= scaling_factor

# where scaling_factor is either 1 or 2

对我来说,上面的代码看起来像是取 WindowValues 的平方和(即 Hamming),然后将每个值除以result(即生成的 DFT),最后乘以比例因子。

这看起来正确吗?

1个回答

首先,当您说“采用结果矩阵的前半部分(n / 2 + 1)”时,您是什么意思?

FFT 将产生一个向量,但也许您的意思是只取 FFT 样本的前半部分,因为其他样本是负频率,因此是多余的?

无论如何,你描述的过程实际上是正确的,不需要做任何其他事情。在您使用结果矩阵 a 的示例中,您显然采用了大小为 8 的 FFT(如果您随后切掉了它的后半部分,则为 16)。但是你所做的只是取这些向量的所有第一个数字的平均值,这将是 f = 1*fs/NFFT 处的功率谱密度的估计。取所有第二个数字的平均值将是 f = 2*fs/NFFT 等处的 PSD 估计值。

在示例中,PDS 将是

PSD = 1/3*[(1+2+4) , (2+5+5) ,(3+8+6) , ... ];

当您在执行计算时进行实时分析时,如果信号是广义平稳的,那么它应该收敛或悬停在某个值附近,但如果不是,它会随着时间的推移而偏离以适应新的统计数据的信号。

如果我理解正确的话,应该是这样。

编辑:哎呀,我忘记了重要的比例因子。应引入比例因子以保留 PSD 与其变换(自相关)之间的解析定理。如果您首先对信号进行窗口化,我认为您应该应用比例因子 1/sum(W*fs/NFFT),其中 W 是您的窗口向量。因为您只是在频域中除以窗口函数的积分,所以当您首先通过窗口进行 FFT 时,这就是您添加到频率分量估计中的内容。因为仅 FFT 就已经保存了能量。

编辑2:

我对二维的东西更加困惑。让我试着问你几个问题:

1 - 你想处理什么类型的信号?即:它是什么类型的应用程序?它是一维信号吗,例如以 44.1Khz 采样的音频?还是像图像或视频这样的多维信号?

2 - 你在哪里进行这些计算?Matlab、Octave、python 还是其他?

3 - 当您说 2D 向量(称其为矩阵可能会更容易混淆)时,里面的数字是什么意思?什么是列,什么是行?

4 - 你检查到 mathworks 的链接了吗?我想你会发现你正在尝试做的事情,在那里得到了很好的解释。

此外,为了确保您充分理解背景,您可以参考一些对主题进行了很好解释的经典书籍:

  • 数字信号处理、原理、算法和应用-Proakis & Manolakis - 第 3 版。通道。12

以及所有光谱估计书籍之父:

  • 信号的频谱分析- Stoica & Moses

编辑3:

啊,好的,现在我明白你想要做什么了。所以,事情就是这样。我快速阅读了 Stoica 和 Proakis 的书中关于 FFT 和 PSD 的部分,但仍然不太明白为什么他们提出 FFT 的比例因子仅为 1/N,而 PSD 的 matlab 函数使用周期图方法将 FFT 缩放 2/(Fs*N),即 N 为 FFt 的长度,在您的情况下为 256。

所以我不太了解 C++,但我会说执行以下操作:

1 - 取第一帧 X,它由 256 个音频信号样本组成。

2 - 对其应用 256 FFT。您获得 Xfft。

3 - 对于每个复数值 Xfft(i),对于 i = 0...255,执行 xfft(i)*conj(xfft(i)) 等于 abs(xfft(i))^2。这是你已经做过的,所以到目前为止没有什么新鲜事。

4 - 将整个向量 Xfft 乘以 2/(Fs*N)。

这将为您提供帧 X 的功率谱密度。现在获取下一帧并执行相同操作,当您达到要绘制的帧数时,您停止并绘制向量。

现在,由于您每 128 个样本获取帧,因此您在每个时间步的估计值将被挤在一起,因此您将使用的一个技巧是语音/音频信号在一个间隔内近似为广域静态 (WSS) 20-50 毫秒(参见语音增强 - Jacob Benesty)。所以你可以做的是假设你有一个 Fs = 44100,它给你一个 50 毫秒的周期,大约 2205 个样本。

使用您拍摄的帧的尺寸,您可以轻松平均 15 或 16 个重叠帧,并获得更平滑的 PSD 估计。但选择权在你,尝试一下,玩得开心!