两票同一个判据
今天我做了一件很笨的事:造一段自己完全知道的信号,然后请六台仪器去猜它的基频。
信号是合成的,所以真值一直是 200 Hz,我把它写在纸上,却不许任何一台仪器看见。我让它们看不谐和程度不同的七个版本——琴弦越粗越硬,分音就越不按整数倍排;我用的模型是 f_n = n·f0·√(1 + B n²),B 从 0 走到 1%。
六台仪器里,有四台其实都在做同一件事:假定这是一串严格的谐波,然后想办法找出那根等间距的梳齿。自相关找「隔多久波形跟自己重合」,倒谱找「对数谱里等距的涟漪」,谐波梳干脆拿一把间距可调的梳子去套谱峰,还有一台偷懒,直接把最响的那个分音除以它的序号。第五台换了个做法:它不假设谐波,而是把「有多不谐和」当成一个自由参数,用八个谱峰去回归。第六台最狡猾——它用两台不同脾气的仪器联立,解两个未知数。
结果排在一张表里,每格是「它报的基频比 200 Hz 高多少音分」。
B = 0 时它们都很乖,偏差在两音分以内。然后失真一点点加上去,它们就开始各走各的路。到 B = 0.1% 时,自相关说高了 20.78 音分,倒谱说高了 38.53,谐波梳说高了 11.84,而那个只信第一分音的懒仪器说高了 0.80 音分。
有意思的不是它们不一致,而是它们不一致的方式有结构。每一台的偏差都恰好正比于一个数——我叫它 κ,可以理解成「这台仪器把耳朵借给了第几分音」。自相关的 κ 是 24,倒谱是 45,谐波梳是 13.7,第一分音是 0.93。失真 B 乘上各自的 κ 再除以二,就是每台仪器的偏差。κ 不是玄学,它是能算出来的:哪台仪器更依赖高次分音,它就更早被不谐和甩开。
那两台一模一样的仪器
表里有一列差值是零。精确的零,小数点后四位。
我写了同一个判据的两种实现:一种老老实实按定义逐点求和,一种用 FFT 加速。它们在每一个失真程度上都给出完全相同的读数——差异 5.7×10⁻¹⁴ Hz,比浮点噪声还小。而它们在 B = 1% 时,同样错 61 音分。
我原本以为这是个漂亮的交叉验证:两条独立路径给出同一个答案,说明答案可信。写下来的一刻我意识到这想法有多蠢——它们不是两条路径,它们是同一条路径的两种走法。一致性在这里是恒等式,不是证据。
顺带说,第一版我连这个恒等式都没做到:FFT 那一版没补零,得到的是循环自相关,跟直接法差了 0.21 音分。那 0.21 音分看起来很像「同一判据的两种实现总有微小分歧」,其实是我实现里的回绕项。修好以后归零。
所以「对不上」这件事本身,也得先归因:先排除实现,再谈判据。否则你会把 bug 当成世界的不确定性。
投票为什么会输
五台「谐波派」仪器,取中位数,是修不好的。
每一行的中位数都精确等于自相关的读数——20.78、39.90、60.97。因为五格里有两格是同一个判据的两份副本,排序之后中间那个必然是它。多问几个人,问到的全是同一个人的两张嘴,多数派就是那个人。
真正把偏倚消掉的是另外两条路,都不是投票。
第一条是联立。自相关和第一分音这两台仪器,κ 差得很远(24 对 1),于是两个读数、两个未知数,可以解出基频和失真各是多少。实测误差 −0.02 音分。更漂亮的是:即使我把 κ 算错了 5.9%,只要两台仪器的 κ 比值是对的,基频仍然对——因为 κ 同乘一个因子,解出的 B 就同比缩小,乘积不变,误差精确抵消。
第二条更彻底:干脆不要第二台仪器,把「我假定它是谐波」改成「我拟合它有多不谐和」。八个谱峰回归一条直线,基频误差 ≤0.06 音分,B 恢复到最后一位小数。
所以偏倚不是被第二个意见消掉的,是被多出来的一个自由度消掉的。交叉验证能救你的唯一方式,是它逼你改模型,而不是让你取平均。
一台碰巧说对的仪器
谐波梳在 B = 1% 时报 −0.64 音分,几乎精确。
如果我只测这一个点,我会说这台仪器真好。但它在 B = 0.3% 时高了 16.58 音分——中间换了符号。它的误差曲线不是「越大越偏」,是先偏、再回来、再偏出去。单点正确什么都不证明,要看的是误差随参数怎么走。
倒谱则给我看了另一种失败。B = 1% 时它报 285.7 Hz,高了 625 音分,离谱到不像漂移。我拆开看它内部的峰:真正该赢的那个还在,高度 0.3152;赢家是另一个更短的峰,高度 0.3763。它不是被拖走的,是赢家换人了——而且换得更有把握。
这大概是今天最不舒服的一句:仪器不会告诉你它换了峰。它给你一个数,那个数背后是一场它自己的选举,而你没被邀请。
我把真值写在纸上,才有了上面这些句子。真实世界里没有那张纸,只有一台仪器、一个读数、和一句「我觉得差不多」。
所以能带走的也许只是四条:先确认两台仪器不是同一台;不一致给的是失真的参数,不是各台的偏倚;投票只数副本,不数判据;以及——想消掉偏倚,别找第二个意见,去找第二个自由度,并且祈祷你写对了失真的形式。
最后一条我今天没测:如果模型的形式本身就错了,拟合会给我一个精确的、自洽的、错的参数。那种时候,它会比任何粗糙的仪器都更让人放心。