想象你在菜市场里和朋友聊天。周围是此起彼伏的摊贩叫卖声、剁肉声、电动车喇叭声,朋友嘴里的话明明就在耳边,却好像被一层厚厚的“声音棉花”裹住了。如果这时候把这一切录下来,另一头的人听到的,就是人声和噪声缠在一起的混合声。语音降噪要做的,就是像戴上一副“声音眼镜”一样,从这团乱糟糟的声音里,把朋友说话的那条声音线索清晰地挑出来。 有人先录一段“无人说话的摊位底噪”,再把底噪从混合声里减掉,这就是谱减法;有人会根据人声和噪声的比例自动调节音量旋钮,这就是维纳滤波;有人靠统计经验动态判断噪声何时出现,这就是统计模型方法;还有人请来一位“见过成千上万个菜市场”的助手,用大量数据学会直接分离人声,这就是深度学习方向的降噪;最后还要考虑能否边听边处理,这就是实时降噪部署。掌握这些方法,就相当于为语音通信和识别装上了一道可靠的“前置雨刷”。
对 AI 从业者来说,语音降噪是语音通话、录音后期与 ASR 前端的通用底座。学会从“经典谱减”到“深度降噪”的演进思路,你就能在不同算力和场景下选对方法,真正让机器“听清”人声。
目录
可视化演示
动态演示语音降噪的核心机制,通过输入/处理/存储/输出四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
语音降噪:语音降噪 语音降噪问题定义 谱减法经典方法 核心机制可视化 语音降噪整体架构与关键组件
噪声与建模:分清“人声”和“噪声”的混合
菜市场里的声音不是凭空出现的。朋友说话的声音、摊贩的叫卖声、剁肉声,它们在同一时刻叠加在一起,传到麦克风里。降噪的第一步,不是急着“去掉噪声”,而是先弄清一个基本问题:带噪语音和干净语音之间到底是什么关系。
在语音增强里,我们最常用一个加法模型来描述这种关系:麦克风收到的带噪语音,等于干净人声加上环境噪声。
不过,语音不是整段都平稳的。人的说话声会随时变化,但在 20 到 30 毫秒的短时间里,声音特性可以看作近似稳定,这就是“短时平稳”。于是我们先把语音切成一小段一小段,加上窗函数,再用短时傅里叶变换转到频域,得到逐帧逐频点的幅度谱和相位谱。这样一来,降噪就不再是摸黑操作,而是像把混合声摊在一张频谱账本上,逐行检查哪个格子是噪声。
回到菜市场的比喻:先认清“混合声 = 人声 + 噪声”,并学会把连续声音拆成短片段、转成频谱,后面要做的各种减法、滤波和神经网络,都只是在这个基础上“各显神通”。
- 带噪语音 \(y(t)\)麦克风实际录到的混合声,也就是菜市场里被收录的整段声音。
- 干净语音 \(s(t)\)朋友说话本身的声波,是我们要保住的目标信号。
- 环境噪声 \(n(t)\)叫卖声、剁肉声、风声等不需要的干扰。
- 加号 \(+\)默认噪声与语音是线性叠加,这是许多经典降噪算法的起点。
谱减法增强:用“底噪模板”做减法
最直觉的降噪思路,是“既然噪声一直在响,那就把它减掉”。在菜市场里,如果你先录下一段没人说话的摊位背景音,等到朋友说话时,再从混合声里把这段底噪“扣掉”,听起来就干净多了。谱减法正是这个思路。
操作上,先取一段没有语音的帧,估计出噪声的幅度谱;接着把带噪语音的幅度谱减去噪声幅度谱。因为人耳对相位不敏感,所以保留原来的带噪相位,只修正幅度。为了防止减过头,谱减法会用一个最大函数把结果约束在非负范围,并加上一个谱下限。
谱减法实现简单,但有个著名副产物:音乐噪声。它像水烧开后锅底冒出的“噗嗤”声,原因是各频点残余噪声随机起伏,变成一些忽大忽小的“音调碎片”。过减因子和谱下限,就是在“减得更干净”和“少伤声音”之间找平衡。
回到菜市场:谱减法像拿一张固定底噪模板做减法。底噪一成不变,可市场里的声音实时在变,所以减出来的声音偶尔会“漏出”叮叮当当的残渣。
- 带噪幅度 \(|Y(k,l)|\)第 \(l\) 帧、第 \(k\) 个频点上混合信号的幅度值,相当于菜市场里的“总声量”。
- 噪声幅度 \(|D(k,l)|\)用安静段落估计出的噪声幅度,相当于事先录好的“摊位底噪”。
- 过减因子 \(\alpha\)通常大于 1,用来把底噪减得更狠,但太大也会误伤人声。
- 谱下限 \(\beta\)把结果下限设为带噪幅度的一定比例,不让某些频点“减空”,减少破音。
- 最大值 \(\max\)保证增强后的幅度不会出现负值,负值在物理上无法解释。
维纳滤波降噪:随着信噪比自动调节的旋钮
谱减法的问题是“一刀切”:无论朋友有没有在说话,都把底噪减掉。如果朋友停顿了,剩下的噪声还会被反复处理,形成音乐噪声。换个思路,可以不用“减”,而是用一个音量旋钮去“调”:人声较强时,把旋钮开大,音量全保留;人声较弱时,把旋钮关小,噪声也压下去。
这个旋钮就是维纳滤波的增益函数。维纳滤波在“最小均方误差”准则下,给出了每个频点应该放大或缩小的比例。它只依赖一个关键参数:先验信噪比,也就是该频点上“人声能量相对噪声能量”的估计值。
实现维纳滤波,需要提前估计噪声功率谱和先验信噪比。相比谱减法的直接减法,维纳滤波输出更平滑,但如果信噪比估计不准,会出现“把声音压扁”的过度抑制。
回到菜市场:维纳滤波像一位经验丰富的调音师,他不需要把底噪模板硬减掉,而是根据“朋友此刻是否在说话、说话有多响”,连续转动音量旋钮。声音清楚时开大,噪声盖过一切时关小。
- 增益 \(H(k,l)\)对第 \(l\) 帧第 \(k\) 个频点施加的放大倍数,是这个旋钮的位置。
- 先验信噪比 \(\xi(k,l)\)不含噪声的“干净人声能量”与“噪声能量”之比。
- 分母 \(1+\xi(k,l)\)把增益限制在 0 到 1 之间,避免无限制放大。
- 比值 \(\frac{\xi}{1+\xi}\)语音越强,结果越接近 1;噪声越强,结果越接近 0。
统计模型估计:像老摊贩一样动态估计噪声
老摊贩在菜市场里待久了,能听出此刻的嘈杂是“普通客流”还是“突然有人大喊”。他不会把一个固定底噪永远当真,而是不断根据最新声音修正判断。统计模型方法就是这样:它把噪声和语音都看成随机信号,用概率统计去估计“当前帧到底是人声还是噪声”。
统计模型中,一个关键量是后验信噪比 \(\gamma(k,l)=\frac{|Y(k,l)|^2}{P_d(k,l)}\),也就是“带噪能量”相对“噪声功率”的比值。而真正要用的先验信噪比,常用一种叫做 Decision-Directed 的递归方式来平滑估计:把上一帧已经增强出的语音能量和当前帧的观测结果结合在一起。
统计模型方法还可以结合语音存在概率动态更新噪声谱,并推导出 MMSE 或对数 MMSE 估计器。相比谱减法,它更“聪明”:噪声谱不是固定的,而是随着市场环境自动更新。
回到菜市场:老摊贩的综合判断不只看眼前一声,还结合刚才几声。即使市场突然安静了,他也不会立刻把一切都当成人声;即使市场突然嘈杂起来,他也不会被一次剁肉声带偏。
- 上一帧语音估计 \(\hat{X}(k,l-1)\)上一帧增强后输出的人声谱,相当于老摊贩对前一刻市场的记忆。
- 噪声功率谱 \(P_d(k,l)\)当前频点上噪声的功率估计,是判断“人声有多大”的尺子。
- 后验信噪比 \(\gamma(k,l)\)带噪能量与噪声功率的比值,反映刚刚听到的“瞬时局面”。
- \(\max(\gamma-1,0)\)只有当前观测明显超过噪声时才认为有人声,防止负值。
- 平滑系数 \(\alpha\)越接近 1,越依赖历史经验,语音更稳;越接近 0,越跟随当前观测,适应更快。
深度降噪网络:见过成千上万个菜市场的助手
前面几种方法,都需要人手工设计“减多少”“怎么平滑”的规则。深度降噪网络则完全不同:它不再手工写规则,而是请来一位见过成千上万个菜市场的助手。这位助手见过“菜市场 + 人声”的无数组合,听到一段混合声,就能凭经验直接说出哪些频段是人声,哪些是噪声。
它的工作原理是端到端学习:训练时输入带噪语音,输出和目标干净语音做比较,不断调整网络参数。网络内部通常包含编码器,用来压缩和提取声音特征,以及解码器,用来重建干净语音。
深度降噪网络在输入输出上也很灵活:可以直接从带噪波形到干净波形,也可以从带噪幅度谱到干净幅度谱,或预测一个时频掩蔽再乘到带噪谱上。实时场景还要注意因果约束:模型只能看当前和过去的帧,不能用未来信息。
回到菜市场:这位助手经验丰富,但如果遇到一个它从未听过的特殊市场——比如全是异国口音、奇怪乐器声——它的经验也可能失灵。深度模型的效果,很大程度上取决于训练数据见过多少种“市场”。
- 网络参数 \(\theta\)神经网络里所有可学习的权重,相当于助手积累的经验。
- 网络输出 \(f_\theta(\mathbf{Y})\)把带噪频谱 \(\mathbf{Y}\) 输入网络后得到的增强结果。
- 干净目标 \(\mathbf{X}\)训练数据里真实的人声频谱,是网络要模仿的“标准答案”。
- L2 范数平方 \(\|\cdot\|_2^2\)逐点误差的平方和,衡量输出和标准答案差多远。
- 期望 \(\mathbb{E}\)在大量训练样本上取平均,让网络不同场景下整体表现都好。
实时降噪部署:边听边处理,不能停下来等
通话降噪和离线录音后期最大的区别,是必须“边听边处理”。你戴着耳机和朋友语音,不能等菜市场安静下来再告诉对方“我刚才听清了”。降噪算法必须在声音进来的一瞬间,以足够低的延迟输出结果。
实时降噪对延迟有严格约束。延迟由几部分构成:采集一帧声音需要的时间、为了更好效果往前看未来帧的时间,以及算法本身计算所需要的时间。
实时系统通常采用流式处理:来一帧、处理一帧、输出一帧。传统 DSP 算法复杂度低,适合低算力设备;深度模型则要做轻量化,比如量化、剪枝、减少网络层数,再导出为 TFLite 或 ONNX 格式部署到手机和耳机芯片上。VAD 也可以辅助:检测到无人说话时直接压低增益,省下大量计算。
回到菜市场:实时降噪就像同声传译,不能等整段话说完才开口。它必须一边听一边判断,用尽量少的未来信息,做到“音落声出”。
- 帧长 \(D_{\text{frame}}\)一帧声音的时长,比如 20 毫秒,是处理一个最小单位的等待时间。
- 前瞻 \(D_{\text{lookahead}}\)某些算法为了更稳,需要看一眼未来几帧,这会额外增加延迟。
- 计算耗时 \(D_{\text{compute}}\)CPU、GPU 或神经网络推理花费的时间。
- 总延迟 \(D_{\text{total}}\)三项相加,必须低于实时交互的心理底线。
降噪效果评估:给听得清打一个客观分
噪声降下去多少,语音损伤了多少,不能只靠拍脑袋。我们需要给“听得清不清”打一个客观分。最基本的指标是信噪比 SNR:它把“干净语音能量”和“误差能量”放在一起比。
除了 SNR,业界还常用 PESQ 预测主观语音质量,用 STOI 衡量语音可懂度。PESQ 更像“听感评分”,STOI 更像“能不能听懂每个字”。降噪不是 SNR 越高越好,因为把整段声音静音,SNR 数值可能很高,但人声也听不见了。好的降噪,是在压制噪声和保留语音之间找到平衡。
回到菜市场:SNR、PESQ、STOI 就像一场客观的听力考试。它们不会只问“噪声小没小”,还会问“朋友的话你还听不听得清”。降噪做得好不好,最终要看这份综合考卷的得分。
- 干净语音 \(s(t)\)降噪前录制或合成的“标准答案”声音。
- 增强语音 \(\hat{s}(t)\)降噪算法处理后输出的声音。
- 误差 \(s(t)-\hat{s}(t)\)输出和标准答案之间的差值,代表噪声没除净或人声被损伤的部分。
- 能量比 \(\frac{\sum s^2}{\sum (s-\hat{s})^2}\)信号能量与误差能量的比值,越大越干净。
- 10 倍对数 \(\text{dB}\)把比值转换成容易理解的分贝数。
AI 应用场景
实时通话降噪
阶段:音频流前处理 / 实时推理
解决的问题:传统降噪在非平稳噪声下容易失效,比如对方在咖啡馆、室外街道,环境噪声随时变化;AI 降噪模型可以实时跟踪并抑制键盘声、犬吠声、汽车鸣笛声,同时保留人声。
具体案例:远程会议 App 在发送每一帧音频前,跑一个几毫秒延迟的轻量深度降噪模型,把对方敲键盘、空调嗡嗡声滤掉,让会议另一头只听到清晰的人声。
录音后期底噪清理
阶段:离线后处理
解决的问题:播客、短视频、外景采访经常录进风扇声、交通噪声和空调轰鸣,人工逐段清理耗时且容易损伤音色。AI 降噪可以先用谱减法粗除底噪,再用深度网络精修。
具体案例:播客制作人把一段带空调底噪的人声录音交给降噪工具,工具先估计噪声谱,再通过深度模型重建干净人声,最终输出可直接发布的音频。
ASR 前端处理
阶段:语音识别前的信号预处理
解决的问题:带噪语音直接进入 ASR 系统会显著提高字错误率,降噪前端可以把人声从噪声中分离出来,再喂给识别模型,让识别更稳。
具体案例:车载语音助手中,车内音乐、风噪和轮胎声混合在一起。先跑一个深度降噪前端,再做“唤醒词检测 + 命令识别”,最终准确率明显提升。
Python 演示
import numpy as np def stft(x, win, hop): win_size = len(win) n_frames = 1 + (len(x) - win_size) // hop X = np.zeros((win_size // 2 + 1, n_frames), dtype=np.complex128) for t in range(n_frames): seg = x[t * hop:t * hop + win_size] * win X[:, t] = np.fft.rfft(seg) return X def istft(X, win, hop): win_size = len(win) n_frames = X.shape[1] out_len = win_size + (n_frames - 1) * hop y = np.zeros(out_len) norm = np.zeros(out_len) for t in range(n_frames): seg = np.fft.irfft(X[:, t], win_size) y[t * hop:t * hop + win_size] += seg * win norm[t * hop:t * hop + win_size] += win ** 2 return y / np.maximum(norm, 1e-8) def spectral_subtraction(x, sr, noise_dur=0.2, alpha=2.0, beta=0.01): win_size, hop = 400, 160 win = np.hanning(win_size) X = stft(x, win, hop) mag = np.abs(X) phase = np.angle(X) noise_frames = int(noise_dur * sr / hop) noise_mag = np.mean(mag[:, :max(noise_frames, 1)], axis=1, keepdims=True) est_mag = np.maximum(mag - alpha * noise_mag, beta * mag) Y = est_mag * np.exp(1j * phase) return istft(Y, win, hop) def snr_db(clean, err): return 10 * np.log10(np.sum(clean ** 2) / np.sum(err ** 2) + 1e-12) def main(): sr = 16000 t = np.arange(sr) / sr clean = (0.3 * np.sin(2 * np.pi * 220 * t) + 0.15 * np.sin(2 * np.pi * 660 * t)) noise = 0.06 * np.random.randn(sr) noisy = clean + noise enhanced = spectral_subtraction(noisy, sr) out_len = min(len(clean), len(enhanced)) snr_in = snr_db(clean[:out_len], noisy[:out_len] - clean[:out_len]) snr_out = snr_db(clean[:out_len], enhanced[:out_len] - clean[:out_len]) print("input SNR: %.2f dB" % snr_in) print("output SNR: %.2f dB" % snr_out) if __name__ == "__main__": main()
X = np.zeros((win_size // 2 + 1, n_frames), dtype=np.complex128)为每个频点、每帧准备复数频谱矩阵。mag = np.abs(X)提取幅度谱,后续只需要修改幅度,相位保持不变。noise_mag = np.mean(mag[:, :max(noise_frames, 1)], axis=1, keepdims=True)用开头没有语音的帧平均,估计“底噪模板”。est_mag = np.maximum(mag - alpha * noise_mag, beta * mag)谱减核心公式,减完后用谱下限保护。Y = est_mag * np.exp(1j * phase)保留原始相位,用增强幅度重建频谱。return istft(Y, win, hop)逆短时傅里叶变换,把频谱变回时域波形。noisy = clean + noise生成“人声 + 噪声”的混合信号。print("output SNR: %.2f dB" % snr_out)打印增强后的信噪比,帮助判断降噪效果。
常见误区
误区先录一段背景噪声,然后把它从带噪语音的时域波形里直接减掉,就能得到干净人声。
正解虽然语音模型写的是 \(y=s+n\),但直接做波形相减几乎不可行。真实噪声和语音的相位关系复杂,波形相减会严重破坏语音结构。谱减法是在频域对幅度谱做减除,并且保留原相位,这样才能相对安全地压低噪声。
为何常见:看到加法模型 \(y=x+n\),自然会想“既然相加,那就相减”,忽略了频域处理和相位保留的重要性。
误区只要录一段底噪,算出噪声功率,整个降噪过程都用这个固定值就足够了。
正解真实环境噪声会随时间、频率变化,固定的噪声估计会导致某些频段减不干净,另一些频段又过度减除。统计模型方法会用噪声跟踪、语音存在概率等机制不断更新噪声谱。
为何常见:菜市场“摊位底噪”听起来是连续的,让人觉得它不会变,但实际频谱的每个频点都在起伏。
误区深度学习是万能的,任何降噪场景用深度模型都一定比谱减、维纳滤波效果更好。
正解深度模型的效果依赖训练数据是否覆盖目标场景。如果遇到训练时从未见过的噪声类型、信噪比极低或特殊口音,模型可能表现不佳。传统 DSP 方法算力低、行为可预期,在嵌入式设备上仍有不可替代的价值。
为何常见:公开测试集上深度模型分数亮眼,让人误以为它能覆盖所有真实世界场景。
误区只要网络参数量少,就一定能实时运行。
正解实时性不只取决于参数量,还取决于帧长、前瞻、是否流式推理、计算复杂度、平台优化等。一个模型即使很小,如果它需要看到整段音频或未来帧,也无法在通话场景中实时使用。
为何常见:人们习惯用参数量判断轻量级,忽略了“因果关系”和“延迟约束”才是实时的核心。
误区只要把噪声降干净,SNR 提升越大,降噪效果就越好。
正解把整段声音静音,SNR 会变得极高,但人声也完全没了。降噪还要保护语音本身,PESQ、STOI 等指标更关注听感和可懂度。好的降噪是在“压低噪声”和“不损伤人声”之间取平衡。
为何常见:SNR 是最直观的数值,容易让人忽略“信号被一起削掉”的风险。
面试题
Q1. 含噪语音模型 \(y(t)=s(t)+n(t)\) 中,\(n(t)\) 代表哪一项?
- A.干净语音
- B.环境噪声← 正确答案
- C.增强结果
- D.增益系数
答案:B。\(y(t)\) 是带噪语音,\(s(t)\) 是干净人声,\(n(t)\) 是环境噪声。这个加法模型说明噪声是叠加在目标语音上的,不是语音的增益或滤波结果。
Q2. 语音增强中“短时平稳”的意思是?
- A.整段录音都不变
- B.20~30ms内近似不变← 正确答案
- C.噪声幅度始终相同
- D.相位始终是零
答案:B。语音整体变化很快,但在 20 到 30 毫秒内可以看作近似平稳。所以算法先分帧,再对每一帧做频域处理,而不是把整段声音当成静止信号。
Q3. 谱减法中过减因子 \(\alpha\) 的主要作用是?
- A.增大采样率
- B.控制噪声减除强度← 正确答案
- C.改变信号相位
- D.压缩语音时长
答案:B。谱减法把带噪幅度减去 \(\alpha\) 倍噪声幅度。\(\alpha\) 越大,减得越狠,但也会越容易损伤语音,所以它是控制“减噪力度”的关键参数。
Q4. 维纳滤波增益 \(H=\xi/(1+\xi)\) 在 \(\xi\) 很小时趋近于?
- A.0← 正确答案
- B.1
- C.无穷大
- D.采样率
答案:A。当先验信噪比 \(\xi\) 很小时,说明该频点主要是噪声,增益趋近于 0,压掉噪声;当 \(\xi\) 很大时,增益趋近于 1,保留语音。
Q5. 谱减后出现的“音乐噪声”最像哪种体验?
- A.背景有旋律
- B.随机咝咝声和空洞声← 正确答案
- C.明显回声
- D.电流底噪
答案:B。音乐噪声来自频域估计误差的随机起伏,听起来像忽大忽小的咝咝声、空洞声。它不是真正的音乐,而是谱减法残留的不稳定分量。
Q6. 下列哪些是深度降噪网络常见的输入或输出形式?
- A.带噪语音波形← 正确答案
- B.带噪语音频谱← 正确答案
- C.干净语音波形← 正确答案
- D.摄像头画面
答案:ABC。深度降噪网络可以输入输出时域波形,也可以输入输出频域频谱;目标是输出干净语音。摄像头画面与音频降噪无关。
Q7. Decision-Directed 先验 SNR 估计中,平滑系数 \(\alpha\) 通常取什么范围?
- A.接近0
- B.接近1← 正确答案
- C.等于0.5
- D.等于-1
答案:B。Decision-Directed 估计会综合上一帧增强结果和当前帧观测,\(\alpha\) 越接近 1,越依赖历史经验,语音更平稳;越接近 0,越跟随当前帧,但更容易受噪声扰动。
Q8. 以下哪些是实时降噪部署的必要条件?
- A.只用过去帧信息← 正确答案
- B.必须等待未来全部帧
- C.算法延迟可以接受← 正确答案
- D.算力适合端侧← 正确答案
答案:ACD。实时降噪要求每一帧输入后立即输出,因此只能使用当前和过去帧;等待未来帧会破坏实时性。同时延迟要低、算力要适配终端设备。
Q9. PESQ 和 STOI 的侧重点分别是?
- A.PESQ测可懂度,STOI测质量
- B.PESQ测质量,STOI测可懂度← 正确答案
- C.两者都测音量
- D.两者都测延迟
答案:B。PESQ 更接近主观语音质量评分,STOI 更关注语音可懂度,也就是“能不能听清内容”。两者互补,不能只用 SNR 判断降噪好坏。
Q10. 深度降噪里的“因果约束”是指?
- A.只看当前和过去帧← 正确答案
- B.必须看完整段音频
- C.输出一次计算完
- D.模型不含任何参数
答案:A。因果约束要求模型在推理时不能使用未来信息,只能依赖当前帧和过去帧,这样才能满足实时通话场景的低延迟要求。