最近复现论文需要用到短时傅里叶变换的代码,在百度谷歌都找了一番,没有找到合适的代码,于是scipy文档内的stft()函数翻译了一遍。
一、scipy.signal.stft函数介绍
scipy.signal.stft(x,fs=1.0,window='hann',nperseg=256,noverlap=None,nfft=None,
detrend=False,return_onesided=True,boundary='zeros',padded=True,axis=-1)
短时傅里叶变换可以用于量化非平稳信号频率和相位随时间的变化
参数说明:
x: 数组类型
时间序列测量值
fs: 浮点型,可选
x时间序列的采样频率,默认1.0。
window : 字符串或元祖或数组,可选
需要使用的窗。如果window是一个字符串或元组,则传递给它window是数组类型,直接以其为窗,其长度必须是nperseg。默认为Hann窗。
nperseg : int,可选
每个段的长度。默认为256。
noverlap : int,可选
段之间重叠的点数。如果没有,noverlap = nperseg // 2 .默认为无。如有提前指定时,必须满足COLA约束。
nfft : int,可选
如果需要零填充FFT,则为使用FFT的长度。如果为 None,则FFT长度为nperseg。默认为无。
detrend : str或function或False,可选
指定如何去除每个段的趋势。如果类型参数传递给False,则不进行去除趋势。默认为False。
return_onesided : bool,可选
如果为True,则返回实际数据的单侧频谱。如果 False返回双侧频谱。默认为 True。请注意,对于复杂数据,始终返回双侧频谱。
boundary : str或None,可选
指定输入信号是否在两端扩展,以及如何生成新值,以使第一个窗口段在第一个输入点上居中。这具有当所采用的窗函数从零开始时能够重建第一输入点的益处。有效选项是['even', 'odd', 'constant', 'zeros', None].默认为‘zeros’,对于补零操作[1, 2, 3, 4]变成[0, 1, 2, 3, 4, 0] 当nperseg=3.
填充: bool,可选
指定输入信号在末尾是否填充零以使信号精确地拟合为整数个窗口段,以便所有信号都包含在输出中。默认为True。填充发生在边界扩展之后,如果边界不是None,则填充为True,默认情况下也是如此。
axis : int,可选
计算STFT的轴; 默认值超过最后一个轴(即axis=-1)。
返回值
f: ndarray
采样频率。
t: ndarray
时间。
Zxx: ndarray
x的 STFT 。默认情况下,Zxx的最后一个轴对应于段时间。
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
# 产生一个测试信号,振幅为2的正弦波,其频率在3kHZ缓慢调制,振幅以指数形式下降的白噪声
fs = 10e3
N = 1e5
amp = 2 * np.sqrt(2)
noise_power = 0.01 * fs / 2
time = np.arange(N)/float(fs)
mod = 500 * np.cos(2*np.pi*0.25*time)
carrier = amp * np.sin(2*np.pi*3e3*time+mod)
noise = np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
noise *= np.exp(-time/5)
x = carrier + noise
# 计算并绘制STFT的大小
f, t, Zxx = signal.stft(x, fs, nperseg=1000)
plt.pcolormesh(t, f, np.abs(Zxx), vmin = 0, vmax = amp)
plt.title('STFT Magnitude')
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()