调和分析 · 傅里叶变换 · 离散傅里叶变换 · 快速傅里叶变换
序章:一个统一的大画面
graph TD A调和分析:研究 "任何东西都能拆成波" 的学问 --> B傅里叶级数 (周期信号) A --> C傅里叶变换 (任意信号) A --> D其他分解 (小波、拉普拉斯...) B --> E离散傅里叶变换 DFT C --> E E --> F快速傅里叶变换 FFT
一句话概括整条路: 调和分析是"把万物拆成波"的大学问;傅里叶变换是它最著名的工具;DFT 是给计算机用的版本;FFT 是让 DFT 跑得飞快的算法。
一:调和分析到底是什么?
1.1 先看一个日常问题
你听到一段音乐。你耳朵听到的是"空气在振动"。但你脑子里感知到的是"钢琴、小提琴、鼓、人声"。
同一段空气振动,你的耳朵自动把它拆成了不同的"乐器"和"音高"。你的耳朵,天生就在做调和分析。
1.2 "调和"这个词从哪来?
"调和"(\(harmonic\))这个词,最早来自音乐。
一根琴弦振动时,它不只发出一个音,而是同时发出:
- 基音:最响的那个音,决定音高;
- 泛音:比基音高整数倍的音,决定音色。
text
基音: 频率 f ━━━━━━━━━━
第二泛音:频率 2f ━━━━━━━━━━━
第三泛音:频率 3f ━━━━━━━━━━━
第四泛音:频率 4f ━━━━━━━━━━━
...
这些频率是"整数倍关系"的音,听起来和谐 ,所以叫"调和"。
调和分析,就是研究"一个复杂的东西,能不能拆成这些和谐的波"。
1.3 一个更形象的说法:三棱镜
白光看起来是"白色",但用三棱镜一照,它其实是红橙黄绿蓝靛紫混在一起。
graph TD A白光-->B三棱镜 B-->C红 B-->D橙 B-->E黄 B-->F绿 B-->G蓝 B-->H靛 B-->I紫
调和分析就是数学上的三棱镜:
graph TD A复杂信号-->B调和分析 B-->C各种频率的波
- 白光 = 复杂信号
- 三棱镜 = 傅里叶变换
- 七色光 = 频率成分
这就是整份讲解的核心比喻,后面会反复用到。
1.4 调和分析的三大问题
调和分析这门学问,核心就回答三个问题:
- 能不能拆? 任何信号都能拆成波吗?
- 怎么拆? 拆的方法是什么?
- 拆了有什么用? 拆开之后能干什么?
傅里叶变换,就是第 \(2\) 个问题的第一个、也是最著名的答案。
二:傅里叶的疯狂想法
2.1 一个被嘲笑的年轻人
\(1807\) 年,法国数学家 傅里叶(Fourier) 提交了一篇论文,里面有一个惊人的断言:
任何周期信号,不管形状多奇怪,都能拆成一堆正弦波和余弦波的和。
当时的数学权威拉格朗日看了,直接说:"这不可能。方波有棱有角,正弦波圆滑,怎么可能拼出来?"
二十年后,人们发现他的方法不仅对,而且成了整个现代信号处理的基石。
2.2 为什么方波能拼出来?
拉格朗日的疑问很自然:方波是"直上直下"的,正弦波是"弯弯曲曲"的,怎么能拼成一样?
答案是:用很多很多个正弦波叠加,棱角会被"堆"出来。
看这个过程(公式不用看!!!):
1 个正弦波:
\S_1(x)=\\frac{4}{\\pi}\\sin x \\
3 个正弦波叠加:
\S_3(x)=\\frac{4}{\\pi}\\left(\\sin x+\\frac{1}{3}\\sin 3x+\\frac{1}{5}\\sin 5x\\right) \\
6 个正弦波叠加:
\S_6(x)=\\frac{4}{\\pi}\\left(\\sin x+\\frac{1}{3}\\sin 3x+\\frac{1}{5}\\sin 5x+\\frac{1}{7}\\sin 7x+\\frac{1}{9}\\sin 9x+\\frac{1}{11}\\sin 11x\\right) \\
很多个正弦波叠加:
\\\cdot\\cdot\\cdot\\cdot\\cdot\\space\\cdot \\
动图:
\S_N(x)=\\frac{4}{\\pi}\\sum_{m=0}\^{N-1}\\frac{\\sin((2m+1)x)}{2m+1} \\
数学上可以严格证明:当正弦波的数量趋于无穷,叠加结果就无限接近方波。
2.3 一个重要区分:加法,不是替换
注意:傅里叶说的是叠加,不是"用正弦波代替方波"。
\方波 = 正弦1 + 正弦2 + 正弦3 + ... \\
每个正弦波都真实存在,只是它们叠在一起,看起来像方波。
这就像:一首交响乐 = 小提琴声 + 大提琴声 + 长笛声 + ...
每个乐器都真实在响,只是混在一起你听到的是"整体"。
三:傅里叶级数(FS)------周期信号的拆法
3.1 先限定:只拆"会重复"的信号
傅里叶级数只管一类信号:周期信号,也就是会一遍一遍重复的信号。
比如:
心电图:
正弦波:
方波:
这些都会"周而复始"。
3.2 拆出来的"信号"长什么样?
傅里叶级数用的波形只有两种:
- 正弦波(sin)
- 余弦波(cos)
它们都是"圆滑地上下摆动"的波。
而且,用的频率都是"整数倍"关系:
这就像乐高积木:用同一种规格的积木,拼出各种形状。
3.3 每个波形需要几个信息?
一个正弦波,只需要两个信息就能完全确定:
- 多响(振幅):波有多高;
- 从哪里开始 (相位):波是从 \(0\) 开始,还是从最高点开始。
所以,拆出来的结果,就是一张表:
| 频率 | 多响 | 从哪里开始 |
|---|---|---|
| 1f | 2.0 | 0° |
| 2f | 0.5 | 90° |
| 3f | 0.3 | 180° |
| ... | ... | ... |
这张表,就是频谱。
3.4 形象的画面:合唱团
把傅里叶级数想成一个合唱团:
- 每个歌手负责一个频率;
- 每个歌手有自己的音量(振幅);
- 每个歌手有自己的起唱时机(相位);
- 所有人同时唱,混在一起就是原始信号。
傅里叶级数做的事,就是"听出合唱团里每个歌手唱得多响、什么时候起唱"。
3.5 傅里叶级数的局限
傅里叶级数只适用于周期信号。
但现实中的信号大多不是周期性的:
- 你说的一句话,不会重复;
- 一次地震,不会周期出现;
- 一个脉冲,只出现一次。
怎么办?傅里叶变换就是答案。
四:傅里叶变换(FT)------任意信号的拆法
4.1 一个巧妙的想法:把周期拉到无穷大
傅里叶级数要求信号"会重复"。
但如果一个信号只出现一次,我们可以认为它"重复周期是无穷大"。
text
周期 = 1 秒: [信号][信号][信号][信号]...
周期 = 10 秒: [信号..............][信号..............]...
周期 = 无穷大: [信号........................................]
(只出现一次,再也不重复)
当周期趋于无穷大,傅里叶级数就"进化"成了傅里叶变换(Fourier Transform)。
4.2 从"离散的频率"变成"连续的频率"
这是最关键的区别。
傅里叶级数 :频率是一根一根的柱子,只在 \((f, 2f, 3f, \dots)\) 这些地方有值。
text
傅里叶级数频谱:
█
█ █
█ █ █
────┴───┴───┴────> 频率
f 2f 3f
傅里叶变换:频率是连续的一片,每个频率都可能有一点点。
text
傅里叶变换频谱:
██
████
██████
████████
─────────────────> 频率
(连续的曲线)
形象地说:
- 傅里叶级数像"钢琴":只有固定的几个键能响;
- 傅里叶变换像"小提琴":任意音高都能拉出来。
4.3 傅里叶变换在问什么?
傅里叶变换对每一个可能的频率都问一个问题:
"你这个频率,在原始信号里占多大份量?"
然后给出两个答案:
- 份量多大(幅度);
- 起点在哪(相位)。
所以傅里叶变换的输出,是一个关于频率的函数:
text
输入:时间 → 数值 (信号)
输出:频率 → 复数 (频谱)
这个"复数"就是同时装"幅度"和"相位"的容器。
4.4 形象画面:无数个音叉
想象你面前有无穷多个音叉,每个音叉对应一个频率。
傅里叶变换做的事:
- 拿起每个音叉,对着信号敲一下;
- 如果信号里真的有这个频率,音叉会"共振",响得很大;
- 如果没有,音叉纹丝不动。
对每个频率都试一遍,就得到了完整的频谱。
这就是傅里叶变换最形象的画面:用无穷多个音叉,去探测信号里有哪些频率。
4.5 傅里叶变换的"三棱镜"版本
回到三棱镜的比喻:
graph TD a白光(复杂信号)-->b三棱镜(傅里叶变换) b-->c七色光(频谱): 红:多亮? 橙:多亮? 黄:多亮? ...
傅里叶变换就是那个三棱镜。
4.6 傅里叶变换的两个方向
傅里叶变换有两个方向,非常重要:
正变换:时间 → 频率
"这段声音里有哪些频率?"
逆变换:频率 → 时间
"如果我把这些频率按这个谱子叠加,会得到什么声音?"
正变换是"拆",逆变换是"拼"。
graph LR a信号-->b正变换 b-->c频谱
graph RL c频谱-->b逆变换 b-->a信号
两个方向都重要。 正变换用于"分析",逆变换用于"合成"。
五:离散傅里叶变换(DFT)------计算机的版本
5.1 计算机的困境
傅里叶变换是给"连续信号"用的。
但计算机只认识离散的数字。
text
连续信号(模拟): ~~~~~~~~~~
(每个瞬间都有值)
离散信号(数字): ● ● ● ● ●
(只记录了几个点)
所以,要把傅里叶变换搬进计算机,必须做两件事:
- 时间离散化:只取有限个采样点;
- 频率离散化:只算有限个频率。
这就是 离散傅里叶变换(Discrete Fourier Transform)。
5.2 DFT 的三个"离散"
| 项目 | 连续傅里叶变换 | DFT |
|---|---|---|
| 时间 | 连续 | 离散(N 个点) |
| 频率 | 连续 | 离散(N 个频率) |
| 计算 | 积分 | 求和 |
DFT 就是把"积分"换成"求和"。
积分是"连续地累加",求和是"一个一个加起来"。
计算机只会后者。
5.3 DFT 的画面:\(N\) 个音叉排成一排
想象你面前有 \(N\) 个音叉 ,排成一排,对应 \(N\) 个频率:
text
音叉0 音叉1 音叉2 ... 音叉N-1
│ │ │ │
f0 f1 f2 fN-1
你手里有 \(N\) 个采样点:
text
● ● ● ● ● ● ● ●
x0 x1 x2 x3 x4 x5 x6 x7
DFT 做的事:
- 拿起音叉 \(0\),和 \(N\) 个采样点逐个"比对",加起来;
- 拿起音叉 \(1\),重复;
- ...
- 拿起音叉 \(N - 1\),重复。
每个音叉给出一个结果。\(N\) 个音叉给出 \(N\) 个结果。
这就是 DFT 的全部。
5.4 "比对"到底怎么比?
这是最容易被含糊过去的地方。仔细说。
每个音叉对应一个频率。这个频率有自己的"标准波形":
text
音叉 k 的标准波形:一个会转圈的指针
具体说,音叉 \(k\) 的标准波形是"每走一个采样点,指针转 \(\frac{k}{N}\) 圈"。
text
音叉 0:每步转 0 圈 (原地不动)
音叉 1:每步转 1/N 圈
音叉 2:每步转 2/N 圈
...
音叉 N/2:每步转半圈 (正负交替)
...
比对的方法:
- 信号在第 \(n\) 个点的值,乘以音叉 \(k\) 在第 \(n\) 步的指针位置;
- 把所有 \(n\) 的乘积加起来。
如果信号和这个音叉"合拍",乘积会同向叠加,和很大;
如果不合拍,乘积会正负抵消,和接近 \(0\)。
这和前面"拿音叉去敲"的画面完全一致。
5.5 DFT 的结果怎么读?
DFT 输出 \(N\) 个复数。每个复数包含两个信息:
text
第 k 个结果 = 幅度 + 相位
│ │
│ └── 这个频率的波从哪里开始
│
└────────── 这个频率有多响
第 \(0\) 个结果特别重要:
text
第 0 个结果 = 所有采样点的和 = 直流成分
因为它对应的音叉"原地不动",所以比对就是"全部加起来"。
5.6 DFT 的对称性:实信号只算一半
如果输入是实数(现实信号几乎都是),DFT 有一个漂亮的对称性:
text
第 k 个结果 和 第 N-k 个结果,是"共轭"关系
(幅度相同,相位相反)
意思是:
text
频谱的前一半和后一半,是镜像的
所以实际中经常只算前一半(\(0\) 到 \(\frac{N}{2}\)),省一半工作量。
形象地说: 实信号的频谱像一只蝴蝶,左右对称。你只需要看一边。
5.7 DFT 的致命问题:太慢
DFT 的计算量:
- \(N\) 个采样点;
- \(N\) 个频率;
- 每个频率要做 \(N\) 次乘加。
总共:\(N \times N = N^2\) 次操作。
| N | N² | 直观感受 |
|---|---|---|
| 8 | 64 | 瞬间 |
| 1024 | 约 100 万 | 一瞬间 |
| 100 万 | 1 万亿 | 算到天荒地老 |
\(N\) 稍微大一点,DFT 就算不动了。 这就是 FFT 出场的理由。
六:快速傅里叶变换(FFT)------让 DFT 飞起来
6.1 FFT 不是新变换
FFT 不是一种新的变换。它算出来的结果,和 DFT 一模一样。
FFT 只是计算 DFT 的一种更快的算法。
6.2 FFT 的核心发现:重复劳动
DFT 里,每个频率都要和每个采样点乘一遍。
但仔细看,很多乘法是重复的。
具体说,DFT 用的"指针",有一个重要性质:
text
指针转一圈,回到原地
指针转半圈,方向相反
这意味着:
- 音叉 \(k\) 和音叉 \(k+N\) 的指针位置完全一样;
- 音叉 \(k\) 和音叉 \(k+\frac{N}{2}\) 的指针位置正好相反。
这些重复,可以合并。
6.3 天才的一刀:按奇偶拆
FFT 的核心操作,简单到不可思议: 把采样点按编号的奇偶,分成两队。
text
原始: x0 x1 x2 x3 x4 x5 x6 x7
偶数队:x0 x2 x4 x6
奇数队: x1 x3 x5 x7
然后:
- 偶数队自己算一次 DFT(长度 \(\frac{N}{2}\));
- 奇数队自己算一次 DFT(长度 \(\frac{N}{2}\));
- 把两个结果合并成 \(N\) 个结果。
原来的问题:\(N\) 个点算 \(N\) 个频率。
拆开后:两个 \(\frac{N}{2}\) 点问题,最后合并一下。
这就是分治。
6.4 为什么按奇偶拆能成立?
DFT 里,音叉 \(k\) 的指针"每步转 \(\frac{k}{N}\) 圈"。
现在看偶数位置 \((0, 2, 4, 6)\) 和奇数位置 \((1, 3, 5, 7)\):
text
偶数位置:指针走了 0 步、2 步、4 步、6 步
奇数位置:指针走了 1 步、3 步、5 步、7 步
偶数位置上,指针实际是"每步转 \(\frac{2k}{N}\) 圈"。
这正好是"长度 \(\frac{N}{2}\) 的 DFT"用的指针转速(因为 \(\frac{2k}{N} = \frac{k}{\frac{N}{2}}\)))。
所以,偶数位置的 DFT,就是一个长度 \(\frac{N}{2}\) 的 DFT。
奇数位置同理。
这就是"拆"能成立的数学原因:指针转两步等于小指针转一步。
6.5 合并的秘诀:蝶形
现在把两个小 DFT 的结果合并。
设偶数队算出 \(E\),奇数队算出 \(O\)。
要得到原始 \(N\) 点的结果,需要做:
\上结果 = E + (指针方向 × O)\\\\ \\\\ 下结果 = E - (指针方向 × O) \\
形状像蝴蝶,所以叫蝶形运算。
三个关键点:
- 一个乘法 :只算一次"\(指针方向 \times O\)";
- 两个输出:加一次、减一次;
- 上下互补:指针转半圈时,上下结果互换。
这就是 FFT 省时间的核心:一次乘法,喂出两个结果。
6.6 一层一层往上搭
拆一次不够,要一直拆到单个点:
graph TD a8 点-->b偶数 4 点 b-->d偶偶 2 点 b-->e偶奇 2 点 d-->f1 点 d-->g1 点 e-->h1 点 e-->i1 点 a-->c奇数 4 点 c-->j奇偶 2 点 c-->k奇奇 2 点 j-->l1 点 j-->m1 点 k-->n1 点 k-->o1 点
\(1\) 点的 DFT 就是它自己。 拆到这一步就到底了。
然后从下往上合并:
text
第 1 层:每 2 个点合并
第 2 层:每 4 个点合并
第 3 层:每 8 个点合并
层数 \(=\) \(N\) 连续除以 \(2\) 多少次到 \(1\),即 \(log(N)\)。
6.7 座位重排:位反转
拆分时按奇偶分,最后叶子顺序会乱掉。
为了在程序里"不递归、直接迭代",需要一开始就把输入重排好。
重排规则:把编号写成二进制,然后倒过来读。
text
0 (000) → 000 → 0
1 (001) → 100 → 4
2 (010) → 010 → 2
3 (011) → 110 → 6
4 (100) → 001 → 1
5 (101) → 101 → 5
6 (110) → 011 → 3
7 (111) → 111 → 7
新顺序:
text
0, 4, 2, 6, 1, 5, 3, 7
这就是 FFT 程序开头那几行"交换座位"在干的事。
6.8 完整流程(\(8\) 点为例)
graph TD a输入: x0 x1 x2 x3 x4 x5 x6 x7-->b位反转重排 x0 x4 x2 x6 x1 x5 x3 x7 b-->c第 1 层:相邻两两蝶形 ● ● ● ● ● ● ● ● c-->d第 2 层:每 4 个一组蝶形 ●───────●●───────● d-->e第 3 层:整体蝶形 ●───────────────● e-->f输出: x0 x1 x2 x3 x4 x5 x6 x7
6.9 一个具体例子:全 1 信号
输入:
text
1 1 1 1 1 1 1 1
第 1 层(相邻两两蝶形,指针原地):
text
1+1=2, 1-1=0 → 2 0 2 0 2 0 2 0
第 2 层(每 4 个一组):
text
前半 2 0 和 2 0: 上=4,下=0;另一对 O=0,所以都是 2
得到:4 2 0 2
后半同理:4 2 0 2
合起来:4 2 0 2 4 2 0 2
第 3 层(整体):
text
前半和后半完全一样,所以:
4+4=8,4-4=0,其余同理
得到:8 0 0 0 0 0 0 0
结果:
text
第 0 个 = 8 (直流,所有点加起来)
其余 = 0 (没有其他频率)
完全符合直觉:全 \(1\) 的常数信号,只有直流。
七:四者关系总图
现在把整条路串起来:
graph TD a傅里叶级数 (周期信号) 频率离散 用和式表示--周期 ∞-->b傅里叶变换 (任意信号) 频率连续 用积分表示 b--时间、频率都离散-->cDFT (计算机版本) 时间离散 频率离散 用求和表示 c--用分治加速-->dFFT (DFT 的快算法)结果和 DFT 相同 复杂度 N log N
用一句话串起来:
调和分析是"拆波"的学问;傅里叶级数拆周期信号;傅里叶变换拆任意信号;DFT 是计算机能算的离散版本;FFT 是 DFT 的快速算法。
八:最后一句话
如果整份讲解你只能记住一句话,请记住这句:
傅里叶变换是数学的三棱镜,把复杂信号拆成简单的波;DFT 是给计算机用的离散版;FFT 是让 DFT 从"算不动"变成"秒算"的分治算法。
再简化成三个动作:
graph LR a拆(按奇偶分)-->b转(指针方向) b-->c合(蝶形加减)
这三个动作,就是 FFT 的全部灵魂。
而 FFT,只是调和分析这棵大树上,最实用的一根枝干。
祝你从"萌新"走到"能自己实现 FFT"。
附:
声明:此内容由作者请教 deepseek 生成,deepseek 生成的很难看懂,本人又经过尽半天的加工,如:添加了许多内容,让文章更形象易懂,所有流程图、公式、图片等均为本人费时费力添加。制作不易,请谅解。(如果觉得对你有帮助,就帮忙点个赞吧!)