2. 傅里叶变换基础:从时域到频域的桥梁
聊声学特征提取,绕不开傅里叶变换。说白了,它就是一把钥匙,帮我们把声音从「随时间怎么变」转换到「随频率怎么分布」。我刚开始接触语音信号处理时,总觉得时域波形看着挺直观,干嘛非要折腾到频域去?后来做第一个语音识别项目,发现两个读音相似的词在时域上几乎没法区分,但一转到频域,特征差异一目了然。嗯,从那以后我就明白了——时域是表象,频域才是本质。
2.1 为什么需要傅里叶变换?
声音的本质是空气振动,麦克风采集到的是一维时间序列。但人耳对声音的感知,其实更接近频域——我们听到的是音调、音色,而不是每个时刻的瞬时气压值。
核心思想:任何周期信号都可以分解为一系列不同频率、不同幅度、不同相位的正弦波之和。这就是傅里叶级数,也是傅里叶变换的理论根基。
举个例子,一个钢琴弹奏的中央C(约261.6 Hz),在时域里是一条不断振荡的波形。但它的频域表示,就是在261.6 Hz处有一个尖峰,再加上若干倍频的泛音。你想想看,这种表示方式对声学特征提取有多友好——我们关心的基频、共振峰、谐波结构,全都在频域里一目了然。
2.2 连续傅里叶变换(CFT)
连续傅里叶变换是理论上的完美模型。它假设信号是连续的、无限长的,定义如下:
X(f) = ∫_{-∞}^{∞} x(t) · e^{-j2πft} dt
其中 x(t) 是时域信号,X(f) 是频域表示,f 是频率。这个公式的物理含义很直观:把信号 x(t) 与不同频率的复指数函数做内积,看看信号在哪个频率上「能量最大」。
逆变换同样重要,它告诉我们如何从频域恢复时域:
x(t) = ∫_{-∞}^{∞} X(f) · e^{j2πft} df
我在读研时,导师让我推导一个连续信号的频谱。我拿着公式算了半天,最后发现——现实中根本没有真正的连续信号。计算机只能处理离散的、有限长的数据。所以CFT虽然漂亮,但只能停留在纸面上。
注意:CFT要求信号绝对可积,即 ∫|x(t)|dt < ∞。实际中的语音信号通常满足这个条件,但纯周期信号(如正弦波)严格来说不满足,需要用傅里叶级数或广义函数来处理。
2.3 离散傅里叶变换(DFT)
这才是我们真正用的东西。DFT把连续傅里叶变换离散化,让计算机能够处理:
X[k] = Σ_{n=0}^{N-1} x[n] · e^{-j2πkn/N}, k = 0, 1, ..., N-1
其中 x[n] 是时域采样点,N 是采样点数,X[k] 是第 k 个频率分量的复数值。这个公式看起来复杂,但你可以把它理解成:用 N 个不同频率的「探针」去探测信号,每个探针返回一个复数,包含幅度和相位信息。
DFT有几个关键参数,我整理了一个表格:
| 参数 | 符号 | 说明 |
|---|---|---|
| 采样点数 | N | DFT的计算长度,通常取2的幂次(如512、1024) |
| 频率分辨率 | Δf = fs / N | 相邻两个频率点之间的间隔,N越大分辨率越高 |
| 频率范围 | 0 ~ fs | DFT输出覆盖从0到采样率的全部频率 |
| 对称性 | X[N-k] = X*[k] | 实信号的DFT结果共轭对称,只需看前一半 |
经验之谈:我曾经在做一个语音端点检测时,用了256点的DFT,结果频率分辨率太低,把两个相邻的共振峰混在一起了。后来改成512点,效果明显改善。但N也不是越大越好——N越大,时间分辨率越差,这就是所谓的「不确定性原理」在时频分析中的体现。
2.4 从CFT到DFT:发生了什么变化?
CFT和DFT之间有三个关键差异,我建议你记住:
- 时域采样:连续信号变成离散序列,引入了采样定理的限制(奈奎斯特频率 = fs/2)
- 时域截断:无限长信号变成有限长窗口,引入了频谱泄漏
- 频域离散:连续频谱变成离散谱线,引入了栅栏效应
这三个变化,每一个都会影响最终的声学特征质量。我在做语音增强时,就吃过频谱泄漏的亏——一个强频率成分的能量泄漏到相邻频点,把弱信号完全淹没了。后来加了汉宁窗,情况好很多。
2.5 快速傅里叶变换(FFT)
直接计算DFT的复杂度是 O(N²),对于1024点数据,需要约100万次复数乘法。这在实时系统中根本跑不动。FFT利用旋转因子的对称性和周期性,把复杂度降到 O(N log₂N)。
以基2-FFT为例,它的核心思想是分治:
// 伪代码:8点FFT的蝶形运算示意
// 输入:x[0]...x[7]
// 输出:X[0]...X[7]
// 第一步:按奇偶重排
// 偶数索引:x[0], x[2], x[4], x[6]
// 奇数索引:x[1], x[3], x[5], x[7]
// 第二步:对4点序列做DFT
// 第三步:用蝶形运算合并结果
for k = 0 to 3:
X[k] = E[k] + W^k * O[k]
X[k+4] = E[k] - W^k * O[k]
// 其中W = e^{-j2π/8},E是偶数部分DFT,O是奇数部分DFT
我建议你在实际项目中直接调用FFT库(如FFTW、Python的numpy.fft),但理解蝶形运算的原理很重要——它帮你理解为什么FFT要求数据长度是2的幂次,以及为什么FFT这么快。
性能对比:1024点DFT直接计算约需100万次操作,FFT只需约1万次操作,快了100倍。对于实时语音处理,这个差距就是「能用」和「不能用」的区别。
2.6 知识体系总览
下面这张图总结了本章的核心逻辑,从时域到频域的完整路径:
2.7 避坑指南
最后分享几个我踩过的坑:
- 频谱泄漏:我曾经直接用矩形窗截断信号做FFT,结果频谱里出现了很多虚假的旁瓣。后来改用汉宁窗,旁瓣抑制了40 dB以上。记住:加窗不是可选项,是必选项。
- 频率分辨率 vs 时间分辨率:做语谱图时,我一开始用了很长的FFT窗口(4096点),频率分辨率是高了,但时间上模糊得一塌糊涂,连音节边界都看不清。后来根据应用场景动态调整窗口长度——分析稳态元音用长窗,分析爆破音用短窗。
- 直流分量:很多麦克风信号有直流偏置,做FFT前一定要去直流(减去均值),否则0 Hz处会有一个巨大的尖峰,把低频细节全盖住了。
嗯,傅里叶变换这块内容就这些。理解了CFT、DFT、FFT的关系,后面讲语谱图、MFCC、滤波器组就顺了。记住:时域是原料,频域才是我们真正要用的食材。