3、音频采集与预处理:麦克风阵列选型、AEC、AGC、降噪算法

好,咱们进入第三章。这一章聊的是车载语音系统的「耳朵」和「听力矫正」。说白了,麦克风就是车的耳朵,而AEC、AGC、降噪这些算法,就是帮这耳朵把声音听清楚、听准确的手段。

我见过不少团队,把精力全砸在语音识别模型上,结果上车一测,识别率惨不忍睹。为什么?因为前端音频没处理好。你想想看,车里开着空调、放着音乐、路噪胎噪嗡嗡响,麦克风收进来的信号就是一锅粥。后端模型再强,也架不住输入信号太烂。

所以,这一章咱们把音频采集和预处理这块掰开揉碎了讲。我个人习惯是:先定硬件选型,再搞算法链路。顺序不能乱。

3.1 麦克风阵列选型:不是越多越好

车载场景下,麦克风阵列的选型有几个硬约束:

  • 安装位置:通常在内后视镜、顶棚、A柱或方向盘附近
  • 拾音距离:要覆盖主驾、副驾,甚至后排
  • 抗干扰:风噪、空调出风口气流、发动机振动

常见的阵列构型有这几种:

阵列类型 麦克风数量 适用场景 我的评价
单麦 1 仅主驾唤醒 成本低,但基本告别多音区
双麦线阵 2 主驾+副驾 波束成型勉强能用,但后排没戏
四麦环形 4 全车四音区 我比较推荐,性价比高
六麦及以上 6-8 高端车型、主动降噪 效果好,但算法复杂度翻倍

我个人建议:量产项目起步选四麦环形阵列。既能覆盖前后排,又不会把DSP算力吃光。

选型时还要注意麦克风的灵敏度、信噪比和声学过载点。我踩过一个坑:某款麦克风灵敏度标称-26dB,上车实测发现高频段衰减严重,导致语音识别对「s」「sh」这类齿音特别差。后来换了-24dB、频响更平直的型号,问题才解决。

3.2 AEC(回声消除):别让车机自己跟自己说话

AEC要解决什么问题?很简单:车机播放音乐或导航语音时,麦克风也把这些声音收进去了。如果不做消除,语音识别就会听到「导航语音+你的指令」的混合体,结果可想而知。

AEC的核心原理是自适应滤波。大致流程是:

  1. 参考信号提取:从音频播放通道拿到正在播的信号
  2. 自适应滤波器:模拟声音从扬声器到麦克风的传输路径
  3. 相减操作:从麦克风采集信号中减去估计的回声分量
  4. 双讲检测:判断是只有回声,还是人也在说话

这里有个关键点:双讲检测(Double-Talk Detection)做不好,AEC会把人的声音也消掉。我见过一个项目,车主说话时AEC还在疯狂收敛,结果语音指令被削成了半截。后来我们把双讲检测的阈值调低,并加入了非线性处理,才稳住。

代码层面,AEC通常跑在DSP或ARM的Cortex-M核上。一个简化的处理流程如下:

// 伪代码:AEC核心循环
while (1) {
    ref_buf = get_playback_buffer();   // 获取参考信号
    mic_buf = get_mic_buffer();        // 获取麦克风信号
    
    // 双讲检测
    dt_state = double_talk_detect(ref_buf, mic_buf);
    
    if (dt_state == ECHO_ONLY) {
        // 只有回声,正常更新滤波器
        adapt_filter(ref_buf, mic_buf);
        echo_est = apply_filter(ref_buf);
        output = mic_buf - echo_est;
    } else if (dt_state == DOUBLE_TALK) {
        // 人在说话,冻结滤波器系数
        echo_est = apply_filter(ref_buf);  // 用旧系数
        output = mic_buf - echo_est;
    }
    
    send_to_voice_engine(output);
}

嗯,这里要注意:滤波器长度要跟车内混响时间匹配。一般车内混响时间在50-150ms,采样率16kHz的话,滤波器阶数大概在800-2400阶。太短消不干净,太长算力扛不住。

3.3 AGC(自动增益控制):让大声小声都能听清

AGC的作用是:不管说话人离麦克风远还是近,输出音量都保持在一个稳定范围

车载场景下,主驾离麦克风可能只有30cm,后排乘客可能有1.5米。如果不做AGC,后排说话的声音会比主驾小6-10dB,识别率直接崩。

AGC的实现策略一般分两种:

  • 模拟AGC:在ADC之前调整前置放大器增益。好处是动态范围大,坏处是硬件成本高。
  • 数字AGC:在数字域做增益调整。灵活,但要注意噪声放大问题。

我曾经在项目里吃过数字AGC的亏:当环境安静时,AGC检测到信号弱,疯狂拉高增益,结果把底噪也放大了。车主一说话,反而被底噪淹没。后来我们加了噪声门限,信号低于底噪时不做增益提升,才解决。

AGC的典型参数:

参数 推荐值 说明
目标电平 -26 dBFS 语音信号峰值的目标幅度
攻击时间 5-10 ms 信号变强时,增益下降的速度
释放时间 100-500 ms 信号变弱时,增益恢复的速度
最大增益 20-30 dB 防止噪声过度放大

攻击时间要短,这样突然的大声不会削波。释放时间要长,避免增益在说话间隙频繁跳变——你想想看,一句话里增益忽大忽小,听着多难受。

3.4 降噪算法:把信号从噪声里捞出来

车载噪声种类多、变化快。有稳态的(发动机怠速、空调风声),也有非稳态的(转向灯滴答声、雨刮器声、路噪)。

常用的降噪方法有:

  • 谱减法:估计噪声谱,从信号谱中减去。简单,但容易产生「音乐噪声」。
  • 维纳滤波:基于统计模型,效果比谱减法好,但计算量大。
  • 子空间法:把信号分解到噪声子空间和语音子空间,保留语音部分。适合低信噪比场景。
  • 深度学习降噪:用DNN/RNN做端到端降噪。效果好,但需要NPU或GPU支持。

我个人在量产项目里最常用的是「谱减法+维纳滤波」的组合。谱减法做粗降噪,维纳滤波做精细处理。算力消耗可控,效果也够用。

降噪算法的一个关键指标是降噪量语音失真的平衡。降噪太狠,语音会变得「闷」或者「有金属感」。我见过一个方案,降噪量做到20dB,但语音听起来像机器人,车主投诉说「你们这车机是不是坏了」。

所以,我的经验是:降噪量控制在10-15dB就够了。剩下的交给语音识别模型的鲁棒性去处理。别想着一步到位把噪声全干掉,那不现实。

3.5 整体处理链路

把上面这些串起来,一个完整的音频预处理链路是这样的:

  1. 麦克风阵列采集多通道音频
  2. 波束成型(Beamforming):指向说话人方向
  3. AEC:消除播放回声
  4. 降噪:去除环境噪声
  5. AGC:统一音量
  6. 输出给语音唤醒和识别引擎

这个链路的顺序不能乱。比如,如果先做AGC再做降噪,AGC会把噪声也放大,降噪压力就大了。如果先做降噪再做AEC,AEC的参考信号和麦克风信号之间的相关性会被破坏,回声消除效果大打折扣。

我建议你在调试时,先把每个模块单独调通,再联调。尤其是AEC和降噪之间的交互,很容易出现「降噪把回声的残留部分当噪声消掉,AEC又以为回声没消干净继续调整」的死循环。嗯,这问题我调了整整两周才搞定。

好了,这一章的内容就到这。音频预处理是车载语音系统的地基,地基不稳,上层建筑再漂亮也白搭。下一章咱们聊语音唤醒——怎么让车在嘈杂环境中准确喊出「你好,XX」。