1. 声音的数字化:从模拟信号到数字信号的转换过程,采样定理与量化噪声
好,咱们正式开始。第一章,我打算先聊聊声音是怎么变成数字的。
你可能会想,这有什么好聊的?不就是麦克风录进去,电脑存下来吗?
嗯,表面上看确实是这样。但这里面藏着两个核心问题:什么时候采,和怎么量化。
这两个问题没处理好,你后面做再牛的降噪算法,也是白搭。我当年刚入行时就在这上面栽过跟头,后面细说。
1.1 从模拟到数字:ADC 在干什么?
声音在自然界里是连续的——声带振动、琴弦抖动,都是连续变化的空气压力波。我们叫它模拟信号。
但计算机不认连续的东西。它只认 0 和 1,而且只能处理离散的数值。
所以中间需要一块芯片,叫 ADC(模数转换器)。
ADC 的工作,说白了就两步:
- 采样:每隔一小段时间,把当前电压值记下来。
- 量化:把这个电压值,用有限个二进制位表示出来。
我习惯把采样比作「拍照」。你对着一条连续变化的波形,每隔固定间隔拍一张快照。拍下来的这些快照,就是采样点。
核心概念:采样是时间上的离散化,量化是幅度上的离散化。两者缺一不可。
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 本章知识结构图
下面这张图,把声音数字化的核心流程和关键概念串起来了。你可以对照着看。
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 操作的基础。采样率和位深这两个参数,你会在每一个音频项目里反复遇到。搞懂它们,后面就顺了。