FFT分析

一、从傅里叶级数到傅里叶变换

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 落在两者之间,导致:

  1. 能量铺开:能量分散到 Bin 25、26、27 等多个 bin
  2. 主峰变宽:谱线变成有宽度的峰
  3. 出现旁瓣:主峰两侧出现 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 窗函数:缓解泄漏的工具

窗函数通过平滑信号两端幅度,减缓周期性延拓时的跳变。常见窗函数:

  1. 汉宁窗(Hanning):旁瓣衰减快,主瓣较宽
  2. 汉明窗(Hamming):第一旁瓣更低,衰减较慢
  3. 布莱克曼窗(Blackman):旁瓣极低,主瓣最宽

选择窗函数需权衡以下方面:

窗函数 主瓣宽度 第一旁瓣电平 旁瓣衰减速度 适用场景
矩形窗 最窄 -13dB 6dB/octave 整周期采样,频率分辨率优先
汉宁窗 较宽 -31dB 18dB/octave 一般频谱分析,兼顾分辨率和泄漏抑制
汉明窗 较宽 -41dB 6dB/octave 需要极低第一旁瓣的场景
布莱克曼窗 最宽 -58dB 18dB/octave 极低旁瓣、大动态范围场景
4.2.7 总结:泄漏的完整链条
  1. 物理现实:采集非整数周期(如 25.6 个)
  2. 信号处理:DFT 将其当作完整周期循环播放,首尾不连续
  3. 数学本质:时域被矩形窗截断,频域原谱线与 sinc 函数卷积
  4. 最终现象:能量扩散,主峰变宽,出现旁瓣

理解频谱泄漏是工程实践的关键。选择合适的窗函数、调整采样参数、理解泄漏对测量的影响,是 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 实践中的操作流程
  1. 先不加窗分析:用矩形窗跑一次 FFT,观察频谱形态。
  2. 判断泄漏程度:查看主峰是否尖锐、旁瓣是否明显。
  3. 选择合适的窗:参考上表选择窗函数,对比加窗前后频谱变化。
  4. 注意幅度补偿:加窗后能量减小,精确幅值需除以相干增益或使用归一化系数。

掌握这些原则和流程,即可在实际工程中灵活应对各种频谱分析需求。

相关推荐
水龙吟啸1 小时前
华为2026.6.17机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·华为
凌波粒1 小时前
LeetCode--53. 最大子序和(贪心算法)
算法·leetcode·贪心算法
Hesionberger2 小时前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
c238562 小时前
《序列 DP:C++ 中的“最长”套路与编辑距离》
c++·算法·动态规划
aqiu1111112 小时前
【算法日记 19】LeetCode 1. 两数之和:梦开始的地方,哈希表的降维打击
算法·leetcode·职场和发展
CS创新实验室11 小时前
算法、齿轮与硅基大脑:数值计算发展简史
人工智能·算法·数值计算
海石13 小时前
1563分的简单题,可能就简单在能被暴力AC
算法·leetcode
海石13 小时前
1400分的dp汗流浃背之【交替子数组计数】
算法·leetcode
奋发向前wcx13 小时前
P2590 树的统计 题目解析
数据结构·算法·深度优先