想象你从菜市场拎回一袋带泥的土豆、番茄和青椒。直接下锅当然可以,但聪明的厨师会先洗、切、按味道分类,最后做成方便携带的调味包。语音识别的输入——麦克风录下的声波——也像一袋未经处理的食材。FBank 和 MFCC,就是厨房里两条经典的加工流水线:一个保留食材原本的色泽,一个浓缩成便于保存的精华。本文会带你从菜市场走到餐桌,逐步看懂预加重、分帧加窗、FFT、梅尔滤波器组,最后学会在工程中选对那道菜。

岗位关联

掌握 FBank 与 MFCC 的提取原理,是做语音识别落地、调优声学模型的基础,也是从“会用接口”走向“理解系统”的关键一步。

目录
  1. 可视化演示
  2. 特征基础概念
  3. 预加重与分帧
  4. 频谱与FFT
  5. 梅尔滤波器组
  6. MFCC与FBank
  7. 工程实践与选型
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示MFCC与FBank声学特征的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

MFCC与FBank声学特征:语音信号 语音信号预处理:预加重与分帧加 FFT频谱分析与功率谱密度估计 核心机制可视化 MFCC与FBank声学特征整体架构与关键组件

特征基础概念

走进语音识别厨房,第一步不是炒菜,而是决定把哪些食材端上桌。未经处理的波形就像整袋带泥的菜,信息全但太杂。特征提取的目的,就是把它变成几盘方便模型下口的菜。整个语音识别系统通常由前端信号处理、特征提取、声学模型、语言模型和解码器组成,而声学特征就是前端与模型之间的“标准食材包”。

一条语音先被麦克风变成电信号,再由 ADC 按固定周期采样,变成离散的数字序列。这个过程叫采样与量化。每秒钟采样的次数就是采样率 \(f_s\),16kHz 是电话语音的常见值。采样率越高,声音细节越多,但数据量也越大,所以要在清晰度与成本之间做取舍。

在此基础上,FBank 和 MFCC 都是描述短时功率谱的特征。它们不是直接处理整段音频,而是先切割成帧,再把每一帧转成特征向量。从特征类型上看,FBank 属于滤波器组输出的对数能量,MFCC 则是再经过离散余弦变换压缩后的倒谱特征。

所以选择特征就像选菜:FBank 是新鲜沙拉,MFCC 是浓缩汤汁,核心目标都是让模型吃得舒服,只是后厨加工方式不同。

x[n]=xa(nT),T=1fs\displaystyle x[n] = x_a(nT), \quad T = \frac{1}{f_s}
简单说:连续声音被按固定间隔“拍照”,每秒拍多少张由采样率决定。
  1. 连续信号采样\(x[n]\) 是从连续信号 \(x_a(t)\) 上每隔 \(T\) 秒取一个点得到的离散序列。
    x[n]=xa(nT)\displaystyle x[n] = x_a(nT)
  2. 采样周期\(T\) 是两个采样点之间的时间间隔,单位为秒。
    T=1fs\displaystyle T = \frac{1}{f_s}
  3. 采样率\(f_s\) 是每秒采样点数,16kHz 表示每秒 16000 个样本。
    fs=1T\displaystyle f_s = \frac{1}{T}

预加重与分帧

切菜最怕鱼皮打滑,语音信号也有个类似麻烦:低频能量高,高频能量低,且频率越高衰减越厉害。预加重就像在刀上抹一层盐,把高频的边缘提起来,方便后续分析。它用一阶高通差分器实现:当前样本减去上一样本乘以系数 \(\alpha\)。

预加重让变化快的高频分量相对变大,而变化慢的低频分量被压低。工程上 \(\alpha\) 通常取 0.97。做完预加重后,长语音要被切成 25ms 左右的小段,相邻帧之间帧移 10ms,重叠 15ms,避免大切大合造成的信息断裂。分帧后每帧还要加汉明窗,让帧两端平滑归零,防止矩形截断产生的频谱泄漏。

预加重、分帧、加窗就像洗好切好、给食材抹油,接下来才能进蒸锅做频谱分析。

y[n]=x[n]−αx[n−1]\displaystyle y[n] = x[n] - \alpha x[n-1]
简单说:预加重是把高频“拎出来”,分帧和加窗则是把长语音切成适合后续分析的小块。
  1. 当前样本保留输出 \(y[n]\) 由当前输入 \(x[n]\) 减去上一时刻输入的一部分得到。
    y[n]=x[n]−αx[n−1]\displaystyle y[n] = x[n] - \alpha x[n-1]
  2. 差分项\(-\alpha x[n-1]\) 实现一阶高通,\(\alpha\) 越接近 1,高频提升越强。
    α≈0.97\displaystyle \alpha \approx 0.97
  3. 高通效果低频相邻样本变化慢、差值小;高频变化快、差值大,于是高频被相对放大。
    y[n]=x[n]−0.97x[n−1]\displaystyle y[n] = x[n] - 0.97x[n-1]

