声音的物理基础:声波、频率、振幅、相位

各位同学好,我是你们这门课的主讲。今天咱们来聊聊声音的物理基础。说实话,这部分内容看起来有点理论,但它是整个语音信号处理的根基。我在做降噪算法的时候,经常要回头翻这些基本概念——你想想看,连声音的本质都没搞明白,怎么去降噪呢?

声波到底是什么?

声音说白了就是一种机械波。空气被压缩、膨胀,再压缩、再膨胀,这样一波一波地传到你耳朵里。我刚开始做音频处理时,总把声波想象成水面上的涟漪——其实不太准确。声波是纵波,空气分子沿着传播方向来回振动,而不是上下振动。

声波有几个关键参数:

  • 频率:每秒振动的次数,单位是赫兹(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。这个习惯帮我避免了很多精度问题。

知识体系总览

下面这张图总结了本章的核心知识点,我习惯用这种图来梳理思路:

声音的物理基础 声波 机械波,纵波传播 频率 振幅 相位 时域与频域 时域:时间→幅度 频域:频率→幅度 傅里叶变换 采样与量化 采样:时间离散化 量化:幅度离散化 采样定理:fs ≥ 2 × fmax 量化位数:8/16/24/32 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