语音信号的同态处理、倒谱分析和Mel频率倒谱系数

1 同态处理

信号的同态处理也称同态滤波。大概步骤为:

f(x,y)→ln→DFT→H(u,v)→(DFT)-1→exp→g(x,y)

虽然,一般用于图像处理。但是,博主将同态滤波用于语音信号的滤波。直接上程序吧

clc;clear
%%
filedir=[];                             % 指定文件路径
filename='bluesky3.wav';                % 指定文件名
fle=[filedir filename]                  % 构成路径和文件名的字符串
[xx,fs]=audioread(fle);                   % 读入数据文件
xx=xx-mean(xx);                         % 消除直流分量
x=xx/max(abs(xx));                      % 幅值归一化
SNR=5;                                  % 设置SNR
I=Gnoisegen(x,SNR);                % 叠加噪声
N=length(x);                            % 信号长度
time=(0:N-1)/fs;                        % 设置时间

%%
%同态滤波
[M,N]=size(I);  
rL=0.2;  
rH=7.7;%可根据需要效果调整参数  
c=2;  
d0=10;  
I1=log(I+1);%取对数  
FI=fft2(I1);%傅里叶变换  
n1=floor(M/2);  
n2=floor(N/2);  
for i=1:M  
    for j=1:N  
        D(i,j)=((i-n1).^2+(j-n2).^2);  
        H(i,j)=(rH-rL).*(exp(c*(-D(i,j)./(d0^2))))+rL;%高斯同态滤波  
    end  
end  
I2=ifft2(H.*FI);%傅里叶逆变换  
output=real(exp(I2))-1; 
%%
% 作图
subplot 311; plot(time,xx,'k'); ylabel('幅值') 
ylim([-1 1 ]); title('原始语音信号');
subplot 312; plot(time,I,'k'); ylabel('幅值') 
ylim([-1 1 ]); title('带噪语音信号');
subplot 313; plot(time,output,'k'); 
ylim([-1 1 ]); title('同态滤波输出语音信号');
xlabel('时间/s'); ylabel('幅值')
结果

       当语音信号加入信噪比为5的高斯白噪声之后,得到了带噪语音信号,经过同态滤波之后,虽然达不到完全滤波,但是跟带噪语音相比,达到了降噪效果。这里,博主并未对语音信号进行分帧,之前试过,效果都差不多,最后还需要把分帧后的信号进行整合。语音信号与图像信号不同之处在于前者是一维,后者是二维。博主之前从电影上面剪下一段语音,来进行语音处理,但是发现无法处理。这是因为剪下来的语音的双声道,而我们一般处理的语音信号都是单声道,所以博主最后用Goldwave软件,将双声道语音变为单声道。


2 倒谱分析

                                                                                            (1)

序列c(n)是x(n)对数幅值谱的逆傅立叶变换,称做倒频谱,简称倒谱。这里,c(n)的量纲是Quefrency,又被称做倒频,它实际的单位还是时间的单位。

       例子:从su1.txt中读入语音信号,信号采样频率是16000Hz,要求如下:

a.按照公式(1)计算信号的倒谱;

b.把语音的声门激励信号和声道冲激响应分离,分别计算相应的频谱。

clear all; clc; close all;
y=load('su1.txt');                            % 读入数据
fs=16000; nfft=1024;                          % 采样频率和FFT的长度
time=(0:nfft-1)/fs;                           % 时间刻度
figure(1), subplot 211; plot(time,y,'k');     % 画出信号波形
title('信号波形'); axis([0 max(time) -0.7 0.7]);
ylabel('幅值'); xlabel(['时间/s' 10 '(a)']); grid;
figure(2)
nn=1:nfft/2; ff=(nn-1)*fs/nfft;               % 计算频率刻度
Y=log(abs(fft(y)));                           % 按式(1)取实数部分
subplot 211; plot(ff,Y(nn),'k'); hold on;     % 画出信号的频谱图
z=ifft(Y);                                    % 按式(1)求取倒谱
figure(1), subplot 212; plot(time,z,'k');     % 画出倒谱图
title('信号倒谱图'); axis([0 time(512) -0.2 0.2]); grid; 
ylabel('幅值'); xlabel(['倒频率/s' 10 '(b)']);
mcep=29;                                      % 分离声门激励脉冲和声道冲激响应
zy=z(1:mcep+1);
zy=[zy' zeros(1,1000-2*mcep-1) zy(end:-1:2)']; % 构建声道冲激响应的倒谱序列
ZY=fft(zy);                                   % 计算声道冲激响应的频谱
figure(2),                                    % 画出声道冲激响应的频谱,用灰线表示
line(ff,real(ZY(nn)),'color',[.6 .6 .6],'linewidth',3);
grid; hold off; ylim([-4 5]);
title('信号频谱(黑线)和声道冲激响频谱(灰线)')
ylabel('幅值'); xlabel(['频率/Hz' 10 '(a)']); 