频谱与FFT

一整锅汤看不出每味料的含量。用 FFT 就像把汤倒进分光棱镜,每一缕颜色对应一个频率,汤的配方一目了然。对每一帧加窗后的信号做离散傅里叶变换,就得到 \(N\) 个频点上的复数值。取模平方就是功率谱,它描述每个频率携带多少能量。

帧长 \(N\) 决定频率分辨率:\(\Delta f = f_s / N\)。帧长越长,频率上越细腻,但时间上更模糊;帧长越短,时间上更敏锐,但频率上更粗糙。实际常用 N_FFT=512,配合 16kHz 采样率,频率分辨率约 31.25Hz,兼顾效率和细节。

频谱是后厨的半成品,可以按不同口味继续加工成不同菜式。

X[k]=∑n=0N−1x[n]e−j2πNkn\displaystyle X[k] = \sum_{n=0}^{N-1} x[n] e^{-j\frac{2\pi}{N}kn}
简单说:FFT 把时域波形拆成频域配料表,功率谱就是每个频率的调料分量。
  1. 频率分量\(X[k]\) 是第 \(k\) 个频点的复数结果,模长表示该频率的强度。
    X[k]=∑n=0N−1x[n]e−j2πNkn\displaystyle X[k] = \sum_{n=0}^{N-1} x[n] e^{-j\frac{2\pi}{N}kn}
  2. 累加范围\(N\) 是帧长,\(n\) 从 0 到 \(N-1\),对一帧内所有样本累加。
    n=0,1,…,N−1\displaystyle n = 0,1,\ldots,N-1
  3. 旋转因子\(e^{-j\frac{2\pi}{N}kn}\) 是不同频率的复指数基底,相当于用不同频率的“尺子”去量信号。
    e−j2πNkn=cos⁡(2πNkn)−jsin⁡(2πNkn)\displaystyle e^{-j\frac{2\pi}{N}kn} = \cos\left(\frac{2\pi}{N}kn\right) - j\sin\left(\frac{2\pi}{N}kn\right)

梅尔滤波器组

人耳不是仪表盘,对低频变化敏锐、对高频迟钝。梅尔刻度就是这个“人耳味觉曲线”。把频谱按梅尔刻度分组,就像把食材按酸甜苦辣分碗装。梅尔频率与线性频率的关系常用下面的公式表示,1000Hz 在梅尔刻度上约等于 1000 梅尔,频率越高,梅尔间距被压缩得越厉害。

梅尔滤波器组由一组三角滤波器组成,每个滤波器对功率谱做加权求和,输出一个能量值。对能量取对数,得到 log-mel 特征,也就是 FBank。滤波器数量通常取 40 或 80,太多会引入冗余,太低则会丢失分辨率。

梅尔滤波器组像装菜的盆,按人耳口味分好类,下一道工序决定它上桌的形式。

mel(f)=2595log⁡10(1+f700)\displaystyle \text{mel}(f) = 2595 \log_{10}\left(1+\frac{f}{700}\right)
简单说:梅尔滤波器组把频谱按人耳感知分成一组“味道碗”,每个碗里盛一个能量值。
  1. 梅尔频率\(\text{mel}(f)\) 把线性频率 \(f\) 映射到模拟人耳听感的梅尔刻度。
    mel(f)=2595log⁡10(1+f700)\displaystyle \text{mel}(f) = 2595 \log_{10}\left(1+\frac{f}{700}\right)
  2. 常数 2595这是让 1000Hz 时 \(\text{mel}(1000) \approx 1000\) 的归一化常数。
    mel(1000)=2595log⁡10(1+1000700)≈1000\displaystyle \text{mel}(1000) = 2595 \log_{10}\left(1+\frac{1000}{700}\right) \approx 1000
  3. 对数压缩分母 700 控制压缩程度,高频区域被压得更密,模拟人耳对高频不敏感的特性。
    f2>f1⇒mel(f2)−mel(f1)<f2−f1\displaystyle f_2 > f_1 \Rightarrow \text{mel}(f_2) - \text{mel}(f_1) < f_2 - f_1

MFCC与FBank

