基于MATLAB和Python实现MFCC特征参数提取


Posted in Python onAugust 13, 2019

1、MFCC概述

在语音识别(Speech Recognition)和话者识别(Speaker Recognition)方面,最常用到的语音特征就是梅尔倒谱系数(Mel-scale FrequencyCepstral Coefficients,简称MFCC)。根据人耳听觉机理的研究发现,人耳对不同频率的声波有不同的听觉敏感度。从200Hz到5000Hz的语音信号对语音的清晰度影响较大。两个响度不等的声音作用于人耳时,则响度较高的频率成分的存在会影响到对响度较低的频率成分的感受,使其变得不易察觉,这种现象称为掩蔽效应。由于频率较低的声音在内耳蜗基底膜上行波传递的距离大于频率较高的声音,故一般来说,低音容易掩蔽高音,而高音掩蔽低音较困难。在低频处的声音掩蔽的临界带宽较高频要小。所以,人们从低频到高频这一段频带内按临界带宽的大小由密到疏安排一组带通滤波器,对输入信号进行滤波。将每个带通滤波器输出的信号能量作为信号的基本特征,对此特征经过进一步处理后就可以作为语音的输入特征。由于这种特征不依赖于信号的性质,对输入信号不做任何的假设和限制,又利用了听觉模型的研究成果。因此,这种参数比基于声道模型的LPCC相比具有更好的鲁邦性,更符合人耳的听觉特性,而且当信噪比降低时仍然具有较好的识别性能。

梅尔倒谱系数是在Mel标度频率域提取出来的倒谱参数,Mel标度描述了人耳频率的非线性特性,它与频率的关系可用下式近似表示:

基于MATLAB和Python实现MFCC特征参数提取

式中f为频率,单位为Hz。下图为Mel频率与线性频率的关系:

基于MATLAB和Python实现MFCC特征参数提取

2、 MFCC特征参数提取过程详解

基于MATLAB和Python实现MFCC特征参数提取

(1)预处理

预处理包括预加重、分帧、加窗函数。

预加重:预加重的目的是提升高频部分,使信号的频谱变得平坦,保持在低频到高频的整个频带中,能用同样的信噪比求频谱。同时,也是为了消除发生过程中声带和嘴唇的效应,来补偿语音信号受到发音系统所抑制的高频部分,也为了突出高频的共振峰。预加重处理其实是将语音信号通过一个高通滤波器:

基于MATLAB和Python实现MFCC特征参数提取

分帧:先将N个采样点集合成一个观测单位,称为帧。通常情况下N的值为256或512,涵盖的时间约为20~30ms左右。为了避免相邻两帧的变化过大,因此会让两相邻帧之间有一段重叠区域,此重叠区域包含了M个取样点,通常M的值约为N的1/2或1/3。通常语音识别所采用语音信号的采样频率为8KHz或16KHz,以8KHz来说,若帧长度为256个采样点,则对应的时间长度是256/8000×1000=32ms。

加窗:将每一帧乘以汉明窗,以增加帧左端和右端的连续性。假设分帧后的信号为S(n), n=0,1…,N-1, N为帧的大小,那么乘上汉明窗

基于MATLAB和Python实现MFCC特征参数提取

后 ,W(n)形式如下:

基于MATLAB和Python实现MFCC特征参数提取

(2)FFT

由于信号在时域上的变换通常很难看出信号的特性,所以通常将它转换为频域上的能量分布来观察,不同的能量分布,就能代表不同语音的特性。所以在乘上汉明窗后,每帧还必须再经过快速傅里叶变换以得到在频谱上的能量分布。对分帧加窗后的各帧信号进行快速傅里叶变换得到各帧的频谱。

(3)谱线能量

对语音信号的频谱取模平方得到语音信号的谱线能量。

(4)计算通过Mel滤波器的能量

将能量谱通过一组Mel尺度的三角形滤波器组,定义一个有M个滤波器的滤波器组(滤波器的个数和临界带的个数相近),采用的滤波器为三角滤波器,中心频率为f(m) 。M通常取22-26。各f(m)之间的间隔随着m值的减小而缩小,随着m值的增大而增宽,如图所示:

基于MATLAB和Python实现MFCC特征参数提取 

三角滤波器的频率响应定义为:

基于MATLAB和Python实现MFCC特征参数提取

对频谱进行平滑化,并消除谐波的作用,突显原先语音的共振峰。(因此一段语音的音调或音高,是不会呈现在MFCC 参数内,换句话说,以MFCC 为特征的语音辨识系统,并不会受到输入语音的音调不同而有所影响)此外,还可以降低运算量。

计算每个滤波器组输出的对数能量为 :

基于MATLAB和Python实现MFCC特征参数提取

(5)计算DCT倒谱

经离散余弦变换(DCT)得到MFCC系数 :

基于MATLAB和Python实现MFCC特征参数提取

将上述的对数能量带入离散余弦变换,求出L阶的Mel参数。L阶指MFCC系数阶数,通常取12-16。这里M是三角滤波器个数。

3、MATLAB实现方法

注:在提取MFCC参数之前需要加载并使用VOICEBOX工具包

Df=5;
fs=8000; 
N=fs/Df;
t=0:1./fs:(N-1)./fs;
x=sin(2*pi*200*t);  
bank=melbankm(24,256,8000,0,0.5,'t');%Mel滤波器的阶数为24,fft变换的长度为256,采样频率为8000Hz 
%归一化mel滤波器组系数 
bank=full(bank); 
bank=bank/max(bank(:)); 
% DCT系数,12*p
for k=1:12      
n=0:23; 
dctcoef(k,:)=cos((2*n+1)*k*pi/(2*24)); 
end 
%归一化倒谱提升窗口 
w=1+6*sin(pi*[1:12]./12); 
%w=w/max(w);
%语音信号分帧 
xx=enframe(x,256,80);%对x 256点分为一帧  
%计算每帧的MFCC参数 
for i=1:size(xx,1) 
y=xx(i,:); 
s=y'.*hamming(256); 
t=abs(fft(s));%fft快速傅立叶变换 
t=t.^2; 
c1=dctcoef*log(bank*t(1:129)); 
c2=c1.*w'; 
end  
plot(c2);title('MFCC');

结果:

基于MATLAB和Python实现MFCC特征参数提取

4、Python实现方法

import numpy as np 
from scipy import signal
from scipy.fftpack import dct
import pylab as plt

def enframe(wave_data, nw, inc, winfunc):
  '''将音频信号转化为帧。
  参数含义:
  wave_data:原始音频型号
  nw:每一帧的长度(这里指采样点的长度,即采样频率乘以时间间隔)
  inc:相邻帧的间隔(同上定义)
  '''
  wlen=len(wave_data) #信号总长度
  if wlen<=nw: #若信号长度小于一个帧的长度,则帧数定义为1
    nf=1
  else: #否则,计算帧的总长度
    nf=int(np.ceil((1.0*wlen-nw+inc)/inc))
  pad_length=int((nf-1)*inc+nw) #所有帧加起来总的铺平后的长度
  zeros=np.zeros((pad_length-wlen,)) #不够的长度使用0填补,类似于FFT中的扩充数组操作
  pad_signal=np.concatenate((wave_data,zeros)) #填补后的信号记为pad_signal
  indices=np.tile(np.arange(0,nw),(nf,1))+np.tile(np.arange(0,nf*inc,inc),(nw,1)).T #相当于对所有帧的时间点进行抽取,得到nf*nw长度的矩阵
  indices=np.array(indices,dtype=np.int32) #将indices转化为矩阵
  frames=pad_signal[indices] #得到帧信号
  win=np.tile(winfunc,(nf,1)) #window窗函数,这里默认取1
  return frames*win  #返回帧信号矩阵

Df=5
fs=8000
N=fs/Df
t = np.arange(0,(N-1)/fs,1/fs)   
wave_data=np.sin(2*np.pi*200*t)
#预加重
#b,a = signal.butter(1,1-0.97,'high')
#emphasized_signal = signal.filtfilt(b,a,wave_data)
#归一化倒谱提升窗口
lifts=[]
for n in range(1,13):
  lift =1 + 6 * np.sin(np.pi * n / 12)
  lifts.append(lift)
#print(lifts)  

#分帧、加窗 
winfunc = signal.hamming(256) 
X=enframe(wave_data, 256, 80, winfunc)  #转置的原因是分帧函数enframe的输出矩阵是帧数*帧长
frameNum =X.shape[0] #返回矩阵行数18,获取帧数
#print(frameNum)
for i in range(frameNum):
  y=X[i,:]
  #fft
  yf = np.abs(np.fft.fft(y)) 
  #print(yf.shape)
  #谱线能量
  yf = yf**2
  #梅尔滤波器系数
  nfilt = 24
  low_freq_mel = 0
  NFFT=256
  high_freq_mel = (2595 * np.log10(1 + (fs / 2) / 700)) # 把 Hz 变成 Mel
  mel_points = np.linspace(low_freq_mel, high_freq_mel, nfilt + 2) # 将梅尔刻度等间隔
  hz_points = (700 * (10**(mel_points / 2595) - 1)) # 把 Mel 变成 Hz
  bin = np.floor((NFFT + 1) * hz_points / fs)
  fbank = np.zeros((nfilt, int(np.floor(NFFT / 2 + 1))))
  for m in range(1, nfilt + 1):
    f_m_minus = int(bin[m - 1])  # left
    f_m = int(bin[m])       # center
    f_m_plus = int(bin[m + 1])  # right
    for k in range(f_m_minus, f_m):
      fbank[m - 1, k] = (k - bin[m - 1]) / (bin[m] - bin[m - 1])
    for k in range(f_m, f_m_plus):
      fbank[m - 1, k] = (bin[m + 1] - k) / (bin[m + 1] - bin[m])
  filter_banks = np.dot(yf[0:129], fbank.T)
  filter_banks = np.where(filter_banks == 0, np.finfo(float).eps, filter_banks) # 数值稳定性
  filter_banks = 10 * np.log10(filter_banks) # dB 
  filter_banks -= (np.mean(filter_banks, axis=0) + 1e-8)
  #print(filter_banks)
  #DCT系数
  num_ceps = 12
  c2 = dct(filter_banks, type=2, axis=-1, norm='ortho')[ 1 : (num_ceps + 1)] # Keep 2-13
  c2 *= lifts
