在进行端点处理之后,就可以得到需要处理的信号。但是要进行语音识别就必须进行一个处理:特征提取。进行特征提取我们这里采用的就是FMCC。
具体的流程是怎么样的呢?
那就是:
概述:
MFCC:Mel频率倒谱系数的缩写。Mel频率是基于人耳听觉特性提出来的,它与Hz频率成非线性对应关系。Mel频率倒谱系数(MFCC)则是利用它们之间的这种关系,计算得到的Hz频谱特征。
应用:
MFCC已经广泛地应用在语音识别领域。由于Mel频率与Hz频率之间非线性的对应关系,使得MFCC随着频率的提高,其计算精度随之下降。因此,在应用中常常只使用低频MFCC,而丢弃中高频MFCC。
提取流程 :
MFCC参数的提取包括以下几个步骤:
1. 预滤波:CODEC前端带宽为300-3400Hz的抗混叠滤波器。
2. A/D变换:8kHz的采样频率,12bit的线性量化精度。
3. 预加重:通过一个一阶有限激励响应高通滤波器,使信号的频谱变得平坦,不易受到有限字长效应的影响。
4. 分帧:根据语音的短时平稳特性,语音可以以帧为单位进行处理,实验中选取的语音帧长为32ms,帧叠为16ms。
5. 加窗:采用哈明窗对一帧语音加窗,以减小吉布斯效应的影响。
参考:
以上matlab部分来自于: http://www.ee.columbia.edu/~dpwe/resources/matlab/rastamat/
以及截图来自于JIE的李明老师的ppt。
6. 快速傅立叶变换(Fast Fourier Transformation,FFT):将时域信号变换成为信号的功率谱。
FFT可以用IPP实现,但是用起来好复杂。我找到更简单粗暴的方法:
下面给的C++代码的fft其实是有错的,需要细心的读者发现问题,参考下面两篇博客你就可以知道下面的c++代码错在哪里了。
http://blog.csdn.net/hippig/article/details/8778753
http://bbs.csdn.net/topics/300168593
7.三角窗滤波:用一组Mel频标上线性分布的三角窗滤波器(共24个三角窗滤波器),对信号的功率谱滤波,每一个三角窗滤波器覆盖的范围都近似于人耳的一个临界带宽,以此来模拟人耳的掩蔽效应。
8. 求对数:三角窗滤波器组的输出求取对数,可以得到近似于同态变换的结果。
9. 离散余弦变换(Discrete Cosine Transformation,DCT):去除各维信号之间的相关性,将信号映射到低维空间。
把信号转换到频域之后就更好处理了。在这里我们对于DFT做一些简单的介绍:离散傅立叶变化不能对非周期信号进行处理。我们把这个信号进行处理的时候看作是无限长的周期信号的一个周期。我们可以把我们要做的那部分信号进行扩展成周期性无限的信号进行处理。
可以转换成:
计算公式如下:
10.谱加权:由于倒谱的低阶参数易受说话人特性、信道特性等的影响,而高阶参数的分辨能力比较低,所以需要进行谱加权,抑制其低阶和高阶参数。
11. 倒谱均值减(Cepstrum Mean Subtraction,CMS):CMS可以有效地减小语音输入信道对特征参数的影响。
12.差分参数:大量实验表明,在语音特征中加入表征语音动态特性的差分参数,能够提高系统的识别性能。在本系统中,我们也用到了MFCC参数的一阶差分参数和二阶差分参数。
13. 短时能量:语音的短时能量也是重要的特征参数,本系统中我们采用了语音的短时归一化对数能量及其一阶差分、二阶差分参数。
流程图:
代码:
//ASR.h
#include <stdio.h>
#include <math.h>
#define MAXDATA (256*400) //一般采样数据大小,语音文件的数据不能大于该数据
#define SFREMQ (8000) //采样数据的采样频率8khz
typedef struct WaveStruck//wav数据结构
{
//data head
struct HEAD{
char cRiffFlag[4];
int nFileLen;
char cWaveFlag[4];//WAV文件标志
char cFmtFlag[4];
int cTransition;
short nFormatTag;
short nChannels;
int nSamplesPerSec;//采样频率,mfcc为8khz
int nAvgBytesperSec;
short nBlockAlign;
short nBitNumPerSample;//样本数据位数,mfcc为12bit
} head;
//data block
struct BLOCK{
char cDataFlag[4];//数据标志符(data)
int nAudioLength;//采样数据总数
} block;
} WAVE;
typedef struct //定义实数结构
{
double real;
double image;
}complex;
//获取wav数据样本数据,sample数组的长度至少为MAXDATA,函数返回读入的数据的长度
int getWaveData(char* file,double *sample);
int copy