FBank 是新鲜的什锦沙拉,色彩丰富但叶子互相纠缠;如果厨师需要方便携带,就把它做成浓缩汤包,去掉水分和纠缠,只留下最有代表性的味道。这个浓缩动作就是离散余弦变换。FBank 各维之间有较强相关性,直接喂给对角协方差的 GMM 会浪费建模能力。对 FBank 做 DCT,再只取前 13 维,得到的就是 MFCC。

DCT 相当于把能量集中到少数系数上,达到去相关和降维的目的。MFCC 在噪声鲁棒性和特征压缩上更有优势,是 GMM-HMM 时代的主流;而 DNN 声学模型能利用冗余信息,因此常常直接用 FBank,省去 DCT 反而保留更多细节。选型要看模型,不能绝对地说谁更好。

沙拉还是汤包?取决于后面吃饭的模型是喜欢原味还是喜欢便携。

Cm=∑k=1MSkcos⁡[πmM(k−12)]\displaystyle C_m = \sum_{k=1}^{M} S_k \cos\left[\frac{\pi m}{M}\left(k-\frac{1}{2}\right)\right]
简单说:FBank 是原汁原味的频谱沙拉,MFCC 是去掉相关性、只留精华的浓缩汤包。
  1. 输入对数能量\(S_k\) 是第 \(k\) 个梅尔滤波器输出的对数能量,也就是 FBank 的第 \(k\) 维。
    Sk=log⁡(∑fE(f)Hk(f))\displaystyle S_k = \log\left(\sum_f E(f) H_k(f)\right)
  2. 余弦基函数\(\cos\left[\frac{\pi m}{M}\left(k-\frac{1}{2}\right)\right]\) 是 DCT 的基函数,用于与 FBank 向量做内积。
    cos⁡[πmM(k−12)],k=1,…,M\displaystyle \cos\left[\frac{\pi m}{M}\left(k-\frac{1}{2}\right)\right], \quad k=1,\ldots,M
  3. 输出倒谱系数\(C_m\) 是第 \(m\) 个 MFCC 系数,通常取 \(m=1,\ldots,13\),能量集中且相关性低。
    Cm=∑k=1MSkcos⁡[πmM(k−12)]\displaystyle C_m = \sum_{k=1}^{M} S_k \cos\left[\frac{\pi m}{M}\left(k-\frac{1}{2}\right)\right]

工程实践与选型

同样的菜品,餐厅会根据菜单定位调整份量和摆盘。特征工程也一样,要决定维度、要不要加配料、如何标准化。实践中常用 40 维 FBank 或 13 维 MFCC,再拼接一阶差分 \(\Delta\) 和二阶差分 \(\Delta\Delta\),捕捉帧间的动态变化。有时还做倒谱均值归一化,消除信道和说话人带来的整体偏移。

归一化公式把特征分布拉回零均值单位方差,避免某些维度过大主导训练。工具方面,librosa 适合快速提取原型,Kaldi 更适合大规模 ASR 数据管线和 GMM-HMM/Chain 模型训练。工程选型时,还要考虑实时性、硬件算力和模型结构。

最后端上桌的,是经过打磨、符合具体场景的那一份特征拼盘。

x^=x−μσ\displaystyle \hat{x} = \frac{x-\mu}{\sigma}
简单说:归一化让每个维度的“咸淡”一致,模型训练才不会被个别重口味维度带偏。
  1. 均值 \(\mu\)统计特征每个维度的平均值,代表整体偏移。
    μ=1T∑t=1Txt\displaystyle \mu = \frac{1}{T}\sum_{t=1}^{T} x_t
  2. 标准差 \(\sigma\)衡量特征值围绕均值的波动范围。
    σ=1T∑t=1T(xt−μ)2\displaystyle \sigma = \sqrt{\frac{1}{T}\sum_{t=1}^{T} (x_t - \mu)^2}
  3. 标准化输出\(\hat{x}\) 将原始特征变成零均值单位方差,利于加速模型收敛。
    x^=x−μσ\displaystyle \hat{x} = \frac{x-\mu}{\sigma}

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 演示

