3、频域降噪方法:STFT、谱减法、维纳滤波与MMSE
频域降噪,说白了就是把声音从时域搬到频域去处理。为什么要这么折腾?因为噪声和语音在频域里更容易分开。我刚开始做这行时,总觉得时域滤波更直观,直到碰到一个非平稳噪声的案例——时域怎么调都压不住,换到频域,几行代码就解决了。
这一章我们聊四个核心方法:短时傅里叶变换(STFT)是频域处理的基础;谱减法是最直观的降噪思路;维纳滤波在频域里有个漂亮的闭合解;MMSE估计器则是统计最优的频域方法。嗯,一个一个来。
3.1 短时傅里叶变换(STFT)
STFT 是频域降噪的基石。你想想看,语音信号是非平稳的,但如果我们只取一小段(比如 20-40ms),这段信号可以近似看成平稳的。STFT 做的就是这件事——加窗、分帧、做 FFT。
核心公式:
X(m, k) = Σ x[n] · w[n - mR] · e^(-j2πkn/N)
其中 m 是帧索引,k 是频率索引,w[n] 是窗函数,R 是帧移。
我在项目中遇到过一个问题:窗函数选错了,降噪效果直接打对折。常用的窗函数有这些:
| 窗函数 | 主瓣宽度 | 旁瓣衰减 | 推荐场景 |
|---|---|---|---|
| 汉宁窗 | 较宽 | -31dB | 通用语音处理 |
| 汉明窗 | 较宽 | -43dB | 语音增强 |
| 布莱克曼窗 | 最宽 | -58dB | 高动态范围 |
| 矩形窗 | 最窄 | -13dB | 不推荐用于降噪 |
我的经验:帧长选 20-30ms,帧移 50% 重叠。汉宁窗是默认选择,频谱泄漏和频率分辨率之间平衡得最好。如果你做实时系统,帧移可以调到 75%,但计算量会翻倍。
STFT 的流程其实不复杂:
- 分帧:把信号切成重叠的帧
- 加窗:每帧乘以窗函数,减少频谱泄漏
- FFT:对每帧做 N 点 FFT,得到复数频谱
- 处理:在频域做降噪(谱减、维纳、MMSE 等)
- IFFT:逆变换回时域
- 重叠相加:把处理后的帧拼接成完整信号
这里有个坑——重叠相加处理不好,会有明显的块状噪声。我曾经调试一个降噪算法,降噪效果很好,但听起来像有人在"打嗝"。查了两天才发现是重叠相加的增益补偿没做对。
注意:STFT 的时频分辨率受海森堡不确定性原理限制。时间分辨率高,频率分辨率就低,反之亦然。没有完美的窗函数,只有适合你场景的窗函数。
3.2 谱减法
谱减法是最直观的频域降噪方法。它的思路很简单:带噪语音的幅度谱 - 噪声幅度谱 = 干净语音幅度谱。配合带噪语音的相位,就能重建出干净语音。
基本公式:
|Ŝ(k)| = |X(k)| - |N̂(k)| 如果结果大于 0
|Ŝ(k)| = 0 如果结果小于 0
这里 |X(k)| 是带噪语音的幅度谱,|N̂(k)| 是估计的噪声幅度谱。相位直接用带噪语音的相位——人耳对相位不敏感,这个近似在大多数场景下都够用。
但谱减法有个致命问题:音乐噪声。你想想看,当 |X(k)| 接近 |N̂(k)| 时,相减后会出现随机的小峰值,听起来像背景里有人在弹钢琴。嗯,这就是音乐噪声。
改进方案:
- 过减因子 α:|Ŝ(k)| = |X(k)| - α · |N̂(k)|,α > 1 可以压得更狠,但音乐噪声更明显
- 谱底限 β:|Ŝ(k)| = max(|X(k)| - α · |N̂(k)|, β · |X(k)|),β 通常取 0.01-0.1
- 平滑处理:对估计的幅度谱做时域或频域平滑
我在项目中用过一种"自适应谱减法":根据当前帧的信噪比动态调整 α 和 β。信噪比高时 α 小一点,保留更多语音细节;信噪比低时 α 大一点,压得更狠。效果比固定参数好不少。
3.3 维纳滤波的频域实现
维纳滤波在时域里推导起来挺复杂,但在频域里,它有一个漂亮的闭合解。说白了,维纳滤波就是找一个最优的滤波器 H(k),使得估计误差的均方值最小。
频域维纳滤波器的形式:
H(k) = ξ(k) / (1 + ξ(k))
其中 ξ(k) = Ps(k) / Pn(k) 是先验信噪比,Ps(k) 是语音功率谱,Pn(k) 是噪声功率谱。
你看这个公式,当信噪比很高时(ξ(k) >> 1),H(k) ≈ 1,滤波器几乎不衰减;当信噪比很低时(ξ(k) << 1),H(k) ≈ ξ(k),滤波器大幅衰减。这个特性很符合直觉——信噪比高的频段保留,信噪比低的频段压制。
实际实现的关键:先验信噪比 ξ(k) 需要估计。常用的方法是"判决引导法"(Decision-Directed):
ξ(m, k) = α · |Ŝ(m-1, k)|² / Pn(m, k) + (1-α) · max(γ(m, k) - 1, 0)
其中 α 通常取 0.98,γ(m, k) 是后验信噪比。这个方法能有效减少音乐噪声。
维纳滤波比谱减法好在哪里?我个人的体会是:维纳滤波的过渡更平滑。谱减法在信噪比临界点附近会有"硬切"的感觉,而维纳滤波是连续衰减的,听起来更自然。
但维纳滤波也有缺点:它假设语音和噪声都是平稳的,而且需要准确的噪声功率谱估计。如果噪声估计不准,维纳滤波的效果还不如谱减法。
3.4 MMSE 估计器
MMSE(最小均方误差)估计器,是频域降噪的"天花板"方法之一。它从统计最优的角度出发,直接估计干净语音的幅度谱。
Ephraim 和 Malah 在 1984 年提出的 MMSE-STSA 估计器,公式长这样:
|Ŝ(k)| = G(ξ(k), γ(k)) · |X(k)|
其中增益函数 G 是:
G(ξ, γ) = √(ξ/(1+ξ)) · Γ(1.5) · M(-0.5; 1; -ν) / γ
这里 Γ 是伽马函数,M 是合流超几何函数,ν = ξ·γ/(1+ξ)。
说实话,这个公式看着挺吓人的。我第一次实现时,查了半天合流超几何函数的数值计算方法。后来发现,可以用查表法或者多项式近似来加速。
MMSE 的核心优势:
- 理论上最优——在均方误差准则下,没有比它更好的估计器
- 音乐噪声最少——因为它是统计意义上的最优估计,不会出现谱减法那种随机峰值
- 对低信噪比场景特别有效——-5dB 甚至 -10dB 下仍有可用的降噪效果
MMSE 的变体也很多:
| 变体名称 | 估计目标 | 特点 |
|---|---|---|
| MMSE-STSA | 短时幅度谱 | 原始版本,计算量大 |
| MMSE-LSA | 对数幅度谱 | 对语音失真更不敏感,听感更好 |
| MMSE-SP | 语音存在概率 | 结合 VAD,减少噪声过估计 |
我在项目中用过 MMSE-LSA,听感确实比谱减法好很多。但代价是计算量——在嵌入式平台上,MMSE 的实时实现需要做不少优化。比如用多项式近似代替合流超几何函数,或者用查表法预计算增益值。
注意:MMSE 估计器对噪声功率谱的估计误差非常敏感。如果噪声估计偏差超过 3dB,MMSE 的效果可能还不如一个调参调好的谱减法。所以,噪声跟踪算法(比如最小值跟踪、MCRA)是 MMSE 的前置必修课。
3.5 四种方法的对比与选择
说了这么多,到底该用哪个?我画了一张对比图,帮你快速决策:
选型建议:
- 资源受限的嵌入式平台:谱减法 + 过减因子 + 谱底限,调参到位效果够用
- 实时通信系统:维纳滤波,计算量和效果平衡得最好
- 高保真语音处理:MMSE-LSA,听感最好,但要做好计算优化
- 科研或离线处理:直接上 MMSE,或者它的改进版(如 MMSE-SP)
最后说一句:没有银弹。我在项目中见过有人花三个月调 MMSE 的参数,效果还不如一个调了两周的谱减法。算法选型要结合你的硬件平台、实时性要求和听感目标来定。先跑通一个简单的版本,再逐步优化,这是最稳妥的路。