概念
过零率 (Zero Crossing Rate):过零率(zero crossing rate)是一个信号符号变化的比率,即,在每帧中,语音信号从正变为负或从负变为正的次数。 这个特征已在语音识别和音乐信息检索领域得到广泛使用,通常对类似金属、摇滚等高冲击性的声音的具有更高的价值。一般情况下,过零率越大,频率近似越高。
频谱质心 (Spectral Centroid):谱质心(Spectral Centroid)是描述音色属性的重要物理参数之一,是频率成分的重心,是在一定频率范围内通过能量加权平均的频率,其单位是Hz。它是声音信号的频率分布和能量分布的重要信息。在主观感知领域,谱质心描述了声音的明亮度,具有阴暗、低沉品质的声音倾向有较多低频内容,谱质心相对较低,具有明亮、欢快品质的多数集中在高频,谱质心相对较高。该参数常用于对乐器声色的分析研究。
声谱衰减 (Spectral Roll-off):它是对声音信号形状(波形图)的一种衡量,表示低于总频谱能量的指定百分比的频率。
梅尔频率倒谱系数 (Mel-frequency cepstral coefficients ,MFCC):在语音识别(SpeechRecognition)和话者识别(SpeakerRecognition)方面,最常用到的语音特征就是梅尔倒谱系数(Mel-scaleFrequency Cepstral Coefficients,简称MFCC)。根据人耳听觉机理的研究发现,人耳对不同频率的声波有不同的听觉敏感度。从200Hz到5000Hz的语音信号对语音的清晰度影响对大。两个响度不等的声音作用于人耳时,则响度较高的频率成分的存在会影响到对响度较低的频率成分的感受,使其变得不易察觉,这种现象称为掩蔽效应。由于频率较低的声音在内耳蜗基底膜上行波传递的距离大于频率较高的声音,故一般来说,低音容易掩蔽高音,而高音掩蔽低音较困难。在低频处的声音掩蔽的临界带宽较高频要小。所以,人们从低频到高频这一段频带内按临界带宽的大小由密到疏安排一组带通滤波器,对输入信号进行滤波。将每个带通滤波器输出的信号能量作为信号的基本特征,对此特征经过进一步处理后就可以作为语音的输入特征。由于这种特征不依赖于信号的性质,对输入信号不做任何的假设和限制,又利用了听觉模型的研究成果。因此,这种参数比基于声道模型的LPCC相比具有更好的鲁邦性,更符合人耳的听觉特性,而且当信噪比降低时仍然具有较好的识别性能。梅尔倒谱系数(Mel-scale Frequency Cepstral Coefficients,简称MFCC)是在Mel标度频率域提取出来的倒谱参数,Mel标度描述了人耳频率的非线性特性,它与频率的关系可用下式近似表示:
色度频率 (Chroma Frequencies):色度频率是音乐音频有趣且强大的表示,其中整个频谱被投影到12个区间,代表音乐八度音的12个不同的半音(或色度)
MFCC提取
提取流程
参考:https://zhuanlan.zhihu.com/p/69103667
一,处理.wav格式的音频文件,得到信号数据和采样频率
首先是拿到.wav格式的音频文件,其它格式比如.mp3需要进行转换,转换软件或方法有很多,不在本文讨论范围。大家很好奇该文件究竟存的什么东西,我一言以蔽之,其实除了文件头以外,就是声音波形图按照某一刻度刻画出来的离散点的值,粗暴点可以描述为信号signal = [ 0 0 -1 ..., 627 611 702],这是我自己demo的数据(接下来都以这一数据作研究)。.wav文件进行处理后就是含有107000个元素的数组,怎么从 .wav文件得到这个数组,参考python(scipy和numpy库)的(rate,signal) = scipy.io.wavfile.read("Ansel.wav"),python库的这一个方法就可以读取到.wav文件的信号数组signal和该声音文件的采样频率,此处频率rate=8000HZ。
二,预加重,{A(1*107000)}
预加重我至今没完全理解,看了一些资料,也专门加了qq群去问人,也没问到,可能我资质太低,我一直不理解时域上的采样点为啥有高低频之分,时域采样点都是固定的采样频率(8000HZ或16000HZ),所以我对下面这段话:
[语音和图像信号低频段能量大,高频段能量小...低频段信噪比大,高频信噪比低...增大高频段信噪比....]
我的理解:
这里说的高频低频是指时域上采样点分帧后的频率,针对每一帧,作傅利叶变换得到频域的N个分量,这N个分量按照频率为横坐标,振幅为纵坐标。如果没有噪音,这N个分量振幅值应该随着频率增大逐渐递减,但因为噪音存在,在某一高频段处,振幅值出现反常,变得很大,导致信噪比很小,而预加重就是为了把高频段的信号都放大,从而增大高频段的信噪比。
我的理解极有可能是错的,但我知道预加重的做法,还是以我做的demo做数据,signal = [ 0 0 -1 ..., 627 611 702]含有107000个点,预加重做法就是针对这些点,套用公式signal[i]=signal[i+1]-0.97*signal[i],因此得到一个新的数组A=[ 0. 0. -1. ..., -40.36 2.81 109.33],数组大小还是107000。系数0.97可以自己选取,据说0.95左右。
三,分帧,{B(1336*200)}
分帧原理就不说了,我说下做法:把上述数组A的元素值,200个为一帧,80个为帧移,总共可以得到1336帧,因为不是整除,1336*80+200=107080,多出的80个点用0填补,所以得到1336*200的二维数组B。
上述200个为一帧,80个为帧移是这样来的,因为默认语音信号具有短时平稳性,这平稳性不是说短时采样得到的值相等,而是认为短时间内声带、声道、唇口鼻腔这3个声音信号源头具有平稳性,据说是人体肌肉活动短时平稳。短时默认是0.025s,两个相邻短时间隔默认是0.01s,因为我分析的.wav文件是8000HZ, 所以0.025s内有0.025*8000=200个采样点,帧移0.01*8000=80个采样点。
四,加窗,{C(1336*200)}
需要一个1336*200的窗数组C,这里默认元素值都初始化为1(为了简单,用的矩形窗),实际中需用汉明窗,其实汉明窗一样道理,只不过用汉明窗的的话,这1336*200的二维数组元素值需要根据汉明窗函数计算得到。汉明窗函数是一个余弦函数,作用是为了使帧和帧之间变得平滑,消除吉布斯效应(傅利叶变换时无法得到边界值,据说是傅利叶打败拉格朗日的跨历史争执),接下来说下具体怎么加窗。
分帧后的数组B和窗函数数组C具有相同的维度,把它们对应位置的元素值相乘,即可以得到加窗后的二维数组C,C[i[j]=B[i][j]*C[i][j]],因为我用的矩形窗,C[i][j]值都为1,所以C=B。
五,离散傅利叶变换(FFT),{D(1336*257),E(1336*257),F(1336*1)}
首先还是温习下[傅里叶变换 掐死教程],看完这个教程我认为,已知经过加窗后的信号C具有1336*200维,也就是说有1336行(帧),每行200个点,每相邻两行之间有120个重合点(帧移80)。那么对它做傅利叶变换,粗暴的理解为,对有1336帧,每一帧都作N=512的傅利叶变换,这个过程可以认为每一帧分解为257个分量,每个分量其实是一个正/余弦波的振幅,也就把短时的时域帧(200个点)分解为频域上的257个分量,有点像力学分解...
因此可以得到1336*257维的频域信号D,帧数还是1336,对每一帧的257个点的值(个人认为是振幅)取平方,再乘以1/512,便得到能量,这个公式我不理解,我只记得高中时有印象振幅好像代表能量,但是平方再除以512,我就不明白为啥,难道跟面积/边长计算类似?不管怎样,得到1336*257的能量普E,然后对每一帧的257个能量值简单相加,得到该帧的能量总值,一共有1336帧,于是有1336个能量总值,即拥有1336个元素值,记为数组F,数组中每个元素值代表一帧的能量总值。
六,获得梅尔滤波器{G(26*257)}
如上图,梅尔值是一个新的量度,据说相比频率量度,梅尔更接近人耳的听觉机理,通俗的说,就像纳米和米一样,如果我们用纳米衡量我们身边的事物会是一种什么感受?所以频率的某一个值对应着梅尔的某一个值,该印射关系可以用这个公式描述,梅尔值f(f)=2595*lg(1+f/700.0),如果要反过来,频率f(m)=700*(10**(m/2595.0)-1),10**(m/2595.0)意思是10的(m/2595.0)次方。我们看第一个公式,我们的采样频率除以2就是真实信号的最大频率,真实信号的最小频率为0,依据公式的单调性,我们以这个最大频率和最小频率为界限分别得到梅尔刻度的最大最小值,可以把信号的所有频率值刻画在这个梅尔区间之内。
梅尔滤波器个数一般默认26个,前期准备工作需要在上述最大最小梅尔区间等间距插入26个值,包括边界,就是28个值,然后把这28个值的频率值也算出来,得到28个频率和梅尔的一一对应关系。接下来对这28个频率值,依次代入公式y=(512+1)*x/8000),便可以得到28个y值。我不明白这个公式干嘛的,只知道,512是傅利叶变换的N,8000是采样频率,。
接下来计算26个滤波器的二维数组,先初始化为元素值都为0的26*257二维数组G,然后通过循环填补该二维数组的值,过程大致是针对G的每一行,根据行下标(0~25),再结合上述的28个y值,计算出每行的各个元素值,其计算过程是把相邻两个y值相减作分母,分子是每行的元素值下标减去28个元素的下标为行元素值下标的值,再用28个元素的下标为行元素值下标的值减去每行的元素值下标。针对每一行,这样可以得到三角形形状的数据分布,三角形顶点为1,除此三角形数据分布之外的点都为0,这个二维数组G经过转化之后便得到每行只有一部分有值,其余值为0的二维矩阵,而且有值部分数据呈三角形分布。此处很难解释,没图说个j*,用文字简直不可描述,还是上图来说明。如下所示,图中H1(k)是G的第一行元素值分布,H3(k)是G的第二行元素值分布,H26(k)是G的第26行元素分布,每一行都有257个元素值,比如H1(k),也就是G的第一行,只有开头几个元素值有值,其余200多个值均为0,且有值部分值大小先线形增大到1,再线性减小到0。
七,得到能量特征参数的和能量总值{H(1336*26)}
把第五步得到的二维矩阵能量谱E(1336*257),乘以第六部的二维数组梅尔滤波器G(26*257)的逆,矩阵的逆可得到257*26的矩阵,然后满足矩阵乘法定律,得到参数H=E*G.T,此处的H其实是1336*26的二维矩阵。还有个参数是第五步计算出来的每帧能量总值F(1336*1),即拥有1336个元素值的一维数组F。
八,作自然对数运算,离散余弦变换(DCT)和升倒谱运算{J(1336*13),K(13*1),L(1336*13),feat[1336*13]}
对H的每一个元素值做ln运算,即H[i][j]=ln(H[i][j]),此处我也不明白原理,但很多资料记载说需要做这一部操作,好像是什么公式。接着对feat的每一行做离散余弦变换(离散余弦变换类似傅利叶变换,只不过作用在实数范围)。据说离散余弦变换后的数据分布可以把冗余数据分开,而且大部分信号数据一般集中在变换后的低频区,所以对每一帧只取前13个数据就好了,于是得到1336*13的二维数组J。
针对1336*13的二维数组J做升倒谱操作,默认升倒谱系数为22,这个过程做法是先产生一个拥有13个元素的一维数组K,这13个元素的值K[i]=1+(22 /2)*sin(pi*i/22),其中22是升倒谱系数,pi是圆周率3.1415926。得到这个数组K之后,针对1336*13的二维数组J,J[i][j] = J[i][j]*K[j],得到1336*13的二维数组L,这其实就是mfcc参数的第一组。如果这组参数想要加上能量作为其表示方式,可以把这1336帧,也就是每一行的的第一个元素用一维数组F的每个值替换,即L[i][0] = F[i]。
我们把这经过错综复杂得到的L记为feat,它是个二维数组,拥有1336*13个值,这也是mfcc参数的基础参数,也是第一组,默认是有3组,接下来计算第二和第三组参数。
九,计算第二组和第三组参数{feat[1336*13],feat'[1336*13],feat''[1336*13]}
一言以蔽之,第二组参数其实就是在已有的基础参数下作一阶微分操作,第三组参数在第二组参数下作一阶微分操作,相当于对基础参数导数的导数。微分(dx)如果忘了,就把他理解为自变量增长为1的函数值的变化量,准确点描述是要计算离散点之间的变换率,而不是连续函数的导数,但原理类似。
具体操作是这样的,抽取一个计算一阶微分的函数,然后把1336*13的二维数组feat作为参数传入,返回feat的一阶微分feat‘,feat'同样有1336*13个元素值。这个函数有点复杂,我把python函数贴上来。我简要说两句,其实这个过程是把feat按照行作循环,每一行拥有13个元素值,如果不考虑边际效应,feat'[i][j]={feat[i][j+1]-feat[i][j-1] + 2(feat[i][j+2]-feat[i][j-2]) + 3(feat[i][j+3]-feat[i][j-3]) + ... + n(feat[i][j+n]-feat[i][j-n])} / M,M作为分母,是这个函数输入的big_theta来决定的,big_theta默认值是2,此处的M值可以算出是10,过程参照函数代码。这个公式可能还是太复杂,如果大家对一阶展开式或者泰勒展开式还有印象,对这些应该就不会陌生,上述公式可以再简化点,大概长成这样f’(x)={f(x+1)-f(x-1) + 2(f(x+2)-f(x-2)) + 3(f(x+3)-f(x-3)) + ...+ n(f(x+n)-f(x-n)) } / M,这个就平易近人了,所以此处的计算一阶微分函数,大致过程就是这样。最后得到的输出是1336*13的二维数组feat',也是mfcc参数的第二组参数。
第三组参数同上,把feat'作为参数运用抽取出来的函数作计算,得到输出记为feat'',feat''二维数组同样有1336*13个元素值,这是mfcc参数的第三组参数。
十,得到最后输出{mfcc(1336*39)}
由前八步和第九步,可以得到feat,feat'和feat'',这3个参数都是拥有1336*13个元素值的二维数组,而且这三个二维数组的每一行第一个元素值可以根据需要,用该行(帧)的能量总值替换。把feat,feat‘和feat''拼在一起,即基于feat,每一行横向追加feat'和feat''每行的元素值,得到拥有1336*39个元素值的一个二维数组,也就是mfcc系数,这就是最后得到的结果。