什么是FBank
FBank(Filter Bank,滤波器组)是语音特征参数提取方法之一,其独特的基于倒谱的提取方式更加符合人类的听觉原理。FBank特征提取相当于MFCC去掉最后一步的离散余弦变换(DCT),因此保留了更多原始语音数据信息。
为什么需要FBank?
在深度学习时代,神经网络具有强大的特征学习能力,能够从更原始的特征中自动学习判别性表示。相比MFCC经过DCT压缩后的特征,FBank具有以下优势:
- 信息保留更完整:未经过DCT有损压缩,保留更多频谱细节
- 适合深度模型:为DNN/CNN/RNN等神经网络提供更丰富的输入
- 更高维度:通常为40维(对应40个滤波器),相比MFCC的12-13维提供更多信息
FBank与MFCC的关系
从提取流程上看:
MFCC = 预加重 → 分帧 → 加窗 → FFT → Mel滤波器组 → 对数 → DCT → 保留2-13系数
FBank = 预加重 → 分帧 → 加窗 → FFT → Mel滤波器组 → 对数
可以看出,FBank = MFCC - DCT,FBank保留了经过Mel滤波器组处理后的所有频带能量信息。
| 特征 | MFCC | FBank |
|---|---|---|
| 维度 | 12-13维 | 通常40维 |
| 信息量 | 经过DCT压缩,有损 | 保留更多原始信息 |
| 去相关性 | DCT去除相关性 | 相邻频带有相关性 |
| 适用场景 | GMM-HMM等传统模型 | DNN/CNN/RNN深度模型 |
| 计算效率 | 维度低,计算快 | 维度高,计算稍慢 |
FBank特征提取流程
完整的FBank提取包含以下5个步骤:

1. 预加重
对原始信号进行高通滤波,增强高频部分:
$$y(n) = x(n) - \alpha \times x(n-1)$$
其中 $\alpha$ 通常取 0.97。
预加重的作用:
- 消除发声过程中声带和嘴唇的效应
- 补偿被发音系统抑制的高频部分
- 突出高频共振峰
- 提高信噪比
原始语音信号波形:

预加重后的效果对比:

2. 分帧
按固定时间长度分割音频样本。
典型参数:
- 采样率:16kHz
- 帧长:25ms(16kHz下为400个采样点)
- 帧移:10ms(16kHz下为160个采样点)
- 帧重叠:约62.5%
通常FFT点数 $N$ 取值 512 或 256,涵盖20-30ms的语音段。相邻帧之间的重叠区域 $M$ 一般为 $N$ 的1/2或1/3。
3. 加窗
对每帧施加汉明窗(Hamming Window),增加帧左右端的连续性,减少频谱泄漏。
汉明窗函数:
$$W(n) = 0.54 - 0.46 \times \cos\left(\frac{2\pi n}{N-1}\right), \quad 0 \leq n \leq N-1$$
加窗后的信号:
$$S’(n) = S(n) \times W(n)$$
汉明窗时域波形:

加窗后的信号效果:

4. 离散傅里叶变换(DFT)
将时域信号转换为频域能量分布。
DFT公式:
$$s(k) = \sum_{n=0}^{N-1} S(n) \times e^{-j2\pi kn/N}$$
功率谱:
$$p(k) = \frac{1}{N} |s(k)|^2$$
在实际实现中,通常使用快速傅里叶变换(FFT)来高效计算DFT。
频谱到功率谱转换示意图:

DFT变换后的频谱:

5. Mel滤波器组
将线性频谱映射到Mel非线性频谱。在Mel频域内,人对音调的感知度为线性关系,更符合听觉特性。
频率到Mel频率转换:
$$f_{mel} = 2595 \times \log_{10}\left(1 + \frac{f}{700}\right)$$
Mel频率到频率转换:
$$f = 700 \times \left(10^{f_{mel}/2595} - 1\right)$$
滤波器组设计步骤:
- 确定频率范围:最低频率(如300Hz)和最高频率(如8000Hz)
- 转换到Mel域并等分:将频率范围转到Mel频率,然后线性等分成 $M+2$ 个点($M$ 为滤波器个数,通常为40)
- 转回Hz频率:将Mel频率点转换回赫兹频率
- 映射到FFT频率索引:
$$f(i) = \left\lfloor \frac{(N+1) \times h(i)}{f_s} \right\rfloor$$
其中 $N$ 为FFT点数,$f_s$ 为采样率
三角滤波器响应:
$$H_m(k) = \begin{cases}
0 & k < f(m-1) \
\frac{k - f(m-1)}{f(m) - f(m-1)} & f(m-1) \leq k < f(m) \
1 & k = f(m) \
\frac{f(m+1) - k}{f(m+1) - f(m)} & f(m) < k \leq f(m+1) \
0 & k > f(m+1)
\end{cases}$$
滤波器组输出(对数能量):
$$FBank(m) = \log\left(\sum_{k=0}^{N-1} |X(k)|^2 \times H_m(k)\right)$$
其中 $m = 0, 1, …, M-1$,$M$ 通常为 22-26 或 40。
Mel滤波器组结构示意图:

Mel滤波器组可视化:

FBank特征提取结果:

