梅尔频率倒谱系数(mfcc)及Python实现


Posted in Python onJune 18, 2019

语音识别系统的第一步是进行特征提取,mfcc是描述短时功率谱包络的一种特征,在语音识别系统中被广泛应用。

一、mel滤波器

每一段语音信号被分为多帧,每帧信号都对应一个频谱(通过FFT变换实现),频谱表示频率与信号能量之间的关系。mel滤波器是指多个带通滤波器,在mel频率中带通滤波器的通带是等宽的,但在赫兹(Hertz)频谱内mel滤波器在低频处较密集切通带较窄,高频处较稀疏且通带较宽,旨在通过在较低频率处更具辨别性并且在较高频率处较少辨别性来模拟非线性人类耳朵对声音的感知。

赫兹频率和梅尔频率之间的关系为:

梅尔频率倒谱系数(mfcc)及Python实现

假设在梅尔频谱内,有M 个带通滤波器Hm (k),0≤m<M,每个带通滤波器的中心频率为F(m) F(m)F(m)每个带通滤波器的传递函数为:

梅尔频率倒谱系数(mfcc)及Python实现

下图为赫兹频率内的mel滤波器,带通滤波器个数为24:

梅尔频率倒谱系数(mfcc)及Python实现

二、mfcc特征

MFCC系数提取步骤:

(1)语音信号分帧处理
(2)每一帧傅里叶变换---->功率谱
(3)将短时功率谱通过mel滤波器
(4)滤波器组系数取对数
(5)将滤波器组系数的对数进行离散余弦变换(DCT)
(6)一般将第2到底13个倒谱系数保留作为短时语音信号的特征

Python实现

import wave
import numpy as np
import math
import matplotlib.pyplot as plt
from scipy.fftpack import dct

def read(data_path):
 '''读取语音信号
 '''
 wavepath = data_path
 f = wave.open(wavepath,'rb')
 params = f.getparams()
 nchannels,sampwidth,framerate,nframes = params[:4] #声道数、量化位数、采样频率、采样点数
 str_data = f.readframes(nframes) #读取音频,字符串格式
 f.close()
 wavedata = np.fromstring(str_data,dtype = np.short) #将字符串转化为浮点型数据
 wavedata = wavedata * 1.0 / (max(abs(wavedata))) #wave幅值归一化
 return wavedata,nframes,framerate

def enframe(data,win,inc):
 '''对语音数据进行分帧处理
 input:data(一维array):语音信号
   wlen(int):滑动窗长
   inc(int):窗口每次移动的长度
 output:f(二维array)每次滑动窗内的数据组成的二维array
 '''
 nx = len(data) #语音信号的长度
 try:
  nwin = len(win)
 except Exception as err:
  nwin = 1 
 if nwin == 1:
  wlen = win
 else:
  wlen = nwin
 nf = int(np.fix((nx - wlen) / inc) + 1) #窗口移动的次数
 f = np.zeros((nf,wlen)) #初始化二维数组
 indf = [inc * j for j in range(nf)]
 indf = (np.mat(indf)).T
 inds = np.mat(range(wlen))
 indf_tile = np.tile(indf,wlen)
 inds_tile = np.tile(inds,(nf,1))
 mix_tile = indf_tile + inds_tile
 f = np.zeros((nf,wlen))
 for i in range(nf):
  for j in range(wlen):
   f[i,j] = data[mix_tile[i,j]]
 return f

def point_check(wavedata,win,inc):
 '''语音信号端点检测
 input:wavedata(一维array):原始语音信号
 output:StartPoint(int):起始端点
   EndPoint(int):终止端点
 '''
 #1.计算短时过零率
 FrameTemp1 = enframe(wavedata[0:-1],win,inc)
 FrameTemp2 = enframe(wavedata[1:],win,inc)
 signs = np.sign(np.multiply(FrameTemp1,FrameTemp2)) # 计算每一位与其相邻的数据是否异号,异号则过零
 signs = list(map(lambda x:[[i,0] [i>0] for i in x],signs))
 signs = list(map(lambda x:[[i,1] [i<0] for i in x], signs))
 diffs = np.sign(abs(FrameTemp1 - FrameTemp2)-0.01)
 diffs = list(map(lambda x:[[i,0] [i<0] for i in x], diffs))
 zcr = list((np.multiply(signs, diffs)).sum(axis = 1))
 #2.计算短时能量
 amp = list((abs(enframe(wavedata,win,inc))).sum(axis = 1))
