You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现梅尔频谱:STFT窗口大小对幅值影响的疑问

关于STFT窗口大小导致幅值和频率范围变化的解答

1. 频率范围“变化”的真实原因

你当前绘图时,x轴用的是FFT的bin索引,而非实际频率值,这才是视觉上频率范围变化的核心原因。每个bin对应的实际频率计算公式为:

freq = bin_index * 采样率(sr) / 窗口大小(windowSize)

举个例子:

  • 若采样率sr=16000,25ms窗口对应的大小是400,此时FFT的bin数为400/2+1=201,x轴索引0-200对应实际频率0-8000Hz(奈奎斯特频率)。
  • 当窗口大小设为2048时,bin数为2048/2+1=1025,x轴索引0-1024对应的实际频率范围依然是0-8000Hz。

修正绘图代码,将x轴转换为实际频率即可统一对比:

window_size_samples = int(window_size * sr)
freq_bins = np.arange(int(window_size_samples/2)+1) * sr / window_size_samples
plt.plot(freq_bins, stft_matrix[0, :])
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.show()

2. 幅值变化的原因

幅值变化主要来自三个因素:

  • 窗口能量差异:Hanning窗的总能量随窗口大小增大而升高,加窗后信号的能量也会随之增加,最终反映在FFT幅值上。
  • FFT的幅值特性:FFT的结果是窗口内所有样本的加权求和,窗口越大包含的样本数越多,幅值绝对值自然越大。
  • 未做幅值归一化:标准STFT通常会对结果做归一化,补偿窗函数带来的能量损失。针对Hanning窗,常用的归一化方式是用2 / np.sum(window)来修正:
    修改你的STFT函数:
    def stft(signal, windowSize, windowStep):
        n_frames = 1 + int((len(signal)-windowSize)/windowStep)
        stft_matrix = np.zeros((n_frames, int(windowSize/2)+1),dtype=np.float32)
        # 预计算窗函数和归一化系数
        window = np.hanning(windowSize)
        norm_factor = 2 / np.sum(window)
        
        for i in range(n_frames):
            start = i * windowStep
            end = start + windowSize
            frame = signal[start:end] * window
            frame_fft = np.fft.fft(frame)[:int(windowSize/2)+1]
            stft_matrix[i, :] = np.abs(frame_fft) * norm_factor
        return stft_matrix
    

3. 额外建议

  • 计算帧数量时,int()截断可能导致丢帧,建议用np.floor()或直接使用librosa的工具函数librosa.util.frame处理帧分割,逻辑更严谨。
  • 可以用librosa官方的STFT实现验证你的结果:
    librosa_stft = np.abs(librosa.stft(x, n_fft=int(window_size*sr), hop_length=int(window_step*sr), window='hann'))
    

你的STFT核心逻辑是正确的,只是缺少频率轴转换和幅值归一化步骤,导致出现视觉上的“异常”,修正后即可得到一致的对比结果。

内容的提问来源于stack exchange,提问作者Naufal Rifqi Habibie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 02:17:48