关键参数总结
| 参数 | 典型值 | 说明 |
|---|---|---|
| 预加重系数 | 0.97 | 高通滤波 |
| 采样率 | 16kHz | 语音采样频率 |
| 帧长 | 25ms (400点) | 短时平稳假设 |
| 帧移 | 10ms (160点) | 帧间重叠 |
| FFT点数 | 512 | 频谱分辨率 |
| 最低频率 | 300Hz | Mel滤波器下限 |
| 最高频率 | 8000Hz | Mel滤波器上限 |
| Mel滤波器数 | 40 | FBank特征维度 |
Python实现
使用Librosa库(推荐)
import librosa
import numpy as np
y, sr = librosa.load('audio.wav', sr=16000)
fbank = librosa.feature.melspectrogram(
y=y,
sr=sr,
n_fft=512,
hop_length=160,
win_length=400,
n_mels=40
)
fbank_db = librosa.power_to_db(fbank, ref=np.max)
print(f"FBank shape: {fbank_db.shape}")
手动实现核心步骤
import numpy as np
import scipy.io.wavfile
from scipy.fftpack import fft
sample_rate, signal = scipy.io.wavfile.read('audio.wav')
pre_emphasis = 0.97
emphasized_signal = np.append(signal[0], signal[1:] - pre_emphasis * signal[:-1])
frame_size = 0.025
frame_stride = 0.01
frame_length = int(round(frame_size * sample_rate))
frame_step = int(round(frame_stride * sample_rate))
signal_length = len(emphasized_signal)
num_frames = int(np.ceil(float(np.abs(signal_length - frame_length)) / frame_step))
pad_signal_length = num_frames * frame_step + frame_length
z = np.zeros((pad_signal_length - signal_length))
pad_signal = np.append(emphasized_signal, z)
indices = np.tile(np.arange(0, frame_length), (num_frames, 1)) + \
np.tile(np.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T
frames = pad_signal[indices.astype(np.int32, copy=False)]
frames *= np.hamming(frame_length)
NFFT = 512
mag_frames = np.absolute(np.fft.rfft(frames, NFFT))
pow_frames = ((1.0 / NFFT) * (mag_frames ** 2))
nfilt = 40
low_freq_mel = 0
high_freq_mel = 2595 * np.log10(1 + (sample_rate / 2) / 700)
mel_points = np.linspace(low_freq_mel, high_freq_mel, nfilt + 2)
hz_points = 700 * (10 ** (mel_points / 2595) - 1)
bin_points = np.floor((NFFT + 1) * hz_points / sample_rate)
fbank = np.zeros((nfilt, int(np.floor(NFFT / 2 + 1))))
for m in range(1, nfilt + 1):
f_m_minus = int(bin_points[m - 1])
f_m = int(bin_points[m])
f_m_plus = int(bin_points[m + 1])
for k in range(f_m_minus, f_m):
fbank[m - 1, k] = (k - bin_points[m - 1]) / (bin_points[m] - bin_points[m - 1])
for k in range(f_m, f_m_plus):
fbank[m - 1, k] = (bin_points[m + 1] - k) / (bin_points[m + 1] - bin_points[m])
filter_banks = np.dot(pow_frames, fbank.T)
filter_banks = np.where(filter_banks == 0, np.finfo(float).eps, filter_banks)
filter_banks = 20 * np.log10(filter_banks)
print(f"FBank shape: {filter_banks.shape}")
从FBank到MFCC
如果需要从FBank继续计算MFCC,只需添加DCT变换:
from scipy.fftpack import dct
num_ceps = 12
mfcc = dct(filter_banks, type=2, axis=1, norm='ortho')[:, 1:(num_ceps + 1)]
mfcc -= (np.mean(mfcc, axis=0) + 1e-8)
print(f"MFCC shape: {mfcc.shape}")
FBank的应用场景
- 深度学习语音识别:作为DNN/CNN/LSTM等模型的输入特征
- 端到端语音识别:在Transformer/Conformer等架构中广泛使用
- 说话人识别:提供丰富的频谱信息用于说话人建模
- 语音合成:用于声学特征建模
- 音频分类:环境声音识别、音乐分类等
为什么深度学习更青睐FBank?
在深度学习时代,FBank相比MFCC更受欢迎,原因包括:
- 信息保留更完整:DCT变换会丢失部分信息,而神经网络可以从更原始的特征中学习
- 相关性由网络处理:MFCC通过DCT去相关性是为了GMM等传统模型,但神经网络可以自己学习处理相关性
- 更高维度提供更多细节:40维FBank比12维MFCC提供更丰富的频谱细节
- 卷积友好:FBank的频带结构更适合CNN学习局部频谱模式
总结
FBank是一种符合人耳听觉特性的语音特征提取方法,其核心优势在于:
- 符合人耳感知:基于Mel刻度,模拟人类听觉系统的非线性频率感知
- 信息丰富:相比MFCC保留更多原始频谱信息
- 适合深度学习:为神经网络提供更充分的学习材料
- 实现简单:比MFCC少一步DCT变换
在现代语音处理系统中,特别是基于深度学习的端到端模型中,FBank已经成为比MFCC更常用的特征表示。它为模型提供了更丰富的输入信息,让神经网络有更大的学习空间来发现最优的特征表示。
参考资料
- Fbank语音特征提取 - 简书
- Python语音信号处理库:librosa, scipy, python_speech_features
- Mel-Frequency Analysis in Speech Processing