# # 设置门限
# print('设置门限')
 ZcrLow = max([round(np.mean(zcr)*0.1),3])#过零率低门限
 ZcrHigh = max([round(max(zcr)*0.1),5])#过零率高门限
 AmpLow = min([min(amp)*10,np.mean(amp)*0.2,max(amp)*0.1])#能量低门限
 AmpHigh = max([min(amp)*10,np.mean(amp)*0.2,max(amp)*0.1])#能量高门限
 # 端点检测
 MaxSilence = 8 #最长语音间隙时间
 MinAudio = 16 #最短语音时间
 Status = 0 #状态0:静音段,1:过渡段,2:语音段,3:结束段
 HoldTime = 0 #语音持续时间
 SilenceTime = 0 #语音间隙时间
 print('开始端点检测')
 StartPoint = 0
 for n in range(len(zcr)):
  if Status ==0 or Status == 1:
   if amp[n] > AmpHigh or zcr[n] > ZcrHigh:
    StartPoint = n - HoldTime
    Status = 2
    HoldTime = HoldTime + 1
    SilenceTime = 0
   elif amp[n] > AmpLow or zcr[n] > ZcrLow:
    Status = 1
    HoldTime = HoldTime + 1
   else:
    Status = 0
    HoldTime = 0
  elif Status == 2:
   if amp[n] > AmpLow or zcr[n] > ZcrLow:
    HoldTime = HoldTime + 1
   else:
    SilenceTime = SilenceTime + 1
    if SilenceTime < MaxSilence:
     HoldTime = HoldTime + 1
    elif (HoldTime - SilenceTime) < MinAudio:
     Status = 0
     HoldTime = 0
     SilenceTime = 0
    else:
     Status = 3
  elif Status == 3:
   break
  if Status == 3:
   break
 HoldTime = HoldTime - SilenceTime
 EndPoint = StartPoint + HoldTime
 return FrameTemp1[StartPoint:EndPoint]


def mfcc(FrameK,framerate,win):
 '''提取mfcc参数 
 input:FrameK(二维array):二维分帧语音信号
   framerate:语音采样频率
   win:分帧窗长(FFT点数)
 output:
 '''
 #mel滤波器
 mel_bank,w2 = mel_filter(24,win,framerate,0,0.5)
 FrameK = FrameK.T
 #计算功率谱
 S = abs(np.fft.fft(FrameK,axis = 0)) ** 2
 #将功率谱通过滤波器
 P = np.dot(mel_bank,S[0:w2,:])
 #取对数
 logP = np.log(P)
 #计算DCT系数
# rDCT = 12
# cDCT = 24
# dctcoef = []
# for i in range(1,rDCT+1):
#  tmp = [np.cos((2*j+1)*i*math.pi*1.0/(2.0*cDCT)) for j in range(cDCT)]
#  dctcoef.append(tmp)
# #取对数后做余弦变换 
# D = np.dot(dctcoef,logP)
 num_ceps = 12
 D = dct(logP,type = 2,axis = 0,norm = 'ortho')[1:(num_ceps+1),:]
 return S,mel_bank,P,logP,D
 


def mel_filter(M,N,fs,l,h):
 '''mel滤波器
 input:M(int):滤波器个数
   N(int):FFT点数
   fs(int):采样频率
   l(float):低频系数
   h(float):高频系数
 output:melbank(二维array):mel滤波器
 '''
 fl = fs * l #滤波器范围的最低频率
 fh = fs * h #滤波器范围的最高频率
 bl = 1125 * np.log(1 + fl / 700) #将频率转换为mel频率
 bh = 1125 * np.log(1 + fh /700) 
 B = bh - bl #频带宽度
 y = np.linspace(0,B,M+2) #将mel刻度等间距
 print('mel间隔',y)
 Fb = 700 * (np.exp(y / 1125) - 1) #将mel变为HZ
 print(Fb)
 w2 = int(N / 2 + 1)
 df = fs / N
 freq = [] #采样频率值
 for n in range(0,w2):
  freqs = int(n * df)
  freq.append(freqs)
 melbank = np.zeros((M,w2))
 print(freq)
 
 for k in range(1,M+1):
  f1 = Fb[k - 1]
  f2 = Fb[k + 1]
  f0 = Fb[k]
  n1 = np.floor(f1/df)
  n2 = np.floor(f2/df)
  n0 = np.floor(f0/df)
  for i in range(1,w2):
   if i >= n1 and i <= n0:
    melbank[k-1,i] = (i-n1)/(n0-n1)
   if i >= n0 and i <= n2:
    melbank[k-1,i] = (n2-i)/(n2-n0)
  plt.plot(freq,melbank[k-1,:])
 plt.show()
 return melbank,w2

