使用 SciPy stft 函数为短时傅立叶变换指定段中的样本数

Specify number of samples in a segment for Short-time Fourier Transform using SciPy stft function

我想对我的数据执行短时傅里叶变换,每个片段都有特定的样本长度。我想使用信号子模块中的 SciPy 函数 stft。但是,当我通过以下方式创建长度为 10e5 的音频数组时:

fs = 10e3 # Sampling frequency
N = 1e5 # Number of samples
time = np.arange(N) / fs
x = 500*np.cos(time) # Some random audio wave
# x.shape gives (100000,)

并应用 SciPy stft 函数和 nperseg=1000,我没有得到预期的 100 段。相反,输出的形状是:

f, t, Zxx = signal.stft(x, fs, nperseg=1000)
print(Zxx.shape) # -> (501, 201)

如果我对文档理解正确,501是"frequency baskets"的数量,20001是不同时间段的数量,我本来打算是N/nperseg或10e5 / 1000 = 100 .我确实看到该函数有一些参数来指定填充和重叠,但是在 Nnperseg 整除的情况下,它到底做了什么?

当我运行你的代码片段:

In [1]: import numpy as np

In [2]: import scipy.signal as signal

In [3]: fs = 10e3 # Sampling frequency
   ...: N = 1e5 # Number of samples
   ...: time = np.arange(N) / fs
   ...: x = 500*np.cos(time) # Some random audio wave
   ...:

In [4]: f, t, Zxx = signal.stft(x, fs, nperseg=1000)
   ...: print(Zxx.shape) # -> (501, 20001)
   ...:
(501, 201)

我看到 Zxx 的输出是 501 x 201。

501就是你说的frequency bins的个数(每段1000个temporal bins,real-only FFT后变成501个frequency bins;如果要full complex FFT,可以传入return_onesided=False).

201 是因为 npersegnoverlap 的组合。 docs 表示 noverlap 是“段之间重叠的点数。如果 Nonenoverlap = nperseg // 2。”所以 STFT 不是 制作 1e5/1e3=1e2 “段”,它通过 500 个样本(半段)重叠 1e3 长的段,所以你最终得到的比200 重叠 段。

要得到你想要的,说 noverlap=0:

In [7]: f, t, Zxx = signal.stft(x, fs, nperseg=1000, noverlap=0)

In [8]: Zxx.shape
Out[8]: (501, 101)

我不太确定为什么 returns 101 段而不是 100 段……

signal.stft 获得了默认的 window 50% 的重叠,这大约使段数翻了一番。 在 google 中搜索 "stft overlap" 将帮助您了解有关此重叠的更多信息。