【数字信号处理】MATLAB OLA(Overlap-Add)实现变调不变速/变速不变调

最近在做数字信号处理实验的大作业~发现很多变调不变速/变速不变调的文章都讲的没有很清楚,记录一下自己看了很多文章之后整理的思路。

最终大作业
【【科技】 MATLAB鬼畜之小狗唱歌 | |数字信号处理实验大作业-哔哩哔哩】

第一步:分帧加窗

分帧加窗

分帧:

设每一帧长度为 N N N个点,总长度为 L L L个点
每一帧与前一帧有 H a H_a Ha个点的非重叠部分,这个 H a H_a Ha并不大。
设原信号为y,则第n帧信号取自
y ( ( ( n − 1 ) × H a ) : ( ( n − 1 ) × H a + N − 1 ) ) y( ((n-1)\times H_a):((n-1)\times H_a+N-1)) y(((n1)×Ha):((n1)×Ha+N1))
比如第一帧就是 y ( 1 : N ) y(1:N) y(1:N),第二帧就是 y ( H a : H a + N − 1 ) y(H_a:H_a+N-1) y(Ha:Ha+N1)

如果我们把信号按一模一样的方式重组,设重组完的信号为 y 1 y_1 y1,即将第一帧按顺序填入 y 1 ( 1 : N ) y_1(1:N) y1(1:N),第二帧填入 y 1 ( H a : H a + N − 1 ) y_1(H_a:H_a+N-1) y1(Ha:Ha+N1),整体信号信息不会发生变化,只是幅度有变,但没有大的影响。

如果重组时微调非重叠部分的间距,信号信息也不会有很大的改变,只是声音速度变慢了,但频率不变,所以通过改变重组时的非重叠部分可以改变速度,实现变速不变调。

加窗:

如果直接按分好的帧重组,相当于给原信号加了一个矩形窗,会造成一些频谱泄露,影响输出信号的效果,所以加一个汉宁窗~

代码:(enframe为MATLAB的voicebox中一个函数,可以实现很方便的分帧加窗~,这里加了一个汉宁窗,以减少频谱泄露的影响,)

第二步:调整非重叠部分长度

调整非重叠部分长度
前文提到,调整非重叠部分长度对信号信息没有很大影响,但可以调整速度。所以我们在重组信号时调整好非重叠部分长度就可以实现调整速度了~

function [Y,Fs] = speedchange(y,fs,alpha)
L=length(y);%音频信号长度
N=0.05*fs;%取50ms为每一帧的长度
N=floor(N);
Ha=floor(N*0.25);
Hs=floor(Ha*alpha);
%给定synthesis hopsize-Hs和α来确定analysis hopsize-Ha
tempy=enframe(y,hanning(N),Ha);%分帧加窗,得到每一帧的系数
%Ha为分帧加窗时非重叠部分点数,Hs为重组成新的信号时的非重叠部分点数
%加汉宁窗,减弱音爆(矩形窗会有更严重的信号突变)
nf=fix((L-N+Ha)/Ha);%帧数
y1=zeros(1,(nf-1)*Hs+N);%构造输出信号,新建一个0矩阵用于存放输出信号
%总时长(nf-1)*Hs+N=((L-N+Ha)/Ha-1)*Hs+N=(L-N)*Hs/Ha+N=(L-N)*alpha+Hs
y1(1:N)=tempy(1,:);%第一帧加入输出信号中
for i=1:nf-1
    y1(1+i*Hs:i*Hs+N)=y1(1+i*Hs:i*Hs+N)+tempy(i+1,1:N);%重组成输出信号
end
%用OLA法得到输出信号
Y=y1;
Fs=fs;
end

系数 α \alpha α与最终信号时间的关系推导:
帧数 n f = ( L + H a − N ) / H a n_f=(L+H_a-N)/H_a nf=(L+HaN)/Ha
重组完的信号点数
L 2 = ( n f − 1 ) ∗ H s = [ ( L + H a − N ) / H a − 1 ] × H s + N = ( L − N ) / H a × H s + N = ( L − N ) × α + N ≈ α L L2=(n_f-1)*H_s=[(L+H_a-N)/H_a-1]\times H_s +N=(L-N)/H_a\times H_s+N=(L-N) \times \alpha +N \approx \alpha L L2=(nf1)Hs=[(L+HaN)/Ha1]×Hs+N=(LN)/Ha×Hs+N=(LN)×α+NαL

就可以实现变速不变调啦~

变调不变速只需要改变采样频率重采样即可~可以使用resample函数改变采样率。

↓将采样率为Fs的音频采样率改为fs

Y=outwav;
Fs=fs*alpha;
[P,Q] = rat(fs/Fs);
Y = resample(Y,P,Q);
Fs=fs;

有兴趣的朋友也可以看看相位声码器

  • 11
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
OLAOverlap-Add)算法是一种常见的音频信号变速算法。下面是 MATLAB 实现 OLA 算法的基本步骤: 1. 对输入的音频信号进行分帧处理,每一帧的长度为 N。 2. 在每一帧之间进行重叠处理,即取相邻两帧的交叠部分,长度为 L(通常 L = N/2)。 3. 对于每一帧,进行 FFT 变换,得到频域的表示。 4. 计算变速因子 s,根据 s 计算每一帧应该占据的时间长度 M。 5. 对每一帧的频域表示进行插值或者抽样操作,得到新的频域表示,使得每一帧占据的时间长度为 M。 6. 对每一帧的频域表示进行 IFFT 变换,得到时域的表示。 7. 对于相邻两帧的交叠部分,进行叠加和平均处理,得到重叠部分的输出。 8. 对于每一帧的输出,输出一段长度为 M 的信号。 下面是一个简单的 MATLAB 代码实现 OLA 音频变速算法: ```matlab % 读取音频文件 [x, fs] = audioread('input.wav'); % 设置变速因子 s = 1.5; % 计算每一帧的长度和重叠长度 N = 1024; L = N/2; % 计算每一帧应该占据的时间长度 M = round(N/s); % 初始化输出信号 y = zeros(length(x)/s, 1); % 遍历每一帧 for i = 1:M:length(x)-N % 取一帧数据 x_frame = x(i:i+N-1); % 进行 FFT 变换 X = fft(x_frame); % 对频域表示进行插值或者抽样 Y = interp1(linspace(0, 1, N), X, linspace(0, 1, M)); % 进行 IFFT 变换 y_frame = ifft(Y); % 对相邻两帧的重叠部分进行叠加和平均处理 y(i+1:i+L) = (y(i+1:i+L) + y_frame(1:L))./2; % 输出一段长度为 M 的信号 y(i+L+1:i+L+M) = y_frame(L+1:end); end % 将输出信号保存为音频文件 audiowrite('output.wav', y, fs); ``` 上述代码仅是一个简单的实现,实际应用中可能需要考虑更多的细节和优化方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值