if __name__ == '__main__':
 data_path = 'audio_data.wav'
 win = 256
 inc = 80
 wavedata,nframes,framerate = read(data_path)
 FrameK = point_check(wavedata,win,inc)
 S,mel_bank,P,logP,D = mfcc(FrameK,framerate,win)

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

Python 相关文章推荐
Python greenlet实现原理和使用示例
Sep 24 Python
Scrapy框架CrawlSpiders的介绍以及使用详解
Nov 29 Python
python+matplotlib实现动态绘制图片实例代码(交互式绘图)
Jan 20 Python
对pycharm代码整体左移和右移缩进快捷键的介绍
Jul 16 Python
Flask框架web开发之零基础入门
Dec 10 Python
python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)
Jun 27 Python
python opencv鼠标事件实现画框圈定目标获取坐标信息
Apr 18 Python
python反转列表的三种方式解析
Nov 08 Python
Python json模块与jsonpath模块区别详解
Mar 05 Python
TensorFlow2.X使用图片制作简单的数据集训练模型
Apr 08 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
Jun 30 Python
python实现黄金分割法的示例代码
Apr 28 Python
Python生成一个迭代器的实操方法
Jun 18 #Python
利用anaconda保证64位和32位的python共存
Mar 09 #Python
python获取地震信息 微信实时推送
Jun 18 #Python
python实现月食效果实例代码
Jun 18 #Python
详解Python3中setuptools、Pip安装教程
Jun 18 #Python
Python生成指定数量的优惠码实操内容
Jun 18 #Python
python实现文件的备份流程详解
Jun 18 #Python
You might like
JavaScript 上万关键字瞬间匹配实现代码
2013/07/07 Javascript
jquery ajax 简单范例(界面+后台)
2013/11/19 Javascript
JS模拟简易滚动条效果代码(附demo源码)
2016/04/05 Javascript
js获取Html元素的实际宽度高度的方法
2016/05/19 Javascript
JS定时器使用,定时定点,固定时刻,循环执行详解
2016/05/31 Javascript
jQuery使用经验小技巧(推荐)
2016/05/31 Javascript
AngularJS指令与控制器之间的交互功能示例
2016/12/14 Javascript
详解ElementUI之表单验证、数据绑定、路由跳转
2017/06/21 Javascript
JS原生数据双向绑定实现代码
2017/08/14 Javascript
vue 粒子特效的示例代码
2017/09/19 Javascript
什么是Vue.js框架 为什么选择它?
2017/10/17 Javascript
详解Vue微信授权登录前后端分离较为优雅的解决方案
2018/06/29 Javascript
layui点击按钮添加可编辑的一行方法
2018/08/15 Javascript
vue .js绑定checkbox并获取、改变选中状态的实例
2018/08/24 Javascript
JS返回页面时自动回滚到历史浏览位置
2018/09/26 Javascript
JQueryDOM之样式操作
2019/03/27 jQuery
vue中监听返回键问题
2019/08/28 Javascript
Vue中错误图片的处理的实现代码
2019/11/07 Javascript
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
简单介绍Python下自己编写web框架的一些要点
2015/04/29 Python
Python使用matplotlib实现绘制自定义图形功能示例
2018/01/18 Python
python爬取个性签名的方法
2018/06/17 Python
Python GUI布局尺寸适配方法
2018/10/11 Python
实例讲解Python中浮点型的基本内容
2019/02/11 Python
Django 批量插入数据的实现方法
2020/01/12 Python
django 利用Q对象与F对象进行查询的实现
2020/05/15 Python
美国知名珠宝首饰品牌:Gemvara
2017/10/06 全球购物
东方红海科技面试题软件测试方面
2012/02/08 面试题
法警的竞聘演讲稿
2014/01/02 职场文书
喜之郎果冻广告词
2014/03/20 职场文书
少儿节目主持串词
2014/04/02 职场文书
小学校园广播稿(3篇)
2014/09/19 职场文书
学生检讨书怎么写
2014/10/09 职场文书
乡镇三严三实学习心得体会
2014/10/13 职场文书
TensorFlow的自动求导原理分析
2021/05/26 Python
使用refresh_token实现无感刷新页面
2022/04/26 Javascript