让分辨率随频率变
上一章的最后一句抱怨是:窗长是个全局参数,整张频谱图上所有像素形状相同。这一章拆掉它,做法自然到有点朴素——低频用长窗,高频用短窗。这一步会把我们带出傅里叶,也会带来这本书里唯一一次「傅里叶输了」的对账单,以及紧接着的一次「它又赢回来了」。
一个 1024 点的信号,长这样:分段常数,一共只有三处跳变(在第 173、604、811 个点,故意不落在 2 的幂上)。除了这三处,它一动不动。
问:要精确表示这个信号(不是近似),两种方法各需要多少个非零系数?
问题出在哪:正弦太长了
傅里叶的基函数是无限长的正弦。它在整条时间轴上一直振荡,没有开始也没有结束。
这个性质让它极擅长描述「一直在那儿」的东西(一个稳定的音、一个周期性的振动),也让它极不擅长描述「就在这一刻发生了一下」的东西。要用一堆无限长的东西拼出一个局部的突变,唯一的办法是让它们在别处互相抵消——而「互相抵消」意味着你需要很多项,而且每一项都很大。
这就是第 15 章那个吉布斯现象的根源,也是这一章的出发点。
换一种积木:短的、可以伸缩的
小波的想法只有两条:
- 基函数要短——它只在一小段时间里非零,别处严格是零。这样它天然就知道「什么时候」。
- 用同一个形状的伸缩和平移,生成一整族——把它拉长一倍得到一个管更低频的,压短一半得到一个管更高频的。
最简单的那个叫 Haar 小波(1909 年,比傅里叶晚一百年,比「小波」这个词早七十年)。它的形状简单到有点可笑:
Haar 的一步:把相邻两个数换成「平均」和「差」
[a, b] → ( (a+b)/√2 , (a−b)/√2 )
└───┬───┘ └───┬───┘
平均(粗) 细节(细)
然后对「平均」那一半再做一遍,再做一遍……做 log₂N 次。
结果:1 个总平均 + 1 个最粗的细节 + 2 个次粗的 + 4 个 + 8 个 + …
一共还是 N 个数(可逆,什么都没丢)。
关键在于每一层的「细节」管的是不同的尺度:最细的那一层每个系数只看 2 个采样点(时间定位极准,频率范围极宽),最粗的那一层每个系数看 512 个点(频率定得细,时间上很糊)。
小波不是「更好的傅里叶」,是把上一章那个「像素形状」的旋钮从全局改成了按频率分层。
STFT: 所有频率共用一个窗长
像素全都一样:宽 T,高 1/T
小波: 低频用长窗,高频用短窗
低频处像素高窄,高频处像素宽扁
(每个像素的面积仍然守恒 —— 第 10 章那条不等式一步都没退)
注意最后那句:不确定性原理没有被绕过,一点都没有。小波只是把同样面积的像素重新排了一下版,让它们的形状和「真实数据的样子」更配。
对账:那个只有三处跳变的信号
1024 点,分段常数,三处跳变
精确表示需要的非零系数:
Haar 小波 ⟨26 个⟩
傅里叶 1024 个 ← 一个都省不掉
为什么是 26 而不是 3?因为跳变的位置没有落在 2 的幂上,所以每一处跳变会在若干层上各留下一两个系数。一处跳变的代价是 O(log N) 个系数,而不是 1 个——但 26 和 1024 之间还是隔着四十倍。
再看近似的情况:只保留最大的 k 个系数,重建之后误差多少(相对 L2):
| 保留系数个数 | Haar 的误差 | 傅里叶的误差 | 谁赢 |
|---|---|---|---|
| 8 | 31.32% | 28.44% | 傅里叶 |
| 16 | 12.57% | 19.59% | Haar |
| 32 | 0.00% | 14.30% | Haar(已经精确) |
| 64 | 0.00% | 10.31% | Haar |
两件事值得注意。
第一,k = 8 那一行傅里叶赢了。这不是笔误。系数很少的时候,Haar 只能拿到几个最粗的尺度,重建出来是个阶梯状的粗坯;傅里叶的低频分量则给出一条光滑的、平均意义上更接近的曲线。小波的优势要到 k 足够大、能触及跳变所在的那些细尺度时才显现。
第二,傅里叶那一列降得非常慢。从 8 个到 64 个,系数翻了八倍,误差只从 28.44% 掉到 10.31%。原因是跳变的傅里叶系数按 1/k 衰减——这是所有「用光滑东西拼尖角」的方法都逃不掉的速度。
把牌翻过来:傅里叶赢回一局
换一个信号:一个 1024 点的纯余弦(8 圈)。
1024 点,纯余弦
精确表示需要的非零系数:
傅里叶 2 个 ← +8 和 −8 那两根
Haar 小波 ⟨1016 个⟩ ← 几乎全满
比分完全颠倒,而且颠倒得更彻底。用一堆短小的方块去拼一条光滑的正弦,每一层每一处都得留一点点残差。
没有哪个基天然更好。「稀疏」不是数据的属性,也不是基的属性,是两者之间的关系。
- 数据里是持续的振荡 → 傅里叶稀疏(2 个 vs 1016 个)
- 数据里是局部的突变 → 小波稀疏(26 个 vs 1024 个)
这句话是整卷 III 最值得带走的一条,而且它一路通向今天:压缩感知的整套理论建立在「信号在某个基下稀疏」这个假设上;字典学习和稀疏编码干脆放弃手工挑基,改成从数据里学一组基出来;而神经网络第一层学到的那些滤波器,长得非常像小波——那是它自己发现「局部的、多尺度的」这组基对自然图像最省。
「小波比傅里叶先进」是 1990 年代小波热潮留下的一句口号,它误导了很多人。准确的说法是:
- 小波是一族变换(Haar、Daubechies、Symlet、Coiflet……几十种),不是一个;选哪一个本身就是门手艺。
- 小波没有绕过不确定性原理,只是重新分配了像素形状。
- 小波在「有局部突变的信号」上稀疏,在「稳定振荡的信号」上比傅里叶差得多。
- 而且小波没有卷积定理——这是下一卷会讲的、频域最值钱的那条性质。小波域里的乘法不对应任何有用的时域运算。
最后一条是小波没能取代傅里叶的根本原因。傅里叶不只是一种表示,它还是一台把卷积变成乘法的机器;小波只是一种表示。
Haar 变换十行,不需要任何库:
import math
def haar(x):
a, n, out = list(x), len(x), list(x)
while n > 1:
t = [0.0]*n
for i in range(n//2):
t[i] = (a[2*i] + a[2*i+1]) / math.sqrt(2)
t[n//2+i] = (a[2*i] - a[2*i+1]) / math.sqrt(2)
out[:n] = t
a, n = t[:n//2], n//2
return out
N = 1024
step = [0.2 if n < 173 else 1.0 if n < 604 else -0.6 if n < 811 else 0.35
for n in range(N)]
h = haar(step)
print('Haar 非零系数:', sum(1 for v in h if abs(v) > 1e-12)) # 26
对照傅里叶(需要 numpy):
import numpy as np
print('傅里叶非零系数:', int((np.abs(np.fft.fft(step)) > 1e-9).sum())) # 1024
sine = np.cos(2*np.pi*8*np.arange(N)/N)
print('纯正弦:Haar', sum(1 for v in haar(sine) if abs(v) > 1e-9),
' 傅里叶', int((np.abs(np.fft.fft(sine)) > 1e-9).sum())) # 1016 2
把 step 的跳变位置改成 512(正好是 2 的幂),Haar 的非零系数会掉到个位数——这一步能让你直观理解那个 O(log N) 是怎么来的。
python3 -c "print('把上面两段拼起来存成 haar.py')"
在线跑:第一段纯标准库,python.org/shell 就够。要用正经的小波库:pip install PyWavelets,然后 pywt.wavedec(x, 'db4')。
- JPEG 2000。它用小波取代了 JPEG 的分块余弦变换,好处是没有块效应(低码率下 JPEG 那种方格子),而且天然支持渐进传输(先传粗尺度,图片由糊变清)。它在技术上确实更好,却几乎没有普及——这是「更好的技术不一定赢」的一个标准案例:JPEG 已经在每一个芯片、每一个浏览器里了,而 JPEG 2000 的专利状况在早期又不够清晰。它今天主要活在数字电影(DCP)和医学影像里。
- FBI 的指纹库。1990 年代 FBI 要把两亿多份指纹卡数字化,用 JPEG 会在纹线上产生块效应,直接影响比对。他们和洛斯阿拉莫斯合作定了一套 WSQ 标准(小波标量量化),压缩比 15:1 还能保住纹线细节。这是小波第一次大规模落地。
- 小波去噪。做法极简单:做小波变换,把绝对值小于某个阈值的系数全部置零,再变回来。因为「信号稀疏、噪声不稀疏」,小系数里主要是噪声。这个方法(Donoho 和 Johnstone 的软阈值)到今天仍然是很多领域的默认基线。
- LIGO 的引力波图。2015 年那张著名的「啁啾」时频图用的是一种小波变换(Q 变换),正是因为引力波信号的频率在最后 0.2 秒里从 35 Hz 飙到 250 Hz——低频段需要长窗,高频段需要短窗,用固定窗长的 STFT 画不好。
「小波是傅里叶的升级版,能同时看清时间和频率,绕过了不确定性原理。」
一点都没绕过。小波把同样面积的像素重新排了个版:低频处高窄,高频处宽扁。总面积一点没变,第 10 章那条不等式在每一个尺度上都严格成立。
「同时看清」这个说法之所以流行,是因为在真实的自然信号上它经常显得如此——自然界里高频事件通常是短促的(敲击、边缘、爆破音),低频事件通常是持久的(背景嗡鸣、大块颜色)。小波的形状恰好和这个统计规律相配,所以看起来「两全其美」。换一个不符合这个规律的信号(比如一个持续很久的高频纯音),小波立刻变成更差的选择——上面那个 1016 vs 2 就是账单。
判据是:问「我的信号里,高频成分是短促的还是持久的」。短促的用小波,持久的用傅里叶。都有的话,这两个工具你都得留着。
正确答案是 B:傅里叶 1024 个,Haar 小波 26 个。
A 「傅里叶 4 个」——大概是想着「四段常数,四个系数」。可惜傅里叶的基是无限长的正弦,用它们拼出一个跳变,需要所有频率参与,而且系数只按 1/k 衰减。这也是为什么方波的傅里叶级数是那个著名的无穷级数,而不是有限项。 C 「任何完备的基都要 N 个系数」——完备的基能表示任何信号,但表示某个特定信号时用到多少个非零系数,完全取决于这个信号和这组基配不配。26 和 1024 的差距就是这个意思。这个直觉的纠正是整章的重点:完备性是基的属性,稀疏性是「基 × 数据」的属性。 D 「各 512 个」——没有任何理由让它是一半。顺便说,如果真要挑一个「无论什么信号都要 N 个系数」的坏基,也很容易构造:把标准基随便转一个无理角度就行。好基的价值全在于「对我要处理的这类数据,它稀疏」。这一章是整本书里唯一一次「换个域看」让事情变糟的例子,而它恰恰把这个动作的本质讲清楚了:换域不是万能钥匙,是一次赌博——赌你的数据在新坐标系里比在老坐标系里更整齐。赌对了(一段音乐、一张照片、一次卷积),收益巨大;赌错了(一串阶跃、一次敲击),你会拿到一份比原来还乱的表示。
而下一卷会给出一个永远不会赌输的理由:无论数据长什么样,频域里的卷积都是乘法。那不是一个关于数据的赌注,是一条关于运算的定理。
这一章的一句话
小波把「像素形状」这个旋钮从全局改成按频率分层,代价是丢掉了傅里叶最值钱的那条性质;而更重要的一课是:稀疏从来不是数据或基单方面的属性,是两者配不配。
卷 III 到此结束,三章讲的都是账单:窗、不确定性、多分辨率。到目前为止,频域一直只是「另一种看法」——一种要付钱的看法。
下一卷回答那个一直没问的问题:那我们为什么还要跑这一趟?答案是一条定理,而它的分量足以让前面所有的账单都变得值得。开场先从一个看起来和频率毫无关系的运算讲起——模糊一张照片、给一段人声加混响、算两个骰子的和、把两个多项式乘起来,这四件事是同一个运算。