一、从傅里叶级数到傅里叶变换
1.1 傅里叶级数的基本思想
傅里叶级数的核心思想是将周期函数分解为正弦和余弦函数的叠加,使我们能在频域分析信号的频率成分。
对于周期为 T 的函数 f(t),其傅里叶级数展开为:
\(f_T(t) = a_0 + \sum_{n=1}^{\infty} \Big a_n \\cos(n\\omega_0 t) + b_n \\sin(n\\omega_0 t) \\Big\)
其中基频 \(\omega_0 = \frac{2\pi}{T}\),系数计算公式为:
\(a_n = \frac{2}{T} \int_{-T/2}^{T/2} f(t) \cos(n\omega_0 t)\, dt \quad (n \ge 1)\)
\(b_n = \frac{2}{T} \int_{-T/2}^{T/2} f(t) \sin(n\omega_0 t)\, dt \quad (n \ge 1)\)
\(a_0 = \frac{1}{T}\int_{-T/2}^{T/2} f(t)\, dt\)
示例:周期为 2π 的方波信号,其傅里叶级数展开为:
\(f(t) = \frac{4}{\pi} \left( \sin(t) + \frac{1}{3}\sin(3t) + \frac{1}{5}\sin(5t) + \cdots \right)\)
方波只含奇次谐波的正弦分量,所有余弦系数 \(a_n = 0\),偶次谐波正弦系数 \(b_{2n} = 0\)。
1.2 从周期函数到非周期函数:傅里叶变换
当周期 T → ∞,周期函数变为非周期函数。此时基频 \(\omega_0 = \frac{2\pi}{T} \to 0\),离散频率 \(n\omega_0\) 变为连续频率 \(\omega\);系数 \(a_n, b_n\) 趋于 0,但 \(\frac{2}{T}a_n\) 和 \(\frac{2}{T}b_n\) 保持有限。为此定义两个实函数:
\(A(\omega) = \int_{-\infty}^{\infty} f(t) \cos(\omega t)\, dt\)
\(B(\omega) = \int_{-\infty}^{\infty} f(t) \sin(\omega t)\, dt\)
这就是实数形式的傅里叶变换,分别表示信号在不同频率上的余弦和正弦分量强度。
1.3 物理意义解释
- \(A(\omega)\):信号中频率为 \(\omega\) 的余弦分量强度
- \(B(\omega)\):信号中频率为 \(\omega\) 的正弦分量强度
- 若某频率的 \(A(\omega)\) 或 \(B(\omega)\) 为 0,则信号不含该频率的相应分量
例如,方波只含奇次谐波,偶数频率的系数全部为 0。
示例:高斯函数 \(f(t) = e^{-t^2}\) 的傅里叶变换为:
\(A(\omega) = \sqrt{\pi} e^{-\omega^2/4}, \quad B(\omega) = 0\)
高斯函数的傅里叶变换仍是高斯函数,且只有余弦分量(偶函数)。
二、从连续到离散:离散傅里叶变换(DFT)
实际数字信号处理中,计算机只能处理有限长度、离散采样的信号。DFT 是连续傅里叶变换在离散域的自然延伸。
2.1 时域采样与离散化
设采样间隔 \(T_s\)(秒),采样频率 \(f_s = 1/T_s\)(Hz)。对连续信号 \(x(t)\) 采样得离散序列:
\(xn = x(nT_s), \quad n = 0, 1, 2, \ldots\)
将积分替换为求和,得离散时间傅里叶变换的实数形式:
\(A(\omega) = \sum_{n=-\infty}^{\infty} xn \cos(\omega n), \quad B(\omega) = \sum_{n=-\infty}^{\infty} xn \sin(\omega n)\)
示例:设 \(f_s = 1000\text{Hz}\)(\(T_s = 1\text{ms}\)),对 \(x(t) = \sin(2\pi \cdot 100t)\) 采样:
\(xn = \sin(2\pi \cdot 100 \cdot n \cdot 0.001) = \sin(0.2\pi n)\)
其中 \(n = 0, 1, 2, \ldots\)。
2.2 频域采样与有限长度
计算机还需在频域采样。在 \([0, 2\pi)\) 内均匀取 N 个点:
\(\omega_k = \frac{2\pi k}{N}, \quad k = 0, 1, 2, \ldots, N-1\)
频域采样点数通常等于时域采样点数 N,得 DFT 实数形式:
\(Ak = \sum_{n=0}^{N-1} xn \cos\!\left(\frac{2\pi k n}{N}\right), \quad Bk = \sum_{n=0}^{N-1} xn \sin\!\left(\frac{2\pi k n}{N}\right)\)
什么是 Bin? DFT 把连续频谱均匀切成 N 小块,每块叫一个 bin (频点)。N 个输出 \(X0, X1, \ldots, XN-1\) 各对应一个 bin。\(k\) 是 bin 序号,Bin k 对应频率 \(k \cdot f_s/N\)。
2.3 复数形式的 DFT
引入欧拉公式 \(e^{-i\theta} = \cos\theta - i\sin\theta\),合并为复数形式:
\(Xk = Ak - iBk = \sum_{n=0}^{N-1} xn e^{-i 2\pi kn/N}\)
其中 \(k = 0, 1, \ldots, N-1\)。
示例:\(N=4\),\(xn = 1, 2, 3, 4\):
\(X0 = 1 + 2 + 3 + 4 = 10\)
\(X1 = 1 + 2e^{-i\pi/2} + 3e^{-i\pi} + 4e^{-i3\pi/2} = -2 + 2i\)
\(X2 = 1 + 2e^{-i\pi} + 3e^{-i2\pi} + 4e^{-i3\pi} = -2\)
\(X3 = 1 + 2e^{-i3\pi/2} + 3e^{-i3\pi} + 4e^{-i9\pi/2} = -2 - 2i\)
可见 \(X3 = X^*1\),符合共轭对称性。
2.4 DFT 输出的物理意义
对 N 点序列 \(xn\),DFT 输出 N 个复数 \(Xk\),每个对应数字频率 \(\omega_k = 2\pi k/N\):
- 实部 \(Re(Xk) = Ak\):余弦分量强度
- 虚部 \(Im(Xk) = -Bk\):正弦分量强度的负数
- 幅度 \(|Xk| = \sqrt{Ak^2 + Bk^2}\):该频率分量的总强度
- 相位 \(\arg(Xk) = \arctan\left(\frac{-Bk}{Ak}\right)\):该频率分量的相位
DFT 的本质是将时域信号分解为 N 个不同频率的正弦和余弦分量,每个分量由幅度和相位描述。
2.5 频率分辨率与 Bin 宽度
每个 bin 在频率轴上的宽度即频率分辨率。采集 N 个点用时 \(T = N/f_s\),频率间隔为:
\(\Delta f = \frac{f_s}{N}\)
第 k 个频率点(\(k = 0, 1, \ldots, N/2\))的物理频率为:
\(f_k = k \cdot \Delta f = k \cdot \frac{f_s}{N}\)
可分析的最高频率(奈奎斯特频率)为 \(f_{\text{max}} = f_s/2\)。
若 \(\Delta f = 1\text{Hz}\),则 Bin 0 对应 0~1Hz,Bin 1 对应 1~2Hz,以此类推。\(X1\) 代表的就是这个 1Hz 宽度内的信号强度。
两个关键参数:
- 采样频率 \(f_s\):决定频率上限(\(f_s/2\))
- 采样点数 \(N\):与 \(f_s\) 共同决定频率分辨率 \(\Delta f\)
示例 1:\(f_s = 1000\text{Hz}\),\(N = 1024\):
- \(\Delta f = 1000/1024 \approx 0.9766\text{Hz}\)
- \(f_{\text{max}} = 500\text{Hz}\)
- Bin 50:\(f_{50} \approx 48.83\text{Hz}\)
示例 2:\(N=8\),\(f_s = 8000\text{Hz}\):
- 8 个 bin(0~7),\(\Delta f = 1000\text{Hz}\)
- Bin 0:\(0\text{Hz}\)(直流)
- Bin 1:\(1000\text{Hz}\)(基频)
- Bin 2:\(2000\text{Hz}\)(二次谐波)
- Bin 3:\(3000\text{Hz}\)(三次谐波)
分辨率仅 1000Hz 时,500Hz 信号会在 Bin 0 和 Bin 1 之间"跑偏"------这就是频谱泄漏的根源。
2.6 直观理解:整数次振动
DFT 的本质:用一系列能在观测窗口内完成"整数次振动"的正弦波去"丈量"原始信号。
设定观测窗口 \(T\)(采集 N 个点所用时间):
基频(k=1):在 \(T\) 秒内完成 1 次完整振动,频率 = \(1/T = \Delta f\)。
2倍基频(k=2):在同样的 \(T\) 秒内完成 2 次完整振动,频率 = \(2/T = 2\Delta f\)。
第 k 个频率分量在窗口 \(T\) 内正好完成 k 次完整振动。这就是 DFT 只能分析频率为 \(\Delta f\) 整数倍的信号成分的原因。
三、DFT 的快速算法FFT
直接计算 N 点 DFT 需 \(O(N^2)\) 次复数乘法,FFT 通过分解降至 \(O(N\log N)\)。下面介绍基‑2 时间抽取(DIT)FFT。
3.1 定义与旋转因子
N 点 DFT:
\(Xk = \sum_{n=0}^{N-1} xn W_N^{kn}, \quad W_N = e^{-i 2\pi/N}\)
\(W_N\) 称旋转因子(twiddle factor),具有周期性 \(W_N^{k+N} = W_N^k\) 和对称性 \(W_N^{k+N/2} = -W_N^k\)。
3.2 奇偶分解(时间抽取)
设 N 为 2 的幂,将 \(xn\) 按奇偶分为两个半长序列:
\(x_{\text{even}}m = x2m, \quad x_{\text{odd}}m = x2m+1, \quad m = 0, 1, \ldots, N/2-1\)
代入 DFT 定义:
\( \begin{aligned} Xk &= \sum_{m=0}^{N/2-1} x2m W_N^{k(2m)} + \sum_{m=0}^{N/2-1} x2m+1 W_N^{k(2m+1)} \\ &= \sum_{m=0}^{N/2-1} x_{\text{even}}m (W_N^2)^{km} + W_N^k \sum_{m=0}^{N/2-1} x_{\text{odd}}m (W_N^2)^{km} \end{aligned} \)
因 \(W_N^2 = e^{-i 2\pi/(N/2)} = W_{N/2}\),两个求和分别为偶/奇数序列的 \(N/2\) 点 DFT(记 \(Ek, Ok\)):
\(Xk = Ek + W_N^k Ok\)
3.3 利用周期性完成全部输出
\(Ek\) 和 \(Ok\) 以 \(N/2\) 为周期,且 \(W_N^{k+N/2} = -W_N^k\),后半段可直接由前半段计算:
\( \begin{aligned} Xk &= Ek + W_N^k Ok \\ Xk+N/2 &= Ek - W_N^k Ok \end{aligned} \quad k = 0, 1, \ldots, N/2-1 \)
这就是蝶形运算。递归分解至子变换长度为 1,总运算量降至 \(\frac{N}{2}\log_2 N\) 次复数乘法和 \(N\log_2 N\) 次复数加法。
3.4 位反转的数学根
基‑2 DIT FFT 中,输入序列需按位反转重排。这是因为递归的奇偶分离不断打乱原始顺序。
设 N=2m,输入下标 n 的二进制表示:
\(n = (b_{m-1}b_{m-2}\cdots b_1b_0)_2\)
位反转后下标:
\(\text{rev}(n) = (b_0b_1\cdots b_{m-2}b_{m-1})_2\)
这种排列使蝶形运算可就地完成,无需额外存储。位反转可通过位运算高效实现,是 FFT 高效性的关键。
四、频谱分析的两大核心议题
掌握 DFT/FFT 原理后,频谱分析面临两个核心问题:频率分辨率与 Bin 、频谱泄漏与窗函数。
4.1 频率分辨率与 Bin(深度回顾)
在 DFT/FFT 中,**"bin"(仓/频点)**是把连续频谱从 0 到 \(f_s\) 均匀切成 N 小块后得到的每个小格子。DFT 输出的 N 个复数 \(X0 \sim XN-1\) 各对应一个 bin。
\(k\) 就是bin 的编号(索引):
- Bin 0(\(k=0\)):直流分量(频率为 0)
- Bin 1(\(k=1\)):基频
- Bin k(\(k=k\)):对应频率 \(k \cdot f_s/N\)
一句话:\(k\) 是 bin 序号,Bin 是装"某频率成分能量"的容器。
4.1.1 频率分辨率与 Bin 宽度
每个 bin 在频率轴上的宽度(相邻 k 的频率间隔)为:
\(\Delta f = \frac{f_s}{N}\)
若 \(\Delta f = 1\text{Hz}\),Bin 0 对应 0~1Hz,Bin 1 对应 1~2Hz,依此类推。
4.1.2 数字示例回顾
\(N=8\),\(f_s = 8000\text{Hz}\):8 个 bin(0~7),\(\Delta f = 1000\text{Hz}\)。Bin 0~3 分别对应 0、1000、2000、3000Hz。
分辨率仅 1000Hz 时,500Hz 信号会在 Bin 0 和 Bin 1 间"跑偏"(能量泄漏)------这正是下面要讨论的问题。
4.2 频谱泄漏与窗函数
4.2.1 频谱泄漏的概念
频谱泄漏:信号真实频率未落在 DFT 频率网格(bin)上时,能量扩散到邻近频率点。原本干净的谱线变成被"抹开"的峰,伴随起伏的旁瓣。
根源在于 DFT 的两个基本假设:有限长度观测 和周期性延拓。当它们与信号真实特性不匹配时,便产生泄漏。
4.2.2 泄漏的根本原因:非整周期采样
DFT 默认 N 个采样点是一个周期信号的完整周期,并将其首尾相接、无限循环。它看到的不是原始干净信号,而是这 N 个点拼出的"循环版本"。
例如:\(f_s = 1000\text{Hz}\),\(N = 256\),\(f_{\text{sig}} = 100\text{Hz}\):
\(\text{周期数} = \frac{f_{\text{sig}}}{\Delta f} = \frac{100}{1000/256} \approx 25.6\)
256 个采样点中,100Hz 正弦波走了 25.6 个周期。非整数周期导致周期性延拓时首尾出现跳变 ------平滑正弦波中突然出现尖锐拐点,意味着信号中被强行加入了原本不存在的高频成分。
数学解释:时域截断与频域卷积
有限长度采样等价于给无限长信号乘矩形窗:
\(x_{\text{windowed}}n = xn \cdot wn\)
\(wn\) 在窗口内为 1,外为 0。时域相乘对应频域卷积:
\(X_{\text{windowed}}(f) = X(f) * W(f)\)
\(W(f)\) 是矩形窗的频谱即 sinc 函数。100Hz 正弦波的理想频谱是 ±100Hz 处的两根细线,与 sinc 卷积后被"抹"成 sinc 函数的形状。
4.2.3 泄漏的直观表现
接上例,\(\Delta f = 1000/256 \approx 3.906\text{Hz}\):Bin 25 对应 97.5Hz,Bin 26 对应 101.4Hz。100Hz 落在两者之间,导致:
- 能量铺开:能量分散到 Bin 25、26、27 等多个 bin
- 主峰变宽:谱线变成有宽度的峰
- 出现旁瓣:主峰两侧出现 sinc 旁瓣
4.2.4 矩形窗的固有缺陷
矩形窗频谱(sinc 函数)具有宽大主瓣 、显著旁瓣 (第一旁瓣仅比主瓣低约 13dB)和缓慢衰减的旁瓣(6dB/octave)。即使频率对准网格,旁瓣仍会掩盖小幅频率分量。
判断标准:\(\frac{f_{\text{sig}}}{\Delta f} \notin \mathbb{Z}\),即信号频率与分辨率之比非整数时发生泄漏。
4.2.5 多频信号间的干涉泄漏
多频信号中,强信号(0dB)的泄漏旁瓣可能淹没弱信号(-60dB)的主瓣。即使两者都落在网格上,旁瓣也会互相叠加,造成虚假峰或基线抬升。
4.2.6 窗函数:缓解泄漏的工具
窗函数通过平滑信号两端幅度,减缓周期性延拓时的跳变。常见窗函数:
- 汉宁窗(Hanning):旁瓣衰减快,主瓣较宽
- 汉明窗(Hamming):第一旁瓣更低,衰减较慢
- 布莱克曼窗(Blackman):旁瓣极低,主瓣最宽
选择窗函数需权衡以下方面:
| 窗函数 | 主瓣宽度 | 第一旁瓣电平 | 旁瓣衰减速度 | 适用场景 |
|---|---|---|---|---|
| 矩形窗 | 最窄 | -13dB | 6dB/octave | 整周期采样,频率分辨率优先 |
| 汉宁窗 | 较宽 | -31dB | 18dB/octave | 一般频谱分析,兼顾分辨率和泄漏抑制 |
| 汉明窗 | 较宽 | -41dB | 6dB/octave | 需要极低第一旁瓣的场景 |
| 布莱克曼窗 | 最宽 | -58dB | 18dB/octave | 极低旁瓣、大动态范围场景 |
4.2.7 总结:泄漏的完整链条
- 物理现实:采集非整数周期(如 25.6 个)
- 信号处理:DFT 将其当作完整周期循环播放,首尾不连续
- 数学本质:时域被矩形窗截断,频域原谱线与 sinc 函数卷积
- 最终现象:能量扩散,主峰变宽,出现旁瓣
理解频谱泄漏是工程实践的关键。选择合适的窗函数、调整采样参数、理解泄漏对测量的影响,是 DSP 工程师的基本功。
五、工程实践
本章以 ARM CMSIS-DSP 库为例,展示实数 FFT 的调用方式和输出格式,并给出窗函数选择指南。
5.1 实数 FFT:arm_rfft_fast_f32 的输出
实数信号频谱具有共轭对称性 \(XN-k = X^*k\),可设计专门的实数 FFT 将计算量减半。
以 arm_rfft_fast_f32 为例:输入 N 个实数,输出长度仍为 N 的 float32_t 数组,存放实部与虚部交替的复数。由于共轭对称性,库只计算前 \(N/2+1\) 个频率点,利用对称性填满数组。
输出数组索引 (输出指针 pOut):
| 索引 | 含义 |
|---|---|
pOut[0] |
直流分量(频率 0)的实部 |
pOut[1] |
直流分量的虚部(始终为 0) |
pOut[2*k] |
第 k 个频率分量的实部 \(Ak\) |
pOut[2*k+1] |
第 k 个频率分量的虚部 \(Bk\) |
| ... | ... |
pOut[N-2] |
第 \(N/2\) 个频率(奈奎斯特频率)的实部 |
pOut[N-1] |
奈奎斯特频率的虚部(始终为 0) |
几点说明:
-
虚部对应正弦系数 \(Bk\),符号与数学定义一致:
\(Xk = Ak - iBk\)
pOut[2*k]即 \(Ak\),pOut[2*k+1]即 \(Bk\)。 -
频率 k 对应的物理频率:
\(f_k = k \cdot \frac{f_s}{N}, \quad k = 0, 1, \ldots, N/2\)
-
获取幅度 \(Mk\) 和相位 \(\phik\):
\(Mk = \sqrt{Ak^2 + Bk^2}\)
\(\phik = \arctan2(-Bk, Ak)\)
很多库(如 ARM 的
arm_cmplx_mag_f32)直接用 A、B 算幅度。
5.2 窗函数的实际选择指南
5.2.1 核心权衡维度
- 频率分辨率:主瓣越窄,能分辨的相邻频率越近。矩形窗最窄但旁瓣最差。
- 泄漏抑制:旁瓣越低、衰减越快,对弱信号干扰越小。
- 幅值精度:加窗改变信号幅度,需根据相干增益补偿。
5.2.2 场景化选择建议
| 应用场景 | 推荐窗函数 | 理由 |
|---|---|---|
| 整周期采样/已知频率校准 | 矩形窗 | 无泄漏风险时提供最佳频率分辨率 |
| 通用频谱分析 | 汉宁窗 | 主瓣宽度和旁瓣衰减的最佳平衡,最常用 |
| 检测微弱信号/大动态范围 | 布莱克曼窗 | 旁瓣极低(-58dB),避免强信号掩盖弱信号 |
| 精确测量单频幅值 | 平顶窗(Flat Top) | 主瓣顶部平坦,幅值误差极小;频率分辨率差 |
| 音频处理/语谱图 | 汉明窗 | 第一旁瓣很低(-41dB),适合短时傅里叶变换 |
5.2.3 实践中的操作流程
- 先不加窗分析:用矩形窗跑一次 FFT,观察频谱形态。
- 判断泄漏程度:查看主峰是否尖锐、旁瓣是否明显。
- 选择合适的窗:参考上表选择窗函数,对比加窗前后频谱变化。
- 注意幅度补偿:加窗后能量减小,精确幅值需除以相干增益或使用归一化系数。
掌握这些原则和流程,即可在实际工程中灵活应对各种频谱分析需求。