4、傅里叶变换入门:从时域到频域,理解频谱分析
说实话,我刚入行那会儿,看示波器上的波形看得眼睛都快瞎了。一个信号在时间轴上扭来扭去,你根本不知道它里面到底藏着什么。直到我真正搞懂了傅里叶变换,才恍然大悟——原来那些乱七八糟的波形,不过是几个正弦波叠在一起罢了。
这一章,我们就来聊聊这个神奇的工具。它能把信号从时域搬到频域,让你一眼看穿信号的“底细”。
4.1 为什么我们需要频域?
先问个问题:给你一段音频,里面有人声、有吉他、有背景噪音。你在时域里能看到什么?
嗯,就是一条上下抖动的曲线。你分不清哪个是歌声,哪个是噪音。
但在频域里呢?每个频率分量都清清楚楚。人声在 300Hz-3kHz 附近,吉他泛音在更高频段,噪音可能集中在某个固定频率。你一看频谱图,就知道该砍掉哪部分。
我在做工业设备故障诊断时遇到过类似情况。电机振动信号在时域里看着很正常,但一转到频域,某个特定频率的幅值突然飙升——那就是轴承磨损的特征。没有频域分析,你根本发现不了。
核心思想:时域告诉我们“信号什么时候变化”,频域告诉我们“信号由哪些频率组成”。两者是同一信号的不同视角。
4.2 傅里叶变换的本质
傅里叶变换的数学公式长这样:
X(f) = ∫ x(t) · e^(-j2πft) dt
别被这个积分吓到。说白了,它干的事情就三步:
- 拿一个已知频率的正弦波,跟你的信号做乘法
- 把乘积积分(也就是求和)
- 看结果有多大——结果越大,说明信号里这个频率的成分越多
你想想看,如果信号里恰好有一个 100Hz 的分量,而你拿一个 100Hz 的正弦波去跟它相乘再积分,结果会很大。如果你拿 200Hz 的去乘,结果几乎为零。就这么简单。
我习惯把这个过程叫做“频率探针”——你拿不同频率的探针去戳信号,看哪个频率能引起“共振”。
4.3 从连续到离散:我们实际用的是 DFT
现实世界里的信号都是离散的采样点,不是连续的数学函数。所以我们需要离散傅里叶变换(DFT)。
公式变成这样:
X[k] = Σ x[n] · e^(-j2πkn/N) (n = 0, 1, ..., N-1)
其中:
- x[n] 是时域采样值
- N 是采样点数
- k 对应频率索引,k=0 是直流分量,k=1 是基频,以此类推
这里有个关键点:频率分辨率。它等于采样率除以 N。比如你以 1000Hz 采样,采了 1000 个点,那频率分辨率就是 1Hz。你想分辨出 0.5Hz 的差异?那就得采更多点。
实用技巧:我在做音频降噪时,通常把帧长设为 1024 或 2048 点。太短了频率分辨率不够,太长了时域定位不准。这个平衡点需要根据实际信号来调。
4.4 频谱图怎么看?
做完傅里叶变换,你得到的是复数。通常我们取它的幅值,画成频谱图。
横轴是频率,纵轴是幅值。一个典型的频谱图长这样:
幅值
↑
| ██
| ██
| ██ ██
| ██ ██ ██
| ██ ██ ██ ██
+--------------------------------→ 频率
0 100 200 300 (Hz)
看到那几个尖峰了吗?那就是信号里的主要频率成分。
我刚开始看频谱图时犯过一个错误:以为幅值最高的就是最重要的。其实不一定。有时候低频分量幅值很大,但那是直流偏置,不是有用信号。真正要关注的是那些跟你的应用相关的频段。
4.5 快速傅里叶变换(FFT)——工程界的救星
直接按 DFT 公式计算,复杂度是 O(N²)。N=1024 时还好,N=百万级时根本算不动。
FFT 的出现解决了这个问题。它把复杂度降到 O(N log N),快了不止一个数量级。
FFT 的核心思想是分治:把一个大 DFT 拆成两个小 DFT,再递归下去。具体实现有基-2、基-4 等算法,但作为使用者,你只需要知道:
- 输入点数必须是 2 的幂(1024、2048、4096...)
- 输出是对称的,前一半是正频率,后一半是负频率(通常只看前一半)
- 幅值需要做归一化处理
避坑指南:我曾经在项目里直接用 FFT 的原始输出幅值去做阈值判断,结果发现数值忽大忽小。后来才意识到,FFT 输出的幅值跟采样点数 N 有关,必须除以 N/2 才能得到真实的幅值。这个坑,很多新手都会踩。
4.6 频谱泄露与窗函数
现实中的信号不可能是无限长的。我们只能截取一段来做 FFT。这个截断操作,会在频谱上引入“泄露”——本来应该集中在一个频率的能量,扩散到了相邻频率上。
怎么解决?加窗。
常用的窗函数有:
| 窗类型 | 主瓣宽度 | 旁瓣衰减 | 适用场景 |
|---|---|---|---|
| 矩形窗 | 窄 | 差(-13dB) | 瞬态信号、频率成分间隔大 |
| 汉宁窗 | 中等 | 较好(-32dB) | 通用、音频处理 |
| 海明窗 | 中等 | 好(-43dB) | 语音、窄带信号 |
| 布莱克曼窗 | 宽 | 优秀(-58dB) | 需要高动态范围 |
我个人习惯在降噪滤波器里用汉宁窗。它在主瓣宽度和旁瓣衰减之间取得了不错的平衡。如果你需要检测两个频率很近的信号,可以考虑矩形窗或凯泽窗。
4.7 本章知识体系
下面这张图帮你理清傅里叶变换的核心脉络:
4.8 动手试试:一个简单的 FFT 示例
光说不练假把式。下面这个 Python 代码,生成一个 50Hz + 120Hz 的混合信号,然后做 FFT 看看频谱:
import numpy as np
import matplotlib.pyplot as plt
# 参数设置
fs = 1000 # 采样率 1000Hz
T = 1.0 # 时长 1 秒
N = int(fs * T) # 采样点数
t = np.linspace(0, T, N, endpoint=False)
# 生成信号:50Hz + 120Hz
f1, f2 = 50, 120
x = 0.7 * np.sin(2 * np.pi * f1 * t) + 1.2 * np.sin(2 * np.pi * f2 * t)
# 加汉宁窗
window = np.hanning(N)
x_windowed = x * window
# FFT
X = np.fft.fft(x_windowed)
freqs = np.fft.fftfreq(N, 1/fs)
# 只取正频率部分
half = N // 2
X_mag = np.abs(X[:half]) * 2 / N
# 打印前几个峰值
print("频率 (Hz) | 幅值")
print("-----------------")
for i in range(5):
print(f" {freqs[i]:.1f} | {X_mag[i]:.4f}")
运行这段代码,你会看到在 50Hz 和 120Hz 处出现明显的尖峰。幅值分别是 0.7 和 1.2——跟原始信号完全一致。
小提示:注意代码里的 * 2 / N 这一步。这就是我之前说的归一化。不加的话,幅值会偏大 N/2 倍。
好了,傅里叶变换的基本概念就讲到这里。你掌握了时域到频域的转换思路,理解了 DFT 和 FFT 的区别,也知道了频谱泄露和窗函数是怎么回事。这些知识,是后面所有降噪滤波器设计的基础。