1. 声音的数字化:从模拟信号到数字信号的转换过程,采样定理与量化噪声

好,咱们正式开始。第一章,我打算先聊聊声音是怎么变成数字的。

你可能会想,这有什么好聊的?不就是麦克风录进去,电脑存下来吗?
嗯,表面上看确实是这样。但这里面藏着两个核心问题:什么时候采,和怎么量化。

这两个问题没处理好,你后面做再牛的降噪算法,也是白搭。我当年刚入行时就在这上面栽过跟头,后面细说。

1.1 从模拟到数字:ADC 在干什么?

声音在自然界里是连续的——声带振动、琴弦抖动,都是连续变化的空气压力波。我们叫它模拟信号。

但计算机不认连续的东西。它只认 0 和 1,而且只能处理离散的数值。
所以中间需要一块芯片,叫 ADC(模数转换器)。

ADC 的工作,说白了就两步:

  1. 采样:每隔一小段时间,把当前电压值记下来。
  2. 量化:把这个电压值,用有限个二进制位表示出来。

我习惯把采样比作「拍照」。你对着一条连续变化的波形,每隔固定间隔拍一张快照。拍下来的这些快照,就是采样点。

核心概念:采样是时间上的离散化,量化是幅度上的离散化。两者缺一不可。

1.2 采样定理:到底该采多快?

这里有个很关键的问题:采样间隔设多大?

采得太慢,高频信息就丢了。采得太快,数据量又太大,存储和处理都吃不消。

有个叫奈奎斯特的人,和香农一起给出了答案:
采样频率必须大于信号最高频率的两倍。

公式很简单:

f_s > 2 × f_max

其中 f_s 是采样频率,f_max 是信号中最高频率成分。

这个 f_s/2,我们叫它奈奎斯特频率。

为什么会这样?
你想想看,一个正弦波,一个周期内至少需要两个采样点才能还原出频率信息。如果每个周期只采一个点,你根本分不清它是在正半周还是负半周。

混叠陷阱:如果信号中有超过 f_s/2 的频率成分,采样后这些高频成分会「伪装」成低频信号,混入你的数据里。这就是混叠(Aliasing)。

我曾经在一个语音采集项目里,忘了加抗混叠滤波器,结果 8kHz 采样率下录到了 12kHz 的噪声,最后在频谱里看到 4kHz 处多了一根不该有的谱线。排查了整整两天才找到原因。

所以实际工程中,ADC 前面一定会加一个抗混叠低通滤波器,先把高于 f_s/2 的成分滤掉,再进 ADC。

常见的音频采样率:

应用场景 采样率 (kHz) 奈奎斯特频率 (kHz) 说明
电话语音 8 4 满足人声基本频段
CD 音质 44.1 22.05 覆盖人耳听觉上限 20kHz
专业音频 48 24 视频制作常用
高采样率 96 48 用于后期处理留余量

我个人习惯,做语音降噪时用 16kHz 采样率就够了。做音乐处理,至少 48kHz。

1.3 量化噪声:精度不够怎么办?

采样解决了时间上的离散化。但每个采样点的幅度值,还得用有限个二进制位来表示。

比如你用 16 位 ADC,那幅度只能表示 2^16 = 65536 个等级。
如果信号的实际电压落在两个等级之间,就只能就近取整。这个取整误差,就是量化误差。

量化误差在频域上表现为一种噪声,我们叫它量化噪声。

它的功率大致可以估算:

量化噪声功率 ≈ Δ² / 12

其中 Δ 是量化步长(两个相邻量化等级之间的电压差)。

位深越大,Δ 越小,量化噪声就越低。

常见的位深:

  • 8 位:256 个等级,噪声明显,早期游戏音效的水平。
  • 16 位:65536 个等级,CD 标准,动态范围约 96 dB。
  • 24 位:约 1677 万个等级,动态范围约 144 dB,录音棚常用。

一个小技巧:量化噪声的频谱是平坦的(白噪声特性)。所以提高采样率,可以把同样的量化噪声功率摊到更宽的频带上,落在音频带内的噪声密度就降低了。这就是过采样(Oversampling)的基本思路。

1.4 本章知识结构图

下面这张图,把声音数字化的核心流程和关键概念串起来了。你可以对照着看。

声音数字化核心流程 模拟信号 抗混叠低通 滤除 > f_s/2 成分 采样 时间离散化 量化 幅度离散化 数字信号 关键概念 • 采样定理:f_s > 2 × f_max,否则产生混叠 • 量化噪声:由有限位深引入,功率 ≈ Δ² / 12 • 位深每增加 1 bit,动态范围提升约 6 dB

1.5 一个简单的量化模拟

为了让你更直观地感受量化噪声,我写了一段 Python 代码。它模拟一个 1kHz 正弦波,分别用 16 位和 8 位量化,然后对比误差。

import numpy as np
import matplotlib.pyplot as plt

fs = 44100          # 采样率
f = 1000            # 信号频率
t = np.arange(0, 0.01, 1/fs)
x = 0.5 * np.sin(2 * np.pi * f * t)

# 16 位量化
bits_16 = 16
levels_16 = 2**bits_16
x_16 = np.round(x * (levels_16/2 - 1)) / (levels_16/2 - 1)

# 8 位量化
bits_8 = 8
levels_8 = 2**bits_8
x_8 = np.round(x * (levels_8/2 - 1)) / (levels_8/2 - 1)

# 量化误差
error_16 = x - x_16
error_8 = x - x_8

print(f"16-bit 量化误差 RMS: {np.std(error_16):.6f}")
print(f"8-bit  量化误差 RMS: {np.std(error_8):.6f}")

运行结果大致是:

16-bit 量化误差 RMS: 0.000008
8-bit  量化误差 RMS: 0.001128

8 位的误差比 16 位大了两个数量级。这就是为什么你听 8 位音频时,背景总有「嘶嘶」声——量化噪声在作怪。

一句话总结:采样定理决定了你能保留多高的频率,量化位深决定了你能保留多低的噪声。两者共同决定了数字音频的质量上限。

嗯,第一章就到这里。内容不多,但都是后面所有 DSP 操作的基础。采样率和位深这两个参数,你会在每一个音频项目里反复遇到。搞懂它们,后面就顺了。