需要解释specgram函数如何在python中工作(matplotlib - MATLAB兼容函数)

hoa*_*gpx 2 python signal-processing fft matplotlib spectrogram

我正在努力将我的代码从 python 转换为目标 c。在 matplotlib.mlab.specgram 函数中,我在 fft 之前看到了 3 个重要的函数:

 result = stride_windows(x, NFFT, noverlap, axis=0)
 result = detrend(result, detrend_func, axis=0)
 result, windowVals = apply_window(result, window, axis=0,
                                      return_window=True)
 result = np.fft.fft(result, n=pad_to, axis=0)[:numFreqs, :]
Run Code Online (Sandbox Code Playgroud)

我试图调试以了解每个的目的。例如我有输入数组:

x = [1,2,3,4,5,6,7,8,9,10,11,12]
Run Code Online (Sandbox Code Playgroud)

在第一个函数 stride_windows 之后(这个是为了防止泄漏?),如果 NFFT = 4,noverlap = 2 那么:

x = [ [1,3,5,7,9],
      [2,4,6,8,10],
      [3,5,7,9,11],
      [4,6,8,10,12] 
    ]
Run Code Online (Sandbox Code Playgroud)

在 detrend 之后没有任何变化(我了解 fft 之前的 detrend)

在 apply_window 里面(我不明白这一步):

    xshape = list(x.shape) 
    xshapetarg = xshape.pop(axis) // =4
    windowVals = window(np.ones(xshapetarg, dtype=x.dtype))
    //result of 4 elements [0.0, 0.75, 0.75, 0.0]
    xshapeother = xshape.pop() // =5
    otheraxis = (axis+1) % 2  // =1
    windowValsRep = stride_repeat(windowVals, xshapeother, axis=otheraxis)
    // result windowValsRep = [
                                [ 0. ,0. ,0. ,0. ,0. ,],
                                [0.75, 0.75, 0.75, 0.75, 
                                [0.75, 0.75, 0.75, 0.75, 
                                [ 0. ,0. ,0. ,0. ,0. ,]
                              ]
Run Code Online (Sandbox Code Playgroud)

然后乘以 x

windowValsRep * x
Run Code Online (Sandbox Code Playgroud)

现在

 x =    [ 
          [ 0.  , 0.   , 0.   , 0.   , 0.   ],
          [ 1.5 , 3    , 4.5  , 6.   , 7.5  ],
          [ 2.25, 3.75 , 5.25 , 6.75 , 8.25 ],
          [ 0.  , 0.   , 0.   , 0.   , 0.   ] 
        ]
Run Code Online (Sandbox Code Playgroud)

然后final是fft,因为我知道fft只需要一个数组,但在这里它处理二维数组。为什么 ?

result = np.fft.fft(x, n=pad_to, axis=0)[:numFreqs, :]
Run Code Online (Sandbox Code Playgroud)

谁能为我逐步解释为什么需要在 fft 之前像这样处理数据?

谢谢,

The*_*Cat 6

频谱图和 FFT 不是一回事。一个的目的频谱图是取小,大小相等的时间的块的FFT。这会产生一个 2D 傅立叶变换,其中 X 轴是时间块的开始时间,Y 轴是该时间块中每个频率的能量(或功率等)。这使您可以查看频率分量如何随时间变化。

这在specgram函数的文档中进行了解释

数据被分成 NFFT 长度段,并计算每个部分的频谱。加窗函数window应用于每个段,每个段的重叠量用noverlap指定。

至于各个功能,您要问的很多内容在reach功能的文档中都有描述,但我将尝试更详细地解释一下。

文档中stride_windows所述, 的目的是将一维数据数组转换为连续时间块的二维数组。这些是将在最终频谱图中计算 FFT 的时间块。在您的情况下,它们是长度为 4 ( ) 的时间块(注意每列 4 个元素)。因为您设置了,所以每列的最后 2 个元素与下一列的前 2 个元素相同(这就是重叠的含义)。它被称为“跨步”,因为它使用了一个关于 numpy 数组内部存储的技巧,以允许它创建一个具有重叠窗口的数组,而无需占用任何额外的内存。NFFT=4noverlap=2

detrend 函数,顾名思义,如其文档中所述,从信号中移除趋势。默认情况下,它使用平均值,如detrend_mean 文档所述,去除信号的meanDC 偏移)。

apply_window函数正如其名称所暗示的那样,以及它的文档所说的那样:它将窗口函数应用于每个时间块。这是必要的,因为在时间块的开始和结束时突然切断信号会导致大量的宽带能量爆发,称为瞬态,这会弄乱频谱图。对信号进行窗口化可减少这些瞬变。默认情况下,频谱图函数使用汉宁窗。这减弱了每个时间块的开始和结束。

FFT 并不是真正的 2D。该numpy的FFT功能允许您指定一个轴在采取FFT。所以在这种情况下,我们有一个二维数组,我们对该数组的每一列进行 FFT。在一个步骤中执行此操作比手动循环每一列要干净得多,速度也快一些。