语音的合成和分解 enframe和overlapadd 用法

语音的常用处理就是分帧,分帧,fft变换,做一些处理,然后反变换回到时域。

这里面常用到的就是enframe 和 overlapadd

enframe分帧,我想大家都很熟悉了,这里不再介绍,overlapadd具体含义可以看这篇文章

STFT使用overlap-add重建信号_u010592995的专栏-CSDN博客_overlap

上面这篇文章介绍的很清楚。

一、问题的引入

Description of v_overlapadd

voicebox 中给出了一个example

其实这里面就是一个简单的分解和合成,按此我们可以补充一些代码完成信号的分帧处理

这里面核心部分就是enframe和overlapadd,比较奇怪的就是W做的归一化,这个归一化有些奇怪,是平方归一化,另外是hamming用的periodic,

二、hamming的 'periodic' 选项,其实这个是针对 ‘symmetric‘

matlab给的解释:大致含义就是 在做 FIR滤波器设计时候,需要共轭对称,那么使用 symmetric 选项,在做DFT/FFT的时候,用periodic

我们看下他们的不同:

同样的长度下,symmetric  完全共轭对称(这里是实数,没有虚数,或者虚部为零),头尾一样

periodic更符合DFT的频谱特性

上面比较接近一个实序列的FFT的幅度谱的排列方式,即第一个数,DC分量(直流)单独为一块(没人和它对称),完了其余的头尾对称,中间单独(自己和自己对称,奇数N的FFT不存在)

且窗函数hamming,不一定只用于时域,在频域上也会使用的,那么这个这个periodic更适合频域上的窗,当然用于fft的时候

二、 W的归一化方式

归一化方式是平方和,是因为 信号经过了两次 窗函数,一次是在分解的时候(enframe),一次是在重构的时候(overalapadd),W具有平方特性下的归一:

且刚好是头半个窗乘完之后还要乘一遍,尾部也是同样,本文 三 中代码部分已经描述

OV=2;                               % overlap factor of 2 (4 is also often used)
INC=512;                            % set frame increment in samples
NW=INC*OV;                          % DFT window length

W=sqrt(hamming(NW,'periodic'));     % omit sqrt if OV=4
W=W/sqrt(sum(W(1:INC:NW).^2));      % normalize window


W1 = zeros(1024*10,1);
W2 = zeros(1024*10,1);
W3 = zeros(1024*10,1);
W4 = zeros(1024*10,1);
W1([1:1024]) = W;
W2([1+512:1024+512]) = W;
W3([1+512*2:1024+512*2]) = W;
W4([1+512*3:1024+512*3]) = W;
W_total = W1+W2+W3+W4;
plot(W_total);

W_total = W1.^2+W2.^2+W3.^2+W4.^2;
plot(W_total);

W=W/sqrt(sum(W(1:INC:NW).^2));  后面 W(1) W(1+INC)这两个点的和(交叠,每一个横轴点,用了头和两尾两个点,可以参考下图,如果用了OV=4,那就是四个点相加),恰好都是固定值,每个点都要除以这个倍数,

其他点值都一样,这归根到底是hanning或者hamming窗都是sin 系列的窗,推迟pi/2相位变成cos

sinx*sinx + cosx*cosx ==1,平方能量和总是固定值,其他窗(三角,矩形)应该不满足这个特性

stft的时候,这个数据会用两遍(因为overlap分属不同的帧)

[1 2 3 4 5 6...] *  win( cos)  ,[1 2 3 4 5 6...] *  win( sin) 

在istft的时候,也会再计算两遍,然后做和

[1 2 3 4 5 6...] *  win( cos)  ,[1 2 3 4 5 6...] *  win( sin) 

刚好就是 [12 3 4 56] * (cos^2 + sin^2)

三,整理出来的代码:

整理一下代码吧,如果对模块不熟悉,还是调用enframe和overlapadd函数,现在既然已经知道了这俩函数的根本含义,直接就自己写好了

如果是对静态的文件做处理,那么直接enframe和overlapadd就可以了,现在如果是需要实时的每一帧都要输出结果,那么得考虑下面的写法了:

重构信号 = 信号前半部分*窗的前半部分 + 遗留的上一帧的后半部分*窗的后半部分

S =double(S);
output =[];

for i = 1:nframe-1
    % 步进长度,inc
    loc_data = S([1+(i-1)*INC:1024+(i-1)*INC]).* W;
    
    loc_fft = fft(loc_data);

  % 这里写你要干的操作
    loc_data = ifft(loc_fft);
    
    half_data1 = last_frame_data([513:1024]) .*  half_right_W;
    half_data2 = loc_data([1:512]) .*  half_left_W;
    half_result = half_data1 + half_data2;
    
    last_frame_data = loc_data;
    output = [output;half_result];
end

四、用一个wav信号进行测试:

左边:原始:

右边:重构

其实除了第一帧和最后一帧以外,信号完美重构回去了

猜你喜欢

转载自blog.csdn.net/book_bbyuan/article/details/110133733