You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

手动实现STFT与scipy.signal.stft首段DFT差异的技术求助

嘿,我懂你遇到的问题了——自己手搓的STFT和scipy的对比下来,就多了t=0时刻的一段DFT结果,其余部分完全对齐。这大概率是窗口起始索引的生成逻辑或者时间轴计算和scipy不一致导致的,我给你调整一下关键部分的代码,应该就能解决:

修正后的STFT核心实现

import numpy as np
from scipy.signal import get_window

def my_stft(samples, fs, wind_len_time=0.5, overlap_factor=0.5, zero_padding_factor=4):
    wind_len = int(fs * wind_len_time)
    # 注意:scipy的重叠长度要求是整数,这里转成int避免步长计算误差
    overlap = int(wind_len * overlap_factor)
    step = wind_len - overlap
    nfft = wind_len * zero_padding_factor
    
    # 对齐scipy的窗口起始索引逻辑:最后一个窗口必须完整覆盖信号片段
    # 原来的代码可能把起始索引范围设到了len(samples),导致多生成一个窗口
    section_starts = np.arange(0, len(samples) - wind_len + 1, step)
    
    # 用scipy默认的hann窗,避免窗口类型差异
    window = get_window('hann', wind_len)
    stft_result = []
    
    for start in section_starts:
        end = start + wind_len
        segment = samples[start:end]
        # 补零到指定长度
        padded_segment = np.pad(segment, (0, nfft - wind_len), mode='constant')
        # 加窗后做DFT
        windowed_segment = padded_segment * window
        dft = np.fft.rfft(windowed_segment)
        stft_result.append(dft)
    
    # 时间轴用窗口中心时间,和scipy保持一致(之前可能用了窗口起始时间,导致出现t=0)
    t = (section_starts + wind_len / 2) / fs
    f = np.fft.rfftfreq(nfft, 1/fs)
    
    return f, t, np.array(stft_result).T

关键修正点

  • 窗口起始索引范围:scipy的STFT只会生成能完整覆盖信号的窗口,所以起始索引的上限设为len(samples) - wind_len + 1,避免多生成一个超出信号范围的窗口(哪怕你做了补零,scipy也不会处理这种不完整的窗口)。
  • 重叠长度转整数:scipy的noverlap参数要求是整数,之前如果用浮点数计算重叠,可能导致步长出现小数,进而生成多余的起始点。
  • 时间轴对齐:scipy默认用窗口的中心时间作为每个DFT结果对应的时间点,而不是窗口起始时间——如果之前你用起始时间计算,就会多出t=0这个点,和scipy的时间轴错位。

你可以用这段代码和scipy的signal.stft对比,应该就能完全匹配了。

内容的提问来源于stack exchange,提问作者Gideon Kogan

火山引擎 最新活动