相位:被所有人扔掉的那一半
质心是平面上的一个点,它有长度也有方向。前面三章只用了长度——那正是所有教材封面上、所有音乐播放器里、所有「频谱图」这个词指的东西。这一章去看方向。看完你大概会觉得,我们集体扔掉的是更重要的那一半。
拿两张 32 × 32 的黑白图:一张画着大写字母 F,一张画着大写字母 T。各做一次二维傅里叶变换,各自得到 1024 个复数。
现在做一件很奇怪的事:把 F 那一套复数的长度(幅度),配上 T 那一套复数的角度(相位),拼成一套新的复数,再逆变换回来,画成一张图。
问:这张图看起来像什么?
相位是什么:那个被推来推去的起点
第 1 章说过,一个匀速旋转要三个数才描述得清:转速、半径、起始角。前两个我们已经用上了——转速是横轴的位置,半径是谱线的高度。起始角就是相位,它回答的是:时钟归零的那一刻,这个旋转站在哪儿。
用影子来说更直白:两条 3 Hz 的正弦,一条从 0 开始往上走,一条从最高点开始往下走。它们的频率一样、振幅一样,唯一的区别是在时间轴上被推了不同的距离。这个「推了多远」,就是相位。
把这件事量一下。取一个高斯形状的小鼓包,把它整体往右挪 5 个采样,再比较挪之前和挪之后的谱:
整体平移 5 个采样点之后: 幅度谱 |X[k]| 最大变化 4.4 × 10⁻¹⁶ ← 一点没变 相位 ∠X[1] 变化 −1.963495 理论值 −2π·5/16 −1.963495 ← 严丝合缝
这就是傅里叶最漂亮的性质之一,叫时移定理:
把信号整体平移,幅度谱一点都不变,全部变化都记在相位里。平移得越远,每根谱线的相位转得越多;而且转的量和频率成正比(第 k 根转 −2πkm/N)。
反过来说:幅度谱不知道任何东西在哪里。一段录音和它整体延迟三秒的版本,幅度谱完全相同;一张图和它平移过的版本,幅度谱完全相同。「在哪里」这件事,全部编码在相位里。
这已经足以让人不安了。因为对一张图来说,「东西在哪里」几乎就是全部内容——一张脸就是「眼睛在这儿、鼻子在那儿」。下面这个实验把这件事推到极限。
招牌实验:换脸
两张 32 × 32 的图。左边是 F,右边是 T:
原图 A(F) 原图 B(T) ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ ......###################....... ....########################.... ......###################....... ....########################.... ......###################....... ....########################.... ......###################....... ....########################.... ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......###############........... ..............####.............. ......###############........... ..............####.............. ......###############........... ..............####.............. ......###############........... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................
各做一次二维傅里叶变换(做法就是先对每一行做一次一维变换,再对每一列做一次)。然后交叉拼装:
- 左边:拿 A 的幅度(每个复数的长度),配 B 的相位(每个复数的角度)。
- 右边:拿 B 的幅度,配 A 的相位。
各自逆变换回来。为了在字符里看清楚,两张重建图都按「和它要比对的原图相同的填充率」取阈值做了二值化(F 的填充率 19.5%,T 的 17.2%)——这一步只是显示手段,不改变下面那些相关系数:
|A| 的幅度 + ∠B 的相位 |B| 的幅度 + ∠A 的相位 #...........................#... ................................ ................................ ................................ ................................ ................................ ................................ ................................ .....#######################.... ......###################....... .....#######################.... ......###################....... .....#######################.... .###..#################.#....#.. .....#.#####################.... .###..#################.#....#.. ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... .............######............. ......#############............. .............#####.............. ......#########.###............. ..............####.............. ......###############........... ..............####.............. ......###############........... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... ..............####.............. ......####...................... .................#.............. ................................ ................................ ................................ ................................ ................................ ................................ ................................
左边那张,幅度全部来自 F,长得是个 T。右边那张,幅度全部来自 T,长得是个 F。
相位赢了,而且赢得干干净净。把数摆出来:
| 重建图 | 与 F 的相关系数 | 与 T 的相关系数 | 二值化后逐格一致率 |
|---|---|---|---|
| |F| 的幅度 + ∠T 的相位 | 0.4892 | 0.8789 | 与 T 一致 98.93%(与 F 只有 81.54%) |
| |T| 的幅度 + ∠F 的相位 | 0.8789 | 0.3548 | 与 F 一致 98.54%(与 T 只有 80.57%) |
顺带一个漂亮的巧合——其实不是巧合:表里那两个 0.8789 不是「差不多」,是严格相等(本机实算差 2.2 × 10⁻¹⁶)。原因可以在纸上推出来:两个内积都等于 Σ|Ak||Bk|,而归一化用的两个长度也刚好互换(帕塞瓦尔定理保证「换了相位不改变总能量」)。这条恒等式说明,上面那不是一次运气好的实验,是一个结构性的事实。
为什么是相位赢
因为一张图的内容,说到底是边在哪里。而一条边,是很多个不同频率的分量在那个位置上恰好对齐的结果——它们同时到达波峰,叠出一道陡坎。
「在那个位置上恰好对齐」是一句关于相位的话,跟每个分量有多强没什么关系。你可以把所有分量的强度改得面目全非(这正是「换成另一张图的幅度」做的事),只要它们还在原来的位置对齐,那道坎就还在。
反过来,把相位全扔掉会怎样?做一次极端实验:保留 F 的全部幅度,把所有相位设成 0,再变回来:
相位全部置零,逆变换: 最大值落在 (0, 0) ← 图像的左上角那一个像素 与原图 F 的相关系数 −0.156 ← 一点也不像
所有分量都在原点对齐,于是能量全部堆到了那一个点上,剩下的地方基本是零。幅度谱知道「有多少东西」,完全不知道「东西在哪里」;而图像几乎全是关于「在哪里」的。
频谱这个词在日常使用里几乎总是指幅度谱(有时是它的平方,叫功率谱)。这本书里凡是说「谱」而不加限定,指的是完整的复数结果——幅度加相位,一个不少。
这个用词习惯本身就是这一章要讲的事:整个行业默认「谱」等于「幅度」,因为幅度好画(一张实数曲线),相位难画(一个绕来绕去、还带 2π 跳变的东西)。好画不等于重要。
还有一个坑:能量为零的那些格子上,「相位」是没有意义的。本机数了一下,T 的那 1024 个格子里有 183 个能量严格为零(F 有 96 个)——在那些位置上取 atan2(0, 0),拿到的是各家浮点实现的偶然结果。上面这个实验里如果不先把这些格子挑出来,换一个 FFT 库跑,相关系数的第四位小数就会变。凡是要用相位的地方,先检查那个格子上有没有能量。
这个实验用 numpy 是十行,而且换成你自己的照片会更震撼:
import numpy as np
S = 32
F = np.zeros((S, S)); T = np.zeros((S, S))
F[4:8, 6:25] = 1; F[4:28, 6:10] = 1; F[14:18, 6:21] = 1 # 一个 F
T[4:8, 4:28] = 1; T[4:28, 14:18] = 1 # 一个 T
FA, FB = np.fft.fft2(F), np.fft.fft2(T)
# 能量为零的格子上相位没有意义,先挑出来
def phase(Z):
return np.where(np.abs(Z) < 1e-9 * np.abs(Z).max(), 0.0, np.angle(Z))
ab = np.real(np.fft.ifft2(np.abs(FA) * np.exp(1j * phase(FB)))) # |F| 配 ∠T
def corr(a, b):
a = a.ravel() - a.mean(); b = b.ravel() - b.mean()
return a @ b / np.sqrt((a @ a) * (b @ b))
print('像 F 吗 %.4f 像 T 吗 %.4f' % (corr(ab, F), corr(ab, T)))
# 像 F 吗 0.4892 像 T 吗 0.8789
for row in (ab >= np.sort(ab.ravel())[int(round((1 - T.mean()) * (S*S - 1)))]):
print(''.join('#' if v else '.' for v in row))
换成真实照片(matplotlib.pyplot.imread 读一张灰度图)效果更好:拿你自己的自拍配上一只猫的相位,出来的是猫。这个实验最早出自 Oppenheim 与 Lim 1981 年那篇《The Importance of Phase in Signals》,四十多年了还是最有说服力的一个。
python3 -c "import numpy as np;a=np.random.rand(8,8);A=np.fft.fft2(a);print(np.abs(np.fft.ifft2(np.abs(A))).argmax())"
在线跑:需要 numpy,用 Google Colab 或本机 pip install numpy。纯 JS 版本可以用第 2 章那段绕圈代码套两层循环。
- 晶体学的「相位问题」。这是这一章在现实里最贵的一次出场。X 射线打到晶体上,底片记录的是强度——也就是幅度的平方。相位在测量的那一刻就永久丢失了。而我们真正想要的电子密度,恰恰主要藏在相位里。整个结构生物学花了半个多世纪去发明各种绕开它的办法(同晶置换、反常散射、分子置换),2024 年前后 AlphaFold 一类工具能直接猜出结构,某种意义上也是在替这个丢失的相位补课。
- 音频的变速不变调。把一段录音放慢一倍而不让声音变低沉,标准做法叫相位声码器:把每一小段的幅度谱原样搬过去,把相位按新的时间轴重新推算一遍。做得不好就会出现那种「金属味」「水下感」——那正是相位没接上的声音。
- MP3 反而敢扔相位。因为人耳对单个频率成分的绝对相位极不敏感(把一个和弦里每个音的相位随机打乱,你多半听不出来)。但对相位在时间上的连续性非常敏感——所以音频编码器省相位精度可以,接不上就不行。「相位重不重要」在图像里和在听觉里,答案正好相反。
- 相控阵雷达和 5G 波束赋形。一排天线发同一个信号,只调各自的相位,就能让波束指向任意方向——不需要任何机械转动。整个技术的名字里就写着相位。
「做特征提取的时候取幅度谱就行了,相位是噪声,反正它对平移敏感。」
前半句是行业惯例,后半句是这个惯例的真实理由:相位对平移敏感,扔掉它换来了平移不变性。这在「判断这段音频里有没有人说话」这类任务上是笔划算的买卖。
但代价要说清楚:你同时把「东西在哪里」和「东西之间的相对位置」一起扔了。上面那个实验就是账单——扔掉相位之后,F 和 T 剩下的那点差别,已经不足以决定重建出来的是哪一个字母了。
这也解释了一个常见现象:早期用幅度谱做纹理合成的方法,能造出「材质对了但没有物体」的图;反过来,只保留相位、把幅度全设成 1,出来的图轮廓清清楚楚,只是对比度奇怪。判据是:你的任务关心「有多少」还是关心「在哪里」——关心在哪里,就一个字节的相位都不能扔。
正确答案是 B:像 T。二值化后 98.93% 的格子和 T 对得上,而和 F 只对上 81.54%。
A 「幅度是主要成分」——这个直觉来自「幅度大 = 重要」这种朴素的量级思维,而且被所有画成幅度谱的教材封面加固了一遍。真实情况是:幅度描述的是「这张图整体的粗糙程度」(有多少高频、有多少低频),相位描述的是「具体长什么样」。粗糙程度相同的图有无穷多张。 C 「两者叠在一起」——这个猜测背后是「傅里叶变换是线性的,所以拼起来的东西应该是两者的线性组合」。可惜这个拼装动作本身不是线性的:取模长、取幅角、再重新组装,中间两步都不是线性运算。所以结果不是任何意义上的「平均」。 D 「不对应任何真实图像」——严格说,拼出来的东西确实不保证是一张「合法」的图(逆变换回来可能带虚部、可能有负值,实际上这里取了实部)。但它离「噪声」远得很:与 T 的相关系数 0.8789。幅度可以被换成一张完全不同的图的幅度,而内容还认得出来——这正是这个实验吓人的地方。这个对照是整本书用得最多的一条。到了第 13 章你会看到它的完整版本:时域里的「平移并叠加」(也就是卷积),在频域里就是「逐点相乘」——平移变成乘一个单位复数,叠加变成相加,合起来就是相乘。第 15 章的滤波器、第 16 章的匹配滤波、第 17 章的 FFT,全部是这一条的直接后果。
这一章的一句话
幅度谱告诉你有多少东西,相位谱告诉你东西在哪里;而对绝大多数你真正关心的对象来说,「在哪里」就是全部内容——换脸实验里,相位以 98.93% 对 81.54% 的比分赢下了整张图。
卷 I 到此结束。你现在手里有一台完整的机器:把信号缠到圆上,读出每个转速的长度和方向。
问题是这台机器有一个假设:你能连续地、无限久地看着那个信号。真机器不能——它只能一眼一眼地看,而且只能看有限长的一段。下一卷就是这两条限制的账单,从最反直觉的那一条开始:只要每秒看的次数超过某个门槛,你就一点信息都不会丢。不是「丢得很少」,是一点都不丢——本机实测重建误差 3.86 × 10⁻¹³。