语音与语言:信号处理与计算表征基础
人类语音是自然界最精妙的信号之一,它承载着思想、情感与文化的重量,是文明得以延续和演进的基石。从婴儿的第一次啼哭到诗人最后的吟诵,语音始终是我们理解彼此、构建社会的最根本纽带。然而,对于机器而言,这流动的声波却是一道道复杂、冗余且高度变异的物理振动曲线。要让计算机“听懂”人类语言,首要任务便是将这一连续的模拟信号转化为精确、离散且富含语言学信息的计算表征。本章正是这座桥梁的基石——我们将从语音产生的物理与生理根源出发,逐步深入语音信号的数字世界,系统性地掌握其预处理、特征提取的核心技术,并确立后续所有模型训练与评测的统一语言与标尺。理解这些基础,不仅是为了复现经典流程,更是为了洞察后续端到端系统为何能以如此简洁的方式取代它们,从而真正把握语音AI进化脉络中的“变”与“不变”。
语音产生的物理与生理基础:声学与发音器官
语音的本质是声带振动或气流湍流在声道中调制产生的声波,其物理基础是空气的周期性压力变化。从声学角度看,语音信号是一种非平稳的随机过程,其频谱特性随时间快速变化,但在一段极短的时间(通常10-30毫秒)内可近似为平稳的,这一特性直接催生了后续分帧处理的理论依据。语音信号的能量主要集中在中低频段(300Hz至3400Hz),这也是传统电话信道带宽设计的物理基础。更重要的是,语音信号是一种“激励-滤波”系统的输出:声带产生的周期性或非周期性气流作为激励源,经过咽腔、口腔、鼻腔等组成的复杂声学滤波器(声道)调制后,辐射到空气中形成我们听到的声音。这一模型是线性预测编码(LPC)理论的物理根基。
理解这一物理过程,必须回溯到人类独特的发音器官。肺部提供稳定气流,作为整个发音系统的动力源。声带位于喉部,其振动与否直接区分了浊音(如元音、鼻音、半元音,声带振动,存在基频$F_0$)与清音(如塞音、擦音、塞擦音,声带不振动,激励为白噪声)。声带振动的频率即基频,成人男性平均约120Hz,女性约220Hz,儿童更高,它决定了语音的音高。声带之后是咽腔,它连接喉部与口腔,其形状可调节,参与共鸣。口腔是主要的声道组成部分,通过舌位(前、后、高、低)、唇形(圆唇、展唇)、下颌开合等肌肉的精细协同运动,形成不同的共鸣腔,从而产生丰富的元音和辅音。鼻腔通过软腭的开启与关闭参与共鸣,产生鼻音和鼻化元音。这套“发动机-滤波器”系统,以极高的效率将肺部气流转化为承载信息的声波。
语音的生理产生过程可概括为三个紧密耦合的子系统:动力系统(肺、气管、喉)、振动系统(声带)和构音系统(咽、口腔、鼻腔)。大脑语言中枢发出指令,通过运动神经精确控制各发音器官的肌肉群,实现毫秒级的协调运动。这种生理上的复杂性,正是语音信号多变性的根源:同一说话人、同一词汇,在不同语速、语调、情感状态下,其声学表现差异巨大;不同说话人则因声道物理尺寸(如男性声道长、女性声道短)的固有差异,形成独特的“音色”,即音质。这种说话人差异性和时间变异性,是自动语音识别系统必须应对的两大核心挑战。
基于上述生理机制,语音可按照发音方法进行声学分类,这对理解信号特性至关重要。塞音(如/p/, /t/, /k/)由气流完全阻塞后突然释放产生,能量爆发在高频段,有显著的瞬态特性,且存在过渡音(从阻塞到释放的滑动音)。擦音(如/f/, /s/, /ʃ/)由气流通过狭窄通道产生湍流,能量集中在高频,是典型的宽带噪声。塞擦音(如/tʃ/, /dʒ/)结合了二者特征。鼻音(如/m/, /n/, /ŋ/)因软腭下垂,气流同时从口腔和鼻腔流出,在低频段有显著的能量峰(鼻共振峰)。滑音/半元音(如/j/, /w/)是元音间的平滑过渡,具有类似元音的共振峰结构但时长极短。元音本身由声带周期性激励、声道特定形状产生,是能量最集中的部分,其频谱特性由前三个共振峰(Formant)频率$F_1, F_2, F_3$主导,分别对应声道不同腔体的共鸣频率,是区分不同元音的核心声学线索。例如,元音/i/(如“衣”)的$F_1$低、$F_2$高,而元音/a/(如“啊”)的$F_1$和$F_2$均较高。这种“共振峰理论”是语音信号处理,尤其是LPC和MFCC方法的重要物理依据。
---
语音信号的数字化:从模拟波形到离散序列
计算机无法直接处理连续的模拟声波,必须通过模数转换将其离散化。这一过程包含两个核心步骤:采样与量化。
采样以固定的时间间隔对模拟信号幅度进行“快照”。根据奈奎斯特-香农采样定理,要无失真地重建信号,采样频率$f_s$必须至少是信号最高频率分量$f_{max}$的两倍,即$f_s \geq 2f_{max}$。人类语音有效频率范围通常视为300Hz至3400Hz(电话带宽),因此最低采样率需为8kHz。但为保留更丰富的音质信息(如$F_3$以上信息、清音的高频能量),CD音质采用44.1kHz,而语音识别任务中,16kHz已成为兼顾信息量与计算效率的常用标准。采样将时间轴离散化,得到序列$x[n] = x_c(nT_s)$,其中$T_s = 1/f_s$为采样周期。
量化则将每个采样点的连续幅度值映射到有限个离散电平上。若使用$B$比特量化,则有$2^B$个量化级。量化过程引入量化噪声,其功率与量化间隔的平方成正比。信噪比(SQNR)理论极限约为$6.02B + 1.76$ dB。例如,16-bit量化(CD标准)的SQNR可达约98dB,人耳几乎无法察觉;而8-bit量化(电话质量PCM)的SQNR约为50dB,虽有一定噪声,但语音可懂度仍高。量化级数需在存储/传输成本与信号保真度间权衡。
数字化后的语音数据通常以波形文件形式存储,最常见的是WAV格式。它是一种基于资源交换文件格式的简单容器,核心结构包括: 1. RIFF头(12字节):标识文件类型("RIFF")、文件总长度。 2. 格式块(fmt chunk):关键参数,包括音频编码格式(如1为PCM)、声道数(单声道为1,双声道为2)、采样率、字节率、块对齐、位深度。 3. 数据块(data chunk):实际的语音采样点数据,按声道交错排列(对于多声道)。 WAV格式无损、简单、广泛支持,是语音处理实验的标准起点。Python中可通过`wave`或`soundfile`库轻松读写,而`librosa`等高级库则进一步封装,直接加载为数值数组。
```python import librosa import soundfile as sf
加载WAV文件,自动重采样至目标采样率(如16kHz)
y, sr = librosa.load('speech.wav', sr=16000) print(f"信号长度: {len(y)} 采样点, 采样率: {sr} Hz, 时长: {len(y)/sr:.2f} 秒")
保存为WAV
sf.write('output.wav', y, sr, subtype='PCM_16') ```
---
语音预处理:为特征提取扫清障碍
原始数字化语音波形包含大量冗余信息与不希望的畸变,直接用于分析或识别效率低下。预处理旨在突出语音内容、抑制干扰,为后续特征提取创造有利条件。核心步骤包括预加重、分帧与加窗。
预加重:提升高频能量
声波在传播过程中,高频成分比低频成分更易衰减,且从声带辐射的语音信号其频谱存在约-6dB/octave(即每倍频程衰减6分贝)的自然滚降。为补偿这种高频损失,使后续处理(如LPC分析)更关注高频细节,需进行预加重。其本质是一个简单的一阶高通滤波器:
$$ \hat{x}[n] = x[n] - \alpha x[n-1] $$
其中$\alpha$为预加重系数,通常取0.95至0.97。其传递函数为$H(z) = 1 - \alpha z^{-1}$,在$z=1$处有零点,低频增益小于1,高频增益趋近1,从而实现高频提升。时域实现即为当前样本减去前一延迟样本的$\alpha$倍。此操作可逆,解码端可通过互补的低通滤波(去加重)恢复原始频谱斜率。
分帧:利用短时平稳性
语音信号是非平稳的,其统计特性(如均值、方差)随时间剧烈变化。然而,在10-30毫秒的极短时间窗内,声道形状相对稳定,可视为短时平稳。基于此,将连续语音切分为重叠的短时段(帧),是几乎所有语音处理算法的前提。帧长通常取20-40毫秒:过短则频域分辨率低,无法有效捕捉共振峰结构;过长则跨度过多个音素,违背平稳假设。常见选择为25ms(400采样点@16kHz)。帧移(相邻帧起始点间隔)通常为10ms,以保证足够的时间分辨率并形成帧间重叠(50%重叠最常见),避免信息丢失。
设原始信号为$x[n]$,帧长$N$,帧移$M$,则第$i$帧信号为: $$ x_i[n] = x[i \cdot M + n], \quad n = 0, 1, ..., N-1 $$
加窗:减少频谱泄漏
直接对一帧信号进行截断(相当于乘以矩形窗)会在频谱上引入严重的频谱泄漏:真实频谱的单一频率分量会“扩散”到邻近频率 bins,形成旁瓣,掩盖弱频率分量。为抑制这种效应,需在分帧后对每帧信号乘以一个窗函数,使帧两端平滑衰减至零。窗函数在时域加权,在频域表现为主瓣宽度与旁瓣衰减的权衡。
最常用的窗函数是汉明窗,其数学表达式为: $$ w[n] = 0.54 - 0.46 \cos\left(\frac{2\pi n}{N-1}\right), \quad n = 0, 1, ..., N-1 $$
汉明窗的主瓣宽度较宽(频率分辨率略低),但旁瓣衰减高(约-42dB),能有效抑制泄漏,是语音特征提取的标准选择。其他窗如汉宁窗、布莱克曼窗旁瓣更低但主瓣更宽,应用较少。
预加重、分帧、加窗的顺序至关重要:先预加重,再分帧,最后对每帧加窗。预加重是全局操作,应在分帧前完成,以确保高频提升作用于整个信号。以下Python代码展示了标准预处理流程:
```python import numpy as np import librosa
def preprocess_audio(y, sr, preemph=0.97, frame_len=0.025, frame_step=0.010): """ 语音预处理流水线:预加重 -> 分帧 -> 加窗 参数: y: 原始音频信号 (一维numpy数组) sr: 采样率 preemph: 预加重系数 frame_len: 帧长(秒) frame_step: 帧移(秒) 返回: frames: 处理后的帧矩阵,形状 (帧数, 帧长采样点数) """
1. 预加重
y_preemph = np.append(y[0], y[1:] - preemph * y[:-1])
2. 分帧参数
frame_length = int(round(frame_len * sr)) frame_step = int(round(frame_step * sr)) signal_length = len(y_preemph) num_frames = 1 + int(np.ceil((signal_length - frame_length) / frame_step))
3. 补零以确保所有帧等长
pad_signal_length = num_frames * frame_step + frame_length z = np.zeros((pad_signal_length - signal_length)) pad_signal = np.concatenate((y_preemph, z))
4. 构建帧索引矩阵,高效分帧
indices = np.tile(np.arange(0, frame_length), (num_frames, 1)) + \ np.tile(np.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T frames = pad_signal[indices.astype(np.int32, copy=False)]
5. 加汉明窗
win = np.hamming(frame_length) frames_windowed = frames * win
return frames_windowed
使用示例
y, sr = librosa.load('example.wav', sr=None) # 保留原始采样率 frames = preprocess_audio(y, sr) print(f"总采样点: {len(y)}, 总帧数: {len(frames)}, 每帧采样点: {frames.shape[1]}") ```
---
线性预测编码:声道模型的参数化
物理意义与核心思想
线性预测编码是一种基于源-滤波器模型的参数化语音编码与分析技术。其核心假设是:语音信号$s[n]$在短时内可视为一个线性系统的输出,该系统由激励源(声带振动或噪声)驱动,通过一个线性时变滤波器(声道)产生。LPC的目标,便是根据过去的$p$个语音样本,通过线性组合预测当前样本,而使得预测误差最小的那组预测系数,恰好就对应着该短时声道的全极点滤波器模型参数。
设第$i$帧语音信号为$s_i[n]$,$n=0,1,...,N-1$。一个$p$阶线性预测器定义为: $$ \hat{s}_i[n] = \sum_{k=1}^{p} a_k s_i[n-k] $$ 其中$a_k$为预测系数,$\hat{s}_i[n]$为对$s_i[n]$的预测值。预测误差(或残差)$e_i[n]$为: $$ e_i[n] = s_i[n] - \hat{s}_i[n] = s_i[n] - \sum_{k=1}^{p} a_k s_i[n-k] $$
LPC分析的目标是,在最小均方误差准则下,求解使帧内总预测误差能量最小的系数向量$\mathbf{a} = [a_1, a_2, ..., a_p]^T$。即最小化: $$ E = \sum_{n=0}^{N-1} e_i^2[n] = \sum_{n=0}^{N-1} \left( s_i[n] - \sum_{k=1}^{p} a_k s_i[n-k] \right)^2 $$
对$E$关于每个$a_j$求偏导并令其为零,得到正规方程(Normal Equations): $$ \sum_{k=1}^{p} a_k \sum_{n=0}^{N-1} s_i[n-j] s_i[n-k] = \sum_{n=0}^{N-1} s_i[n] s_i[n-j], \quad j=1,2,...,p $$
定义自相关序列$r_{i}[m] = \sum_{n=0}^{N-1-m} s_i[n] s_i[n+m]$($m \ge 0$,通常对帧信号加窗后计算),则正规方程可写为紧凑的矩阵形式: $$ \mathbf{R} \mathbf{a} = \mathbf{r} $$ 其中$\mathbf{R}$是$p \times p$的自相关矩阵,元素$R_{j,k} = r_i[|j-k|]$(具有对称Toeplitz结构),$\mathbf{r}$是自相关向量,元素$r_j = r_i[j]$。这是一个对称正定方程组,有唯一解。
Yule-Walker方程与Levinson-Durbin递推
上述$\mathbf{R}\mathbf{a}=\mathbf{r}$称为Yule-Walker方程。由于$\mathbf{R}$的Toeplitz结构,存在高效的Levinson-Durbin递推算法求解,时间复杂度从直接求逆的$O(p^3)$降至$O(p^2)$。该算法递归地计算预测系数$a_k^{(k)}$(阶数为$k$时的系数)和预测误差能量$E_k$。
算法步骤如下: 1. 初始化:$E_0 = r_i[0]$(信号总能量),$a_1^{(1)} = r_i[1] / E_0$,$E_1 = E_0 (1 - (a_1^{(1)})^2)$。 2. 对于$k = 2, 3, ..., p$:
- 计算反射系数(PARCOR系数):$\gamma_k = \left( r_i[k] - \sum_{j=1}^{k-1} a_j^{(k-1)} r_i[k-j] \right) / E_{k-1}$
- 更新预测系数:$a_j^{(k)} = a_j^{(k-1)} - \gamma_k a_{k-j}^{(k-1)}$,$j=1,...,k-1$;$a_k^{(k)} = \gamma_k$
- 更新预测误差能量:$E_k = E_{k-1} (1 - \gamma_k^2)$
3. 最终$p$阶LPC系数为$\mathbf{a} = [a_1^{(p)}, a_2^{(p)}, ..., a_p^{(p)}]^T$。
反射系数$\gamma_k$的绝对值小于1(稳定性条件),且直观反映了声道各段截面的面积比,在语音编码中可用于判断清/浊音。
LPC谱包络与倒谱
LPC系数$\mathbf{a}$定义了一个全极点系统函数: $$ H(z) = \frac{G}{1 - \sum_{k=1}^{p} a_k z^{-k}} = \frac{G}{A(z)} $$ 其中$A(z)$为分析滤波器,其倒数$1/A(z)$即为合成滤波器,$G$为增益(通常取预测误差能量平方根)。该滤波器的频率响应幅度平方$|H(e^{j\omega})|^2$近似于语音短时谱的包络,即共振峰结构。LPC谱包络是离散的,可通过以下方式获得更平滑的连续估计:
- 在$A(z)$的根中提取复共轭对,转换为二阶节形式,计算每个二阶节的频率响应并相乘。
- 更常用的是计算**LPC倒谱**(Cepstrum):对$log|H(e^{j\omega})|$进行逆傅里叶变换。倒谱域中,低阶倒谱系数(如前12-16阶)主要表征谱包络(共振峰),高阶系数表征细节(如基频周期激励)。LPC倒谱系数可通过LPC系数递归计算,是MFC