ft=[zeros(1,mcep+1) z(mcep+2:end-mcep)' zeros(1,mcep)]; % 构建声门激励脉冲的倒谱序列
FT=fft(ft);                                  % 计算声门激励脉冲的频谱
subplot 212; plot(ff,real(FT(nn)),'k'); grid;% 画出声门激励脉冲的频谱
title('声门激励脉冲频谱')
ylabel('幅值'); xlabel(['频率/Hz' 10 '(b)']); 
结果如下:




这里,博主想重点说一下以下三行程序。

mcep=29;
zy=[zy' zeros(1,1000-2*mcep-1) zy(end:-1:2)']; % 构建声道冲激响应的倒谱序列(预加重)
ft=[zeros(1,mcep+1) z(mcep+2:end-mcep)' zeros(1,mcep)]; % 构建声门激励脉冲的倒谱序列(预加重)


  在这个例子中,采样频率为16000HZ,认为基音频率都应低于500HZ,为了留有余量,取16000/550=29,即在倒谱域中第29条谱线之前是反映了包络的系数。所以取29就是这样得来的。 
  信号模型可看成激励模型、声道模型、辐射模型的串联。预加重目的是为了更好的分析声道,去掉激励模型和辐射模型的影响。激励模型是一个二阶的低通模型,辐射模型是一阶高通模型,所以再增加一个预加重,增加加一个一阶高通,以平衡激励模型和辐射模型的影响。 
  倒谱中横坐标不是频率,而是倒频率(quefrency,量纲是时间),它的刻度同时间序列中x对应的刻度相同,在FFT(x)以后包络的起伏比较缓,就是它的倒频率低。倒频谱中的横轴也反映了在采样频率16000下不同频率的周期,550Hz的周期为29,即第29条谱线。在大于第29条谱线以后的谱线,对应的信号分量的频率都要小于550Hz,即在基频的区间中。在倒频率范 围中我们取小于550Hz的倒频谱来求包络。 

3 Mel频率倒谱系数的分析
这里,博主觉得理解了两个知识点,Mel系数就算弄明白了。
3.1 知识点1 Mel滤波器组
程序调用的函数如下:
x=melbankm(24,256,8000,0,0.5,w)
这里,信号采样频率为8000Hz,每帧长256,设置为24个mel滤波器组。
涉及的知识点

这里,f(m)为中心频率。fl为滤波器频率范围内的最低频率;fh为最高;N为DFT(FFT)时的长度;fs为采样频率。最后,每个带通滤波器的传递函数为


知识点2:
对语音信号进行如下操作,最终可以得到Mel滤波器的能量S(i,m)
预加重→分帧 →加窗→倒谱


Mel滤波器的能量取对数后计算DCT:

这里,S是 Mel滤波器能量;m是第m个Mel滤波器(共有M个);i是第i帧;n是DCT的谱线。
function ccc=mfcc_m(x,fs,p,frameSize,inc)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                 function ccc=mfcc_m(x);
%对输入的语音序列x进行MFCC参数的提取,返回MFCC参数和一阶
%差分MFCC参数,Mel滤波器的个数为p,采样频率为fs
%对x每frameSize点分为一帧,相邻两帧之间的帧移为inc
% fft变换的长度为帧长
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 按帧长为frameSize,Mel滤波器的个数为p,采样频率为fs
% 提取Mel滤波器参数,用海明窗函数
bank=melbankm(p,frameSize,fs,0,0.5,'m');
% 归一化mel滤波器组系数
bank=full(bank);
bank=bank/max(bank(:));

% DCT系数,12*p
for k=1:12
  n=0:p-1;
  dctcoef(k,:)=cos((2*n+1)*k*pi/(2*p));
end

% 归一化倒谱提升窗口
w = 1 + 6 * sin(pi * [1:12] ./ 12);
w = w/max(w);

% 预加重滤波器
xx=double(x);
xx=filter([1 -0.9375],1,xx);

% 语音信号分帧
xx=enframe(xx,frameSize,inc);
n2=fix(frameSize/2)+1;
% 计算每帧的MFCC参数
for i=1:size(xx,1)
  y = xx(i,:);
  s = y' .* hamming(frameSize);
  t = abs(fft(s));
  t = t.^2;
  c1=dctcoef * log(bank * t(1:n2));
  c2 = c1.*w';
  m(i,:)=c2';
end

%差分系数
dtm = zeros(size(m));
for i=3:size(m,1)-2
  dtm(i,:) = -2*m(i-2,:) - m(i-1,:) + m(i+1,:) + 2*m(i+2,:);
end
dtm = dtm / 3;
%合并mfcc参数和一阶差分mfcc参数
ccc = [m dtm];
%去除首尾两帧,因为这两帧的一阶差分参数为0
ccc = ccc(3:size(m,1)-2,:);

例子:这里有两个语音,一个是元音i,另外一个是a。利用MFCC参数观察它们的匹配情况,计算它们的MFCC距离。这里,距离我们用马氏距离来进行计算。
%
% pr3_3_2 
clear all; clc; close all;

[x1,fs]=audioread('s1.wav');      % 读入信号s1-\i1\
x3=audioread('a1.wav');           % 读入信号a1-\a1\
wlen=200;                       % 帧长
inc=80;                         % 帧移
x1=x1/max(abs(x1));             % 幅值归一化
x3=x3/max(abs(x3));

% 计算/i1/与/a1/之间的匹配比较
[Dcep,Ccep1,Ccep2]=mel_dist(x1,x3,fs,16,wlen,inc);
figure(2)
plot(Ccep1(3,:),Ccep2(3,:),'k+'); hold on
plot(Ccep1(7,:),Ccep2(7,:),'kx'); 
plot(Ccep1(12,:),Ccep2(12,:),'k^');
plot(Ccep1(16,:),Ccep2(16,:),'kh'); 
legend('第3帧','第7帧','第12帧','第16帧')
xlabel('信号x1');ylabel('信号x3')
axis([-12 12 -12 12]);
line([-12 12],[-12 12],'color','k','linestyle','--');
title('/i1/与/a1/之间的MFCC参数匹配比较')

结果如下:


PS:楼主这里matlab版本是2016b,这个版本里面很多函数与之前的不一样。比如:wavread变成了audioread。







你可能感兴趣的:(语音处理杂谈)