MFCC声纹特征提取

目录

前言

语音识别本质上是一种模式识别的过程,其基本结构原理图如下图所示,主要包括语音信号预处理,特征参数提取,特征建模、模式匹配等几个功能模块。

一个声音识别系统主要包括训练和识别两个阶段,无论是训练还是识别,都需要对输入信号的原始声音进行预处理,并进行特征提取。在提取了相关的特征之后,识别的工作会变得相对简单很多,本文主要介绍声纹如何提取的。

预处理

声音信号的预处理包括滤波、A/D转换、预加重、分帧、端点检测等,假设经A/D转换后的数字音频信号为x(n),预处理过程如下:

1) 归一化处理。归一化处理的目的是消除不同样本声音之间的大小差异,将样本幅值限定在[-1,1]范围内。

2)预加重。预加重通常使用带有6dB/倍频的一阶数字滤波器来实现,如:H(z)=1-\mu z^{-1}

其中\mu为常数,通常取0.97。

3)对音频信号进行加窗分帧。虽然声音信号是非线性时变信号,但它具有短时平稳的特点,对其进行分帧可以提取其短时特性。通常取帧长为10~30ms,为了避免帧与帧之间的特性变化过大, 帧移通常取帧长的 1 /2, 即相邻帧之间有 1 /2 的重叠数据。为了进行短时分析, 必须通过加窗来选取窗口内的声音信号, 窗口外的声音信号为 0, 最常用的窗口函数是汉明窗。一般取 256 点为一帧, 帧间重叠为 128 点。

特征参数提取

        声音特征的选择取决于具体的系统, 比较有代表性的特征包括幅度( 或功率) 、过零率、线性预测系数特征矢量( LPC) 、LPC 倒谱特征矢量( LPCC) 、梅尔倒谱系数( MFCC) 等。特征提取完成对声音信号进行分析处理, 去掉与声音识别无关的冗余信息, 获得影响声音识别的重要信息。由于倒频谱( cepstrum) 有着能将频谱上的高低频分开的优点, 因此被广泛地应用在声音识别领域, 如 LPCC 和 MFCC。
 

         由于声音信号在时域上的变化快速且不稳定, 通常将它转换到频域上来分析其特征参数。梅尔倒频谱特征参数提取过程如上图所示。预处理后的声音数据经过快速傅里叶变换( FFT) , 计算出每帧数据的频谱参数, 再将每帧数据的频谱参数通过一组 N( N 的值通常为 20 ~ 40) 个三角形带通滤波器构成的梅尔频率滤波器做卷积运算, 之后对每个频带的输出取对数, 求出每个输出的对数能量( Log Energy) S( m) , m = 1, 2, 3, …, N。最后对此 N 个参数进行离散余弦变换, 求出梅尔倒谱系数作为声音特征参数

其中, n 为所取 MFCC 个数; Ci( n) 为第 i 帧的第 n 个 MFCC 系数; S( m) 为音频信号的对数功率谱; M 为三角滤波器个数。

预加重

        为了避免在后边的FFT操作中出现数值问题,我们需要加强一下高频信息,因为一般高频能量比低频小。其预加重函数如下所示:

        y(n)=x(n)−α⋅x(n−1)

分帧

        我们要对语音数据做傅里叶变换,将信息从时域转化为频域。但是如果对整段语音做FFT,就会损失时序信息。因此,我们假设在很短的一段时间t内的频率信息不变,对长度为t的帧做傅里叶变换,就能得到对语音数据的频域和时域信息的适当表达。举个例子,假如我们这里的采样点数为200000个点,如果真的这样做的话,就很麻烦了,于是我们在语音分析中引入分帧的概念,将原始语音信号分成大小固定的N段语音信号,这里每一段语音信号都被称为一帧。

加窗

        将信号分帧后,我们将每一帧代入窗函数,窗外的值设定为0,其目的是消除各个帧两端可能会造成的信号不连续性(即谱泄露 spectral leakage)。常用的窗函数有方窗、汉明窗和汉宁窗等,根据窗函数的频域特性,常采用汉明窗(hamming window)。接下来我来讲解一下怎么加窗:我们需要做的就是为每一帧数据,也就是301帧数据都加入大小为1103的汉明窗。其汉明窗的表达公式如下所示:

W(n)=(1−a)−a⋅cos(2⋅π⋅n/N)1≤n≤N

傅里叶变换

        傅里叶变换作为一个经常使用的东西,大家可以自行去了解,此处不过多赘述。

梅尔滤波器

        首先我要讲一下什么是梅尔值,这是一个新的量度,相比于正常的频率机制,梅尔值更加接近于人耳的听觉机制,其在低频范围内增长速度很快,但在高频范围内,梅尔值的增长速度很慢。每一个频率值都对应着一个梅尔值,其对应关系如下:

m=2595⋅log10​(1+f/700)

如图展示了梅尔滤波器的一种形状,等高形式。

离散余弦变换

         在进行离散余弦变换之前,我们还需要做的就是把得到的二维矩阵能量谱 E,乘以得到的二维数组梅尔滤波器Hm的转置,得到参数H,其定义如下:

H=E\cdot H^{T}

根据mfcc的定义,我们需要对能量的对数作离散余弦变换,即可得到MFCC参数:

 至此,声纹特征的提取过程到这里就结束了,特征提取出来之后,要对其进行识别就显得十分简单,GMM、SVM、BP等算法都可对其进行训练识别,并达到一个不错的效果。

代码实现(MATLAB)

clc
clear

load sample_date5


%%
%参数设置,数据读取
frameSize=1024;%帧长
inc=512;%帧移
p = 32;%梅尔滤波器个数
x = sample_date5;
fs = 48000;
N2=length(x);  %语音信号长度

%%
%数据归一化处理,消除不同声音之间的大小差异
[x,inputps]=mapminmax(x);

%%
%预加重
for i=2:N2
    y(i)=x(i)-0.97*x(i-1);
end

%%
%分帧
y=y';%对y取转置
S=enframe(y,frameSize,inc);%分帧,对语音信号x进行分帧,
[a,b]=size(S);  %a为矩阵行数,b为矩阵列数

%%
%加窗
C=zeros(a,b);
ham=hamming(b);
for i=1:a
    C(i,:)=ham;
end
%将汉明窗C和S相乘得SC
SC=S.*C;
F=0;
N=frameSize;

%%
%傅里叶快速变换
for i=1:a
    %对SC作N=1024的FFT变换
    D(i,:)=fft(SC(i,:),N);
    %以下循环实现求取谱线能量
    for j=1:N
        t=abs(D(i,j));
        E(i,j)=(t^2);
    end
end

fl=0;       %低频
fh=fs/2;    %高频
bl=2595*log10(1+fl/700);    %得到梅尔刻度的最小值
bh=2595*log10(1+fh/700);    %得到梅尔刻度的最大值
%梅尔坐标范围
B=bh-bl;%梅尔刻度长度
mm=linspace(0,B,p+2);%规划34个不同的梅尔刻度。但只有32个梅尔滤波器
fm=700*(10.^(mm/2595)-1);%将Mel频率转换为频率
W2=N/2+1;%fs/2内对应的FFT点数,1024个频率分量

k=((N+1)*fm)/fs;%计算34个不同的k值
hm=zeros(p,N);%创建hm矩阵
df=fs/N;
freq=(0:N-1)*df;%采样频率值

%%
%梅尔滤波器
for i=2:p+1
    %取整
    n0=floor(k(i-1));  %向下取整
    n1=floor(k(i));
    n2=floor(k(i+1));
   
    for j=1:N
       if n0<=j & j<=n1
           hm(i-1,j)=(j-n0)/(n1-n0);
       elseif n1<=j & j<=n2
           hm(i-1,j)=(n2-j)/(n2-n1);
       end
   end
   %此处求取H1(k)结束。
end

 %梅尔滤波器滤波
 H=E*hm';
 
 %对H作自然对数运算
 for i=1:a
     for j=1:p
         H(i,j)=log(H(i,j));
     end
 end
 
 %%
 %作离散余弦变换 
 Fbank = H';
 Fbank1 = dct(Fbank);
 mfcc = Fbank1';

function frameout=enframe(x,win,inc)

nx=length(x(:));            % 取数据长度
nwin=length(win);           % 取窗长
if (nwin == 1)              % 判断窗长是否为1,若为1,即表示没有设窗函数
   len = win;               % 是,帧长=win
else
   len = nwin;              % 否,帧长=窗长
end
if (nargin < 3)             % 如果只有两个参数,设帧inc=帧长
   inc = len;
end
nf = fix((nx-len+inc)/inc); % 计算帧数
frameout=zeros(nf,len);     % 初始化
indf= inc*(0:(nf-1)).';     % 设置每帧在x中的位移量位置
inds = (1:len);             % 每帧数据对应1:len
frameout(:) = x(indf(:,ones(1,len))+inds(ones(nf,1),:));   % 对数据分帧
if (nwin > 1)               % 若参数中包括窗函数,把每帧乘以窗函数
    w = win(:)';            % 把win转成行数据
    frameout = frameout .* w(ones(nf,1),:);  % 乘窗函数
end

结果展示

提取出来的特征如下图所示,变得有规律可循.

感谢观看,希望本文能对你有所帮助!

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2022年5月17日
下一篇 2022年5月17日

相关推荐