⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 endpoint_xhg.cpp

📁 语音识别的端点检测程序
💻 CPP
字号:
#include <math.h>

#include "cst_lib.h"
#include "basop.h"
#include "EndPoint_xhg.h"



/*=====================================================
函数名称:	EndPointDetection
函数功能:	端点检测
输入参数:	EnergyArray		Frame_Num长的数组,存储每一个Frame的能量
			fRatioFreq		存储每一个Frame的低频域对数能量。
			nZeroPassArray	存储每一个Frame的过零次数。
			Frame_Num		总的帧数
			Energy_Th		噪声能量门限
输出参数:	nStartFrame		返回检测的起始端点
			nEndFrame		返回终止端点。

备注:		
基本思路:	根据观察数据, 元音段的过零率一般都要小于30, 而噪声的过零率一般都要小于100
			另外的两个特征都比较的稳健, 一般来说, 起伏不大
			//	由于对于孤立词, 不同的句子, 存在着一些比较异常的情况, 
			//  如从句子的开始就是语音, 或者是句子的托尾比较长, 直到句子末尾
			//	这样靠前后帧的能量作为端点就不太稳定, 而用很多句话自适应出来的能量
			//	门限如果各种话的背景不太一样, 那么这样的能量门限也是不可靠的
			//  所以根据低频能量的想法, 把总的能量也进行最大值的归一化, 其实实验发现这样也不行, 

====================================================*/
void	EndPointDetection(float *EnergyArray, short *nZeroPassArray, float *fRatioFreq, short Frame_Num, short &nStartFrame, short &nEndFrame, float Energy_Th)
{
	short	nCrudeStart, nCrudeEnd;				//粗略的起点和终点
	short	Wait_Duration = 0;					//统计计数用变量
	short	Wait_Duration1= 0;					//统计计数用变量
	short	wFrameCount;						//循环计数变量
	float	EnergyThreshUsed;					//可以调节的门限

	/**********************************************************
	<------------------粗判
	**********************************************************/
	EnergyThreshUsed =Energy_Th + 1.3f ; //由于Energy_Th是对数能量, 相对于能量域, 相当于Energy_Th * 27
	
	//确定元音段, 从第0帧开始
	for(wFrameCount=0; wFrameCount<Frame_Num; wFrameCount++)
	{
		//同时用过零率, 区段频域能量, 总的能量作为判断条件
		//可以先找到元音段, 如果针对汉语来做的话, 肯定是有元音段的, 
		if( (fRatioFreq[wFrameCount]>-4) && (nZeroPassArray[wFrameCount]<70) && (EnergyArray[wFrameCount]>EnergyThreshUsed))
		{
			Wait_Duration++;
			//如果连续有3帧满足条件, 即认为找到起始点
			if (Wait_Duration > 3)
				break;
		}
		else
			Wait_Duration = 0;
	}
	nCrudeStart = wFrameCount - 3;

	//如果在上述条件下没有找到起始帧nCrudeStart, 即端点的搜索已经到了最后一帧,则放宽条件
	if(wFrameCount == Frame_Num)  
	{
		Wait_Duration = 0;
		for (wFrameCount=0; wFrameCount<Frame_Num; wFrameCount++)
		{
			//此时仅仅用能量作为判断条件
			//相当于最大能量的0.135
			if (EnergyArray[wFrameCount] > (EnergyThreshUsed + 1 ))
			{
				Wait_Duration++;
				//如果连续有4帧满足条件, 即认为找到起始点
				if (Wait_Duration> 4)
					break;
			}
			else
				Wait_Duration = 0;
		}
		nCrudeStart = wFrameCount - 4;
	}

	//从语音的尾部, 倒数第4帧开始找结束帧nCrudeEnd
	Wait_Duration = 0;
	for (wFrameCount=Frame_Num-4; wFrameCount>nCrudeStart; wFrameCount--)
	{
		//同时用低频能量, 和总的能量作为条件, 过零率作为条件搜寻元音段, 即过零率<40
		if ((fRatioFreq[wFrameCount]>-4) && (EnergyArray[wFrameCount]>EnergyThreshUsed) && (nZeroPassArray[wFrameCount]<70))
		{
			Wait_Duration++;
			if (Wait_Duration> 2)
				break;
		}
		else
			Wait_Duration = 0;
	}
	nCrudeEnd = wFrameCount + 2;

	//如果在上述条件下没有找到结束帧nCrudeEnd, 则放宽条件
	if (wFrameCount == nCrudeStart)  
	{
		Wait_Duration = 0;
		for (wFrameCount=Frame_Num-1; wFrameCount>nCrudeStart; wFrameCount--)
		{
			//仅仅用能量作为标准来判断
			if (EnergyArray[wFrameCount] > (EnergyThreshUsed + 1))
			{
				Wait_Duration++;
				if (Wait_Duration > 2)
					break;
			}
			else
				Wait_Duration = 0;
		}
		nCrudeEnd = wFrameCount + 2;
	}

	//如果起始帧和结束帧的距离太小, 则将起始帧设为4, 结束帧设为最后一帧, 交给下一级
	if (nCrudeEnd - nCrudeStart < 2)
	{
		nCrudeStart = 4;
		nCrudeEnd = Frame_Num - 1;
	}
/***********************************************************
			细判
***********************************************************/
	//寻找结束帧, 从粗判的结束帧开始向后找静音段, 因为在
	//孤立词识别中, 它是必然会有一个结束帧的, 所有应该存在一定的静音段
	//通过数据发现, 过零率作为一个特征, 在找结束帧时, 不稳定, 不好用
	//EnergyThreshUsed = Energy_Th * 5
	EnergyThreshUsed = Energy_Th + 1.3f;
	Wait_Duration = 0;
	for (wFrameCount = nCrudeEnd; wFrameCount < Frame_Num; wFrameCount++)
	{
		//判断过零率, 如果过零率>100, 则认为是轻音, 而不是静音
		if((nZeroPassArray[wFrameCount] < 100) && ((EnergyArray[wFrameCount]<EnergyThreshUsed + 0.5) || (fRatioFreq[wFrameCount]<-4.5)))
		{
			if(EnergyArray[wFrameCount] < (EnergyThreshUsed))	//Energy_Th * 6
				Wait_Duration++;
			else
				Wait_Duration = 0;
			if(fRatioFreq[wFrameCount] < -5.1)
				Wait_Duration1++;
			else
				Wait_Duration1 = 0;
			if ((Wait_Duration > 2) || (Wait_Duration1 >2))
				break;
		}
		else
		{
			Wait_Duration = 0;
			Wait_Duration1 = 0;
		}
	}
	nEndFrame = wFrameCount - 2;

	//寻找起始帧, 从粗判的起始帧往前找
	Wait_Duration = 0;
	Wait_Duration1 = 0;
	for (wFrameCount = nCrudeStart; wFrameCount >= 0; wFrameCount--)
	{
		if((nZeroPassArray[wFrameCount] < 100) && ((EnergyArray[wFrameCount]<EnergyThreshUsed + 0.5) || (fRatioFreq[wFrameCount]<-4.5)))
		{
			if(EnergyArray[wFrameCount] < (EnergyThreshUsed))	//Energy_Th * 6
				Wait_Duration++;
			else
				Wait_Duration = 0;
			if(fRatioFreq[wFrameCount] < -5.0)
				Wait_Duration1++;
			else
				Wait_Duration1 = 0;
			if ((Wait_Duration > 2) || (Wait_Duration1 >2))
				break;
		}
		else
		{
			Wait_Duration = 0;
			Wait_Duration1 = 0;
		}
	}
	nStartFrame = wFrameCount + 2;

	if (nStartFrame < 4)              
		nStartFrame = 4;
	if (nEndFrame > Frame_Num - 4)
		nEndFrame = Frame_Num - 4;

	//如果有声段太短, 则端点检测失败, 将整个语音交给下一级
	if ((nEndFrame - nStartFrame) < 5)        
	{
		nEndFrame = Frame_Num - 4;
		nStartFrame = 4;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -