2. 数字音频基础

说实话,刚入行做音频处理那会儿,我总觉得时域信号看着就挺直观的——波形上下跳,振幅大小一目了然。但直到第一次调试降噪算法,我才发现光看时域波形根本看不出噪声藏在哪个频率段。那次折腾了两周,最后用频谱图一看,问题瞬间就清楚了。

所以这一章,咱们就把傅里叶变换、短时傅里叶变换和频谱图这些东西彻底聊透。你想想看,音频DSP里百分之八十的问题,最后都要回到频域去解决。

为什么非要去频域?

时域信号描述的是「什么时间发生了什么」,频域描述的是「什么频率发生了什么」。说白了,就是换了个角度看问题。

举个例子,你录了一段吉他声,时域波形看起来就是一堆乱糟糟的振动。但转到频域,你能清楚看到基频在哪个位置,泛音怎么分布,甚至能分辨出是哪根弦在响。

核心观点:时域和频域是同一信号的两个投影,没有谁更「真实」,只有谁更适合当前任务。

傅里叶变换:从时域到频域的桥梁

傅里叶变换的数学公式长这样:

X(f) = ∫ x(t) · e^(-j2πft) dt

别被积分符号吓到。我习惯这么理解:把信号x(t)和不同频率的正弦波做内积,如果某个频率分量存在,内积结果就大;不存在,结果就接近零。

离散版本(DFT)才是我们实际用的:

X[k] = Σ x[n] · e^(-j2πkn/N),  n=0..N-1

快速傅里叶变换(FFT)只是DFT的高效算法实现。我在项目中几乎从不手写FFT,直接用成熟库就好,但必须理解它的几个关键参数:

参数含义我的经验值
FFT点数(N)频率分辨率 = 采样率 / N通常1024或2048
采样率(fs)决定可分析的最高频率 = fs/2音频常用44100或48000
频率分辨率相邻频点间隔1024点@44100Hz ≈ 43Hz

注意:FFT点数越大,频率分辨率越高,但时间分辨率会下降。这是傅里叶变换的固有矛盾——你不可能同时获得无限精确的时间和频率信息。

短时傅里叶变换(STFT):给信号加窗

标准的傅里叶变换假设信号是平稳的。但音频信号呢?语音、音乐都是非平稳的——频率成分随时间变化。怎么办?

STFT的思路很简单:把信号切成一小段一小段,假设每段内信号是平稳的,然后对每段做FFT。

STFT{x[n]}(m, ω) = Σ x[n] · w[n-m] · e^(-jωn)

其中w[n]是窗函数。我常用的窗函数有这些:

窗类型主瓣宽度旁瓣衰减我什么时候用
汉宁窗较宽-31dB通用场景,默认选择
汉明窗较宽-43dB语音处理,旁瓣抑制更好
布莱克曼窗最宽-58dB需要极低频谱泄漏时
矩形窗最窄-13dB几乎不用,泄漏太严重

我曾经在一个语音增强项目里,默认用了矩形窗,结果频谱图上全是假峰,折腾了两天才发现是窗函数选错了。嗯,从那以后我再也不敢随便用矩形窗了。

频谱图:把STFT结果画出来

频谱图就是把STFT的结果用图像展示出来:

  • 横轴:时间
  • 纵轴:频率
  • 颜色/亮度:能量强度

我习惯用Python的librosa库来画频谱图,代码大概这样:

import librosa
import librosa.display
import matplotlib.pyplot as plt

# 加载音频
y, sr = librosa.load('guitar.wav', sr=44100)

# 计算STFT
D = librosa.stft(y, n_fft=2048, hop_length=512, win_length=2048)

# 转换为dB刻度
D_db = librosa.amplitude_to_db(abs(D), ref=np.max)

# 显示频谱图
plt.figure(figsize=(12, 6))
librosa.display.specshow(D_db, sr=sr, hop_length=512, x_axis='time', y_axis='hz')
plt.colorbar(format='%+2.0f dB')
plt.title('频谱图')
plt.tight_layout()

读频谱图有几个要点:

  1. 看横条纹:代表某个频率持续存在,比如电源噪声的50Hz/60Hz
  2. 看竖条纹:代表某个时刻的瞬态冲击,比如鼓点、拍手声
  3. 看谐波结构:等间距的水平亮线,代表乐器的泛音列
  4. 看能量分布:颜色越亮,能量越强

小技巧:调试降噪算法时,我习惯先看频谱图找到噪声的「频率指纹」,再针对性设计滤波器。比盲目调参数高效十倍。

STFT参数怎么选?

这是实际项目中最常遇到的问题。我一般按这个流程来:

  1. 先定帧长:语音用20-30ms,音乐用40-60ms
  2. 再定帧移:通常取帧长的25%-50%
  3. 最后选窗函数:默认汉宁窗,特殊需求再换

举个例子,采样率44100Hz,帧长取2048点(约46ms),帧移512点(约11.6ms),汉宁窗。这个配置在大多数音频任务里表现都不错。

避坑:帧移太大(比如超过75%帧长)会导致频谱图时间分辨率太差,瞬态事件被模糊掉。帧移太小(比如小于12.5%)则计算量暴增,而且相邻帧之间信息冗余严重。

知识体系总览

下面这张图把本章的核心逻辑串起来了:

时域与频域知识体系 时域信号 x(t) 傅里叶变换 (FT/DFT) 频域信号 X(f) 非平稳信号 (语音/音乐) 短时傅里叶变换 (STFT) 帧长 (窗口大小) 帧移 (步长) 窗函数类型 频谱图 (时间-频率-能量) 实际应用 降噪/特征提取/编解码 核心矛盾 时间分辨率 ↕ 频率分辨率

从这张图能清楚看到:时域信号通过傅里叶变换到频域,但非平稳信号需要STFT这个「升级版」。STFT的三个参数(帧长、帧移、窗函数)直接决定了频谱图的质量,而频谱图又是我们做音频分析、降噪、特征提取的基础工具。

我个人习惯在项目初期先用默认参数跑一遍频谱图,看看整体情况,再根据具体任务微调参数。比如做语音端点检测,我会用短帧(20ms)提高时间精度;做音高分析,我会用长帧(60ms)提高频率精度。

嗯,这一章的内容就到这里。记住一句话:频谱图是音频DSP工程师的「听诊器」——不会看频谱图,很多问题你根本找不到病因。