基于相位声码器的时间拉伸 (Phase Vocoder Time Stretching)
项目2提供实验文件如下:
📁 项目文件夹 ├── 📁 audio/ │ └── 🎵 orig.wav ├── 📄 README.MD ├── 📝 ex0_synthesize_all.m ← 主函数(无需修改) ├── 📝 ex1_frame_signal.m ← 信号分帧 ├── 📝 ex2_window_signal.m ← 加窗处理 ├── 📝 ex3_compute_spectrum.m ← 频谱计算 ├── 📝 ex4_modify_STFT.m ← 频域插值法(基础) ├── 📝 ex5_reconstruct_signal.m ← 信号重建 ├── 📝 ex6_Phase_Vocoder.m ← 相位声码器(进阶) ├── 🔒 test_project2.p ← 加密测试文件 └── 📋 音频变速实验手册.html
? 标记的地方需用合适的代码替换audio 文件夹与 .m 文件在同一目录test_project2.p 文件test_project2.p 文件20230001_张三.zip)test_project2.p 对于每个 ex 的批改是独立的audio 文件夹下提供了测试音频ex0_synthesize_all.m 尝试其他音频功能:调用所有子函数完成完整的音频变速流程(无需修改)
参数设置
Lwin = 1024 - 帧长(窗函数大小)Ra = 256 - 分析帧移factor = 1.5 - 拉伸因子(>1 拉伸,<1 压缩)method = 'interp' - 方法选择('interp' 或 'pv')函数签名
function frames = ex1_frame_signal(x, Lwin, Ra)
功能说明
将输入音频信号分成若干重叠的帧。每帧长度为Lwin,相邻帧之间的起始位置相差Ra(帧移)。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
x |
向量 | 输入音频信号 |
Lwin |
整数 | 帧长(如1024) |
Ra |
整数 | 帧移(如256) |
| 输出 | ||
frames |
矩阵 | 分帧后的信号 [Lwin × numFrames] |
函数签名
function windowed = ex2_window_signal(frames, Lwin)
功能说明
对分帧后的信号施加Hann窗,减少频谱泄露。窗函数使帧边界平滑过渡到零。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
frames |
矩阵 | 分帧后的信号 |
Lwin |
整数 | 帧长 |
| 输出 | ||
windowed |
矩阵 | 加窗后的帧 [Lwin × numFrames] |
hann(Lwin) 生成Hann窗,与每帧逐点相乘(点乘 .*)
函数签名
function spectrum = ex3_compute_spectrum(windowed)
功能说明
对每一帧加窗后的信号进行FFT,得到复数频谱矩阵。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
windowed |
矩阵 | 加窗后的帧 |
| 输出 | ||
spectrum |
复数矩阵 | FFT频谱 [Lwin × numFrames] |
fft() 对每列进行傅里叶变换
函数签名
function newSpectrum = ex4_modify_STFT(spectrum, factor)
功能说明
使用频域插值法修改频谱,实现时间拉伸。通过对帧进行插值改变帧数。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
spectrum |
复数矩阵 | 原始频谱 |
factor |
标量 | 拉伸因子 |
| 输出 | ||
newSpectrum |
复数矩阵 | 插值后的频谱 |
interp1() 对每个频率bin进行插值函数签名
function y = ex5_reconstruct_signal(spectrum, Lwin, Rs)
功能说明
使用OLA(Overlap-Add)方法重建时域信号。对每帧频谱进行IFFT,加窗后按帧移叠加。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
spectrum |
复数矩阵 | 修改后的频谱 |
Lwin |
整数 | 帧长 |
Rs |
整数 | 合成帧移 |
| 输出 | ||
y |
向量 | 重建的时域信号 |
ifft(..., 'symmetric') 确保输出为实数函数签名
function newSpectrum = ex6_Phase_Vocoder(spectrum, Ra, Rs, Lwin)
功能说明
使用相位声码器方法修改频谱。保持幅度不变,通过相位调整实现帧间连续。
| 参数 | 类型 | 说明 |
|---|---|---|
| 输入 | ||
spectrum |
复数矩阵 | 原始频谱 |
Ra |
整数 | 分析帧移 |
Rs |
整数 | 合成帧移 |
Lwin |
整数 | 帧长 |
| 输出 | ||
newSpectrum |
复数矩阵 | 相位调整后的频谱 |
在提交前,请确认:
? 都已替换为正确代码test_project2.p 输入1-5全部通过ex0_synthesize_all.m 能够正常执行Q1: 频域插值法和相位声码器有什么区别?
A:
Q2: 为什么要使用 ifft(..., 'symmetric')?
A: 这个选项告诉MATLAB输入满足共轭对称性,输出应该是纯实数。这避免了由于数值误差产生的小虚部。
Q3: 相位展开公式 mod(Δφ+π, 2π)-π 是什么意思?
A: 相位具有2π周期性,这个公式将任意相位差归一化到 [-π, π] 范围内,避免相位跳变。
Q4: 如何调试代码?
A: 使用以下调试方法:
1. 检查维度
% 分帧后应该是 [Lwin × numFrames]
size(frames)
% 频谱矩阵应该是复数
whos spectrum
2. 可视化调试
% 查看频谱幅度
imagesc(abs(spectrum));
colorbar;
title('STFT幅度谱');
% 对比原始和重建波形
figure;
subplot(2,1,1); plot(x(1:5000)); title('原始');
subplot(2,1,2); plot(y(1:5000)); title('重建');
3. 听音频结果
% 播放原始音频
sound(x, fs);
% 播放变速后音频
sound(y, fs);
通过本实验,你将掌握: