音频特征基础:时域信号、采样率、帧长、窗函数(汉明窗)、短时傅里叶变换(STFT)的基本原理
TinyML 音频模型处理的不是“声音”本身,而是声音经过数字化和变换后留下的数值痕迹。理解这些痕迹如何产生,是后续讨论 Int8 量化对频谱特征影响的前提。本章从声波进入麦克风成为电信号开始,逐步拆解采样、分帧、加窗、STFT 这一标准链路,并指出每个环节中可能被量化误差放大的敏感点。
上图展示了从连续声波到二维特征图的完整链路。麦克风将声压变化转换为连续电压信号,ADC 以固定采样率读取电压值并量化为离散整数,随后数字信号处理器按帧长切分信号,对每一帧乘以窗函数,再执行 FFT 得到频谱。最终将多帧频谱堆叠为“时间×频率”的特征图,供神经网络消费。图中右侧虚线框标注了 Int8 量化可能侵蚀的六个关键位置,后续章节将逐一展开。
核心原理:从连续声波到离散数值
声音本质是空气分子周期性疏密变化的纵波。麦克风振膜感知气压变化后,将其转换为电压信号,此时信号在时间和幅度上都是连续的。数字系统无法直接处理连续量,必须通过模数转换器(ADC)完成两步离散化:时间离散化(采样)和幅度离散化(量化)。
采样率(fs)决定每秒钟采集多少个时间点。根据奈奎斯特采样定理,要无失真地重建信号,采样率必须大于信号最高频率的两倍。对于语音识别任务,常见采样率为 16kHz,可覆盖 0-8kHz 频带,足以捕捉语音的主要能量集中区(元音共振峰通常在 300Hz-3kHz)。若采样率不足,高频成分会折叠到低频区域,产生混叠失真,这种失真在量化后会被进一步固化。
幅度量化则是将连续的电压值映射到有限个离散等级。16-bit 量化提供 65536 个等级,而 Int8 量化仅提供 256 个等级。对于幅度较小的背景噪声或弱辅音(如 /f/、/s/ 的摩擦噪声),Int8 的量化步长可能大于信号本身的幅度变化,导致这些微弱成分被“抹平”或变成阶梯状噪声。这是量化影响音频特征的第一道关卡。
量化步长计算示例:假设 ADC 输入范围是 ±1V,16-bit 量化步长为 2V/65536 ≈ 30.5μV;而 Int8 量化步长为 2V/256 ≈ 7.8mV。两者相差 256 倍。若某段弱辅音信号幅度仅为 2mV,16-bit 下可分辨约 65 个等级,Int8 下则完全落入一个量化区间内,信息几乎全部丢失。
帧长与帧移:时间分辨率的工程权衡
音频信号是时变的,直接对整个信号做傅里叶变换只能得到全局频率成分,丢失时间演化信息。因此需要将信号切分为短时片段,假设每个片段内信号近似平稳,再对每个片段独立做频谱分析。这就是短时分析的基本思想。
帧长(N)决定每个片段包含的采样点数。帧长越长,频率分辨率越高(频率bin宽度 = fs/N),但时间分辨率越低,且平稳性假设越难成立。帧长越短,时间定位越精确,但频率分辨率下降,低频成分难以区分。对于 16kHz 采样率,常用帧长为 512 点(32ms)或 400 点(25ms)。
帧移(H)是相邻两帧起始点之间的间隔。帧移小于帧长时,相邻帧有重叠区域,避免信号边缘被截断导致的信息丢失。常见设置为帧长的 1/3 到 1/2,例如帧长 512、帧移 160(10ms),重叠率约 68.75%。重叠保证了特征图在时间轴上的平滑过渡,减少帧间突变。
| 参数 | 典型值(16kHz采样) | 频率分辨率 | 时间分辨率 | 适用场景 |
|---|---|---|---|---|
| 帧长 256 | 16ms | 62.5 Hz | 高 | 瞬时事件检测(如拍手声) |
| 帧长 512 | 32ms | 31.25 Hz | 中 | 语音识别、关键词唤醒 |
| 帧长 1024 | 64ms | 15.625 Hz | 低 | 音乐分析、慢变环境声 |
帧长选择直接影响 STFT 输出特征图的维度。帧长 512 时,FFT 输出 256 个频率bin(去除对称部分),若使用 40 维 Mel 滤波器组降维,则每帧特征为 40 维。帧长翻倍至 1024,频率bin数增至 512,但时间帧数减半(相同信号长度下),特征图整体尺寸变化需要模型输入层相应调整。
窗函数与汉明窗:抑制频谱泄漏的关键
对有限长度的帧直接做 FFT,相当于在时域乘了一个矩形窗。矩形窗在频域表现为 sinc 函数,主瓣窄但旁瓣高(第一旁瓣仅比主瓣低约 13dB),导致频谱能量向邻近频率泄漏,弱信号可能被强信号的旁瓣掩盖。
汉明窗是一种余弦类窗函数,其系数定义为:
w[n] = 0.54 - 0.46 * cos(2πn / (N-1)), 0 ≤ n ≤ N-1
汉明窗将帧边缘的采样值衰减到接近零,降低帧边界的不连续性,从而将旁瓣抑制到约 -43dB(比矩形窗改善 30dB)。代价是主瓣宽度增加约一倍,频率分辨率略有下降。对于语音信号,汉明窗是默认选择,因为语音的频谱包络变化较慢,略微降低的频率分辨率对共振峰估计影响不大,而旁瓣抑制带来的信噪比提升收益显著。
量化陷阱:窗函数系数在浮点实现中通常以 double 存储,但 Int8 量化时,窗系数需要被量化为 8-bit 整数。若直接对窗系数做均匀量化,0.54 和 0.46 这类小数会引入较大相对误差。更稳健的做法是:先对时域信号加窗(浮点),再对加窗后的信号做 Int8 量化;或者将窗系数与 FFT 的旋转因子合并量化。切勿先量化窗系数再乘信号,这会引入双重误差。
STFT:从一维信号到二维时频表示
短时傅里叶变换(STFT)将加窗后的每一帧执行离散傅里叶变换(DFT),得到复数频谱。DFT 的计算复杂度为 O(N²),实际工程中使用快速傅里叶变换(FFT)将复杂度降至 O(N log N)。对于帧长 512 的 FFT,输出 512 个复数点,其中前 256 个点对应 0 到 fs/2 的正频率成分,后 256 个点是对称的负频率镜像,通常丢弃。
STFT 的输出包含幅度谱和相位谱。幅度谱表示各频率成分的能量大小,相位谱表示各频率成分的起始相位。在大多数音频分类任务中,模型只使用幅度谱(或进一步转换为 Mel 频谱、MFCC),因为人耳对相位不敏感,且相位信息在量化后极易失真。但若任务涉及信号重建(如语音增强),相位则不可忽略。
STFT 的数学表达式为:
X(m, k) = Σ_{n=0}^{N-1} x[n + mH] · w[n] · e^{-j2πkn/N}
其中 m 为帧索引,k 为频率bin索引,w[n] 为窗函数。输出 X(m, k) 是一个复数矩阵,其幅度谱 |X(m, k)| 构成特征图的一个通道。
案例拆解:16kHz 语音唤醒场景下的参数选择与量化影响
假设我们要为一个关键词唤醒(KWS)模型设计前端特征提取流程,目标是在 Cortex-M4 内核的 MCU 上运行,内存预算 256KB,模型输入为 40 维 Mel 特征,时间帧数为 32。
初始参数设定:采样率 16kHz,帧长 512(32ms),帧移 160(10ms)。32 帧对应约 320ms 的音频窗口,足以覆盖一个两音节关键词(如“Hey Siri”约 300ms)。每帧 FFT 得到 256 个频率bin,经 Mel 滤波器组降维至 40 维,最终特征图尺寸为 32×40。
Int8 量化前后的对比实验:
- 浮点基线:使用 float32 计算 STFT 和 Mel 特征,模型准确率 95.2%。
- 直接 Int8 量化(时域信号):将 16-bit PCM 数据直接截断为 8-bit,即除以 256 后取整。准确率降至 91.8%,主要错误集中在噪声环境下的弱唤醒词。
- 分段量化(推荐方案):保留 16-bit 时域数据,在 STFT 输出后对幅度谱做 Int8 量化。准确率 94.6%,仅下降 0.6 个百分点。
分析过程:直接量化时域信号导致弱辅音(如 /s/、/f/)的幅度信息丢失,这些音素能量集中在 4-8kHz 高频段且幅度仅为元音的 1/10 到 1/20。Int8 的 256 个等级中,大部分被强元音占据,弱辅音仅能分配到 1-2 个量化等级。而分段量化在 STFT 之后进行,此时幅度谱已经过 FFT 的能量累积,弱频率成分的幅度相对提升,量化损失减小。
实际操作步骤:
// 伪代码:分段量化流程
1. 读取 16-bit PCM 数据(保留完整动态范围)
2. 分帧(帧长512,帧移160)
3. 对每帧乘以汉明窗(浮点计算)
4. 执行 FFT,得到复数频谱
5. 计算幅度谱 |X(m,k)| = sqrt(Re² + Im²)
6. 对幅度谱取 log(压缩动态范围)
7. 将 log 幅度谱线性映射到 [-128, 127] Int8 范围
8. 输入 Mel 滤波器组(滤波器系数预先量化为 Int8)
结果对比:分段量化方案在安静环境下准确率与浮点基线几乎一致(94.8% vs 95.2%),在 10dB 信噪比噪声环境下准确率下降 2.1%,而直接量化方案下降 5.3%。代价是分段量化需要额外存储 16-bit 时域数据(每帧 1KB),但 MCU 内存预算可承受。
复盘经验:量化位置的选择比量化位宽本身更重要。在信号能量集中的域(如 log 幅度谱)做量化,比在原始时域做量化更鲁棒。此外,Mel 滤波器组的系数也应预先量化,避免在运行时进行浮点乘法。
常见误区与总结复盘
- 误区一:采样率越高越好。高采样率意味着更多数据、更大计算量,但若信号本身不含高频成分,过高的采样率只会浪费 MCU 的算力和内存。应根据任务频带需求选择采样率,语音 16kHz 足够,音乐可考虑 44.1kHz。
- 误区二:帧长越长,特征越好。长帧提高频率分辨率,但降低时间分辨率,且平稳性假设失效。对于瞬态声音(如拍手、敲击),长帧会模糊事件的时间边界。
- 误区三:窗函数可有可无。省略窗函数(即使用矩形窗)会导致频谱泄漏,弱频率成分被强成分旁瓣掩盖。在量化场景下,泄漏效应会被放大,因为量化本身已引入噪声。
- 误区四:STFT 后直接丢弃相位。对于分类任务可以丢弃,但若后续需要做数据增强(如 SpecAugment 的时频掩码),相位信息虽不直接使用,但幅度谱的修改会影响重建质量(若未来需要逆变换)。
- 误区五:Int8 量化只影响幅度,不影响频率位置。实际上,量化误差可能改变 FFT 输出的峰值位置,导致频率bin偏移,尤其在低幅度帧中,噪声可能被误判为弱音素。
工程建议:在 TinyML 项目中,建议先使用浮点模型验证特征提取参数(帧长、帧移、窗类型),确定最优组合后,再针对量化做专项优化。量化时优先选择在幅度谱或 log 幅度谱域进行,并配合 MinMax 或 Percentile 校准方法确定量化范围,避免使用固定 [-1, 1] 映射导致动态范围浪费。