卷 III · 付账CH 12深度 12/20

让分辨率随频率变

上一章的最后一句抱怨是:窗长是个全局参数,整张频谱图上所有像素形状相同。这一章拆掉它,做法自然到有点朴素——低频用长窗,高频用短窗。这一步会把我们带出傅里叶,也会带来这本书里唯一一次「傅里叶输了」的对账单,以及紧接着的一次「它又赢回来了」。

26 个 vs 1024 个诚实的反例稀疏是一种关系

▷ 先猜一下

一个 1024 点的信号,长这样:分段常数,一共只有三处跳变(在第 173、604、811 个点,故意不落在 2 的幂上)。除了这三处,它一动不动。

问:要精确表示这个信号(不是近似),两种方法各需要多少个非零系数?

A 傅里叶 4 个 / Haar 小波 1024 个 B 傅里叶 1024 个 / Haar 小波 26 个 C 两者都是 1024 个。任何完备的基都要 N 个系数才能精确表示 N 个点 D 傅里叶 512 个 / Haar 小波 512 个

问题出在哪:正弦太长了

傅里叶的基函数是无限长的正弦。它在整条时间轴上一直振荡,没有开始也没有结束。

这个性质让它极擅长描述「一直在那儿」的东西(一个稳定的音、一个周期性的振动),也让它极不擅长描述「就在这一刻发生了一下」的东西。要用一堆无限长的东西拼出一个局部的突变,唯一的办法是让它们在别处互相抵消——而「互相抵消」意味着你需要很多项,而且每一项都很大。

这就是第 15 章那个吉布斯现象的根源,也是这一章的出发点。

换一种积木:短的、可以伸缩的

小波的想法只有两条:

  1. 基函数要短——它只在一小段时间里非零,别处严格是零。这样它天然就知道「什么时候」。
  2. 用同一个形状的伸缩和平移,生成一整族——把它拉长一倍得到一个管更低频的,压短一半得到一个管更高频的。

最简单的那个叫 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 的误差傅里叶的误差谁赢
831.32%28.44%傅里叶
1612.57%19.59%Haar
320.00%14.30%Haar(已经精确)
640.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 个系数」的坏基,也很容易构造:把标准基随便转一个无理角度就行。好基的价值全在于「对我要处理的这类数据,它稀疏」。
⟳ 换个域看
时域里,那个信号是 1024 个数,其中 1021 个和它前一个相同。看起来极其冗余——凭直觉,它应该很容易压缩。 傅里叶域里,它是 1024 个非零系数,一个都省不掉。换错了域,冗余的东西会变得不冗余。

这一章是整本书里唯一一次「换个域看」让事情变糟的例子,而它恰恰把这个动作的本质讲清楚了:换域不是万能钥匙,是一次赌博——赌你的数据在新坐标系里比在老坐标系里更整齐。赌对了(一段音乐、一张照片、一次卷积),收益巨大;赌错了(一串阶跃、一次敲击),你会拿到一份比原来还乱的表示。

而下一卷会给出一个永远不会赌输的理由:无论数据长什么样,频域里的卷积都是乘法。那不是一个关于数据的赌注,是一条关于运算的定理。

这一章的一句话

小波把「像素形状」这个旋钮从全局改成按频率分层,代价是丢掉了傅里叶最值钱的那条性质;而更重要的一课是:稀疏从来不是数据或基单方面的属性,是两者配不配。

卷 III 到此结束,三章讲的都是账单:窗、不确定性、多分辨率。到目前为止,频域一直只是「另一种看法」——一种要付钱的看法。

下一卷回答那个一直没问的问题:那我们为什么还要跑这一趟?答案是一条定理,而它的分量足以让前面所有的账单都变得值得。开场先从一个看起来和频率毫无关系的运算讲起——模糊一张照片、给一段人声加混响、算两个骰子的和、把两个多项式乘起来,这四件事是同一个运算。