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 本章知识体系总览
下面这张图,把音频采集与预处理的整个流程串起来了。从麦克风选型开始,到最终输出干净的语音帧给模型,每一步都有讲究。
嗯,这一章的内容就这些。从麦克风选型到VAD输出,每一步都不复杂,但每一步都容易出错。我的建议是:先把“16kHz/16bit/单声道/WAV”这个组合跑通,再慢慢调降噪和VAD的参数。别一上来就想搞全套,容易顾此失彼。