梅尔频率倒谱系数(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的Tqdm模块的使用
Jan 10 Python
python使用matplotlib库生成随机漫步图
Aug 27 Python
python远程连接MySQL数据库
Apr 19 Python
python在openstreetmap地图上绘制路线图的实现
Jul 11 Python
对python中的os.getpid()和os.fork()函数详解
Aug 08 Python
python线程的几种创建方式详解
Aug 29 Python
Python的互斥锁与信号量详解
Sep 12 Python
python实现输出一个序列的所有子序列示例
Nov 18 Python
Python批量安装卸载1000个apk的方法
Apr 10 Python
详解pycharm2020.1.1专业版安装指南(推荐)
Aug 07 Python
Django配置Bootstrap, js实现过程详解
Oct 13 Python
python设置 matplotlib 正确显示中文的四种方式
May 10 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
Destoon旺旺无法正常显示,点击提示“会员名不存在”的解决办法
2014/06/21 PHP
基于php的微信公众平台开发入门实例
2015/04/15 PHP
PHP数据库编程之MySQL优化策略概述
2017/08/16 PHP
PHP调用API接口实现天气查询功能的示例
2017/09/21 PHP
jQuery学习笔记 操作jQuery对象 属性处理
2012/09/19 Javascript
JQuery调用WebServices的方法和4个实例
2014/05/06 Javascript
javascript中clipboardData对象用法详解
2015/05/13 Javascript
使用ngView配合AngularJS应用实现动画效果的方法
2015/06/19 Javascript
jquery+ajax请求且带返回值的代码
2015/08/12 Javascript
JavaScript将DOM事件处理程序封装为event.js 出现的低级错误问题
2016/08/03 Javascript
jQuery实现的无缝广告图片左右滚动功能详解
2016/12/24 Javascript
微信小程序 tabs选项卡效果的实现
2017/01/05 Javascript
JavaScript中filter的用法实例分析
2019/02/27 Javascript
vue实现跳转接口push 转场动画示例
2019/11/01 Javascript
微信小程序开发(一):服务器获取数据列表渲染操作示例
2020/06/01 Javascript
[32:07]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第一场 12.16
2020/12/17 DOTA
用Python脚本来删除指定容量以上的文件的教程
2015/05/04 Python
使用Python编写简单的端口扫描器的实例分享
2015/12/18 Python
简单讲解Python编程中namedtuple类的用法
2016/06/21 Python
python 调用c语言函数的方法
2017/09/29 Python
TensorFlow实现RNN循环神经网络
2018/02/28 Python
Python求解任意闭区间的所有素数
2018/06/10 Python
对Python 内建函数和保留字详解
2018/10/15 Python
OpenCV里的imshow()和Matplotlib.pyplot的imshow()的实现
2019/11/25 Python
keras实现调用自己训练的模型,并去掉全连接层
2020/06/09 Python
Python DataFrame使用drop_duplicates()函数去重(保留重复值,取重复值)
2020/07/20 Python
可以随进度显示不同颜色的css3进度条分享
2014/04/11 HTML / CSS
梅西百货澳大利亚:Macy’s Australia
2017/07/26 全球购物
总裁办公室主任职责
2014/01/02 职场文书
委托书的写法
2014/08/30 职场文书
高一军训的心得体会
2014/09/01 职场文书
党委领导班子整改方案
2014/09/30 职场文书
城南旧事读书笔记
2015/06/29 职场文书
中国梦宣传标语口号
2015/12/26 职场文书
MySQL官方导出工具mysqlpump的使用
2021/05/21 MySQL
Apache Hudi的多版本清理服务彻底讲解
2022/03/31 Servers