十四个开关 · 第 01 份 · Cooley & Tukey 1965(高斯 1805 年的手稿里已有)

傅里叶开关

你手机收到的每一个 5G 符号,都是 2048 个子载波叠在一起的一团噪声,接收端要靠一次傅里叶变换把它们拆开——而且必须在 71.4 微秒内做完,因为下一个符号已经在路上了。下面这个开关把 FFT 换成按定义写的 DFT。

总闸

收到的信号 · 时域

2048 个子载波叠加的结果 —— 肉眼看不出任何信息

解出来的星座图

每个点是一个子载波上的 16-QAM 符号;DFT 是逐个频点算的,所以它能给部分答案
虚拟时钟(按芯片速率折算,不是浏览器秒表)0.0 μs
FFT
DFT(按定义,旋转因子已预先算好)

两把尺子 · 它们不一致

正在浏览器里真跑…
次数比 = 2n / log₂n(可算、精确) 秒表比(这台机器上真跑出来的) 1 倍线:以下就是 FFT 没赢

关掉的是哪一行

fft(x) 换成按定义写的双重和 dft(x)不是稻草人:这份 DFT 的旋转因子是预先算好放进表里的,内层只有乘加,和 FFT 一样公平。

两条路算出来的是同一个答案——n = 256 上最大差 8×10⁻¹⁴,纯粹是浮点舍入。DFT 没有算错,它只是慢。

为什么是「赶不上」而不是「慢一点」

5G 的一个 OFDM 符号是 1/15 kHz = 66.7 μs,加上循环前缀约 71.4 μs,每秒 14006 个。变换做不完,下一个符号已经来了——这不是等一会儿的事,是数据直接丢掉。

2048 点:FFT 要 11 264 次复乘,DFT 要 4 194 304 次。要卡进 71.4 μs,FFT 只需一颗 0.16 G 复乘/秒的芯片,DFT 需要 58.7 G。⇒ OFDM 这种调制方式本身就建立在「FFT 很便宜」这个前提上。

⚠ 我预期错了两处

① 我原以为「二维图像上比值是 4096 倍」——两层都错。拿不可分离的 N⁴ 双重和比是 8192 倍,可那种实现没人会写;两边都用可分离算法(先按行再按列)才是公平的,256×256 上是 64 倍

② 我原以为「小 n 时 DFT 更快,交叉点在 16~64」——没有交叉点,FFT 从 n = 4 就赢。真实的情况见右边那张卡。

它什么时候不赢

看那张双尺子图:秒表比一直低于次数比。n = 2048 该赢 372 倍,实测只赢 109 倍;n = 4 该赢 4 倍,实测只赢 1.22 倍——位反转和循环开销把 FFT 的优势吃掉了大半。这正是 FFTW 对小 n 用硬编码直接算法、而不是递归的原因。

另外基-2 的 Cooley–Tukey 要求 n 是 2 的幂。n 是质数时它压根不适用,得换 Rader 或 Bluestein。⚠ 还有一条自己踩的:我第一版的 DFT 内层在调 Math.cos,把秒表比夸大成 1194 倍——对照版本不干净,量出来的就是假的。