声音的物理基础:声波、频率、振幅、相位
各位同学好,我是你们这门课的主讲。今天咱们来聊聊声音的物理基础。说实话,这部分内容看起来有点理论,但它是整个语音信号处理的根基。我在做降噪算法的时候,经常要回头翻这些基本概念——你想想看,连声音的本质都没搞明白,怎么去降噪呢?
声波到底是什么?
声音说白了就是一种机械波。空气被压缩、膨胀,再压缩、再膨胀,这样一波一波地传到你耳朵里。我刚开始做音频处理时,总把声波想象成水面上的涟漪——其实不太准确。声波是纵波,空气分子沿着传播方向来回振动,而不是上下振动。
声波有几个关键参数:
- 频率:每秒振动的次数,单位是赫兹(Hz)。人耳能听到的大概是20Hz到20kHz。
- 振幅:振动的幅度大小,决定了声音的响度。振幅越大,声音越响。
- 相位:描述振动在某个时刻所处的状态,单位是角度或弧度。
重要概念:频率决定音调,振幅决定响度,相位决定声音的叠加效果。这三个参数缺一不可。
我在项目中遇到过一件事:有一次做麦克风阵列的波束成形,相位没算对,结果降噪效果反而变差了。嗯,相位这东西,看似简单,实际坑很多。
时域与频域的基本概念
咱们平时看到的波形图,横轴是时间,纵轴是振幅——这就是时域表示。但很多时候,时域里看不出什么名堂。比如一段嘈杂的录音,你盯着波形看半天,也分不清哪些是噪声哪些是人声。
这时候就需要频域了。频域把信号拆解成不同频率的成分,横轴是频率,纵轴是幅度(或能量)。说白了,就是告诉你这个声音里,低频有多少、中频有多少、高频有多少。
为什么会这样?因为人耳本身就是个频谱分析仪。你听到一段音乐,能分辨出小提琴和钢琴,靠的就是它们在不同频率上的能量分布不同。
我的经验:做语音增强时,我习惯先在频域里观察噪声的分布。比如空调噪声集中在低频,风扇噪声在中高频。知道了噪声在哪,才好对症下药。
时域和频域之间怎么转换?靠的是傅里叶变换。这个后面我们会详细讲,现在你只需要记住:时域和频域是同一个信号的两种不同视角,就像硬币的正反面。
采样定理与量化
好了,现在问题来了:计算机怎么处理声音?声音是连续的模拟信号,计算机只能处理离散的数字信号。这就涉及两个关键步骤:采样和量化。
采样定理
采样定理也叫奈奎斯特-香农采样定理。它的核心思想很简单:要完整地还原一个信号,采样频率必须至少是信号最高频率的两倍。
举个例子:人声的最高频率大概在8kHz左右,那么采样频率至少要16kHz。CD音质的采样率是44.1kHz,为什么?因为人耳能听到20kHz,两倍就是40kHz,留点余量就定到了44.1kHz。
避坑指南:我曾经在项目里采样率设得太低,结果高频信号出现了混叠(aliasing),听起来像是一种奇怪的失真。后来我养成了一个习惯:采样率至少设成目标最高频率的2.5倍,留足余量。
混叠是什么?简单说就是高频信号被错误地采样成了低频信号。你想想看,本来想录个高音,结果录出来变成了低音,这肯定不行。
量化
采样是把时间离散化,量化则是把幅度离散化。每个采样点的幅度值,要用有限个比特来表示。
常见的量化位数:
| 量化位数 | 动态范围 | 常见应用 |
|---|---|---|
| 8 bit | 48 dB | 早期电话、低质量录音 |
| 16 bit | 96 dB | CD音质、WAV文件 |
| 24 bit | 144 dB | 专业录音、后期制作 |
| 32 bit float | 理论上无限 | 音频处理内部格式 |
量化位数越高,动态范围越大,声音的细节保留得越好。但文件体积也越大。16 bit是性价比最高的选择,这也是为什么大多数音频文件都用16 bit。
我的建议:做语音增强算法时,内部处理建议用32 bit float,避免累积误差。最终输出再转成16 bit。这个习惯帮我避免了很多精度问题。
知识体系总览
下面这张图总结了本章的核心知识点,我习惯用这种图来梳理思路:
这张图把本章的三个核心模块串起来了。声波是物理基础,时域频域是分析工具,采样量化是数字化的桥梁。三者缺一不可。
一个简单的代码示例
说了这么多理论,咱们来点实际的。下面这段Python代码演示了如何生成一个正弦波,并观察它的时域和频域特征:
import numpy as np
import matplotlib.pyplot as plt
# 参数设置
fs = 44100 # 采样率 44.1kHz
f = 440 # 频率 440Hz (A4音)
duration = 0.1 # 时长 0.1秒
amplitude = 0.8 # 振幅
# 生成时间轴
t = np.arange(0, duration, 1/fs)
# 生成正弦波
signal = amplitude * np.sin(2 * np.pi * f * t)
# 计算频谱
fft_result = np.fft.fft(signal)
freqs = np.fft.fftfreq(len(signal), 1/fs)
# 只取正频率部分
positive_freqs = freqs[:len(freqs)//2]
positive_magnitude = np.abs(fft_result[:len(fft_result)//2])
print(f"信号长度: {len(signal)} 个采样点")
print(f"频率分辨率: {freqs[1] - freqs[0]:.2f} Hz")
print(f"最大幅度: {np.max(positive_magnitude):.2f}")
这段代码我用了很多次。每次测试新算法时,我都会先拿一个纯音信号试试水,看看时域波形对不对、频谱峰值是不是在预期频率上。这是个好习惯,建议你们也养成。
关键点总结:
- 声波是纵波,频率、振幅、相位是三个基本参数
- 时域看波形,频域看成分,两者通过傅里叶变换联系
- 采样定理告诉我们:采样率要大于最高频率的两倍
- 量化位数决定了动态范围和精度,16 bit是主流选择
好了,这一章的内容就到这里。记住这些基础概念,后面讲降噪算法时,我们会反复用到它们。有什么问题欢迎随时交流。
公众号:蓝海资料掘金营,微信deep3321