← 返回实验主页

🎵 DSP 项目2 说明 - 音频变速实验

基于相位声码器的时间拉伸 (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

文件说明


🔄 项目流程

1️⃣ 阅读实验手册

2️⃣ 设置MATLAB环境

3️⃣ 完成代码编写

基础任务:完成 ex1 - ex5,实现基于频域插值的音频变速
进阶任务:完成 ex6,实现相位声码器方法(可选)

4️⃣ 使用测试文件检查

a) 运行测试程序

b) 检查各个模块

c) 查看结果

5️⃣ 完成所有代码后提交实验

a) 生成加密成绩

b) 压缩文件

c) 提交到学习通


⚠️ 项目备注

📌 重要提醒

  1. 截止时间
    • 学习通成绩提交截止本次实验课结束
    • 所有内容当堂完成,不可延期
  2. 分组要求
    • 分组完成,每组不超过 6 人
  3. 独立提交
    • 在学习通提交成绩需要独立完成
    • 成绩按人次给分
  4. 模块独立批改
    • test_project2.p 对于每个 ex 的批改是独立的
    • 如果有无法完成的部分可以跳过
    • ex6(相位声码器)为进阶任务,可选完成
  5. 音频文件说明
    • 项目中 audio 文件夹下提供了测试音频
    • 完成代码后可修改 ex0_synthesize_all.m 尝试其他音频

📚 实验模块说明

📌 ex0_synthesize_all.m - 主函数

功能:调用所有子函数完成完整的音频变速流程(无需修改)

参数设置


1️⃣ ex1_frame_signal - 信号分帧

函数签名

function frames = ex1_frame_signal(x, Lwin, Ra)

功能说明

将输入音频信号分成若干重叠的帧。每帧长度为Lwin,相邻帧之间的起始位置相差Ra(帧移)。

参数 类型 说明
输入
x 向量 输入音频信号
Lwin 整数 帧长(如1024)
Ra 整数 帧移(如256)
输出
frames 矩阵 分帧后的信号 [Lwin × numFrames]
💡 关键公式:

2️⃣ ex2_window_signal - 加窗处理

函数签名

function windowed = ex2_window_signal(frames, Lwin)

功能说明

对分帧后的信号施加Hann窗,减少频谱泄露。窗函数使帧边界平滑过渡到零。

参数 类型 说明
输入
frames 矩阵 分帧后的信号
Lwin 整数 帧长
输出
windowed 矩阵 加窗后的帧 [Lwin × numFrames]
💡 提示:使用 hann(Lwin) 生成Hann窗,与每帧逐点相乘(点乘 .*

3️⃣ ex3_compute_spectrum - 频谱计算

函数签名

function spectrum = ex3_compute_spectrum(windowed)

功能说明

对每一帧加窗后的信号进行FFT,得到复数频谱矩阵。

参数 类型 说明
输入
windowed 矩阵 加窗后的帧
输出
spectrum 复数矩阵 FFT频谱 [Lwin × numFrames]
💡 提示:使用 fft() 对每列进行傅里叶变换

4️⃣ ex4_modify_STFT - 频域插值法 基础

函数签名

function newSpectrum = ex4_modify_STFT(spectrum, factor)

功能说明

使用频域插值法修改频谱,实现时间拉伸。通过对帧进行插值改变帧数。

参数 类型 说明
输入
spectrum 复数矩阵 原始频谱
factor 标量 拉伸因子
输出
newSpectrum 复数矩阵 插值后的频谱
💡 关键步骤:
  1. 计算新帧数 = floor(原帧数 × factor)
  2. 使用 interp1() 对每个频率bin进行插值
  3. 重建时使用原始帧移Ra

5️⃣ ex5_reconstruct_signal - 信号重建

函数签名

function y = ex5_reconstruct_signal(spectrum, Lwin, Rs)

功能说明

使用OLA(Overlap-Add)方法重建时域信号。对每帧频谱进行IFFT,加窗后按帧移叠加。

参数 类型 说明
输入
spectrum 复数矩阵 修改后的频谱
Lwin 整数 帧长
Rs 整数 合成帧移
输出
y 向量 重建的时域信号
💡 关键步骤:
  1. 输出长度 = (帧数-1) × Rs + Lwin
  2. 对每帧:IFFT → 加窗(Hamming) → 叠加到输出
  3. 使用 ifft(..., 'symmetric') 确保输出为实数

6️⃣ ex6_Phase_Vocoder - 相位声码器 进阶

函数签名

function newSpectrum = ex6_Phase_Vocoder(spectrum, Ra, Rs, Lwin)

功能说明

使用相位声码器方法修改频谱。保持幅度不变,通过相位调整实现帧间连续。

参数 类型 说明
输入
spectrum 复数矩阵 原始频谱
Ra 整数 分析帧移
Rs 整数 合成帧移
Lwin 整数 帧长
输出
newSpectrum 复数矩阵 相位调整后的频谱
🔬 相位声码器核心公式:
  1. 理论角频率:Ω(k) = 2πk / Lwin
  2. 相位差:Δφ = φ_current - φ_prev - Ω × Ra
  3. 相位展开:Δφ_wrapped = mod(Δφ + π, 2π) - π
  4. 频率偏移:Δω = Δφ_wrapped / Ra
  5. 真实频率:ω_true = Ω + Δω
  6. 输出相位累积:φ_out = φ_out + ω_true × Rs

✅ 检查清单

在提交前,请确认:


📞 常见问题

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);

🎯 学习目标

通过本实验,你将掌握:

  1. STFT(短时傅里叶变换)的原理和实现
  2. 时频对偶关系的理解
  3. 频域插值法实现音频变速
  4. 相位声码器的核心原理(进阶)
  5. OLA(重叠相加)信号重建方法
  6. 音高保持的时间拉伸技术

祝实验顺利! 🎵🎉