3. 核心概念解析

好,咱们进入第三章。这一章讲的是音频管线的“入口”部分——从物理世界的声音,变成算法能啃的数字信号。说白了,就是怎么把声音“喂”给模型。

我见过不少团队,模型调得挺漂亮,一上硬件就翻车。为什么?音频采集这步没做好。你想想看,模型吃的是数据,数据源头就脏了,后面再怎么洗也白搭。所以这一章,咱们把麦克风选型、采样率设置、格式转换、降噪和VAD这些基本功,一个一个捋清楚。

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

唤醒词场景里,麦克风阵列不是摆设。它直接决定了你的算法能拿到什么质量的信号。

先看几个关键参数:

  • 信噪比(SNR):低于60dB的麦克风,我建议直接pass。我在项目里踩过坑,用了55dB的麦,远场唤醒率直接掉了15个点。
  • 灵敏度:-26dBFS ± 3dB 是主流区间。太灵敏容易饱和,太迟钝又收不到远场声音。
  • 麦克风数量:2麦可以做基本波束成形,4麦能覆盖360°水平面,6麦以上通常用于垂直方向也需要的场景。唤醒词场景,我个人习惯用4麦圆形阵列,性价比最高。
阵列类型 麦克风数 适用场景 典型波束数
线性阵列 2-4 桌面设备、电视 1-3
圆形阵列 4-6 智能音箱、机器人 4-8
球形阵列 6+ 会议系统、高端设备 8+

我的经验: 别盲目追求麦克风数量。阵列算法复杂度随麦克风数呈平方增长。4麦能解决的问题,别上8麦。省下的算力留给模型推理,更划算。

3.2 采样率与位深设置:别让信息丢在门口

采样率和位深,这两个参数决定了音频的“分辨率”。

采样率:唤醒词模型通常用16kHz。为什么?人声的主要能量集中在4kHz以下,16kHz采样率(奈奎斯特频率8kHz)足够覆盖。我见过有人用48kHz采样,模型没变好,反而多了两倍数据量,处理延迟也上去了。没必要。

位深:16bit是标配。8bit量化噪声太大,24bit/32bit在唤醒词场景里属于浪费。16bit的动态范围是96dB,配合60dB SNR的麦克风,绰绰有余。

核心原则: 16kHz / 16bit / 单声道,这是唤醒词场景的“黄金三角”。除非你有特殊需求(比如同时做语音识别),否则别动它。

3.3 音频格式转换:WAV vs FLAC

采集到的原始音频通常是PCM格式,但存储和传输时我们需要封装成文件格式。WAV和FLAC是两种最常见的选择。

WAV(无压缩):

  • 优点:解码零延迟,直接内存映射就能读
  • 缺点:体积大,1分钟16kHz/16bit单声道约1.9MB
  • 适用:实时推理、嵌入式本地存储

FLAC(无损压缩):

  • 优点:压缩比约50%-60%,节省空间
  • 缺点:解码需要CPU开销,约5-10ms/秒音频
  • 适用:云端存储、数据集归档

我在做离线唤醒词设备时,全部用WAV。为什么?因为MCU上解FLAC太费劲,而且唤醒词模型只处理几秒音频,WAV那点体积根本不算事。

格式转换代码示例(Python):

import wave
import numpy as np

# 读取WAV
with wave.open('input.wav', 'rb') as wf:
    sr = wf.getframerate()
    n_frames = wf.getnframes()
    raw = wf.readframes(n_frames)
    audio = np.frombuffer(raw, dtype=np.int16)

# 写入WAV(16kHz/16bit/单声道)
with wave.open('output.wav', 'wb') as wf:
    wf.setnchannels(1)
    wf.setsampwidth(2)  # 16bit = 2字节
    wf.setframerate(16000)
    wf.writeframes(audio.tobytes())

注意: 格式转换时一定要检查采样率和位深。我曾经遇到过,采集卡输出的是32bit float,直接当16bit写进去,结果音频全是噪声。血的教训。

3.4 降噪基础:别把信号也滤掉了

降噪的目的是去除背景噪声,保留人声。但这里有个度——降噪太狠,会把语音的细节也干掉,模型反而认不出来。

常见降噪方法:

  • 谱减法:简单粗暴,适合稳态噪声(风扇、空调)。但容易产生“音乐噪声”。
  • 维纳滤波:效果更好,但需要估计噪声谱。我在项目里常用这个。
  • RNNoise:基于RNN的降噪,效果好但吃算力。适合有NPU的设备。

我个人习惯的做法是:在麦克风端做轻量级降噪(比如谱减法),把明显的底噪去掉。剩下的交给模型自己去适应。模型训练时加一些噪声增强,比在推理时猛降噪更有效。

3.5 VAD(语音活动检测)基础:别让模型白干活

VAD的作用很简单:判断当前音频里有没有人说话。没有的话,就不送给模型推理。省电、省算力、省延迟。

VAD的三种实现方式:

方法 原理 优点 缺点
能量阈值 计算帧能量,超过阈值判为语音 极轻量,零开销 对噪声敏感,容易误判
过零率+能量 结合过零率区分清浊音 比纯能量好一些 仍受噪声影响
WebRTC VAD 基于GMM的统计模型 成熟稳定,参数可调 需要少量内存和计算

我在嵌入式设备上,通常用WebRTC VAD。它有个好处:可以设置“激进程度”,从0(最宽松)到3(最严格)。唤醒词场景我一般设成1或2,太严格会把轻声的唤醒词漏掉。

WebRTC VAD使用示例:

import webrtcvad

vad = webrtcvad.Vad(2)  # 激进程度设为2
frame = audio[i*320:(i+1)*320]  # 16kHz下,20ms = 320采样点
is_speech = vad.is_speech(frame.tobytes(), 16000)

避坑指南: 我曾经把VAD的帧长设成10ms,结果WebRTC VAD频繁误判。后来改成30ms帧长,配合50%帧移,稳定多了。记住:VAD的帧长要和模型推理的窗口对齐,不然会出时序问题。

3.6 本章知识体系总览

下面这张图,把音频采集与预处理的整个流程串起来了。从麦克风选型开始,到最终输出干净的语音帧给模型,每一步都有讲究。

音频采集与预处理流程 麦克风阵列选型 4麦圆形 / SNR≥60dB 采样率 & 位深 16kHz / 16bit / 单声道 音频格式转换 WAV / FLAC 降噪处理 谱减法 / 维纳滤波 VAD 语音活动检测 WebRTC VAD / 能量法 输出语音帧 30ms帧长 / 16kHz / 16bit 关键原则 降噪要适度,VAD要可靠,格式要统一。每一步都影响唤醒率。

嗯,这一章的内容就这些。从麦克风选型到VAD输出,每一步都不复杂,但每一步都容易出错。我的建议是:先把“16kHz/16bit/单声道/WAV”这个组合跑通,再慢慢调降噪和VAD的参数。别一上来就想搞全套,容易顾此失彼。