想象你从菜市场拎回一袋带泥的土豆、番茄和青椒。直接下锅当然可以,但聪明的厨师会先洗、切、按味道分类,最后做成方便携带的调味包。语音识别的输入——麦克风录下的声波——也像一袋未经处理的食材。FBank 和 MFCC,就是厨房里两条经典的加工流水线:一个保留食材原本的色泽,一个浓缩成便于保存的精华。本文会带你从菜市场走到餐桌,逐步看懂预加重、分帧加窗、FFT、梅尔滤波器组,最后学会在工程中选对那道菜。
掌握 FBank 与 MFCC 的提取原理,是做语音识别落地、调优声学模型的基础,也是从“会用接口”走向“理解系统”的关键一步。
可视化演示
动态演示MFCC与FBank声学特征的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
MFCC与FBank声学特征:语音信号 语音信号预处理:预加重与分帧加 FFT频谱分析与功率谱密度估计 核心机制可视化 MFCC与FBank声学特征整体架构与关键组件
特征基础概念
走进语音识别厨房,第一步不是炒菜,而是决定把哪些食材端上桌。未经处理的波形就像整袋带泥的菜,信息全但太杂。特征提取的目的,就是把它变成几盘方便模型下口的菜。整个语音识别系统通常由前端信号处理、特征提取、声学模型、语言模型和解码器组成,而声学特征就是前端与模型之间的“标准食材包”。
一条语音先被麦克风变成电信号,再由 ADC 按固定周期采样,变成离散的数字序列。这个过程叫采样与量化。每秒钟采样的次数就是采样率 \(f_s\),16kHz 是电话语音的常见值。采样率越高,声音细节越多,但数据量也越大,所以要在清晰度与成本之间做取舍。
在此基础上,FBank 和 MFCC 都是描述短时功率谱的特征。它们不是直接处理整段音频,而是先切割成帧,再把每一帧转成特征向量。从特征类型上看,FBank 属于滤波器组输出的对数能量,MFCC 则是再经过离散余弦变换压缩后的倒谱特征。
所以选择特征就像选菜:FBank 是新鲜沙拉,MFCC 是浓缩汤汁,核心目标都是让模型吃得舒服,只是后厨加工方式不同。
- 连续信号采样\(x[n]\) 是从连续信号 \(x_a(t)\) 上每隔 \(T\) 秒取一个点得到的离散序列。
- 采样周期\(T\) 是两个采样点之间的时间间隔,单位为秒。
- 采样率\(f_s\) 是每秒采样点数,16kHz 表示每秒 16000 个样本。
预加重与分帧
切菜最怕鱼皮打滑,语音信号也有个类似麻烦:低频能量高,高频能量低,且频率越高衰减越厉害。预加重就像在刀上抹一层盐,把高频的边缘提起来,方便后续分析。它用一阶高通差分器实现:当前样本减去上一样本乘以系数 \(\alpha\)。
预加重让变化快的高频分量相对变大,而变化慢的低频分量被压低。工程上 \(\alpha\) 通常取 0.97。做完预加重后,长语音要被切成 25ms 左右的小段,相邻帧之间帧移 10ms,重叠 15ms,避免大切大合造成的信息断裂。分帧后每帧还要加汉明窗,让帧两端平滑归零,防止矩形截断产生的频谱泄漏。
预加重、分帧、加窗就像洗好切好、给食材抹油,接下来才能进蒸锅做频谱分析。
- 当前样本保留输出 \(y[n]\) 由当前输入 \(x[n]\) 减去上一时刻输入的一部分得到。
- 差分项\(-\alpha x[n-1]\) 实现一阶高通,\(\alpha\) 越接近 1,高频提升越强。
- 高通效果低频相邻样本变化慢、差值小;高频变化快、差值大,于是高频被相对放大。
频谱与FFT
一整锅汤看不出每味料的含量。用 FFT 就像把汤倒进分光棱镜,每一缕颜色对应一个频率,汤的配方一目了然。对每一帧加窗后的信号做离散傅里叶变换,就得到 \(N\) 个频点上的复数值。取模平方就是功率谱,它描述每个频率携带多少能量。
帧长 \(N\) 决定频率分辨率:\(\Delta f = f_s / N\)。帧长越长,频率上越细腻,但时间上更模糊;帧长越短,时间上更敏锐,但频率上更粗糙。实际常用 N_FFT=512,配合 16kHz 采样率,频率分辨率约 31.25Hz,兼顾效率和细节。
频谱是后厨的半成品,可以按不同口味继续加工成不同菜式。
- 频率分量\(X[k]\) 是第 \(k\) 个频点的复数结果,模长表示该频率的强度。
- 累加范围\(N\) 是帧长,\(n\) 从 0 到 \(N-1\),对一帧内所有样本累加。
- 旋转因子\(e^{-j\frac{2\pi}{N}kn}\) 是不同频率的复指数基底,相当于用不同频率的“尺子”去量信号。
梅尔滤波器组
人耳不是仪表盘,对低频变化敏锐、对高频迟钝。梅尔刻度就是这个“人耳味觉曲线”。把频谱按梅尔刻度分组,就像把食材按酸甜苦辣分碗装。梅尔频率与线性频率的关系常用下面的公式表示,1000Hz 在梅尔刻度上约等于 1000 梅尔,频率越高,梅尔间距被压缩得越厉害。
梅尔滤波器组由一组三角滤波器组成,每个滤波器对功率谱做加权求和,输出一个能量值。对能量取对数,得到 log-mel 特征,也就是 FBank。滤波器数量通常取 40 或 80,太多会引入冗余,太低则会丢失分辨率。
梅尔滤波器组像装菜的盆,按人耳口味分好类,下一道工序决定它上桌的形式。
- 梅尔频率\(\text{mel}(f)\) 把线性频率 \(f\) 映射到模拟人耳听感的梅尔刻度。
- 常数 2595这是让 1000Hz 时 \(\text{mel}(1000) \approx 1000\) 的归一化常数。
- 对数压缩分母 700 控制压缩程度,高频区域被压得更密,模拟人耳对高频不敏感的特性。
MFCC与FBank
FBank 是新鲜的什锦沙拉,色彩丰富但叶子互相纠缠;如果厨师需要方便携带,就把它做成浓缩汤包,去掉水分和纠缠,只留下最有代表性的味道。这个浓缩动作就是离散余弦变换。FBank 各维之间有较强相关性,直接喂给对角协方差的 GMM 会浪费建模能力。对 FBank 做 DCT,再只取前 13 维,得到的就是 MFCC。
DCT 相当于把能量集中到少数系数上,达到去相关和降维的目的。MFCC 在噪声鲁棒性和特征压缩上更有优势,是 GMM-HMM 时代的主流;而 DNN 声学模型能利用冗余信息,因此常常直接用 FBank,省去 DCT 反而保留更多细节。选型要看模型,不能绝对地说谁更好。
沙拉还是汤包?取决于后面吃饭的模型是喜欢原味还是喜欢便携。
- 输入对数能量\(S_k\) 是第 \(k\) 个梅尔滤波器输出的对数能量,也就是 FBank 的第 \(k\) 维。
- 余弦基函数\(\cos\left[\frac{\pi m}{M}\left(k-\frac{1}{2}\right)\right]\) 是 DCT 的基函数,用于与 FBank 向量做内积。
- 输出倒谱系数\(C_m\) 是第 \(m\) 个 MFCC 系数,通常取 \(m=1,\ldots,13\),能量集中且相关性低。
工程实践与选型
同样的菜品,餐厅会根据菜单定位调整份量和摆盘。特征工程也一样,要决定维度、要不要加配料、如何标准化。实践中常用 40 维 FBank 或 13 维 MFCC,再拼接一阶差分 \(\Delta\) 和二阶差分 \(\Delta\Delta\),捕捉帧间的动态变化。有时还做倒谱均值归一化,消除信道和说话人带来的整体偏移。
归一化公式把特征分布拉回零均值单位方差,避免某些维度过大主导训练。工具方面,librosa 适合快速提取原型,Kaldi 更适合大规模 ASR 数据管线和 GMM-HMM/Chain 模型训练。工程选型时,还要考虑实时性、硬件算力和模型结构。
最后端上桌的,是经过打磨、符合具体场景的那一份特征拼盘。
- 均值 \(\mu\)统计特征每个维度的平均值,代表整体偏移。
- 标准差 \(\sigma\)衡量特征值围绕均值的波动范围。
- 标准化输出\(\hat{x}\) 将原始特征变成零均值单位方差,利于加速模型收敛。
AI 应用场景
智能音箱唤醒词检测
阶段:特征提取 / 前端信号处理
解决的问题:传统唤醒词用模板匹配,在噪声环境下误唤醒率高。AI 方式用 DNN 分类器,需要输入对噪声鲁棒、信息完整的特征。FBank 保留了频谱细节,配合数据增强后,模型能学到更鲁棒的模式。
具体案例:米家/天猫精灵在低功耗唤醒场景,先把 16kHz 音频分帧加窗,提取 40 维 FBank,输入一个小型 CNN,检测到“小爱同学”再启动主引擎。
呼叫中心质检
阶段:ASR 声学模型训练
解决的问题:人工抽检录音成本高,全量转写需要高准确率。基于 GMM-HMM 的传统系统偏好使用去相关、低维的 MFCC,配合说话人自适应。
具体案例:某银行每天 20 万通电话,使用 Kaldi 流程提取 13 维 MFCC 并拼接 \(\Delta/\Delta\Delta\),训练声学模型后转写文本,再用 NLP 检测违规话术。
实时语音翻译耳机
阶段:端上推理与压缩
解决的问题:耳机芯片算力有限,特征提取要轻量、维度要低。MFCC 维度低且能量集中,能减少模型输入和计算量。
具体案例:某翻译耳机在 DSP 上实现预加重、分帧、FFT、梅尔滤波和 DCT,提取 13 维 MFCC,在低功耗 MCU 上完成实时识别。
Python 演示
import numpy as np def pre_emphasis(x, alpha=0.97): return np.append(x[0], x[1:] - alpha * x[:-1]) def framing(y, sr=16000, win=0.025, hop=0.010): n = int(sr * win) h = int(sr * hop) return [y[i:i + n] for i in range(0, len(y) - n + 1, h)] def power_spectrum(frame, n_fft=512): win = 0.54 - 0.46 * np.cos(2 * np.pi * np.arange(len(frame)) / (len(frame) - 1)) spec = np.fft.rfft(frame * win, n=n_fft) return np.abs(spec) ** 2 def mel_filter_bank(n_filters=40, n_fft=512, sr=16000): low = 0 high = 2595 * np.log10(1 + (sr / 2) / 700) mels = np.linspace(low, high, n_filters + 2) freqs = 700 * (10 ** (mels / 2595) - 1) bins = np.floor((n_fft + 1) * freqs / sr).astype(int) fbank = np.zeros((n_filters, n_fft // 2 + 1)) for i in range(1, n_filters + 1): l, m, r = bins[i - 1], bins[i], bins[i + 1] if m > l: fbank[i - 1, l:m] = (np.arange(l, m) - l) / (m - l) if r > m: fbank[i - 1, m:r] = (r - np.arange(m, r)) / (r - m) return fbank def dct13(x): n = len(x) out = np.zeros(13) for k in range(13): out[k] = np.sum(x * np.cos(np.pi * k * (np.arange(n) + 0.5) / n)) return out def extract(signal, sr=16000): y = pre_emphasis(signal) frames = framing(y, sr) fbank = mel_filter_bank(40, 512, sr) fb_feats = [] for f in frames: pspec = power_spectrum(f) log_energy = np.log(pspec @ fbank.T + 1e-10) fb_feats.append(log_energy) fb_feats = np.asarray(fb_feats) mfcc_feats = np.apply_along_axis(dct13, 1, fb_feats) return fb_feats, mfcc_feats if __name__ == "__main__": sr = 16000 t = np.arange(int(sr * 0.1)) / sr signal = np.sin(2 * np.pi * 440 * t) + 0.5 * np.sin(2 * np.pi * 2200 * t) fbank, mfcc = extract(signal, sr) print("FBank shape:", fbank.shape) print("MFCC shape:", mfcc.shape)
def pre_emphasis(x, alpha=0.97):做一阶高通预加重,抬高高频分量。return np.append(x[0], x[1:] - alpha * x[:-1])当前采样点减去 0.97 倍上一采样点。def framing(y, sr=16000, win=0.025, hop=0.010):将信号切成 25ms 帧、10ms 帧移。win = 0.54 - 0.46 * np.cos(...)构造汉明窗,减少频谱泄漏。spec = np.fft.rfft(frame * win, n=n_fft)对加窗后的帧做 FFT。high = 2595 * np.log10(1 + (sr / 2) / 700)计算 Nyquist 频率对应的梅尔值。fbank[i - 1, l:m] = (np.arange(l, m) - l) / (m - l)填充三角形滤波器上升沿。log_energy = np.log(pspec @ fbank.T + 1e-10)频率能量与梅尔滤波器组矩阵相乘并取对数,得到 FBank。mfcc_feats = np.apply_along_axis(dct13, 1, fb_feats)对每帧 FBank 做 DCT 得到 MFCC。
常见误区
误区我常看论文里用 MFCC,觉得 MFCC 就是更高级的特征,FBank 只是中间态,能上 MFCC 就不用 FBank。
正解不一定。FBank 保留更多原始频谱细节,特征间冗余对 DNN 来说反而是信息,许多现代 ASR(如语音唤醒、端到端模型)直接用 FBank 效果更好。MFCC 的 DCT 去掉相关性,适合 GMM 等对角协方差模型,但会丢失人耳不敏感但模型可能需要的细节。
为何常见:早期 GMM-HMM 时代论文几乎都是 MFCC,给人留下“标准答案”的印象。
误区预加重是为了增强高频,那把 α 设成 0.999 甚至 1.0,高频不是更强更好吗?
正解过大的 α 会把高频噪声放得很大,同时让低频能量被压到几乎为零,反而破坏频谱结构。0.97 是长期工程实践折中;实际要根据数据和噪声情况调整,而不是越大越好。
为何常见:看到公式 \(y[n]=x[n]-\alpha x[n-1]\) 时,以为 α 是控制“增强强度”的旋钮,忽略了它是一个差分滤波器的反馈系数。
误区汉明窗把帧两端变成 0,数据不是少了一截吗?直接用矩形窗保留全部信号不是更好?
正解矩形窗在帧边界突然截断,会在频谱上产生旁瓣泄漏,把本不存在的频率成分混进来。汉明窗通过平滑渐变消除了截断突变,虽然时域幅度有衰减,但频域反而更干净,信息更可用。
为何常见:直觉上“保留越多越好”,忽略 DFT 周期性假设对边界的要求。
误区滤波器数量从 40 加到 80,特征维度更高,应该能保留更多信息,为什么不用更多?
正解滤波器数量增加会让相邻滤波器重叠部分更多,特征维间相关性增大,模型需要更多参数去拟合冗余,训练数据不够时容易过拟合。实际 40 维 FBank 已经能覆盖人耳主要感知范围,80 维通常用于更细粒度的场景。
为何常见:存在“特征维度越高=信息越多”的直觉,但特征质量和相关性更重要。
面试题
Q1. 语音预加重公式 \(y[n]=x[n]-\alpha x[n-1]\) 中,α 的常用取值是?
- A.0.97← 正确答案
- B.0.50
- C.1.50
- D.0.10
答案:A。α 通常取 0.97,既提升高频又不过分放大噪声。1.5 会让系统不稳定,0.5 和 0.1 高频补偿不足,工程上很少使用。
Q2. 16kHz 采样率下,25ms 帧长对应的采样点数是?
- A.400 点← 正确答案
- B.160 点
- C.250 点
- D.1000 点
答案:A。16000 × 0.025 = 400。帧长决定一帧内包含的样本数量,也是 FFT 输入长度的基础。
Q3. 1000Hz 在线性频率刻度上大致对应多少 Mel?
- A.约 1000 梅尔← 正确答案
- B.约 500 梅尔
- C.约 2000 梅尔
- D.约 7000 梅尔
答案:A。\(\text{mel}(1000)=2595\log_{10}(1+1000/700)\approx999.9\),所以约等于 1000 梅尔,这是梅尔刻度的设计中点。
Q4. FBank 与 MFCC 的核心区别是 MFCC 多做了哪一步?
- A.离散余弦变换← 正确答案
- B.逆傅里叶变换
- C.快速傅里叶变换
- D.一阶预加重
答案:A。FBank 是对数梅尔能量,MFCC 在 FBank 基础上做 DCT 并截断前若干维,达到去相关和降维的目的。
Q5. 深度神经网络语音模型常直接使用 FBank 的原因是什么?
- A.保留频谱细节并利用冗余← 正确答案
- B.特征维度更小更省内存
- C.特征已经完成去相关
- D.完全不需要分帧和加窗
答案:A。DNN 能拟合多维相关特征,FBank 保留更多频谱细节,冗余信息对深层模型有助益。MFCC 的 DCT 反而会丢失部分细节,且 FBank 同样需要分帧加窗。
Q6. 其他条件不变时,增大帧长对频域特征的影响是?
- A.频率分辨率提高← 正确答案
- B.时间分辨率提高
- C.频率分辨率降低
- D.不影响频域特征
答案:A。频率分辨率 \(\Delta f = f_s / N\),帧长 \(N\) 增大使 \(\Delta f\) 变小,频率上更精细;但一帧覆盖时间变长,时间分辨率会下降,两者此消彼长。
Q7. 加汉明窗的主要目的是?
- A.减少频谱泄漏← 正确答案
- B.增加采样点数
- C.消除所有噪声
- D.提高采样率
答案:A。矩形窗截断会在频域产生旁瓣泄漏,汉明窗让帧两端平滑归零,减轻截断突变带来的伪频率分量。
Q8. 下列哪些是 FBank 特征的优点?
- A.保留更多音频细节← 正确答案
- B.特征冗余适合深度模型← 正确答案
- C.经过 DCT 维度更低
- D.天然适合 GMM 建模
答案:AB。FBank 保留对数功率谱细节,未经过 DCT 压缩,冗余虽高但能被深度模型消化;GMM 通常需要去相关的 MFCC,所以 D 错误。
Q9. 关于 MFCC 与 FBank,下列说法正确的有?
- A.FBank特征由梅尔滤波得到← 正确答案
- B.MFCC特征由DCT变换得到← 正确答案
- C.FBank特征相关性比较弱
- D.MFCC适合GMM-HMM系统← 正确答案
答案:ABD。FBank 相邻滤波器重叠,相关性较强;MFCC 通过 DCT 去相关,适合 GMM-HMM 对特征独立性的假设,因此 C 错误。
Q10. 下列哪些因素会影响单帧特征最终维数?
- A.梅尔滤波器组数量← 正确答案
- B.MFCC 截断维数← 正确答案
- C.采样率的大小
- D.是否拼接动态特征← 正确答案
答案:ABD。滤波器数量决定 FBank 维度,MFCC 截断维数决定 DCT 输出长度,拼接 Δ/ΔΔ 会让维度翻倍。采样率影响帧长对应的采样点数,但不改变单帧特征维度,因此 C 错误。