print(c2)
plt.plot(c2)
plt.show()

结果:

基于MATLAB和Python实现MFCC特征参数提取 

由MATLAB和Python绘制出来的波形可以看出二者计算出来的MFCC倒谱系数的基本走势相同。

参考:http://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现类的静态变量用法实例
May 08 Python
遍历python字典几种方法总结(推荐)
Sep 11 Python
Python 描述符(Descriptor)入门
Nov 20 Python
Python Socket实现简单TCP Server/client功能示例
Aug 05 Python
基于scrapy的redis安装和配置方法
Jun 13 Python
django框架自定义模板标签(template tag)操作示例
Jun 24 Python
Django 数据库同步操作技巧详解
Jul 19 Python
用Python配平化学方程式的方法
Jul 20 Python
python选取特定列 pandas iloc,loc,icol的使用详解(列切片及行切片)
Aug 06 Python
解决pytorch GPU 计算过程中出现内存耗尽的问题
Aug 19 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
Feb 07 Python
完美解决TensorFlow和Keras大数据量内存溢出的问题
Jul 03 Python
Python 使用 docopt 解析json参数文件过程讲解
Aug 13 #Python
Django项目中实现使用qq第三方登录功能
Aug 13 #Python
一篇文章搞定Python操作文件与目录
Aug 13 #Python
Python Django Cookie 简单用法解析
Aug 13 #Python
Django中ajax发送post请求 报403错误CSRF验证失败解决方案
Aug 13 #Python
Python人工智能之路 jieba gensim 最好别分家之最简单的相似度实现
Aug 13 #Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
Aug 13 #Python
You might like
PHP ajax 分页类代码
2008/11/13 PHP
php表单转换textarea换行符的方法
2010/09/10 PHP
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装(win+linux)
2012/05/05 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
2017/08/01 PHP
JavaScript prototype属性使用说明
2010/05/13 Javascript
原生javascript获取元素样式属性值的方法
2010/12/25 Javascript
使用Jquery Aajx访问WCF服务(GET、POST、PUT、DELETE)
2012/03/16 Javascript
JS图片无缝滚动(简单利于使用)
2013/06/17 Javascript
jQuery ui 利用 datepicker插件实现开始日期(minDate)和结束日期(maxDate)
2014/05/22 Javascript
深入理解jQuery事件绑定
2016/06/02 Javascript
JS实现鼠标移上去显示图片或微信二维码
2016/12/14 Javascript
angularJS之$http:与服务器交互示例
2017/03/17 Javascript
区别JavaScript函数声明与变量声明
2018/09/12 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
2018/09/26 Javascript
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
2021/01/22 Vue.js
[04:02]DOTA2上海特锦赛小组赛第二日recap精彩回顾
2016/02/28 DOTA
[49:41]NB vs NAVI Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
Python下使用Psyco模块优化运行速度
2015/04/05 Python
使用Python发送邮件附件以定时备份MySQL的教程
2015/04/25 Python
python 写入csv乱码问题解决方法
2016/10/23 Python
Python深入06——python的内存管理详解
2016/12/07 Python
Scrapy使用的基本流程与实例讲解
2018/10/21 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
使用python Telnet远程登录执行程序的方法
2019/01/26 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
浅谈Pytorch中的自动求导函数backward()所需参数的含义
2020/02/29 Python
New Balance法国官方网站:购买鞋子和服装
2019/09/01 全球购物
优秀毕业生自我鉴定
2014/02/11 职场文书
黄金酒广告词
2014/03/21 职场文书
党在我心中演讲稿
2014/09/02 职场文书
2014领导班子专题民主生活会对照检查材料思想汇报
2014/09/23 职场文书
个人工作作风整改措施思想汇报
2014/10/13 职场文书
总经理助理岗位职责
2015/01/31 职场文书
故意伤害辩护词
2015/05/21 职场文书
Python中 range | np.arange | np.linspace三者的区别
2022/03/22 Python
TS 类型兼容教程示例详解
2022/09/23 Javascript