第4章 语音算法概述:语音信号处理全链路
好,咱们进入正题。这一章我打算把语音算法的全链路给你捋一遍。你想想看,一个麦克风采集到的原始信号,到最终机器能理解你说什么,中间要经过多少道工序?我做了这么多年嵌入式音频,坦白讲,很多刚入行的工程师容易把注意力只放在ASR或者KWS上,忽略了前端的信号处理。嗯,这是个坑,我踩过。
4.1 为什么需要全链路?
说白了,麦克风收到的不是干净的语音。它混着空调声、马路上的车流声、还有你自己房间里的回声。如果你直接把这种信号丢给语音识别引擎,结果就是——识别率惨不忍睹。
我记得有一次帮客户调试一个智能音箱项目。客户说他们的ASR在安静环境下准确率95%,一放到客厅就掉到60%。我过去一看,AEC和NS根本没做优化。这就是典型的「前端不干活,后端背黑锅」。
所以,全链路的意义在于:把脏活累活在前端干完,让后端只处理干净的语音。
4.2 全链路模块一览
我习惯把语音信号处理全链路分成三个阶段:
- 前端处理:VAD、AEC、NS、DOA、BF
- 唤醒与识别:KWS、ASR
- 语义理解:NLP
下面我一个一个说。
4.3 VAD(语音活动检测)
VAD的任务很简单:判断当前这一段信号里有没有人说话。别小看这个功能,它是整个链路的守门员。
为什么重要?
- 没有VAD,AEC和NS会一直工作,功耗高得吓人
- 没有VAD,KWS会一直尝试识别,误唤醒率飙升
我在项目中遇到过一种情况:客户要求待机功耗低于10mW。我直接把VAD的阈值调高,让芯片在95%的时间里处于休眠状态。效果立竿见影。
4.4 AEC(声学回声消除)
AEC解决的是「自己说的话又被麦克风收回去」的问题。比如你对着音箱说「播放音乐」,音箱播放音乐的同时,麦克风又听到了音乐声。如果不消除,这个音乐声就会干扰下一句指令。
AEC的核心原理:
- 参考信号:从扬声器端拿到正在播放的音频
- 自适应滤波:估计回声路径
- 相减:从麦克风信号中减去估计的回声
我曾经踩过一个坑:AEC的参考信号延迟没对齐。结果回声不但没消掉,反而产生了新的噪声。后来我学乖了,每次调试AEC第一件事就是量延迟。
4.5 NS(噪声抑制)
NS就是把背景噪声压下去。常见的噪声有:空调声、风扇声、马路噪声、键盘敲击声。
NS的两种主流方法:
| 方法 | 优点 | 缺点 |
|---|---|---|
| 谱减法 | 计算量小,适合MCU | 容易产生音乐噪声 |
| 基于DNN的NS | 效果好,噪声残留少 | 需要DSP或NPU |
我个人建议:如果芯片算力有限,用谱减法加一个后处理滤波器就够了。如果芯片有NPU,果断上DNN方案。
4.6 DOA(声源定位)
DOA告诉你声音从哪个方向来。这个信息有什么用?
- 让波束形成(BF)指向说话人
- 实现「谁在说话」的判定
- 用于摄像头联动(比如会议摄像头自动转向说话人)
DOA的精度取决于麦克风阵列的拓扑结构。我常用的阵列有:
- 线性阵列:左右方向精度高,前后方向差
- 圆形阵列:360度全覆盖,但算法复杂
嗯,这里要注意:DOA在低频段精度差,因为波长长,相位差小。所以如果你做远场语音,低频部分的DOA结果要打个折扣。
4.7 BF(波束形成)
BF就是「把耳朵转向说话人」。它利用多个麦克风的信号,增强目标方向的声音,抑制其他方向的声音。
BF的两种常见实现:
- 固定波束形成:指向固定方向,适合已知场景
- 自适应波束形成:根据DOA结果动态调整指向,适合移动说话人
我在一个智能家居项目中用过自适应BF。效果确实好,但有个问题:如果DOA估计错了,BF会把噪声方向当成目标方向,反而把语音抑制了。所以DOA和BF一定要联合调优。
4.8 KWS(关键词唤醒)
KWS就是「小爱同学」、「Hey Siri」这种唤醒词检测。它和ASR的区别在于:KWS只识别几个固定的词,ASR识别任意文本。
KWS的两种主流方案:
| 方案 | 特点 | 适用芯片 |
|---|---|---|
| 基于DNN的KWS | 准确率高,但需要一定算力 | 带NPU的芯片 |
| 基于GMM的KWS | 计算量小,适合MCU | 低端MCU |
我建议:如果芯片有硬件加速器,用DNN方案。如果只是Cortex-M4这种,用GMM方案加一些手工特征就够了。
4.9 ASR(自动语音识别)
ASR把语音转成文字。这是整个链路里最吃算力的环节。
ASR的两种部署方式:
- 本地ASR:模型跑在芯片上,延迟低,但词库有限
- 云端ASR:音频上传到云端识别,词库大,但依赖网络
我个人的经验是:对于智能家居这种场景,本地ASR就够了。对于通用语音助手,必须上云端。但要注意,云端ASR的延迟和网络抖动是个大问题。
4.10 NLP(自然语言处理)
NLP是最后一步,它理解文字的含义。比如你说「打开客厅的灯」,NLP要解析出:
- 动作:打开
- 对象:灯
- 位置:客厅
NLP在嵌入式端通常只做简单的意图分类和槽位填充。复杂的语义理解还是得上云。
我遇到过一种情况:用户说「把灯调暗一点」,NLP解析成「调暗灯」。但用户其实是想调暗客厅的灯,不是卧室的。这就是NLP的上下文理解问题。目前嵌入式端还很难解决,一般会结合场景预设来处理。
4.11 全链路的工程落地建议
最后,我总结几条实战经验:
- 先做前端,再做后端:先把VAD、AEC、NS、BF调好,再调KWS和ASR。否则你永远不知道问题是出在前端还是后端。
- 算力分配要合理:我一般把30%的算力给前端,40%给KWS/ASR,30%留给系统和其他任务。
- 延迟要控制:全链路延迟最好控制在200ms以内。超过300ms,用户就会觉得「卡」。
- 测试场景要覆盖:安静环境、嘈杂环境、远场、近场、多人说话场景,都要测。
好了,这一章就到这里。下一章我会详细讲VAD的算法实现和芯片适配,咱们到时候接着聊。