快速傅立叶变换
嵌入式工程师视角的傅里叶变换完全指南
下面用嵌入式工程视角来讲傅里叶变换。你可以先记住一句话:
傅里叶变换就是:把一个随时间变化的信号,拆成一堆不同频率的正弦波,看看每个频率占多少。
1. 先从一个生活类比开始
假设你听到一段声音:
嗡嗡嗡——滋滋滋——
你在时间上看到的只是一个复杂波形,就像示波器上的曲线:
时域信号: 电压/电流/声音幅值 随 时间 变化
但你真正关心的可能是:
- 里面有没有 50 Hz 工频干扰?
- 有没有 1 kHz 的噪声?
- 电机有没有某个异常振动频率?
- 通信信号的主频是多少?
- 音频里面是哪几个音调?
这时候你不想只看“波形长什么样”,你想知道:
这个信号由哪些频率组成?
每个频率有多强?
这就是傅里叶变换要做的事情。
2. 时域 vs 频域
嵌入式里你平时采 ADC,拿到的是这样的数据:
1 | adc_buf[0], adc_buf[1], adc_buf[2], ... |
这叫时域数据,也就是信号随时间变化的情况。
例如:
| 时间 n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | … |
|---|---|---|---|---|---|---|---|---|
| ADC值 | 2030 | 2100 | 2200 | 2100 | 2030 | 1950 | … | … |
傅里叶变换之后,你得到的是频域数据:
| 频率 | 0Hz | 50Hz | 100Hz | 200Hz | 500Hz | … |
|---|---|---|---|---|---|---|
| 幅值 | 3 | 120 | 5 | 60 | 2 | … |
意思是:
- 50 Hz 成分很强
- 200 Hz 成分也有
- 其他频率较弱
所以:
- 时域:看波形怎么随时间变化
- 频域:看信号由哪些频率组成
3. 傅里叶变换的核心直觉
任何复杂的周期信号,都可以看成很多正弦波叠加出来的。
例如下面这个信号:
$$ x(t) = 1.0 \cdot \sin(2\pi \cdot 50t) + 0.5 \cdot \sin(2\pi \cdot 200t) $$
它的意思是:
- 有一个 50 Hz 的正弦波,幅值是 1.0
- 有一个 200 Hz 的正弦波,幅值是 0.5
- 两个波叠加后,形成一个复杂波形
在示波器上,你看到的是叠加后的结果,可能不容易看出里面有什么。
但做傅里叶变换后,会看到:
- 50 Hz 位置有一个峰
- 200 Hz 位置有一个峰
也就是说,傅里叶变换帮你把“混在一起的频率”分开了。
注:正弦函数公式 $$y=A \cdot sin(ωx+φ)+k$$ 中:
A 为振幅(纵向伸缩)
ω 决定周期(横向伸缩)
φ 为初相(左右平移)
k 为垂直位移(平衡位置)
4. 傅里叶变换到底怎么“找频率”?
先不用看公式,先理解它的工作方式。
傅里叶变换会拿很多不同频率的“标准正弦波”去和你的信号做匹配:
- 拿 10 Hz 的正弦波去试一下:像不像?
- 拿 20 Hz 的正弦波去试一下:像不像?
- 拿 50 Hz 的正弦波去试一下:像不像?
- 拿 100 Hz 的正弦波去试一下:像不像?
- …
如果你的原始信号里真的有 50 Hz 成分,那么用 50 Hz 的正弦波去匹配时,结果会很大。
如果没有 80 Hz 成分,用 80 Hz 去匹配时,正负会互相抵消,结果接近 0。
所以傅里叶变换本质上是在问:
我的信号里,和某个频率的正弦波有多像?
5. 对嵌入式工程师来说,真正常用的是 DFT / FFT
严格来说,傅里叶变换有好几种:
| 名称 | 用途 |
|---|---|
| 傅里叶级数 | 分析周期连续信号 |
| 连续傅里叶变换 (FT) | 分析连续时间信号 |
| 离散傅里叶变换 (DFT) | 分析采样后的离散数据 |
| 快速傅里叶变换 (FFT) | DFT 的快速算法 |
在 MCU / DSP / 上位机程序里,你一般不是直接用“连续傅里叶变换”,而是用:
ADC采样数据 → DFT/FFT → 频谱
实际项目中你最常见的是 FFT。
FFT 不是一种新的变换,它只是快速计算 DFT 的算法。
简单理解:
- DFT:计算频谱,比较慢
- FFT:计算同样的频谱,但速度快很多
6. DFT 的公式,看懂含义就行
DFT 公式是:
$$ X[k] = \sum_{n=0}^{N-1} x[n] \cdot e^{-j \cdot 2\pi \cdot k \cdot n / N} $$
你不需要一开始就死记这个公式,只要理解每个量的含义:
| 符号 | 含义 |
|---|---|
| $x[n]$ | 第 n 个采样点 |
| $N$ | 总采样点数 |
| $k$ | 第 k 个频率点,也叫 bin |
| $X[k]$ | 第 k 个频率上的复数结果 |
| $e^{-j \cdot 2\pi \cdot k \cdot n / N}$ | 可以理解为一组正弦/余弦测试波 |
对嵌入式工程来说,最重要的是这个关系:
第 k 个频点对应的实际频率:
$$ f[k] = k \cdot \frac{F_s}{N} $$
其中:
| 符号 | 含义 |
|---|---|
| $F_s$ | 采样率 (Hz) |
| $N$ | FFT 点数 |
| $k$ | 频率索引 (0 ~ N-1) |
| $f[k]$ | 第 k 个频点对应的 Hz |
这个公式非常重要!
7. 例子:采样率 1000 Hz,FFT 点数 1000
假设你用 ADC 采样:
- $F_s = 1000 \text{ Hz}$
- $N = 1000$ 点
那么采样总时长是:
$$ T = \frac{N}{F_s} = \frac{1000}{1000} = 1 \text{ 秒} $$
频率分辨率是:
$$ \Delta f = \frac{F_s}{N} = \frac{1000}{1000} = 1 \text{ Hz} $$
也就是说 FFT 结果中:
| k 索引 | 对应频率 |
|---|---|
| k = 0 | 0 Hz (DC) |
| k = 1 | 1 Hz |
| k = 2 | 2 Hz |
| k = 50 | 50 Hz |
| k = 200 | 200 Hz |
如果你的信号是:
$$ x(t) = \sin(2\pi \cdot 50t) + 0.5 \cdot \sin(2\pi \cdot 200t) $$
那么 FFT 之后,你会在:
- $k = 50$
- $k = 200$
附近看到明显峰值。
8. 频率分辨率是什么?
频率分辨率是 FFT 中非常重要的概念。
公式:
$$ \Delta f = \frac{F_s}{N} $$
它表示两个相邻频点之间相隔多少 Hz。
例如:
- $F_s = 1000 \text{ Hz}$
- $N = 256$
那么:
$$ \Delta f = \frac{1000}{256} \approx 3.90625 \text{ Hz} $$
频率点分别是:
| k | 频率 (Hz) |
|---|---|
| 0 | 0 |
| 1 | 3.90625 |
| 2 | 7.8125 |
| 3 | 11.71875 |
| 4 | 15.625 |
| … | … |
这意味着 FFT 不是每一个 Hz 都能精确显示,而是按一个个 bin 显示。
如果你的信号是 50 Hz,它不一定刚好落在某个 bin 上。
比如:
- $k = 12 \rightarrow 46.875 \text{ Hz}$
- $k = 13 \rightarrow 50.78125 \text{ Hz}$
50 Hz 位于这两个 bin 附近,所以频谱能量可能会扩散到多个 bin 上。
这就是后面要讲的频谱泄漏。
9. 采样率 $F_s$ 该怎么选?
采样率必须满足奈奎斯特定理(采样频率必须至少是信号最高频率的两倍,才能无失真地还原原始信号):
$$ F_s > 2 \cdot f_{\text{max}} $$
也就是说,如果你想分析最高 5 kHz 的信号,那么采样率至少要大于:
$$ 10 \text{ kHz} $$
工程上通常会留裕量,比如:
- 目标最高频率:5 kHz
- 采样率:20 kHz 或更高
如果采样率不够,会发生混叠。
10. 什么是混叠?
假设你的采样率是:
$$ F_s = 1000 \text{ Hz} $$
理论上你最多只能正确分析:
$$ 0 \sim 500 \text{ Hz} $$
因为 Nyquist 频率 是:
$$ \frac{F_s}{2} = 500 \text{ Hz} $$
如果实际信号里有一个 600 Hz 的成分,它会被错误地看成:
$$ 400 \text{ Hz} $$
这就是混叠。
因为:
- 600 Hz 超过了 $F_s/2$
- 在采样后会折叠回来
- 看起来像 400 Hz
- 折叠计算公式:$$F混叠=|F_s-F真实|=|1000-600|=400Hz$$
所以在 ADC 前面,很多项目会加:模拟低通滤波器 也叫 抗混叠滤波器。
混叠就是:高频信号“伪装”成低频信号,混进你的ADC数据里,让你看走眼。
在数字世界里,采样率$$ F_s $$就像一台相机的“快门速度”。如果被拍的东西动得比快门还快,照片就拍出“慢动作”甚至“倒转”的效果。
混叠就是这种“频率上的慢动作错觉”。
11. FFT 输出为什么是复数?
FFT 的输出通常是复数:
$$ X[k] = \text{real} + j \cdot \text{imag} $$
也就是:
real[k]imag[k]
为什么是复数?
因为一个频率成分不只有“强度”,还有“相位”。
可以理解为:
- 幅值:这个频率有多强
- 相位:这个频率的波形从哪里开始
从复数得到幅值:
$$ \text{magnitude}[k] = \sqrt{\text{real}[k]^2 + \text{imag}[k]^2} $$
从复数得到相位:
$$ \text{phase}[k] = \text{atan2}(\text{imag}[k], \text{real}[k]) $$
很多嵌入式项目里,你只关心频率强弱,所以只看 magnitude 就够了。
12. 实数 FFT 的结果只看一半
ADC 采样到的数据通常是实数:
$$ x[n] \text{ 是实数} $$
对实数信号做 FFT 后,频谱是对称的。
如果 FFT 点数是 $N$,那么你通常只需要看:
$$ 0 \sim \frac{N}{2} $$
对应频率范围是:
$$ 0 \sim \frac{F_s}{2} $$
例如:
- $F_s = 1000 \text{ Hz}$
- $N = 1024$
那么你只看:
$$ k = 0 \sim 512 $$
频率范围:
$$ 0 \sim 500 \text{ Hz} $$
后半部分是镜像信息,一般不用看。
13. 幅值怎么算?这是工程里很容易错的点
假设你做了 $N$ 点 FFT,得到:
real[k]imag[k]
先算模长:
$$ \text{mag}[k] = \sqrt{\text{real}[k]^2 + \text{imag}[k]^2} $$
如果你想得到接近原始正弦波的幅值,常见处理是:
$$ \text{amplitude}[k] = \frac{2 \cdot \text{mag}[k]}{N} $$
但有两个例外:
| 情况 | 计算公式 |
|---|---|
| DC 分量 $k = 0$ | $\text{amplitude}[0] = \text{mag}[0] / N$ |
| Nyquist 点 $k = N/2$ | $\text{amplitude}[N/2] = \text{mag}[N/2] / N$ |
为什么中间频点要乘 2?
因为实数 FFT 的能量原本分布在正频率和负频率两边,你只看单边频谱时,需要把另一半合并过来。
不过注意:如果你加了窗函数,幅值还要考虑窗函数的增益修正。
直流分量(DC):
DC是Direct Current(直流)的缩写,在信号处理语境下特指信号中的直流分量,即信号的平均值或恒定偏移量。
- 物理含义:代表信号中不随时间变化的恒定部分(基线偏移),数学上等于信号在一个周期或整段数据上的算术平均值。
- 命名来源:源自“直流电”概念,类比于电流中方向大小不变的分量;在交流信号分析中,该恒定偏移被视为“直流成分”。
- 去 DC 操作:即从原始信号每个采样点减去其平均值,使处理后的信号均值为零,仅保留交流波动部分
14. DC 分量是什么?
FFT 里的 $k = 0$ 代表 0 Hz,也就是直流分量。
对于 ADC 数据来说,DC 分量通常就是平均值。
例如你的 ADC 数据围绕 2048 上下波动:
$$ 2048 + \text{交流信号} $$
那么 FFT 的 0 Hz 会非常大。
很多时候你不关心 DC,而是关心交流频率,所以 FFT 前会先去均值:
1 | mean = average(adc_buf); |
这样可以减少 DC 对频谱显示的影响。
15. 什么是频谱泄漏?
假设:
- $F_s = 1000 \text{ Hz}$
- $N = 256$
- $\Delta f = 3.90625 \text{ Hz}$
FFT 的频点是:
| k | 频率 (Hz) |
|---|---|
| 0 | 0 |
| 1 | 3.90625 |
| 2 | 7.8125 |
| … | … |
| 12 | 46.875 |
| 13 | 50.78125 |
| 14 | 54.6875 |
| … | … |
如果输入信号是 50 Hz,它并没有刚好落在 FFT 的某一个频点上。
结果会怎样?
它的能量不会只集中在一个 bin,而是扩散到周围很多 bin。
这就叫:频谱泄漏
表现为:
- 原本应该是一个尖峰
- 结果变成一片拖尾
16. 窗函数是干什么的?
FFT 默认假设你截取的这 $N$ 个点是一个完整周期片段,并且会无限重复。
如果你的采样片段开头和结尾接不上,就会产生突变。
这种突变会导致频谱泄漏。
窗函数的作用是:把采样片段两端压低,让边界更平滑
常见窗函数:
| 窗函数 | 特点 |
|---|---|
| 矩形窗 | 不处理,频率刚好对齐时最好,泄漏严重 |
| Hann 窗 | 通用,泄漏较小 |
| Hamming 窗 | 通用,旁瓣较低 |
| Blackman 窗 | 泄漏更低,但主瓣更宽 |
对于很多嵌入式频谱分析项目,初学时可以先用:Hann窗(汉宁窗)
典型流程:
1 | for (i = 0; i < N; i++) |
然后再做 FFT。
17. 窗函数的代价
窗函数不是免费午餐。
它有好处:
- 减少频谱泄漏
但也有代价:
- 会让主峰变宽
- 会影响幅值
所以选择窗函数时要看你的目标:
| 目标 | 建议 |
|---|---|
| 信号频率刚好落在 bin 上 | 矩形窗也可以 |
| 想减少泄漏 | Hann / Hamming |
| 想看小信号,不想被大信号旁瓣淹没 | Blackman 类 |
| 想精确测幅值 | 要做窗增益修正 |
18. 零填充有什么用?
很多人会在 FFT 前补零:
- 原始 $N = 256$ 点
- 补零到 $1024$ 点
这样频谱看起来更细。
但是要注意:
零填充不会真正提高频率分辨率
真正的频率分辨率由采样时长决定:
$$ T = \frac{N}{F_s} $$
$$ \Delta f = \frac{1}{T} = \frac{F_s}{N} $$
补零只是让频谱曲线插值更平滑,看峰值位置更方便。
如果你真的想提高频率分辨率,应该:
增加采样点数 $N$
也就是采更长时间
19. 嵌入式项目中的典型 FFT 流程
一个实用的 FFT 处理流程通常是:
- 定时器触发 ADC 采样
- DMA 存入采样缓冲区
- 收集 $N$ 个点
- 去除平均值(去 DC)
- 乘窗函数
- 执行 FFT
- 计算幅值谱
- 找峰值或做阈值判断
- 输出频率、幅值、报警结果等
对应伪代码:
1 |
|
实际项目里你可以用 DSP 库,比如 ARM Cortex-M 上常见的 CMSIS-DSP,避免自己手写 FFT。
20. 例子一:检测 50 Hz 工频干扰
假设你的系统采集传感器信号,怀疑有 50 Hz 干扰。
设置:
- $F_s = 1000 \text{ Hz}$
- $N = 1000$
频率分辨率:
$$ \Delta f = \frac{1000}{1000} = 1 \text{ Hz} $$
那么:
- 50 Hz 对应 $k = 50$
你做完 FFT 后检查:
mag[50]
如果它明显比周围频点大,就说明 50 Hz 干扰明显。
也可以同时检查:
- 100 Hz
- 150 Hz
- 200 Hz
因为工频干扰有时会带谐波。
21. 例子二:电机振动检测
假设电机转速是:
$$ 3000 \text{ RPM} $$
换算成 Hz:
$$ \frac{3000}{60} = 50 \text{ Hz} $$
如果电机正常,振动频谱可能主要在:
- 50 Hz
- 100 Hz
- 150 Hz
如果轴承、偏心、松动等问题出现,可能会在某些特定频率附近出现异常峰值。
嵌入式设备可以这样做:
加速度传感器采样 → FFT → 找峰值 → 判断是否异常
这种场景下,FFT 非常常用。
22. 例子三:电流纹波分析
假设你在做电源或者电机驱动,采样电流信号。
时域里看到的电流可能只是:
上下波动的一条曲线
但做 FFT 后,你可能发现:
- 20 kHz 附近有明显峰值
这可能对应 PWM 开关频率。
如果还有:
- 40 kHz
- 60 kHz
这些可能是 PWM 谐波。
所以 FFT 可以帮你分析:
- 纹波频率
- 开关噪声
- 谐波分布
- 滤波效果
23. 例子四:判断一个信号是不是正弦波
理想正弦波的频谱很简单:
只有一个主频峰
例如 1 kHz 正弦波,频谱主要在:
- 1 kHz
如果信号失真了,就会出现谐波:
- 2 kHz
- 3 kHz
- 4 kHz
- …
所以可以通过 FFT 看谐波大小来判断失真程度。
这在音频、电机、电源、通信里都很常见。
24. 频域图怎么看?
FFT 后常见的频谱图横轴是频率,纵轴是幅值:
1 | 幅值 |
这表示:
- 50 Hz 有一个频率成分
- 200 Hz 有一个频率成分
如果 50 Hz 的峰比 200 Hz 高,说明 50 Hz 成分更强。
25. 频率 bin 的概念一定要掌握
假设:
- $F_s = 8000 \text{ Hz}$
- $N = 1024$
则:
$$ \Delta f = \frac{8000}{1024} = 7.8125 \text{ Hz} $$
每个 bin 对应:
| k | 频率 (Hz) |
|---|---|
| k = 0 | 0 |
| k = 1 | 7.8125 |
| k = 2 | 15.625 |
| … | … |
| k = 128 | 1000 |
| … | … |
如果你想找 1 kHz 信号:
$$ k = \frac{1000}{7.8125} = 128 $$
所以看:
mag[128]
就可以了。
26. FFT 点数 N 怎么选?
FFT 点数越大:
- 频率分辨率越高
因为:
$$ \Delta f = \frac{F_s}{N} $$
但是 $N$ 越大:
- 需要更多 RAM
- 需要更多计算时间
- 响应速度更慢
例如:
| $F_s$ | $N$ | $\Delta f$ | 采样时长 |
|---|---|---|---|
| 10 kHz | 256 | 39.06 Hz | 25.6 ms |
| 10 kHz | 1024 | 9.77 Hz | 102.4 ms |
| 10 kHz | 4096 | 2.44 Hz | 409.6 ms |
所以工程上要权衡:
- 频率分辨率
- 实时性
- RAM
- CPU算力
如果你只是判断有没有大概 1 kHz 附近的信号,$N$ 不用太大。
如果你要区分:
- 1000 Hz 和 1005 Hz
那你需要很高的频率分辨率,也就是更长的采样时间。
27. FFT 为什么常要求 N 是 2 的幂?
很多 FFT 算法喜欢:
$$ N = 256, 512, 1024, 2048, 4096 $$
因为 2 的幂 可以让 FFT 算法最高效(基2时分抽取/频分抽取)。
虽然有些库支持非 2 的幂长度,但在 MCU 上一般优先选:
$2^n$
例如:
- 256 点
- 512 点
- 1024 点
- 2048 点
28. 实际项目中最常见的坑
坑 1:采样率不准
FFT 的频率轴依赖 $F_s$。
如果你以为采样率是 10 kHz,但实际是 9.8 kHz,那么频率计算就会偏。
建议:用硬件定时器触发 ADC,不要用软件 delay 采样。
坑 2:没有抗混叠滤波
如果 ADC 前没有低通滤波,高频噪声会混叠到低频。
结果你会在频谱里看到一些“莫名其妙”的频率峰。
坑 3:忘记去 DC
ADC 信号如果有很大的直流偏置,0 Hz 分量会非常大,影响观察。
FFT 前建议先:
减去平均值
坑 4:频率不落在 bin 上
如果信号频率不是 bin 的整数倍,会出现频谱泄漏。
解决方法:
- 使用窗函数
- 增加采样长度
- 或者让采样窗口包含整数个周期
坑 5:误以为补零提高真实分辨率
补零只是让图更平滑,不会让你真的区分更近的两个频率。
真正提升分辨率要增加采样时长。
坑 6:幅值标定错误
很多项目中 FFT 峰值看起来“不对”,原因是:
- 没有除以 $N$
- 没有乘 2
- 没有考虑窗函数增益
- ADC 原始值没有换算成电压/电流
坑 7:用 float 还是 fixed-point 没想清楚
在 Cortex-M4F / M7 / M33F 这类带 FPU 的 MCU 上,用 float FFT 比较方便。
在没有 FPU 的小 MCU 上,可以考虑:
- Q15
- Q31
- 定点 FFT
但定点 FFT 要注意:
- 溢出
- 缩放
- 动态范围
- 精度损失
29. 给你一个嵌入式项目中的实战设计模板
假设你的需求是:
采集一个传感器信号,分析 0~2 kHz 内的频率成分。
第一步:确定最高分析频率
最高频率 = 2 kHz
根据奈奎斯特定理:
$$ F_s > 4 \text{ kHz} $$
工程上取:
$$ F_s = 8 \text{ kHz 或 } 10 \text{ kHz} $$
第二步:选择 FFT 点数
如果取:
- $F_s = 10 \text{ kHz}$
- $N = 1024$
则:
$$ \Delta f = \frac{10000}{1024} \approx 9.77 \text{ Hz} $$
可以分辨约 10 Hz 间隔的频率。
采样时长:
$$ T = \frac{1024}{10000} = 102.4 \text{ ms} $$
这意味着每 102.4 ms 可以更新一次频谱。
第三步:ADC 采样
建议:
- 定时器触发 ADC
- ADC + DMA 双缓冲
不要用 while 循环 delay 采样。
第四步:处理数据
处理顺序:
原始 ADC → 转换成电压/电流 → 去均值 → 加窗 → FFT → 幅值谱
第五步:找目标频率
比如要检测 1 kHz:
$$ k = \frac{f \cdot N}{F_s} $$
$$ k = \frac{1000 \cdot 1024}{10000} \approx 102.4 $$
所以应该检查:
- $k = 102$ 或 $k = 103$ 附近
不要只死盯一个 bin,最好检查附近几个 bin 的最大值。
30. 你可以这样理解傅里叶变换
从示波器角度
- 示波器看到的是:信号随时间怎么变化
- 频谱仪看到的是:信号里面有哪些频率
傅里叶变换就是把示波器视角变成频谱仪视角。
从滤波器角度
傅里叶变换像是很多个窄带滤波器:
- 一个滤波器专门看 10 Hz
- 一个滤波器专门看 20 Hz
- 一个滤波器专门看 30 Hz
- …
每个滤波器输出一个强度。
这些强度合起来就是频谱。
从匹配角度
傅里叶变换是在做匹配:
- 这个信号像不像 50 Hz?
- 像不像 100 Hz?
- 像不像 200 Hz?
像,就有峰。
不像,就接近 0。
31. 最小知识闭环
如果你暂时不想学太多数学,只需要先掌握下面这些:
- FFT 用来把时域信号变成频域信号
- ADC 采样得到的是时域数据
- FFT 输出的每个 bin 对应一个频率
- $f[k] = k \cdot F_s / N$
- $\Delta f = F_s / N$
- 最高可分析频率是 $F_s / 2$
- FFT 前通常要去 DC、加窗
- FFT 后通常算 magnitude
- 找频谱峰值就能找到主要频率
- 工程中要注意采样率、混叠、泄漏、幅值标定
32. 一个完整的小例子
假设:
- $F_s = 8000 \text{ Hz}$
- $N = 1024$
那么:
- 最高分析频率 = 4000 Hz
- 频率分辨率 = $8000 / 1024 = 7.8125 \text{ Hz}$
你采到一个信号,做 FFT 后发现:
mag[128]最大
那么主频是:
$$ f = \frac{k \cdot F_s}{N} $$
$$ f = \frac{128 \cdot 8000}{1024} = 1000 \text{ Hz} $$
所以你可以判断:
这个信号的主频大约是 1 kHz
如果又发现:
mag[256]也比较大
对应:
$$ f = \frac{256 \cdot 8000}{1024} = 2000 \text{ Hz} $$
那说明信号里面还有 2 kHz 成分,可能是二次谐波。
33. 项目中应该怎么开始用?
你可以按这个顺序实践:
| 步骤 | 内容 |
|---|---|
| 第一步 | 用 Python 或上位机生成一个 50 Hz + 200 Hz 的测试信号 |
| 第二步 | 对它做 FFT,看频谱峰值 |
| 第三步 | 把同样逻辑移植到 MCU |
| 第四步 | 用 ADC 采真实信号 |
| 第五步 | 处理去 DC、加窗、幅值归一化 |
| 第六步 | 根据目标频率做检测或判断 |
在 MCU 上,一般不要一开始就自己写 FFT。
建议:
优先使用成熟 DSP 库
比如 ARM Cortex-M 项目中常用 CMSIS-DSP 这一类库。
34. 最后用一句工程化的话总结
傅里叶变换在嵌入式里通常不是为了“研究数学”,而是为了把问题从:
这个波形看起来很乱
变成:
这个信号主要包含 50 Hz、200 Hz 和 1 kHz 成分
这样你就可以做:
- 频率检测
- 故障诊断
- 噪声分析
- 滤波设计
- 电机状态监测
- 振动分析
- 音频分析
- 通信解调
- 谐波分析
真正落地时,你重点掌握这几个公式就够用了:
$$ f[k] = \frac{k \cdot F_s}{N} $$
$$ \Delta f = \frac{F_s}{N} $$
$$ f_{\text{max}} = \frac{F_s}{2} $$
$$ \text{幅值} \approx \frac{2 \cdot \sqrt{\text{real}^2 + \text{imag}^2}}{N} $$
其中最关键的是:
- **$F_s$**:采样率
- **$N$**:FFT 点数
- **$k$**:频率 bin
把这三个搞清楚,傅里叶变换在嵌入式项目里就已经能用起来了。
以上内容来源于ChatGPT,仅供参考
