librosa能量_语音MFCC提取:librosa amp;amp; python_speech_feature(2019.12)

最近在阅读语音方向的论文,其中有个被提及很多的语音信号特征MFCC(Mel-Frequency Cepstral Coefficients),找到了基于python的语音库librosa(version=0.7.1)和python_speech_features(version=0.6),下文对这两个库计算MFCC的流程细节稍作梳理。

LibROSA - librosa 0.7.1 documentation​librosa.github.iopython_speech_features​pypi.org
4700c3049b74fb3077aeafa6188679c5.png

一、librosa

f8e53397caa0707fa594dbe24782983d.png

1.源语音信号,shape = wav.length

wav, sample_rate = librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None,dtype=np.float32, res_type='kaiser_best')  #加载语音文件得到原始数据

2.填充及分帧(无预加重处理),分帧后所有帧的shape = n_ftt * n_frames

y = numpy.pad(array, pad_width, mode, **kwargs)     # 原函数及参数
y = numpy.pad(wav, int(n_fft // 2), mode='reflect') # 默认,n_fft 为傅里叶变换维度
y = numpy.pad(wav, (0,pad_need), mode='constant')   # 自定义

librosa调用numpy对源语音数据进行填充,默认模式是'reflect'进行镜像填充,举个例子:

对序列[1,2,3,4,5]进行左填充2个、右填充3个,左边以1作对称轴填充[3,2],右边以5作对称轴填充[4,3,2],最后结果为[3,2,1,2,3,4,5,4,3,2]。

自定义模式是按照python_speech_features的方式设置参数的,pad_need是经过计算得到的需要填充的数据数量,在下文说明。

y_frames = util.frame(y, frame_length=n_fft, hop_length=hop_length) # hop_length为帧移,librosa中默认取窗长的四分之一

一般来说 帧长 = 窗长 = 傅里叶变换维度,否则要进行填充或者截断处理。通过阅读源码发现,librosa调用的分帧方式和python_speech_features一样,这和librosa.feature.melspectrogram()参数里的center描述有所冲突,我把两者对同一语音文件的分帧结果输出到excel文件进行了对比,结果是一样的,当然分帧之前的填充方式也修改成了一致。

730e31677998bb38965aa4e92c8fb6c5.png

3.对所有帧进行加窗,shape = n_ftt * n_frames。librosa中window.shape = n_ftt * 1

fft_window = librosa.filters.get_window(window, Nx, fftbins=True) # 原函数及参数
fft_window = get_window('hann', win_length, fftbins=True)         # 窗长一般等于傅里叶变换维度,短则填充长则截断

librosa加的窗函数调用的scipy,如scipy.signal.windows.hann。python_speech_features加的窗函数调用的numpy,如numpy.hanning,汉宁窗公式为:

567c671fa1784fbb5afbf2ea29b0dab8.png

给原信号加窗的实现方式为相乘:

frames *= 0.5 - 0.5 * numpy.cos((2 * numpy.pi * n) / (frame_length - 1)) # 原信号乘以汉宁窗函数

4.STFT处理得到spectrum(频谱,实际是多帧的),shape = (n_ftt // 2 +1) * n_frames

fft = librosa.core.fft.get_fftlib()
stft_matrix = fft.rfft(fft_window * frames)

librosa和python_speech_features都是调用的numpy进行傅里叶变换,numpy.fft.rfft(frames,NFFT)。

5.取绝对值得到magnitude spectrum/spectrogram(声谱,包含时间维度,即多帧),shape = (n_ftt // 2 +1) * n_frames

magnitude_spectrum = numpy.abs(stft_matrix)    # 承接上一步的STFT
magnitude_spectrum = numpy.abs(librosa.core.spectrum.stft(wav, n_fft=n_fft, hop_length=hop_length,win_length=win_length, center=center,window=window, pad_mode=pad_mode))**power  # librosa封装的计算magnitude spectrum函数,power参数默认为1.0

6.取平方得到power spectrum/spectrogram(声谱,包含时间维度,即多帧),shape = (n_ftt // 2 +1) * n_frames

power_spectrum = numpy.square(magnitude_spectrum)  # 承接上一步的magnitude_spectrum
power_spectrum = numpy.abs(librosa.core.spectrum.stft(wav, n_fft=n_fft, hop_length=hop_length,win_length=win_length, center=center,window=window, pad_mode=pad_mode))**power  # librosa封装的计算power spectrum函数,power参数设置为2.0

7.构造梅尔滤波器组,shape = n_mels * (n_ftt // 2 +1)

mel_basis = librosa.filters.mel(sr, n_fft, n_mels=128, fmin=0.0, fmax=None, htk=False,norm=1, dtype=np.float32)     # 原函数及参数

librosa和python_speech_features构造mel_filtersbank的方式不同,librosa构造细节尚未掌握。

8.矩阵乘法得到mel_spectrogram,shape = n_mels * n_frames

mel_spectrogram = numpy.dot(mel_basis, power_spectrum)

[ n_mels ,(n_ftt // 2 +1) ] * [ (n_ftt // 2 +1) ,n_frames ] = [ n_mels,n_frames]

9.对mel_spectrogram进行log变换,shape = n_mels * n_frames

log_mel_spectrogram = librosa.core.spectrum.power_to_db(mel_spectrogram, ref=1.0, amin=1e-10, top_db=80.0)

S_db ~= 10 * log10(S) - 10 * log10(ref)

librosa采用以上方式计算log映射,python_speech_features定义mfcc( )函数时直接取自然常数e为底的对数。

10.IFFT变换,实际采用DCT得到MFCC,shape = n_mels * n_frames

mfcc = scipy.fftpack.dct(log_mel_spectrogram, type=2, n=None, axis=0, norm=None, overwrite_x=False) 
# n表示计算维度,需与log_mel_spectrogram.shape[axis]相同,否则作填充或者截断处理。axis=0表示沿着自上而下的方向,分别选取每一行所在同一列的元素进行运算。

与python_speech_features相同,librosa也是调用scipy对log_mel_spectrogram进行离散余弦变换:scipy.fftpack.dct()。

11.取MFCC矩阵的低维(低频)部分,shape = n_mfcc * n_frames

mfcc = mfcc[ :n_mfcc]  # 取低频维度上的部分值输出,语音能量大多集中在低频域,数值一般取13。

二、python_speech_features

ea52a048c566cf7090e320de202ec4a2.png

1.源语音信号,shape = wav.length

sample_rate,signal = scipy.io.wavfile.read(filename, mmap=False) # scipy加载语音文件
signal, sample_rate = librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None,dtype=np.float32, res_type='kaiser_best')            # librosa加载语音文件

2.预加重,shape = wav.length

signal = numpy.append(signal[0],signal[1:] - coeff * signal[:-1])

语音信号的预加重,目的是为了对语音的高频部分进行加重,去除口唇辐射的影响,增加语音的高频部分的分辨率和信噪比,计算方式为:y(n))=x(n)-a*x(n-1),系数a一般取0.97。

3.分帧和加窗,shape = n_frames * n_ftt

3d8b5ba76d8b6bcf0d9d9420363c91c9.png
frames = python_speech_features.sigproc.framesig(signal,frame_len,frame_step,winfunc=lambda x:numpy.ones((x,))) # 分帧及加窗函数

python_speech_features中默认帧长取25ms、帧移10ms,对应实际的采样点为:

帧长点数 = 帧长时间 * 采样率 ,帧移点数 = 帧移时间 * 采样率

numframes = 1 + int(math.ceil((1.0*slen - frame_len)/frame_step))  # 计算总分帧数

总分帧数量 = 1 + 向上取整( ( 原信号长度 - 帧长点数 ) / 帧移点数 )

padlen = int((numframes-1)*frame_step + frame_len)     # 计算待填充点的数量
zeros = numpy.zeros((padlen - slen,))                  # 在原数据末尾进行零填充

待填充点数 = ( 总分帧数量 - 1 ) * 帧移点数 + 帧长点数

这种填充方式和上面librosa的自定义的那种填充方式( y = numpy.pad(wav, (0,pad_need), mode='constant') )效果是一样的,可以看出librosa库的功能还是更加多样化的。

加窗的话,python_speech_features默认不加窗,但提供了调用numpy中窗函数的参数接口,经测试numpy.hanning窗函数和scipy.signal.windows.hann窗函数的数值是一致的,只不过前者为矩阵形式(元素相同的多个向量构成),后者为向量形式。

mfcc = python_speech_features.base.mfcc(signal,samplerate=16000,winlen=0.025,winstep=0.01,numcep=13,nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,ceplifter=22,appendEnergy=True,winfunc=lambda x:numpy.ones((x,))) 
# winfunc参数即为窗函数接口,例如 winfunc=numpy.hanning

4.STFT处理得到spectrum(频谱,实际是多帧的),shape = n_frames * (n_ftt // 2 +1)

complex_spec = numpy.fft.rfft(frames,n_fft)    # 离散傅里叶变换得到频谱图

和librosa一致,python_speech_features也是调用numpy下的函数做离散傅里叶变换。

5.取绝对值得到magnitude spectrum/spectrogram(声谱,包含时间维度,即多帧),shape = n_frames * (n_ftt // 2 +1)

mag_spec = numpy.absolute(complex_spec)       # 承接上一步取绝对值得到幅度谱

6.取平方得到power spectrum/spectrogram(声谱,包含时间维度,即多帧),shape = n_frames * (n_ftt // 2 +1)

power_spec = 1.0 / n_fft * numpy.square(mag_spec) # 承接上一步取平方得到功率谱

python_speech_features计算功率谱的方式和libraosa不一致,这里额外除以了傅里叶变换的维度n_fft。

7.构造梅尔滤波器组,shape = n_mels * (n_ftt // 2 +1)

fb = python_speech_features.base.get_filterbanks(nfilt=20,nfft=512,samplerate=16000,lowfreq=0,highfreq=None)

fed2029f8ced71967eb44ad318941b06.png

关于梅尔滤波器的构造细节,参考了这篇文章的部分介绍。具体细节如下:

赫兹转梅尔:mel = 2595 * log10( 1+ hz / 700. )

梅尔转赫兹:hz = 700 * ( 10** ( mel / 2595.0 ) - 1 )

(1)假设构造n_mels=10个梅尔滤波器,建立坐标系纵坐标表示mel刻度、横坐标表示Hz刻度

(2)横坐标(频率)设置最低值300hz、最高值8000hz(采样率的二分之一),对应的纵坐标的最低和最高值分别为401.97mel和2840.02mel。

(3)把纵坐标从低到高划分为12(10+2)个离散的点melpoints = [ 401.97, 623.61,845.25,1066.89,1288.54,1510.18, 1731.82,1953.46, 2175.10,2396.74,2618.38,2840.02] ,这些点映射回横坐标上分别为[ 300,517.34,781.91,1103.98,1496.06,
1973.34,2554.36,3261.65,4122.66,5170.80,6446.75, 8000. ]。

(4)上面横坐标这12(0-11)个点正好对应10个三角滤波器的三个点:例如0、1、2分别对应第一个滤波器的左底点、顶点、右底点,1、2、3对应第二个滤波器,以此类推第十个滤波器对应9、10、11。这十个三角滤波器的函数解析式如下:

6bdd514be2f32d4ff1fa22b108ef5f27.png

(5)对信号的滤波处理本质上是乘法运算,由于待滤波的spectrogram实际是离散的数据,所以要对连续的滤波器函数进行离散的采样,从源代码来看python_speech_features和librosa的采样方式是不同的,经测试发现两者所构造的梅尔滤波器数据确实不一样。

(6)拿第一个滤波器举例来说,其横坐标的采样点选择是根据经傅里叶变换后的spectrogram维度确定的:

bin = numpy.floor( ( n_fft + 1 ) * mel2hz( melpoints ) / samplerate ) # 例子中n_fft取值512,samplerate取值16000
# 构造梅尔采样容器,实际上就是把原横坐标"samplerate/2"上的12个离散点映射到新横坐标"(n_ftt+1)/2"上面,这样做保证了后面的乘法运算维度一致。
# bin = [  9.  16.  25.  35.  47.  63.  81. 104. 132. 165. 206. 256.],例子中n_fft取值512

经过以上映射后,第一个滤波器的函数表达式就确定了:在[9,16)区间为y=(x-9)/(16-9),在[16,25]区间为y=(25-x)/(25-16),其余点y取值为0。在这个滤波器的257(0-256)个离散点中,沿着三角形左边y值逐渐递增,在顶点处达到最大值"1",然后顺着右边y值逐渐递减到0,其余部分点对应的纵坐标取值都为0。

(7)例子中(n_mel=10,n_fft=512,samplerate=16000)构造的梅尔滤波器矩阵具体数值如下(作了转置处理):

3d62ca62e421063e48f5991846ad87d9.png

8.矩阵乘法得到mel_spectrogram,shape = n_frames * n_mels

mel_spectrogram = numpy.dot(power_spec,fb.T)

[ n_frames ,(n_ftt // 2 +1) ] * [ (n_ftt // 2 +1) ,n_mels ] = [ n_frames,n_mels]

mel_spectrogram矩阵中的每个元素其实就是每一帧spectrogram向量和每个滤波器向量的内积。mel_spectrogram(0,1)即为第1帧的spectrogram同第2个三角滤波器内积运算的结果。

9.对mel_spectrogram进行log变换,shape = n_frames * n_mels

log_mel_spectrogram = numpy.log(mel_spectrogram) 
log_mel_spectrogram = python_speech_features.sigproc.logpowspec(frames,n_ftt,norm=1)

python_speech_features.base.mfcc( )函数默认取以自然常数e为底的对数,作者还提供了另一种取对数域的接口python_speech_features.sigproc.logpowspec( ),计算方式与librosa略有差异:log_S = 10 * log10(S)

10.IFFT变换,实际采用DCT得到MFCC,shape = n_frames * n_mels

mfcc = scipy.fftpack.dct(log_mel_spectrogram, type=2, n=None, axis=0, norm=None, overwrite_x=False) 
# n表示计算维度,需与log_mel_spectrogram.shape[axis]相同,否则作填充或者截断处理。axis=0表示自上而下方向分别选取每一行所在同一列的元素进行计算。

11.取MFCC矩阵的低维(低频)部分,shape = n_frames * n_mfcc

mfcc = mfcc[:,:n_mfcc]  # 取低频维度上的部分值输出,语音能量大多集中在低频域,数值一般取13。

python_speech_features.base.mfcc(appendEnergy=True )函数中,appendEnergy参数控制是否把MFCC的第一个倒谱系数替换为每一帧总能量的对数,每一帧总能量的计算方式为:

energy = numpy.sum(power_spec,axis=1) # axis=1表示沿着从左到右的方向,分别选取每一列所在同一行的元素进行运算。

12.倒谱提升,shape = n_frames * n_mfcc

mfcc = python_speech_features.base.lifter(cepstra=mfcc, L=22)

倒谱提升系数默认设置为22,具体实现方式为:

nframes,ncoeff = numpy.shape(cepstra)              # ncoeff=n_mfcc
n = numpy.arange(ncoeff)                           # n=0,1,2...n_mfcc-1
lift = 1 + (L / 2.) * numpy.sin(numpy.pi * n / L)  # lift.shape = n_mfcc * 1
return lift * cepstra                              # shape = n_frames * n_mfcc

13.微分:mfcc的动态特征提取,shape = n_frames * n_mfcc

mfcc_delta_1 = python_speech_features.base.delta(feat=mfcc, N=1)  # 计算mfcc的一阶微分
mfcc_delta_2 = python_speech_features.base.delta(feat=mfcc, N=2)  # 计算mfcc的二阶微分

有时会把MFCC的基础特征同其一阶、二阶微分数据结合起来使用,以做到特征层面的动静结合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Uno 平台 一 WinUI终极跨平台方案(一)

以下是 Uno 平台的官方介绍:关于 Uno 平台Uno平台能够创建像素级完美的,只通过C#XAML编写的应用程序,能够跨平台运行在Windows,iOS,安卓,macOS,Linux和Web上,Uno 平台是免费和开源的…

Python程序员的30个常见错误

全世界只有3.14 % 的人关注了数据与算法之美在这篇文章中,我将总结新老Python程序员常犯的一些错误,以帮助你们在自己的工作避免犯同样或类似错误。推荐阅读《Python3.0科学计算指南》首先我要说明一下的是,这些都是来源于第一手的经验。我以…

Java程序员从笨鸟到菜鸟之(一百零四)java操作office和pdf文件(二)利用POI实现数据导出excel报表...

在上一篇博客中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式。不仅仅简单的读取office中的数据.尤其是在生产管理或者财务系统中用的非常普遍,因…

为什么 HTTP3.0 使用 UDP 协议?

还记得以前我提过的常见面试题么:从浏览器地址栏输入网址,到网页彻底打开,中间都发生了什么?从浏览器输入网址,到网页打开,发生了什么,这题有多经典,很多业内技术大牛说用过这题面试…

程序员为啥365天都背电脑包?这答案我服!

全世界只有3.14 % 的人关注了数据与算法之美最近微博上有个最新热门话题“关于报BUG(漏洞)的礼仪”不要跟程序员说程序有BUG他们第一反应是:你的环境有问题吧?接着就是:XXX你会用吗!(此处不可描…

html li 做瀑布流,js实现瀑布流效果(自动生成新的内容)

当滚动条接近底部会自动生成新的内容(色块)效果图:代码如下:Title*{list-style: none;}div{overflow: hidden;}ul{float: left;}li{width:300px; margin-bottom:10px;}function rnd(n,m){return parseInt(Math.random()*(m-n))n;}function cl(){var li …

jquery实现多行滚动效果

2019独角兽企业重金招聘Python工程师标准>>> 有时jquery博客想,整那么多demo有什么用呢? 有些前端新手朋友不会,为他们服务吧。还有喜欢自己留点字迹,也好方便自己回过头看看。 温故而知新嘛。 前端需要那么多js特效&a…

.NET 搭建简单的通知服务

搭建简单的通知服务Intro很多情况下,我们都会遇到一些需要进行通知报警的场景,比如说服务器资源监控报警,抢到火车票后通知用户进行付款。原来主要是用的钉钉群里的机器人来做的通知,周末看到原来做 【Server 酱】的大佬写了一个简…

c#程序设计教程 唐大仕pdf_C# 添加PDF水印

概述一般我们在向文档添加水印时,会分为直接添加文字水印和加载图片添加图片水印两种情况。常见的,在添加文字水印时会多以声明文档版权、权威性的文字、标语或者名称等;同样的,图片水印也通常可以是某组织的LOGO、印章、或者其他…

电脑病毒竟然被程序员当宠物养!网友:这些都是我逝去的青春

全世界只有3.14 % 的人关注了数据与算法之美起电脑病毒,大家第一时间应该是想到的熊猫烧香,木马等等吧。很多电脑病毒破坏力惊人,熊猫烧香在当年也是让全国人民都陷入一种恐慌状态。但对于我们程序员来说,看过的病毒跟吃的米一样多…

.NET5 WPF进阶教程

↑↑↑ 点击左上角蓝字关注我,为您提供技术新动态。本期内容一、概要本系列将继《.net wpf快速入门教程》带领大家了解wpf,帮助各位在初级向中级过渡的中掌握基本该具备的能力。本系列视频长度大约在15分钟到30分钟左右,视频内容不仅仅会讲解…

python二维列表写入excel_用Python实现合并excel列表

python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。安装xlrd模块,在安装好python的环境下,打开cmd,输入pip install xlrd 回车。安装好后,再输入pip install xlrd回车&#x…

C语言入门经典材料领走不谢!

小天从大学开始,便开启资料收集功能。近几年以大数据的飞速发展,计算机科技进入新的发展阶段,再加上日常的深入研究,小天收集整理了丰富的C语言资料,内容涵盖“入门经典”,“考试必备材料”等。截止到今天&…

vue html引入图片,vue引入图片的几种方式

情况1:图片在/public目录下把图片放到与index.html同级的目录下情况1-1.png方式1因为vue编译后会生成index.html,所以我们将图片与index.html放在同一目录下,相当于在index.html中使用引入图片情况2:图片在/src/assets目录下把图片…

WPF 分页控件的简单实现

想做个分页控件,想了想逻辑实现太复杂了,这不,用奇怪的方式实现了它,就如这张图一样。。。看看效果:下面就直接粘代码喽:新建一个Pagination类:using System; using System.Collections.Generic…

两向量点乘坐标运算_高三数学冲刺复习之向量小题的题型总结(含好用的补充公式)...

高考中,向量小题常从以下几个方面来考查:1、平面向量的有关概念与平面向量的线性运算,主要考查向量的加法、减法运算,考查向量的数乘运算及其几何意义。2、考查平面向量的坐标:主要考查平面向量基本定理及其意义&#…

全球最厉害的14位程序员!

全世界只有3.14 % 的人关注了数据与算法之美导读:全球最厉害的14位程序员是谁?一起来看下让我们膜拜的这些大神都有哪些?(排名不分先后)01 Jon Skeet个人名望:程序技术问答网站Stack Overflow总排名第一的大…

.net5或.net6(Preview) 之 顶级语句

创建一个控制台项目,.net5或.net6(Preview),在Program.cs中写如下代码,F5,能顺利跑起来,没有Program类,没有Main函数。这是C#9带来的顶级语句的功能。System.Console.WriteLine("你好,C#");其实这…

班尼机器人维修方法_梅州市ABB机器人控制器维修中心

梅州市ABB机器人控制器维修中心库卡机器人KSP600-3X64库卡KSP控制器驱动器报警KSP600-3X64/00198268KSP600-3x20/ECMAS3D2224BE531/KSP600-3x40/ECMAS3D4444BE531/产品名称:库卡KSP600-3X64伺服包维修库卡KR控制系统伺服包型号:库卡机器人驱动模块KSP600-3x20/ECMAS3D2224BE531…

c# 获取当前活动窗口句柄,获取窗口大小及位置

2019独角兽企业重金招聘Python工程师标准>>> 需调用API函数 需在开头引入命名空间 using System.Runtime.InteropServices; 获取当前窗口句柄:GetForegroundWindow() [DllImport("user32.dll", CharSet CharSet.Auto, ExactSpelling true)] public stat…