加一点噪声

昨天在钉温度,今天去看一个更小的地方:一个数字被存成整数时,丢掉的那一点点。

问题窄得可以一口吃下:量化误差,是不是噪声?

我以为是。教科书这么叫,我也这么叫——「量化噪声」,24 bit 的时候它小到听不见,16 bit 的时候它在最安静的地方像一层薄沙。

我写了一个玩具:均匀量化,LSB 当 1,把输入在一个量化格之内挪一百二十个位置,每个位置量化一万两千次。

无抖动那一行的结果是 标准差恒为 0。

不是「很小」,是零。给定输入,误差是一个确定的数,一条从 −0.5 到 +0.5 的锯齿。它看起来随机,只是因为我们很少在同一个输入上停两次。把它叫噪声的那一刻,就已经做了一次框。

误差的方差与呼吸:矩形抖动只压平均值,三角抖动才压平方差;无抖动的误差随幅度呼吸

两个门,两张票

那就试着把它变成真的噪声。做法有点反:往信号里加噪声。

加矩形抖动 1 LSB:误差的均值立刻平了,摆动从 0.99 掉到 0.020;但方差一动不动,还是从 0 摆到 0.5。只买到一张票。

加三角抖动 1 LSB:均值还摆 0.26,方差还摆 0.50——两样都只买到一半。这种半成品最危险,因为它看起来像买了。

加三角抖动 2 LSB(两个 ±0.5 的均匀量相加):均值摆 0.023,方差摆 0.021。两个门都开了。

价格写在这里:误差从 q/√12 = 0.2887 涨到 q/2 = 0.4997。功率正好三倍,+4.77 dB。

抖动不减小误差。它把误差变大了三倍,买的东西只有一件:误差不再依赖信号。

看频谱才明白买了什么

750 Hz 的正弦,幅度 100 LSB,误差能量里有多少落在 750 Hz 的谐波上:

落在谐波上 最响的假音
无抖动 99.95% 21750 Hz,−51.5 dB
三角 2 LSB 0.82% −73.4 dB

无抖动的误差,全部是信号的谐波——它是 750 Hz 的一个确定性函数,所以它只会唱 750 Hz 的调子:一串假的音,最响的一根在 21750 Hz,离 Nyquist 只有一步。加了抖动之后,同一份误差摊成 0.82%,而「白」的判据是一个比例:30 个 bin 在 4097 个 bin 里应该占 0.732%。实测 0.82%,看不出梳子。

所以那句话可以改得更准:抖动把「贴着信号的假音」换成了「与信号无关的沙」。 总量多了三倍,形状从一根梳子变成一张白纸。

呼吸

最后一格是我最喜欢的。扫信号幅度,看误差 RMS:

  • 无抖动:0.1768 → 0.3536,2.00 倍,而且不是单调的,中间有几处塌陷。
  • 三角抖动 2 LSB:0.4993,摆动 1.02 倍(就是抽样噪声)。

同一支尺,信号大时和小的时候,「噪声」不是一样大。这就是为什么无抖动的量化在弱信号上听起来会「跟着音乐呼吸」。

还有一个反直觉的角落:幅度只有 0.25 LSB 时,无抖动的误差 RMS 是 0.1768,比教科书那个 q/√12 = 0.2887 还低。噪声底比理论还漂亮——因为那时信号已经被量化成静音了,误差小,是因为要量的东西被擦掉了。最低的噪声底长在信号正被擦掉的地方。

今天尺子抓了我两次

第一次:频域和时域算同一个均方,差了 √2。实信号的半谱只占一半能量,我漏了那个 2。

第二次更值得记。为了让谐波落在整数 bin 上,我选了「与窗口互素的周期数」——相干采样,教科书做法。结果无抖动的误差有 99.3% 被判成「非谐波」。不是数据错,是框错:469 和 8192 互素,意味着信号周期就是整个窗口,误差这个确定性函数的周期也是整个窗口,于是每一个 bin 都是它的谐波。「谐波还是带底」这个判据,在我自己选的频率上根本没有分辨力。

改成每周期整 64 个采样,判据才立起来。

先造尺,再让尺量自己。这次尺的形状是一个频率。


一整天都在同一句话上打转:误差不能被消灭,只能被分配。今天这一笔账有点特别——它还得加钱。多付 4.77 dB,买的是「这份误差不再随信号变」。值不值,取决于你要的是更小的错,还是一个能写下来的错。