你不是删掉频率,你是乘一条曲线
拿到卷积定理之后,「滤波」这件事的面貌整个变了。它不再是「把不想要的频率删掉」这种粗暴的动作,而是拿频谱去乘一条你自己画的曲线。这个视角立刻带来两个不太愉快的结论,其中一个会让你明白为什么完美的滤波器在物理上不可能存在。
要做一个理想低通滤波器:截止频率以下原样通过(增益 1),以上全部干掉(增益 0)。做法是把它的理想冲激响应(一条 sinc 曲线)截成 2M+1 个抽头。
M = 10(21 个抽头)时,实测通带里的最大增益是 1.091164——本该是 1.0,翘起了 9.1164%。
问:把 M 加到 200(401 个抽头,二十倍的计算量),这个翘起变成多少?
换一个定义:滤波是乘法
上一章的定理:时域卷积 = 频域相乘。倒过来读:
一个滤波器就是一条曲线 H(f),它对每一个频率说「你留下多少」。滤波这个动作,就是把信号的频谱逐点乘上这条曲线。
输出的谱[k] = 输入的谱[k] × H[k] H[k] = 1 → 这个频率原样通过 H[k] = 0 → 这个频率被清零 H[k] = 0.5 → 这个频率减半 H[k] = 复数 → 幅度和**相位**都改(相位那一半就是延迟)
而按上一章的定理,这件事在时域里等价于「和某个核做卷积」——那个核就是 H 的逆变换,叫冲激响应。
设计在频域,执行在时域。这是整个滤波器设计学科的工作方式。
理想低通:算一算它长什么样
先在频域里把最想要的那条曲线画出来:一个矩形。通带里是 1,阻带里是 0,中间是一条垂直的墙。
然后逆变换,看看时域里要做什么动作:
H(f) = 矩形(截止 fc)
逆变换
↓
sin(2π fc n)
h[n] = ─────────────── ← 一条 sinc 曲线
π n
三个要命的性质:
1. 它**无限长**(尾巴按 1/n 衰减,永远不到零)
2. 它在 **n < 0 处不为零** —— 也就是要用到**未来**的样本
3. 它衰减得**极慢** —— 截到 401 个抽头,25.0% 的能量还在 n<0 那一侧
第二条是致命的。一个理想的低通滤波器,要算出此刻的输出,需要知道信号未来的值。它不是「难做」,是违反因果性——在实时系统里物理上不可能。
这不是工程上的将就,是第 10 章那条不等式的直接后果:频域上有限(严格带限),时域上就必然无限长。你要一堵垂直的墙,就得付出无限长的时间。
离线处理里可以作弊:整段数据都在手上,「未来」是已知的,于是可以把整条 sinc 平移过来用(代价是一个固定的延迟)。所以「零相位滤波」只存在于离线场合——scipy.signal.filtfilt 就是干这个的,它正着滤一遍再倒着滤一遍。实时系统里没有这个选项。
吉布斯:那个不肯走的 8.9490%
既然无限长做不到,那就截断。截成 2M+1 个抽头,看看频响长什么样:
理想低通(截止 0.25 fs),把 sinc 截成有限抽头:
抽头数 通带最大增益 超调
──────────────────────────────────────
21 1.091164 9.1164%
101 1.089545 8.9545%
401 1.089493 ⟨8.9493%⟩
──────────────────────────────────────
理论极限(闭式): ⟨8.9490%⟩
抽头翻了 20 倍,超调只从 9.1164% 掉到 8.9493%。它不收敛到 0。
这是吉布斯现象,1898 年 Michelson 用他的谐波分析仪画方波时发现的(他一开始以为是机器坏了,写信问 Gibbs;Gibbs 回信解释了这是数学本身的性质)。
为什么加抽头不管用?因为随着 M 增大,那个翘起变得越来越窄,但高度不变——它像一根钉子一样贴着跳变处,越来越细,永远那么高。用数学的话说,部分和逐点收敛到理想曲线,但不一致收敛;用工程的话说:误差的能量确实趋于零,但误差的峰值不趋于零。
那个 8.9490% 有个闭式,本机数值验过:
超调 = ( 2·Si(π)/π − 1 ) / 2 = 8.9490% 其中 Si 是正弦积分。这个数和截止频率无关、和 M 无关、 和你要逼近的是方波还是别的跳变都无关。 **任何用有限个正弦去拼一个跳变的场合,它都在。**
解药还是第 9 章那张表
吉布斯的成因和第 8 章的泄漏一模一样:你在时域里做了一次突然的截断。那解药自然也一样——加窗。
101 个抽头(M = 50),两种截法:
通带超调 过渡带宽度 阻带抑制
───────────────────────────────────────────────────────────
直接截断(矩形窗) 8.9545% 0.0092 fs −35.3 dB
乘一个汉明窗 0.1946% 0.0184 fs −58.7 dB
───────────────────────────────────────────────────────────
超调降到 1/46,阻带好了 23 dB,代价是过渡带宽了一倍。
这张表和第 9 章那张是同一张表,只是换了个说法:那里叫「主瓣宽度 vs 旁瓣高度」,这里叫「过渡带宽度 vs 阻带抑制」。频域里没有免费的形状,这是这本书第三次说这句话。
相位那一半:为什么均线总是「慢半拍」
H(f) 是复数,前面只谈了它的长度。它的角度决定每个频率被延迟多久。
第 4 章说过,延迟 m 个样本对应相位 −2πkm/N,也就是相位正比于频率。反过来:
- 相位随频率线性变化(线性相位)→ 所有频率延迟相同的时间 → 波形不变形,只是整体晚到。
- 相位不是线性的 → 不同频率延迟不同 → 波形被拉扯变形(叫色散)。
对称的 FIR 滤波器(抽头左右对称)天然是线性相位的,这是它最大的卖点。而股票的移动平均线正是一个对称核被只用左半边(因为不能用未来)的结果——所以它有一个固定的延迟,大约是窗长的一半。「均线滞后」不是缺陷也不是调参问题,是因果性的价钱。各种「零滞后均线」的做法,本质上都是在用外推去猜未来。
上面讲的全是 FIR(有限冲激响应)滤波器:输出只由有限个过去的输入决定,就是一次卷积。
另一个大家族是 IIR(无限冲激响应):输出还依赖过去的输出(有反馈)。一行代码就能写出一个:
y[n] = 0.9·y[n−1] + 0.1·x[n] ← 一阶低通,就这一行
IIR 的优势是极便宜——上面那一行的效果,用 FIR 要几十个抽头。代价有三个:相位一定不是线性的(波形会变形)、有反馈就可能不稳定(极点跑到单位圆外就发散)、而且数值误差会在反馈里累积。
选择标准通常是:音频、图像这类在乎波形的场合用 FIR;控制、传感器这类只在乎响应速度和算力的场合用 IIR。你手机里的陀螺仪滤波几乎全是 IIR,你耳机里的均衡器多半是 FIR。(IIR 的反馈稳定性是另一本书的地盘——书架上的《过冲》讲的就是那件事。)
亲手把吉布斯那个不肯走的数字量出来:
import numpy as np
fc = 0.25
def resp(M, win=None):
n = np.arange(-M, M+1)
h = np.where(n == 0, 2*fc, np.sin(2*np.pi*fc*n) / (np.pi*np.where(n == 0, 1, n)))
if win is not None:
h = h * win(2*M+1)
f = np.linspace(0, 0.5, 4096)
return f, np.abs(np.exp(-2j*np.pi*np.outer(f, n)) @ h)
for M in (10, 50, 200):
f, H = resp(M)
print(f'{2*M+1:4d} 抽头 通带最大 {H[f<fc].max():.6f} 超调 {100*(H[f<fc].max()-1):.4f}%')
# 21 抽头 1.091164 9.1164% / 101 1.089545 8.9545% / 401 1.089493 8.9493%
f, H = resp(50, np.hamming)
print('加汉明窗后超调 %.4f%%' % (100*(H[f<fc].max()-1))) # 0.1946%
把 M 加到 2000(4001 个抽头)试试——超调仍然是 8.949%。这是这本书里最值得亲手确认的一个数:它就是不降。
想看图的话(强烈建议,那个尖角非常有说服力):
import matplotlib.pyplot as plt
for M in (10, 50, 200):
f, H = resp(M); plt.plot(f, H, label=f'{2*M+1} taps')
plt.axhline(1.0894, ls='--'); plt.legend(); plt.show()
python3 -c "import numpy as np;M=200;n=np.arange(-M,M+1);h=np.where(n==0,.5,np.sin(np.pi*n/2)/(np.pi*np.where(n==0,1,n)));f=np.linspace(0,.24,2000);print(np.abs(np.exp(-2j*np.pi*np.outer(f,n))@h).max())"
在线跑:Google Colab。正经设计滤波器用 scipy.signal.firwin(窗函数法)或 scipy.signal.remez(等波纹最优法,能把超调均匀摊开)。
- 音频均衡器。你在播放器里拖的那些滑块,拖的就是 H(f) 这条曲线上的几个控制点。而「线性相位 EQ」和「最小相位 EQ」这两个选项,卖的正是上面那一节——前者不改变波形但有延迟,后者延迟低但会拉扯瞬态。混音师在鼓组上一般选后者。
- 图像的锐化。「USM 锐化」的做法是「原图 + k ×(原图 − 模糊图)」,而「原图 − 模糊图」就是一个高通滤波器。它在强边缘处会产生一圈亮边——那圈亮边就是吉布斯现象,在图像处理里叫「振铃」(ringing)。JPEG 在低码率下把高频量化掉,边缘附近出现的鬼影同样是它。
- 心电图的基线漂移。ECG 信号会随呼吸慢慢上下漂,标准做法是用一个 0.5 Hz 的高通滤掉。但这里必须用线性相位滤波器——因为医生要看的是波形的形状(ST 段抬高多少毫米),非线性相位会把波形拉变形,直接影响诊断。这是「相位重不重要」这个问题在临床上的答案。
- 相机的抗混叠滤波片。第 6 章说过,它必须装在传感器前面。它就是一个光学的低通滤波器,而它的「过渡带」有多陡,直接决定了你的相机是更容易出摩尔纹还是更容易糊。这一章的取舍表,被做成了一块玻璃。
「滤波器把不要的频率删掉了。阶数(抽头数)越高,删得越干净,所以只要算力够就该往高了调。」
两个问题。第一,「删掉」是错的说法——你是在乘一条曲线,而那条曲线在阻带里不是 0,是 −35 dB 或 −58 dB 这种有限的小数。强信号透过 −35 dB 之后仍然可能比你想留的弱信号大。「滤掉了」这句话必须带上一个 dB 数才有意义。
第二,加阶数买到的东西比你以为的少。上面那张表:抽头 20 倍,超调从 9.1164% 到 8.9493%,基本没动。加阶数真正买到的是更窄的过渡带(0.0092 → 更小),不是更平的通带、也不是更低的阻带。要改善后两样,得换窗(或者换设计方法),而那要拿过渡带去付。
而且高阶 FIR 还有代价:延迟正比于抽头数。401 抽头的线性相位滤波器意味着 200 个采样的固定延迟——在 48 kHz 下是 4.2 毫秒,在实时监听、主动降噪、控制回路里,这个延迟本身就是个大问题。判据是:先问「我要的是过渡带更窄,还是阻带更低」,这两件事要用不同的旋钮。
正确答案是 C:8.9493%,几乎一点都不降。理论极限是 8.9490%。
A、B 「抽头多二十倍,误差自然小一个数量级」——这个直觉来自我们对绝大多数数值方法的经验:多算一点就准一点。它在这里失效的原因很特别:误差不是在均匀地缩小,而是在被挤到一个越来越窄的地方去。如果你量的是「总误差能量」,它确实趋于零;但如果你量的是「最大偏差」,它稳稳停在 8.949%。这提醒一件事:说「误差变小了」之前,先说清楚量的是哪一种误差。 D 「足够多就完全收敛」——这个答案在某种意义上是对的,正是这一点让吉布斯现象这么绕:在每一个固定的频率点上,增益确实收敛到理想值(逐点收敛)。但那个尖峰的位置会随 M 一起往截止频率靠,所以对任何固定的 M,总存在一个频率点上偏差是 8.949%。「每一点都收敛」和「一致收敛」的区别,第一次被人认真对待就是因为这个现象。这就是滤波器设计的整个工作流:在频域里画出你想要的曲线 → 逆变换成时域系数 → 加窗修理 → 回到频域检查实际做出来的曲线。没有人在时域里手工调抽头,因为在那边你看不出任何东西。
更值得带走的是这个动作背后的模式:凡是「在 A 域里难以表述、在 B 域里一句话就能说清」的需求,正确做法是在 B 域里设计,再变换回 A 域执行。这条经验远远超出信号处理——统计里的正则化、图形学里的采样、优化里的对偶,都是同一个套路。
这一章的一句话
滤波不是删掉频率,是拿频谱乘一条曲线;而那条最想要的曲线(垂直的墙)需要一个无限长、且用到未来的时域动作,所以它不存在——你能买到的每一个近似,都在第 9 章那张价目表上标着价。
下一章是卷 IV 的最后一章,也是这本书里最像魔术的一章。前面十五章都在处理「信号在那儿,怎么看清楚」;下一章处理的是「信号根本看不见」——一段 512 毫秒的信号,埋在比它强 100 倍的噪声里,示波器上是一片雪花,频谱仪上什么都没有。而只要你手里有它的样板,一次相关,它就从噪声里跳出来到 7.1 σ。你的手机现在就在用这一招接收 GPS。