📚 知识回顾:傅里叶变换基础
在开始音频变速实验之前,让我们先回顾数字信号处理中的核心工具——傅里叶变换。本实验将大量使用DFT和FFT,理解它们的原理对掌握音频变速技术至关重要。
1. 离散傅里叶变换 (DFT)
DFT 正变换(时域 → 频域):
$$X[k] = \sum_{n=0}^{N-1} x[n] e^{-j\frac{2\pi}{N}kn}, \quad k=0,1,\ldots,N-1$$
DFT 反变换(频域 → 时域):
$$x[n] = \frac{1}{N}\sum_{k=0}^{N-1} X[k] e^{j\frac{2\pi}{N}kn}, \quad n=0,1,\ldots,N-1$$
DFT将时域的离散信号 $x[n]$ 转换为频域的频谱 $X[k]$。频谱包含两个信息:
- 幅度 $|X[k]|$:表示各频率成分的强度
- 相位 $\angle X[k]$:表示各频率成分的初始相位
可以写成极坐标形式:$X[k] = |X[k]| e^{j\angle X[k]}$
2. 快速傅里叶变换 (FFT)
FFT是DFT的快速算法,通过分治策略将计算复杂度从 $O(N^2)$ 降低到 $O(N\log N)$。在实际应用中,我们总是使用FFT来计算DFT。
MATLAB的 fft() 和 ifft() 函数就是FFT算法的实现,它们计算的结果和DFT完全相同,只是速度更快。
3. 时频对偶关系 ⚡
这是理解音频变速的核心!
- 时域拉伸(信号变长)→ 频域压缩(频率变低)
- 时域压缩(信号变短)→ 频域拉伸(频率变高)
4. 短时傅里叶变换 (STFT)
对于长音频信号,我们需要分析其时变的频谱。STFT的思想是:
第1步:分帧
将长信号分成若干短帧,每帧长度为 $N$ 个采样点。
第2步:加窗
对每帧乘以窗函数(如汉明窗),减少边界效应。
第3步:FFT
对每一帧加窗后的信号进行FFT,得到该帧的频谱。
第4步:组合
所有帧的频谱组成 $N \times M$ 的频谱矩阵。
STFT的数学表达:
第 $n$ 帧,第 $k$ 个频率分量的频谱为:
$$X[n,k] = A[n,k] e^{j\varphi[n,k]}$$
其中 $A[n,k]$ 为幅度,$\varphi[n,k]$ 为相位,$n$ 为帧索引,$k$ 为频率索引。
音频信号是非平稳的——不同时刻的频率成分不同。STFT通过分帧,让我们能够看到时间-频率的二维分布,这是音频变速的基础。
📋 实验概述
音频信号的时间压缩或扩展,也称为"时间拉伸(Time Stretching)",是音高转换的倒数过程。它在改变速度(节奏)的同时保持信号音高不变。
如何改变音频的播放速度,同时保持音高不变?
举例:将一段2分钟的语音拉伸为4分钟,说话速度变慢一半,但音调不变(不能变成"低沉的声音")。
三阶段递进学习
本实验采用三阶段递进式学习,逐步揭示音频变速的正确方法:
🔴 第一阶段:时域插值
直观但错误的方法——时域拉伸会导致频率改变
🟢 第二阶段:频域插值
正确的方法——在频域进行变速可保持音高
🟠 第三阶段:相位声码器
进阶方法——消除帧间不连续性,获得更高音质
🔴 第一阶段思考:时域插值
最直观的想法是:直接在时域对信号进行插值来改变信号长度。比如,要把音频拉伸2倍,就在每两个采样点之间插入一个新的点。
💭 直觉想法
将100点的信号插值成200点的信号,播放时间变为原来的2倍,音频就"变慢"了。
时域插值的问题
从时间轴上看,信号被拉长了2倍,原始音频约5秒,拉伸后接近10秒,且波形相似。但是聆听拉伸后的音频会发现在音高(频率)上变低了,而这是我们不希望发生的。
图1:时域插值对比——拉伸导致周期加倍,频率减半
设有原始正弦信号 $\sin(\omega t)$,时长为 $L$。经过插值后,时间上具有 $2L$ 个点,但从频率来看为原来的 $1/2$。
$$\text{时间长度} \times \text{频率} = \text{常数}$$
拉伸2倍 → 时间×2 → 频率÷2 → 音高降低!❌
图2:频谱对比——简单时域插值/抽取改变了主频率位置
由于时间和频率成反比的关系,我们无法通过直接改变音频时长而得到理想结果。必须采用更高级的信号处理技术!
🟢 第二阶段思考:频域插值
既然时域插值会改变频率,那我们可以换一个思路:先变换到频域,在频域上进行操作,再变换回时域。
频域插值的思路
- 将时域信号分帧,对每帧进行FFT得到频谱
- 在频域上对频谱进行插值或抽取
- 对修改后的频谱进行IFFT
- 得到拉伸后的时域信号,频率成分保持不变 ✓
图3:时域插值 vs 频域插值——频域方法保持了原始频率成分
💡 为什么频域插值有效?
在频域进行2倍抽取(每隔一个点取一个),得到的IFFT结果长度变为原来的一半,但频率成分不变。要得到2倍长的信号,可以通过频域2倍插值(在频点之间插入零值后进行适当处理)。
频域插值的局限
虽然频域插值能够保持音高,但它也有一个问题:相邻帧之间可能产生不连续。
由于每帧独立处理FFT/IFFT,相邻帧在边界处的相位可能不匹配,导致杂音。
🟠 第三阶段思考:相位声码器
相位声码器(Phase Vocoder,简称PV)的概念由 Flanagan 和 Golden 于 1966年 提出,是音频信号处理领域的重要里程碑。
PV核心思想
相位声码器的解决方法就是通过调整相位使得帧和帧之间的频率值无缝衔接。让我们深入理解这个过程:
图4:相位声码器的相位关系分析——展示如何从相邻帧相位计算实际频率
📐 相位关系详解
上半部分:灰色正弦曲线表示原始音频信号的第 $k$ 个频率分量 $\Omega$。$t_1$ 和 $t_2$ 时刻分别是两帧信号的起始点。
时间间隔:两帧之间的时差是 $\Delta t = R_a / F_s$,其中 $R_a$ 是帧移(采样点数),$F_s$ 是采样频率。
下半部分(单位圆):用极坐标直观展示相位角。理论上 $\varphi_2 = \varphi_1 + \Omega\Delta t$,但由于FFT频率分辨率有限,存在误差 $\varphi_{Err}$。
数学推导
步骤1:理论相位递进关系
$$\varphi_2 = \varphi_1 + \Omega\Delta t$$
如果信号是纯正弦波且频率恰好落在FFT频点上,这个关系精确成立。
步骤2:实际相位关系(考虑FFT误差)
$$\varphi_2 = \varphi_1 + \Omega\Delta t + \varphi_{\text{Err}}$$
由于实际频率可能偏离FFT频点,产生相位误差。
步骤3:从相位误差反推频率偏移
$$\Delta\omega = \frac{\varphi_{\text{Err}}}{R_a}$$
相位误差除以帧移时间,得到频率修正量。
步骤4:计算实际角频率
$$\omega = \Omega + \Delta\omega$$
FFT频点频率加上修正量,得到更精确的瞬时频率。
步骤5:输出相位更新
$$\varphi_{\text{out}} = \varphi_{\text{out}} + \omega \cdot R_s$$
用实际频率和新的帧移 $R_s$ 计算输出相位,实现平滑过渡。
由于我们需要用第1、2帧的误差来预测第0帧,以此类推,所以在实验中,我们的计算结果比原始数据少两列。
频域插值法 vs 相位声码器
| 对比项 | 频域插值法 | 相位声码器 |
|---|---|---|
| 修改对象 | 频谱幅度和相位 | 只修改相位,保留幅度 |
| 实现复杂度 | 简单(使用interp1) | 复杂(需要相位展开) |
| 音质 | 较好 | 更好(无帧间杂音) |
| 适用场景 | 基础任务 | 进阶任务,追求高质量 |
⚙️ 音频变速完整流程
依据上述音频变速原理搭建的音频变速器示意图如下所示:
图5:音频变速完整处理流程
🔄 处理流程动态展示
原始音频信号
输入待处理的音频信号 x[n]
分帧处理
将信号分成重叠的短帧,定义帧长和帧移
加窗处理
对每帧乘以汉明窗,减少频谱泄漏
频谱分析
对每帧信号进行FFT,得到频谱矩阵
改变频谱
使用频域插值法或相位声码器修改频谱
反变换
对修改后的频谱进行IFFT,得到时域帧
重叠相加
对时域帧加窗后按新帧移叠加重建
详细步骤解析
1. 分帧 (Frame)
分帧的概念和上一次实验中分割信号的目的相同,都是为了获取更好的结果。但和上次实验的区别是,本次分帧涉及到重叠(Overlap)。
100点序列以20点帧长进行分段:
- 无重叠:第1段: 1-20,第2段: 21-40,第3段: 41-60...
- 有重叠:第1段: 1-20,第2段: 5-24 或 10-29...
帧移(Hop Size) $R_a$:两帧信号之间的距离,通常在帧长的 25%~75%
图6:不同帧移对信号长度的影响(展示重叠分帧原理)
这种仅通过改变帧移来实现变速的方法,和我们第一阶段的思考是类似的,都可能导致频率成分的重叠、失真或不连续性。因此需要配合频域插值或相位声码器使用。
2. 加窗 (Windowing)
分帧以后,我们还需要对每一帧信号作加窗处理。窗函数的作用是削弱帧的两端,使得在分析处理时得到的频谱图更加准确。
图7:时域信号 × 汉明窗 = 加窗后信号(汉明窗公式:$w[n] = 0.54 - 0.46\cos(2\pi n/N)$)
通过加窗,之前帧的频率分量与当前帧的融合由于尾端削弱而更加平滑,减少了频谱泄漏和不连续性。
图8:重叠相加(OLA)示意 - 加窗使相邻帧平滑融合
3. FFT 频谱分析
短时频谱表示:
$$x[n] = \sum_{k_r=1}^{I[n]} A[n,k_r]e^{j\varphi_a[n,k_r]}, \quad n \geq 0$$
式中 $A[n,k]$ 为第 $n$ 帧第 $k$ 频率的幅度,$\varphi_a[n,k]$ 为相位。
4. 改变频谱
方法1: 频域插值法
通过 MATLAB 的 interp1 函数对频率进行插值。
✓ 简单易实现
方法2: 相位声码器
保留频谱幅度不变,只改变相位。
✓ 音质更好
5. 反变换 (IFFT)
修改后的频谱需要经过 IFFT 重新得到时间信号。
6. 重建 (OLA - Overlap-Add)
重建的过程是经过反变换的时间信号再次进行加窗后依序叠加。
- 频域插值法:使用原始帧移 $R_a$
- 相位声码器:使用变速后的帧移 $R_s$
🧪 实验任务
本项目要求完成基于频域插值和相位声码器的音频变速系统的MATLAB实现。根据代码中的提示填写标记为?的部分。
📁 核心文件
🎯 ex0_synthesize_all.m
主函数,调用其他模块
📝 ex1-ex6.m
6个处理模块
✅ test_Project2.p
自动批改程序
🚀 实验步骤
- 仔细阅读本手册,理解音频变速的整体流程
- 将所有实验文件放在同一目录,设置MATLAB当前文件夹
- 按顺序完成ex1到ex5(基础),ex6为进阶
- 运行test_Project2.p检查各模块正确性
- 运行ex0_synthesize_all.m观察完整流程
- 获得加密成绩,压缩为【学号_姓名.zip】提交
- ✅ 可以小组合作(不超过6人),但每人需独立提交
- ⏰ 必须在实验课结束前完成并提交
- 💡 鼓励在理解原理的基础上自己编写代码
本实验旨在加深对音频时频处理和相位声码器原理的理解。请确保理解每一行代码的含义。
📝 总结
通过本实验,我们深入理解了音频变速的原理和实现方法:
- DFT/FFT基础:回顾了时频分析的核心工具
- 时频对偶关系:理解了为什么简单插值会失败
- 频域插值法:学会了在频域保持音高的方法
- 相位声码器:掌握了消除帧间不连续的高级技术
- STFT处理流程:熟悉了分帧、加窗、FFT、修改、IFFT、OLA的完整流程
音频变速技术在现实中有广泛应用:视频播放器的倍速播放、音乐制作中的节奏调整、语音合成和变声效果、DJ设备中的实时音频处理等。