python64 行
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)
目的:用 numpy 从零实现 FBank 与 MFCC 提取,验证 16kHz 语音从预加重到 DCT 的完整流程。
  1. def pre_emphasis(x, alpha=0.97):做一阶高通预加重,抬高高频分量。
  2. return np.append(x[0], x[1:] - alpha * x[:-1])当前采样点减去 0.97 倍上一采样点。
  3. def framing(y, sr=16000, win=0.025, hop=0.010):将信号切成 25ms 帧、10ms 帧移。
  4. win = 0.54 - 0.46 * np.cos(...)构造汉明窗,减少频谱泄漏。
  5. spec = np.fft.rfft(frame * win, n=n_fft)对加窗后的帧做 FFT。
  6. high = 2595 * np.log10(1 + (sr / 2) / 700)计算 Nyquist 频率对应的梅尔值。
  7. fbank[i - 1, l:m] = (np.arange(l, m) - l) / (m - l)填充三角形滤波器上升沿。
  8. log_energy = np.log(pspec @ fbank.T + 1e-10)频率能量与梅尔滤波器组矩阵相乘并取对数,得到 FBank。
  9. 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]\) 中,α 的常用取值是?

单选题 · easy

  • A.0.97← 正确答案
  • B.0.50
  • C.1.50
  • D.0.10

答案:A。α 通常取 0.97,既提升高频又不过分放大噪声。1.5 会让系统不稳定,0.5 和 0.1 高频补偿不足,工程上很少使用。

Q2. 16kHz 采样率下,25ms 帧长对应的采样点数是?

单选题 · easy

  • A.400 点← 正确答案
  • B.160 点
  • C.250 点
  • D.1000 点

答案:A。16000 × 0.025 = 400。帧长决定一帧内包含的样本数量,也是 FFT 输入长度的基础。

Q3. 1000Hz 在线性频率刻度上大致对应多少 Mel?

单选题 · mid

  • 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 多做了哪一步?

单选题 · mid

  • A.离散余弦变换← 正确答案
  • B.逆傅里叶变换
  • C.快速傅里叶变换
  • D.一阶预加重

答案:A。FBank 是对数梅尔能量,MFCC 在 FBank 基础上做 DCT 并截断前若干维,达到去相关和降维的目的。

Q5. 深度神经网络语音模型常直接使用 FBank 的原因是什么?

单选题 · mid

  • A.保留频谱细节并利用冗余← 正确答案
  • B.特征维度更小更省内存
  • C.特征已经完成去相关
  • D.完全不需要分帧和加窗

答案:A。DNN 能拟合多维相关特征,FBank 保留更多频谱细节,冗余信息对深层模型有助益。MFCC 的 DCT 反而会丢失部分细节,且 FBank 同样需要分帧加窗。

Q6. 其他条件不变时,增大帧长对频域特征的影响是?

单选题 · hard

  • A.频率分辨率提高← 正确答案
  • B.时间分辨率提高
  • C.频率分辨率降低
  • D.不影响频域特征

答案:A。频率分辨率 \(\Delta f = f_s / N\),帧长 \(N\) 增大使 \(\Delta f\) 变小,频率上更精细;但一帧覆盖时间变长,时间分辨率会下降,两者此消彼长。

Q7. 加汉明窗的主要目的是?

单选题 · easy

  • A.减少频谱泄漏← 正确答案
  • B.增加采样点数
  • C.消除所有噪声
  • D.提高采样率

答案:A。矩形窗截断会在频域产生旁瓣泄漏,汉明窗让帧两端平滑归零,减轻截断突变带来的伪频率分量。

Q8. 下列哪些是 FBank 特征的优点?

多选题 · mid

  • A.保留更多音频细节← 正确答案
  • B.特征冗余适合深度模型← 正确答案
  • C.经过 DCT 维度更低
  • D.天然适合 GMM 建模

答案:AB。FBank 保留对数功率谱细节,未经过 DCT 压缩,冗余虽高但能被深度模型消化;GMM 通常需要去相关的 MFCC,所以 D 错误。

Q9. 关于 MFCC 与 FBank,下列说法正确的有?

多选题 · hard

  • A.FBank特征由梅尔滤波得到← 正确答案
  • B.MFCC特征由DCT变换得到← 正确答案
  • C.FBank特征相关性比较弱
  • D.MFCC适合GMM-HMM系统← 正确答案

答案:ABD。FBank 相邻滤波器重叠,相关性较强;MFCC 通过 DCT 去相关,适合 GMM-HMM 对特征独立性的假设,因此 C 错误。

Q10. 下列哪些因素会影响单帧特征最终维数?

多选题 · extreme

  • A.梅尔滤波器组数量← 正确答案
  • B.MFCC 截断维数← 正确答案
  • C.采样率的大小
  • D.是否拼接动态特征← 正确答案

答案:ABD。滤波器数量决定 FBank 维度,MFCC 截断维数决定 DCT 输出长度,拼接 Δ/ΔΔ 会让维度翻倍。采样率影响帧长对应的采样点数,但不改变单帧特征维度,因此 C 错误。