?? endpoint_xhg.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 + -