TensorFlow无加窗STFT逆变换无法正确还原信号问题咨询
TensorFlow STFT逆变换重构异常解决方案
核心原因
tf.signal.inverse_stft默认不会自动处理重叠帧的叠加增益归一化,这是和scipy实现的核心差异:scipy默认内置了该归一化逻辑,而TensorFlow的实现更偏向底层,将这部分控制权交给了开发者。
分场景修复方案
1. 无窗函数场景
你观察到的中心区域幅值为原始信号N倍(N = frame_length / frame_step)是正常现象:每一个信号采样点被N个重叠帧各累加了一次,所以总增益为N,直接除以N即可校正:
import matplotlib.pyplot as plt import numpy as np import tensorflow as tf size = 2048 frame_length = 512 frame_step = 128 waveform = np.sin(np.arange(size) * 1 / 100) overlap_factor = frame_length // frame_step stft = tf.signal.stft(waveform, frame_length, frame_step, window_fn=None) inverse_stft = tf.signal.inverse_stft(stft, frame_length, frame_step, window_fn=None) # 校正重叠增益 inverse_stft = inverse_stft / overlap_factor plt.plot(waveform, label='原始信号') plt.plot(inverse_stft, label='重构信号', linestyle='--') plt.legend() plt.show() plt.clf()
2. 带汉宁窗场景
边界衰减的原因有两个:
- 带窗的重叠相加需要专用的逆窗函数做增益补偿,不能直接使用和正变换一致的窗函数
- TensorFlow的STFT默认仅在信号尾部补零,头部和尾部的帧没有足够的重叠采样,叠加后无法达到恒定增益,就会出现边界衰减
修复方案如下:
import matplotlib.pyplot as plt import numpy as np import tensorflow as tf size = 2048 frame_length = 512 frame_step = 128 waveform = np.sin(np.arange(size) * 1 / 100) # 1. 生成适配汉宁窗的逆窗函数 forward_window_fn = tf.signal.hann_window inverse_window_fn = tf.signal.inverse_stft_window_fn(frame_step, forward_window_fn=forward_window_fn) # 2. 预补镜像值消除边界衰减 pad_len = frame_length // 2 padded_waveform = tf.pad(waveform, [[pad_len, pad_len]], mode='reflect') # 3. 执行STFT和逆STFT stft = tf.signal.stft(padded_waveform, frame_length, frame_step, window_fn=forward_window_fn) inverse_stft_padded = tf.signal.inverse_stft(stft, frame_length, frame_step, window_fn=inverse_window_fn) # 4. 裁剪掉预补的区域 inverse_stft = inverse_stft_padded[pad_len:-pad_len] plt.plot(waveform, label='原始信号') plt.plot(inverse_stft, label='重构信号', linestyle='--') plt.legend() plt.show() plt.clf()
按照上述方案调整后,两种场景都可以得到和scipy一致的重构结果。
内容的提问来源于stack exchange,提问作者Gianluca Micchi
相关产品推荐
相关产品推荐

