4、傅里叶变换与频谱:短时傅里叶变换(STFT)、频谱与功率谱
在语音信号处理中,傅里叶变换是连接时域与频域的桥梁。但标准傅里叶变换(FT)对整段信号做全局积分,只能得到信号“平均”的频谱成分,无法反映频率随时间的变化。而语音信号恰恰是典型的非平稳信号——发音时声带振动频率(基频)、共振峰位置、清浊音交替都在快速变化。因此,我们需要一种既能观察频率成分、又能定位时间位置的时频分析工具,这就是短时傅里叶变换(STFT)。本章将系统讲解STFT的数学原理、频谱与功率谱的区别、窗函数的选择策略,以及如何通过频谱图诊断语音质量问题。
4.1 STFT 核心原理:从全局变换到局部加窗
标准傅里叶变换对信号 x(t) 的积分区间为 (-∞, +∞),得到的频谱 X(f) 是信号在整个时间轴上的统计平均。对于语音这种短时平稳信号,直接做全局变换会丢失所有时间信息——我们只知道“有哪些频率成分”,却不知道“这些频率在什么时候出现”。STFT 的解决思路非常直观:用窗函数截取信号的局部片段,对每个片段分别做傅里叶变换。数学表达式为:
X(m, k) = Σ_{n=0}^{N-1} x[n] · w[n - m·H] · e^{-j2πkn/N}
其中,m 表示帧索引,H 为帧移(hop size),w[n] 为窗函数,N 为 FFT 点数。每一帧信号被窗函数加权后,再通过 FFT 得到该帧的频谱向量。将所有帧的频谱按时间顺序排列,就构成了语谱图(Spectrogram)。
这里需要特别理解三个关键参数:帧长(window length)决定了频率分辨率,帧长越长,频率分辨率越高(能区分更接近的频率),但时间分辨率越差(无法精确定位瞬态事件);帧移(hop size)决定了相邻帧的重叠程度,直接影响语谱图的时间平滑度;FFT 点数 N 通常取大于等于帧长的 2 的幂次,不足部分补零(zero-padding),补零只能插值频谱曲线,不能提高真实频率分辨率。
| 参数 | 典型值 | 对时频分辨率的影响 | 适用场景 |
|---|---|---|---|
| 帧长 | 20-30ms(16kHz采样下为320-480点) | 帧长↑ → 频率分辨率↑,时间分辨率↓ | 语音识别、说话人识别 |
| 帧移 | 5-15ms(通常为帧长的1/3~1/2) | 帧移↓ → 时间冗余↑,计算量↑ | 基频检测、语音增强 |
| FFT点数 | 512/1024/2048 | N↑ → 频谱采样更密,但计算量↑ | 需要精细频谱分析时 |
| 窗函数 | 汉明窗/汉宁窗/布莱克曼窗 | 旁瓣衰减↑ → 频谱泄漏↓,但主瓣变宽 | 语音特征提取常用汉明窗 |
4.2 频谱与功率谱:从幅度到能量的视角转换
对每一帧信号做完 FFT 后,我们得到复数频谱 X(m,k) = Re + j·Im。这个复数包含了幅度和相位两部分信息。在实际语音处理中,我们通常更关注幅度谱 |X(m,k)| 和功率谱 |X(m,k)|²。功率谱的定义为:
P(m,k) = |X(m,k)|² / N
其中除以 N 是为了归一化,使功率谱的物理意义更明确(帕塞瓦尔定理保证了时域能量等于频域能量之和)。功率谱表示信号在各频率分量上的能量分布,它丢失了相位信息,但保留了幅度信息,且对噪声的统计特性更敏感。
在 MFCC 特征提取流程中,功率谱是 Mel 滤波器组的输入。Mel 滤波器组将功率谱映射到 Mel 频率刻度上,模拟人耳对频率的非线性感知。这里有一个常见误区:很多初学者直接对幅度谱做 Mel 滤波,而不是对功率谱做。虽然两者在数学上只差一个平方运算,但 Mel 滤波后的结果在取对数后会有明显差异,影响最终特征的判别力。标准流程是:功率谱 → Mel 滤波器组 → 取对数 → DCT → MFCC。
4.3 窗函数的选择:频谱泄漏与主瓣宽度的权衡
窗函数是 STFT 中容易被忽视但至关重要的环节。矩形窗(即不加窗)的频谱旁瓣衰减只有 -13dB,会导致严重的频谱泄漏——一个强频率成分的能量会“泄漏”到邻近频率,掩盖弱信号。汉明窗(Hamming)的旁瓣衰减约为 -43dB,汉宁窗(Hann)约为 -31dB,布莱克曼窗(Blackman)可达 -58dB。旁瓣衰减越大,抑制频谱泄漏的能力越强,但主瓣宽度也越宽,导致频率分辨率下降。
对于语音信号,汉明窗是 MFCC 提取的默认选择,因为它在旁瓣衰减和主瓣宽度之间取得了较好的平衡。汉明窗的时域表达式为:
w[n] = 0.54 - 0.46·cos(2πn/(N-1)), 0 ≤ n ≤ N-1
选择窗函数时还需要考虑窗长的影响。如果窗长太短(如 5ms),频率分辨率只有 200Hz,无法区分基频及其谐波;如果窗长太长(如 50ms),语音的瞬态特性(如爆破音、塞音)会被严重平滑。对于 16kHz 采样率的语音,25ms 窗长(400点)配合 10ms 帧移(160点)是工程上最常用的配置。
4.4 案例拆解:用 STFT 诊断语音信号中的混叠与削波
假设我们收到一段 16kHz/16bit 的录音,听感上声音“发闷”且伴有“沙沙”声。我们使用 Python 的 librosa 库对该信号进行 STFT 分析,定位问题根源。
import librosa
import numpy as np
# 加载音频
y, sr = librosa.load('problem.wav', sr=16000)
# 计算 STFT,帧长 512 点(32ms),帧移 160 点(10ms)
D = librosa.stft(y, n_fft=512, hop_length=160, win_length=400, window='hamming')
magnitude = np.abs(D) # 幅度谱
power = magnitude**2 # 功率谱
# 绘制语谱图
import matplotlib.pyplot as plt
librosa.display.specshow(librosa.amplitude_to_db(magnitude, ref=np.max),
sr=sr, hop_length=160, x_axis='time', y_axis='hz')
plt.colorbar(format='%+2.0f dB')
plt.title('Spectrogram of problem.wav')
plt.show()
分析过程与发现:
- 现象 1:高频能量缺失。语谱图中 6kHz 以上几乎无能量,但语音的齿音(如“s”、“sh”)能量集中在 4-8kHz。结合录音设备信息(某手机内置麦克风),判断为麦克风频率响应不足或低通滤波过度。
- 现象 2:水平条纹噪声。语谱图中出现均匀间隔的水平亮线,间隔约 100Hz。这是典型的 50Hz 工频干扰及其谐波,可能来自电源接地不良。
- 现象 3:时域削波。在波形图上观察到幅度超过 ±0.98 的平顶区域,对应语谱图中出现宽带能量爆发,这是 ADC 输入过载导致的削波失真。
针对上述诊断,我们采取的措施:
- 对 50Hz 及其谐波(100/150/200Hz)使用陷波滤波器(Notch Filter),Q 值设为 30,避免影响邻近语音频率。
- 对削波区域,使用插值修复(如三次样条)或直接丢弃该段并重新录制。
- 对于高频缺失,在后续特征提取中放弃 6kHz 以上频带,或使用高通预加重滤波器(pre-emphasis)补偿高频衰减。
结果对比:修复后信号的语谱图高频成分恢复,水平条纹消失,语音可懂度主观评分从 2.5 分提升到 4.2 分(MOS 5 分制)。此案例说明,STFT 语谱图是语音质量诊断的第一手工具,能同时暴露频域、时域和能量域的问题。
4.5 常见误区与总结复盘
在 STFT 的学习和工程应用中,以下误区值得特别注意:
| 误区 | 错误理解 | 正确认知 |
|---|---|---|
| FFT 点数越大越好 | 认为增大 N 能提高频率分辨率 | 真实分辨率由窗长决定,补零只是插值 |
| 矩形窗最简单就用它 | 忽略频谱泄漏的影响 | 语音处理必须用平滑窗(汉明/汉宁) |
| 帧移越小越好 | 认为重叠越多信息越丰富 | 帧移过小导致计算量剧增且帧间高度相关,不利于后续统计建模 |
| 功率谱和幅度谱等价 | 认为只是平方关系,不影响结果 | 在 Mel 滤波和取对数后差异显著,MFCC 标准流程必须用功率谱 |
| 忽略相位信息 | 认为相位对语音无用 | 相位对语音可懂度重要,但 MFCC 特征通常只用幅度;在语音合成中相位至关重要 |