|
本文主要是描述如何提取MFCC特征,着重于代码层面的实现,留作以后自己参考。具体的声学理论细节可以文后的参考文献。
以下假设语音信号是采样频率是16000赫兹,帧移是10毫秒,帧长25毫秒。记原始语音信号为wave(i)。
首先是信号的分帧,或者说计算帧的数目,根据是否剪边,略有差别。通常的计算方法是:(1 + ((num_samps -frame_length)/ frame_shift))(如果需要剪边,则为num_samples * 1.0/ frame_shift + 0.5)。一般来说MFCC特征的计算方法是逐帧进行的。分帧操作比较简单,也就是将400个采样点读入内存。只是在输入语音的开头和结尾需要做一些对称补齐的操作。在提取出一帧400个采样点之后,需要对其进行添零补齐操作,一般帧长为2的整数次幂,也就是补齐到512个采样点,为了方便快速傅里叶变换。
为了克服某些声音数据的溢出,添加随机噪声(抖动尺度),(*wave)(i) += rand() * dither_value。其中rand()为随机的噪声,是通过Box-Muller变换生成的。(假设U1和U2是被在间隔均匀分布的独立随机变量(0,1)。计算
和
则Z0和Z1是独立随机变量标准正态分布。)接着我们需要移除直流分量,也就是在该帧信号减去该帧信号的平均值。然后我们就可以计算每一帧的对数能量:log_energy =log(sum(wave (i)* wave (i)))。当然也可以在下面加窗操作之后计算对数能量,两种方式都是可以的。
接着我们将经采样后的数字语音信号wave(i),通过一个高通滤波器(high pass filter):,其中在0.9到1.0之间 (一般取0.97左右)。是为预加重。经过预加重后的信号为:,也就是,(*wave)(i) -=preemph_coeff * (*wave)(i-1)。预加重的目的是提升高频部分,使信号的频谱变得平坦,保持在低频到高频的整个频带中,能用同样的信噪比求频谱。同时,也是为了消除发生过程中声带和嘴唇的效应,来补偿语音信号受到发音系统所抑制的高频部分,也为了突出高频的共振峰。
接着我们需要对该帧信号进行加窗操作。加窗的类型有四种,海宁窗(hanning),海明窗(hamming),波维窗(povey),以及矩形窗(rectangular)。Dan Povey设计了一种波维窗,和海明窗较像,但是在边界处趋向于零,海明窗是
window(i) = 0.54 -0.46*cos(2PI * i / (400-1)),
而波维窗是
window(i) = pow(0.5 - 0.5*cos2PI * i / (400-1)),0.85)。
从下图可以看出,两种窗函数基本上重合。一般我们用海明窗,能偶有效克服泄露现象。记加窗后的语音信号为windowed_wave(i)。
以上算是完成了一帧语音信号的预处理,下面我们开始对其进行变换操作。首先我们计算该帧的傅里叶变换。现在采用较广,速度较快的是分裂基(Split-radix fft)算法。一般的快速傅里叶变换是将信号按照角标的奇偶分为两部分(radix-2 fft),分别做傅里叶变换,然后再合并。以上过程一直递归到两个点的傅里叶变换,简单的可以将其表达式列为:
或者分为4部分(radix-4 fft):
而分裂基算法很有意思,是radix-2和radix-4的混合:
这种算法可以较大幅度的降低复杂度,对在线的语音识别比较有用。
在做完傅里叶变换之后,记为fft_x(i)。接着我们要在fft_x(i)的基础上计算功率谱(power spectrum),也就是求fft_x(i)的模的平方:ps_x(i) = real*real + im*im。
接着我们在功率谱的基础上计算梅尔能量(mel energies)。此处我们会用到Mel滤波器组(mel banks),其中有25个滤波器。使用该Mel滤波器组对以上计算得到功率谱使用向量乘法计算得到25维的mel能量。
其中会用到声道长度归一化(vocal tract length normalization)中弯曲函数,如下所示,其中默认的参数为低频下限(20),高频上限(0),声道长度归一化(vocal tract length normalization)中弯曲函数的下限(100)和上限(-500)
以及普通频率到梅尔尺度频率的映射1127.0 * log (1.0 + f /700.0), 其中的log为标准对数。文献[1]中为以10为底的对数,系数略有不同。
接着对得到的25维mel能量做DCT变换。DCT矩阵如下所示
(*M)(k,n) =Normalizer * std::cos( static_cast<double>( PI)/N * (n + 0.5) * k ),其中N为25。通过左乘将25维mel能量映射到倒谱域,原本系数其实有25维,但是一般仅仅取前13维。接着对其做倒谱提升,以下是13维倒谱提升系数(*coeffs)(i) = 1.0 + 0.5 * Q * sin(REAL_PI * i / Q); 其中Q是倒谱系数22.0。使用倒谱提升系数与得到倒谱特征相乘,就得到了语音界用了三十多年的经典的梅尔倒谱系数特征。
注:
1. 定义std::ifstream is("test.wav",std::ifstream::binary)时,必须注意文件是binary还是text的格式的,不然容易读取不到全部数据,引起错误;
参考文献
@book{韩纪庆2004语音信号处理,
title={语音信号处理},
author={韩纪庆},
year={2004},
publisher={清华大学出版社有限公司}
}
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-11-1 09:25
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社