语音的常用处理就是分帧,分帧,fft变换,做一些处理,然后反变换回到时域。
这里面常用到的就是enframe 和 overlapadd
enframe分帧,我想大家都很熟悉了,这里不再介绍,overlapadd具体含义可以看这篇文章
https://blog.csdn.net/u010592995/article/details/81001751
上面这篇文章介绍的很清楚。
一、问题的引入
http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/mdoc/v_mfiles/v_overlapadd.html
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,平方能量和总是固定值,其他窗(三角,矩形)应该不满足这个特性
三,整理出来的代码:
整理一下代码吧,如果对模块不熟悉,还是调用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信号进行测试:
左边:原始:
右边:重构
其实除了第一帧和最后一帧以外,信号完美重构回去了