电子产品世界 » 论坛首页 » 嵌入式开发 » ARM » 客制化DTMF检测算法,使得能够检测到特定的信号


共1条 1/1 1 跳转至

客制化DTMF检测算法,使得能够检测到特定的信号

菜鸟
2018-07-30 19:46:28    评分

[DESCRIPTION]
客制化,新增两个信号,握手信号和确认信号。握手信号是频率1400持续100ms,静音100ms,然后频率2300持续
100ms。确认信号是频率1400持续400ms。
[SOLUTION]
主要的思路是修改函数dtmfAnalyzeFreq,在该函数内部新增2种case来检测握手信号和确认信号。
具体作了如下的改动:
1.
const static int16 DTMF_Freq[10] = { 697, 770, 852, 941, 1209, 1336, 1477, 1633,1400,2300};
2.
const static int16 dtmfFreqTable_new[2] = {'E','F'}; E,F分别代表客户定义的两个pattern(其中E对应到确认信
号: 1400Hz 持续 400ms,F对应到握手信号:1400Hz持续100ms,静音100ms,然后2300Hz持续100ms),同时在侦测过程
中也作为1400/2300频率对应的key.
3.
定义三个变量:
#define SIA_CNT1 100/20 /*100ms/20ms*/ //用来表示1400持续100ms
#define SIA_CNT2 400/20 /*400ms/20ms*///用来表示1400持续400ms
#define SIA_PAUSE_NUMBER 5 /*100ms/20ms*///用来表示静音持续100ms
4.
新增3个成员:
struct dtmfHandle {
int32 block_size;
int32 acum_buf_size;
int32 block_no;
TD_Handle hdl[10];
int32 block_count;
int32 mag[10];
TD_Handle hdl2[10];
int32 block_count2;
int32 mag2[10];
int32 key_threshold;
int16 key;
int16 key_temp;
int16 key_pre; /*decoded key of previous frame*/
int16 key_pre_second; /*decoded key of second previous frame*/
int16 pauseCount; /*continuous low mag or non-key count*/
int32 (*PutData)( DTMF_Handle *hdl, int16 *buf ,int32 len);//return value: consume length of
input buffer
void (*Close)( DTMF_Handle *hdl );
int16 (*GetKey)( DTMF_Handle *hdl );
uint16 status;//记录当前的pattern state,=0表示初始状态,=1表示侦测到1400Hz 持续 100ms,=2表示在
status=1之后侦测到100ms的PAUSE

uint16 framecnt;//用framecnt来计算持续时间。因为一个frame是160字节=20ms.
uint16 silencecnt;//用来计算静音的时间
};
5. 新增4个变量:
uint16 old_framecnt;
uint16 new_framecnt;
uint16 old_silencecnt;
uint16 new_silencecnt;
并且在函数ktDetectDedi中将它们赋值为一样的值,这4个变量将用在函数dtmfAnalyzeFreq中,用以判断当前是否处于
同一次的hisr中。
static void ktDetectDedi( void *data )
{
int16 result;
int16 *buf;
int32 acumBufSize, len, consumedLen;
while ( (uint8)(kt_detect.tmp_w - kt_detect.tmp_r) > 0){
buf = (int16 *)(kt_detect.rb_base + ((kt_detect.tmp_r&FRAME_BUF_MASK) * FRAME_BUF_SIZE));
acumBufSize = 0; len = FRAME_BUF_SIZE; consumedLen = 0;
kal_prompt_trace(MOD_L1SP, " ### DTMF ktDetectDedi begin");
old_framecnt=kt_detect.hdl->framecnt;
new_framecnt=kt_detect.hdl->framecnt; old_silencecnt=kt_detect.hdl->silencecnt;
new_silencecnt=kt_detect.hdl->silencecnt;
while ( acumBufSize < FRAME_BUF_SIZE ){ //not being comsumed to end
consumedLen = kt_detect.hdl->icfansPutData( kt_detect.hdl, buf+acumBufSize, len);
len -= consumedLen;
acumBufSize += consumedLen;
result = kt_detect.hdl->GetKey( kt_detect.hdl );
kal_prompt_trace(MOD_L1SP, " ### DTMF acumBufSize=%d",acumBufSize);
kal_prompt_trace(MOD_L1SP, " ### DTMF ktDetectDedi result =%d",result);
if( result != 0 ) {
kal_prompt_trace( MOD_L1SP, "DTMF =%c, threshold=%d\n", (char)result, kt_detect.hdl-
>key_threshold );
kt_detect.Callback( result );
}
}
kal_prompt_trace(MOD_L1SP, " ### DTMF ktDetectDedi end");
ASSERT(acumBufSize == FRAME_BUF_SIZE);
kt_detect.tmp_r++;
#ifdef KT_DETECT_DEBUG
{
uint32 I;
for( I = 0; I < FRAME_BUF_SIZE; I++ ) {
if( pcmDebugCnt < 80000 )
{

*pcmDebugPtr++ = buf[I];
pcmDebugCnt ++;
}
}
}
#endif
}
}
6.DTMF_Handle *DTMF_Open( int32 block_size, int32 block_no )
{
int32 I;
DTMF_Handle *hdl;
hdl = get_ctrl_buffer( sizeof(DTMF_Handle) );
hdl->block_size = block_size;
hdl->acum_buf_size = 0;
hdl->block_no = hdl->block_count = block_no;
hdl->block_count2 = block_no >> 1;
hdl->key = 0;
hdl->key_temp = 0;
hdl->key_pre = 0;
hdl->key_pre_second = 0;
hdl->pauseCount = 0;
hdl->framecnt = 0;
hdl->silencecnt= 0;
hdl->status= 0;
hdl->PutData = dtmfPutData;
hdl->Close = dtmfClose;
hdl->GetKey = dtmfGetKey;
for( I = 0; I < 10;I++ ) {//carmen lau
TD_Init( &hdl->hdl[I], DTMF_Freq[I], block_size * block_no );
TD_Init( &hdl->hdl2[I], DTMF_Freq[I], block_size * block_no );
}
return hdl;
}
7.
static int32 dtmfPutData( DTMF_Handle *hdl, int16 *buf ,int32 len )
{
int32 I, comsumedLen;
if ( len + hdl->acum_buf_size >= hdl->block_size ){
comsumedLen = hdl->block_size - hdl->acum_buf_size;
}
else{
comsumedLen = len;
}
for( I = 0; I < 10; I++ )
TD_ProcessBlock( &hdl->hdl[I], buf, comsumedLen );

if( hdl->block_no > 1 ) {
for( I = 0; I < 10; I++ )
TD_ProcessBlock( &hdl->hdl2[I], buf, comsumedLen );
}
hdl->acum_buf_size += comsumedLen;
if ( hdl->acum_buf_size < hdl->block_size )
return comsumedLen;
hdl->acum_buf_size = 0;
hdl->block_count--;
if( hdl->block_count == 0 ) {
//printf("Test1 ");
for( I = 0; I < 10; I++ ) {
hdl->mag[I] = TD_GetMagnitudeDB( &hdl->hdl[I] );
TD_Reset( &hdl->hdl[I] );
//printf( "%2d ", hdl->mag[I] );
}
dtmfAnalyzeFreq( hdl, hdl->mag );
hdl->block_count = hdl->block_no;
}
if( hdl->block_no > 1 ) {
hdl->block_count2--;
if( hdl->block_count2 == 0 ) {
//printf("Test2 ");
for( I = 0; I < 10; I++ ) {
hdl->mag2[I] = TD_GetMagnitudeDB( &hdl->hdl2[I] );
TD_Reset( &hdl->hdl2[I] );
//printf( "%2d ", hdl->mag2[I] );
}
dtmfAnalyzeFreq( hdl, hdl->mag2 );
hdl->block_count2 = hdl->block_no;
}
}
return comsumedLen;
}
8.
修改函数dtmfAnalyzeFreq,修改之后的函数如下:
static void dtmfAnalyzeFreq( DTMF_Handle *hdl, int32 *magtab )
{
int I, mag, max1, max2, max3, f1, f2;
int maxLowGroup, maxHighGroup;//max magnitude of Low group ,max magnitude of High group
int idx1, idx2, idx3;
max1 = max2 = max3 = f1 = f2 = 0;
idx1 = idx2 = idx3 = 0;
for( I = 0; I < 10; I++ ) {
mag = magtab[I];
if( mag > max1 ) {

max3 = max2; max2 = max1; max1 = mag;
idx3 = idx2; idx2 = idx1; idx1 = I;
f2 = f1; f1 = I;
}
else if( mag > max2 ) {
max3 = max2; max2 = mag;
idx3 = idx2; idx2 = I;
f2 = I;
}
else if( mag > max3 ) {
max3 = mag; idx3 = I;
}
}
maxLowGroup = max1;
maxHighGroup = max2;
kal_prompt_trace(MOD_L1SP, "DTMF 00 s1(%d)=%2d, s2(%d)=%2d, n(%d)=%2d, (s-n)=%2d\n", idx1, max1,
idx2, max2, idx3, max3, max2-max3);
kal_prompt_trace(MOD_L1SP, "DTMF 00 f1=%d, f2=%d\n", f1, f2);
if(f1 >7)
{
if( (max1 - max2) > 9 ) {
new_framecnt++;
if ((new_framecnt-old_framecnt)== 1)
hdl->framecnt++;
max1 = (int32)dtmfFreqTable_new[f1-8];
if ( (hdl->key_pre == max1||hdl->key_pre == -max1/*a weak signal is received before*/)&& ( hdl-
>key_pre == -hdl->key_pre_second || hdl->key_pre == hdl->key_pre_second ) )
{
if (hdl->framecnt == SIA_CNT2)
{/*output key*/
ASSERT(f1==8);
hdl->key = max1;
hdl->status = 0;
hdl->framecnt = 0;
hdl->pauseCount = 0;
hdl->silencecnt= 0;
}
else if (hdl->framecnt == SIA_CNT1)
{
if (f1==8)
{
hdl->status = 1;

hdl->pauseCount=0;
hdl->silencecnt=0;
}
else /*f==9*/
{
if (hdl->status == 2)
{/*output key*/
hdl->key = max1;;
hdl->status = 0;
hdl->framecnt = 0;
hdl->pauseCount = 0;
hdl->silencecnt=0;
}
}
}
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = max1; /*update previous key*/
}
else if ((hdl->status==0&&f1==8)/*first 1400 signal*/||(hdl->status==2&&f1==9/*first 2300
signal*/))
{
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = max1; /*update previous key*/
hdl->pauseCount = 0;
hdl->silencecnt = 0;
}
else
{
hdl->framecnt = 0;
hdl->status = 0;
}
}
/*magnitude difference larger than noise threshold*/
else if ( (max1 - max2) >= noise_threshold[max2] ){
new_framecnt++;
if ((new_framecnt-old_framecnt)== 1)
hdl->framecnt++;
max1 = (int32)dtmfFreqTable_new[f1-8];
if ( hdl->key_pre == hdl->key_pre_second && hdl->key_pre == max1 )
{
if (hdl->framecnt == SIA_CNT2)
{/*output key*/
ASSERT(f1==8);
hdl->key = max1;
hdl->status = 0;

hdl->framecnt = 0;
hdl->pauseCount = 0;
hdl->silencecnt= 0;
}
else if (hdl->framecnt == SIA_CNT1)
{
if (f1==8)
{
hdl->status = 1;
hdl->pauseCount = 0;
hdl->silencecnt= 0;
}
else /*f==9*/
{
if (hdl->status == 2)
{/*output key*/
hdl->key = max1;;
hdl->status = 0;
hdl->framecnt = 0;
hdl->pauseCount = 0;
hdl->silencecnt= 0;
}
}
}
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = -max1; /*update previous key*/
}
else
{/*A different key or a weak signal is received*/
hdl->framecnt = 0;
hdl->status = 0;
}
}
/*smaller than noise_threshold*/
else{
hdl->pauseCount++;
if(hdl->status==1)
{
new_silencecnt++;
if((new_silencecnt-old_silencecnt)==1)
hdl->silencecnt++;
}
if ( hdl->pauseCount >= CON_PAUSE_NUMBER ){ /*pause detected, output key in this frame*/
if (hdl->status == 1)
{

if (hdl->silencecnt== SIA_PAUSE_NUMBER-1/*allow one count lost*/)
{
hdl->status = 2;
hdl->framecnt=0;
hdl->pauseCount=0;
hdl->silencecnt=0;
hdl->key_pre_second =0;
hdl->key_pre = 0;
}
}
else
{
if ( hdl->key_temp > 0 )
hdl->key = hdl->key_temp;
hdl->key_temp = 0;
hdl->status = 0;
hdl->framecnt=0;
hdl->pauseCount = 0;
hdl->silencecnt=0;
}
}
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = 0;
}
return;
}
else if( f1 > f2 ) { /* swap the frequency index */
I = f1;
f1 = f2;
f2 = I;
maxLowGroup = max2;
maxHighGroup = max1;
}
kal_prompt_trace(MOD_L1SP, "DTMF 11 s1(%d)=%2d, s2(%d)=%2d, n(%d)=%2d, (s-n)=%2d\n", idx1, max1,
idx2, max2, idx3, max3, max2-max3);
kal_prompt_trace(MOD_L1SP, "DTMF 11 f1=%d, f2=%d\n", f1, f2);
/*non-key or over twist constraint */
if( f2 < 4/*this check prevents f2 ==8 or 9*/ || f1 > 3 || (maxLowGroup-maxHighGroup) > 9 ||
(maxLowGroup-maxHighGroup) < -9 ) {
hdl->pauseCount++;
if(hdl->status==1)
{

new_silencecnt++;
if((new_silencecnt-old_silencecnt)==1)
hdl->silencecnt++;
}
if ( hdl->pauseCount >= CON_PAUSE_NUMBER ){
if (hdl->status == 1)
{
if (hdl->silencecnt== SIA_PAUSE_NUMBER-1/*allow one count lost*/)
{
hdl->status = 2;
hdl->framecnt=0;
hdl->pauseCount=0;
hdl->silencecnt=0;
hdl->key_pre_second = 0;
hdl->key_pre = 0;
}
}
else
{
if ( hdl->key_temp > 0 )
hdl->key = hdl->key_temp;
hdl->key_temp = 0;
hdl->status = 0;
hdl->framecnt=0;
hdl->pauseCount=0;
hdl->silencecnt=0;
}
}
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = 0; /*update previous key*/
}
/*magnitude difference between FRACTION_THRESHOLD and nosie_threshold*/
else if ( (max2 - max3) >= FRACTION_THRESHOLD && (max2 - max3) < noise_threshold[max3]){
hdl->status = 0;
f2 -= 4;
max1 = (int32)dtmfFreqTable[f2][f1];
if ( hdl->key_pre == hdl->key_pre_second && hdl->key_pre > 0 && hdl->key_pre == max1 )
hdl->key_temp = max1;
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = -max1; /*update previous key*/
}
/*magnitude difference larger than noise threshold*/

else if ( (max2 - max3) >= noise_threshold[max3] ){
hdl->status = 0;
f2 -= 4;
max1 = (int32)dtmfFreqTable[f2][f1];
if ( hdl->key_pre == max1 && ( hdl->key_pre == -hdl->key_pre_second || hdl->key_pre == hdl-
>key_pre_second ) )
hdl->key_temp = max1;
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = max1; /*update previous key*/
hdl->pauseCount = 0;
hdl->key_threshold = max2 - max3;
}
/*smaller than noise_threshold and FRACTION_THRESHOLD*/
else{
hdl->pauseCount++;
if(hdl->status==1)
{
new_silencecnt++;
if((new_silencecnt-old_silencecnt)==1)
hdl->silencecnt++;
}
if ( hdl->pauseCount >= CON_PAUSE_NUMBER ){ /*pause detected, output key in this frame*/
if (hdl->status == 1)
{
if (hdl->silencecnt== SIA_PAUSE_NUMBER-1/*allow one count lost*/)
{
hdl->status = 2;
hdl->framecnt=0;
hdl->pauseCount = 0;
hdl->silencecnt=0;
hdl->key_pre_second = 0;
hdl->key_pre = 0;
}
}
else
{
if ( hdl->key_temp > 0 )
hdl->key = hdl->key_temp;
hdl->key_temp = 0;
hdl->status = 0;
hdl->framecnt=0;
hdl->pauseCount = 0;
hdl->silencecnt=0;

}
}
hdl->key_pre_second = hdl->key_pre; /*update second previous key*/
hdl->key_pre = 0; /*update previous key*/
}
}



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]