DTMF信号的产生及检测要点Word文件下载.docx
《DTMF信号的产生及检测要点Word文件下载.docx》由会员分享,可在线阅读,更多相关《DTMF信号的产生及检测要点Word文件下载.docx(21页珍藏版)》请在冰豆网上搜索。
![DTMF信号的产生及检测要点Word文件下载.docx](https://file1.bdocx.com/fileroot1/2023-1/6/5fcf48b2-87d2-4128-9e00-9ead22b864ab/5fcf48b2-87d2-4128-9e00-9ead22b864ab1.gif)
DTMF发生器基于两个二阶数字正弦振荡器,一个用于产生行频,一个用于产生列频。
在输入信号中检测DTMF信号,需要在输入的数据信号流中连续地搜索DTMF信号频谱的存在。
整个检测过程分两步:
首先采用Goertzel算法在输入信号中提取频谱信息;
接着作检测结果的有效性检查。
Goertzel算法实质是一个两极点的IIR滤波器。
三、设计方案、算法原理说明
要用DSP产生DTMF信号,只要通过两个正弦波叠加在一起即可;
DTMF检测时采用改进的Goertzel算法,从频域搜索两个正弦波的存在。
(1)DTMF信号的产生
DTMF编码器基于两个二阶数字正弦波振荡器,一个用于产生行频,一个用于产生列频。
向DSP装入相应的系数和初始条件,就可以只用两个振荡器产生所需的八个音频信号。
典型的DTMF信号频率范围是700~1700Hz,选取8000Hz作为采样频率,即可满足Nyquist条件。
DTMF数字振荡器对的二阶系统函数的差分方程为:
其中
,
为采样频率,
为输出正弦波的频率,
为输出正弦波的幅度。
该式初值为
。
用sin函数产生离散的正弦值,生成DTMF的公式为:
buffer[t]=sin(t*2*pi*f1/fs)+sin(t*2*pi*f2/fs)
其中t为采样序数,由0开始递增;
f1,f2为生成DTMF信号的两个正弦波的频率;
fs为采样频率;
buffer[t]为序数t时的得出的采样值。
将这些数据转换为Q15格式然后通过codec发送出去。
CCITT对DTMF信号规定的指标是,传送/接收率为每秒10个数字,即每个数字100ms。
代表数字的音频信号必须持续至少45ms,但不超过55ms。
100ms内其他时间为静音,以便区别连续的两个按键信号。
我们使用8000Hz的采样频率(电话信号的典型抽样频率为
=8kHZ),即1秒采样8000个点,则100ms采样800个点,我们设置800个点的缓存,其中用400个存产生的DTMF信号值,即音频信号必须持续50ms,另外400个存0值,即静音信号。
(2)DTMF信号的检测
DTMF检测是对进入解码端的信号进行检测,并把双音频信号转换成对应的数字信息。
它是一个比DTMF产生更加复杂过程。
由于数据流是连续的,为了保证DTMF检测的实时性,因此要求检测过程必须是实时连续的。
在输入信号中检测DTMF信号,需要在输入的数据信号流中连续地搜索DTMF信号频谱的存在。
首先采用Goertzel算法在输入信号中提取频谱信息;
DTMF解码时在输入信号中搜索出有效的行频和列频。
计算数字信号的频谱可以采用DFT及其快速算法FFT,而在实现DTMF解码时,采用Goertzel算法要比FFT更快。
通过FFT可以计算得到信号所有谱线,了解信号整个频域信息,而对于DTMF信号只需关心其8个行频/列频及其二次谐波信息即可,二次谐波的信息用于将DTMF信号与声音信号区别开。
此时Goertzel算法能更加快速的在输入信号中提取频谱信息。
Goertzel算法实质是一个两极点的IIR滤波器。
Goertzel算法原理:
DTMF检测器的核心是Goertzel算法。
该算法利用二极点的IIR滤波器计算离散傅立叶变换值,能够快速高效地提取输入信号的频谱信息。
由于IIR滤波器是一个递归结构,它利用只有一个实系数的差分方程进行操作,并不像DFT或FFT算法那样需要计算数据块,而是每输入一个样值就执行一次算法。
完成时域到频域的变换可以用离散傅立叶变换(DFT)或快速傅立叶变(FFT).FFT计算出所有点频率,而DFT可以只计算感兴趣的频率点.如果要计算的频率点数少于log2N(N为输入信号点数),采用DFT的计算速度比FFT更快。
直接计算DFT,需要很多复系数,即使只计算一点的DFT也需要N个复系数.采用数字信号处理中的Goertzel算法,如图2,则可明显地提高速度。
图2Goertzel算法原理框图
在实际的DTMF检测中,只需DFT的幅度(本算法为平方幅度)信息就足够了,因此在Goertzel滤波器中,当N点(相当于DFT数据块的长度)样值输入滤波器后,滤波器输出伪DFT值vk(n),由vk(n)即可确定频谱的平方幅度。
其中k=f*N/fs,当N取值为125时,k的取值经计算如表1所示:
信号频率(Hz)
计算值k
取整值k
绝对误差
相对误差
697
10.890625
11
0.109375
1.00430%
770
12.03125
12
0.03125
0.25974%
852
13.3125
13
0.3125
2.34741%
941
14.703125
15
0.296875
2.01912%
1209
18.890625
19
0.57899%
1336
20.875
21
0.125
0.59880%
1477
23.078125
23
0.078125
0.33852%
1633
25.515625
25
0.515625
2.02082%
表1
一旦得到行/列频率的频谱平方幅度信息,就可以通过一系列的判决来确定音频及数字结果的有效性。
首先,检测可能DTMF信号的强度是否足够大。
行频率分量和列频率分量的平方幅度和应高于某一确定门限。
注意与DTMF频率相符的正弦波的能量集中在频域内一段很窄的范围当中,所以门限取值应占动态范围的大部分。
第二,如果DTMF信号存在,由于构成DTMF信号的行频都低于列频,因此从小到大依次判断各个频率点的频谱幅度,得到的第一个达到门限要求的的频率点即为行频,第二个即为列频,综合行频和列频即可得出检测到的按键信息。
检测流程图:
图3检测流程图
四、程序设计、调试与结果分析
(1)发送源程序代码如下:
/*****************************************************************/
/*DTMFsignal发送程序send.c*/
#include<
stdio.h>
math.h>
type.h>
board.h>
codec.h>
mcbsp54.h>
voiddelay(intperiod);
voidgenerate(intnum);
HANDLEhHandset;
floatbuffer[800];
s16num=0;
intcount=0;
floatfreq[16][2]={941,1336,//键值0对应的行频列频
697,1209,//1
697,1336,//2
697,1477,//3
770,1209,//4
770,1336,//5
770,1477,//6
852,1209,//7
852,1336,//8
852,1477,//9
697,1633,//A
770,1633,//B
852,1633,//C
941,1633,//D
941,1209,//*
941,1477//#
};
floatpi=3.1415926;
voidmain()
{
intcnt=2;
if(brd_init(100))
{
return;
}
/*blinktheledsacoupletimes*/
while(cnt--)/*二极管闪两次*/
brd_led_toggle(BRD_LED0);
//brd_delay_msec(1000);
delay(1000);
brd_led_toggle(BRD_LED1);
brd_led_toggle(BRD_LED2);
/*OpenHandsetCodec*/
hHandset=codec_open(HANDSET_CODEC);
/*Acquirehandletocodec*/
/*Setcodecparameters*/
codec_dac_mode(hHandset,CODEC_DAC_15BIT);
/*DACin15-bitmode*/
codec_adc_mode(hHandset,CODEC_ADC_15BIT);
/*ADCin15-bitmode*/
codec_ain_gain(hHandset,CODEC_AIN_6dB);
/*6dBgainonanaloginputtoADC*/
codec_aout_gain(hHandset,CODEC_AOUT_MINUS_12dB);
/*-12dBgainonanalog*/
/*outputfromDAC*/
codec_sample_rate(hHandset,SR_8000);
/*8KHzsamplingrate*/
generate(num);
voidgenerate(intnum)
f32x,y;
intk=0;
inti;
i=0;
while
(1)
//Waitforsamplefromhandset
while(!
MCBSP_XRDY(HANDSET_CODEC)){};
*(volatileu16*)DXR1_ADDR(HANDSET_CODEC)=buffer[i];
i++;
if(i==800)
num++;
if(num==16)
num=0;
x=freq[num][0]/8000;
y=freq[num][1]/8000;
for(k=0;
k<
400;
k++)
{buffer[k]=(0.65*sin(2*pi*y*k)+0.8*sin(2*pi*x*k))*16384;
buffer[k+400]=0;
}
}
}
voiddelay(intperiod)/*延时子程序*/
inti,j;
for(i=0;
i<
period;
i++)
for(j=0;
j<
period>
>
1;
j++);
(2)检测源程序代码如下:
/*DTMFsignal检测程序receive.c*/
floatbuffer[125];
floatpi=3.1415926;
s16receive[125];
s16dacdata;
intdetect_result[100]={0};
intl=0;
intflag=0;
voiddetect();
{
/********************************************
Description:
*vk(n)=2*coef*vk(n-1)-vk(n-2)+x(n)
*
*Coefficientsareinw[8]
*x(n)isinbuffer[256]
*vk(n-2)isa[i][0]
*vk(n-1)isa[i][1]....
*vk(n)isa[i][2]
*********************************************/
{return;
//blinktheledsacoupletimes
while(cnt--)
/*6dBgainonanaloginputtoADC*/
codec_aout_gain(hHandset,CODEC_AOUT_MINUS_6dB);
/*-6dBgainonanalogoutputfromDAC*/
while(!
MCBSP_RRDY(HANDSET_CODEC)){};
dacdata=*(volatileu16*)DRR1_ADDR(HANDSET_CODEC);
receive[k]=dacdata;
buffer[k]=dacdata/16384.0;
k++;
if(k==125)
{
k=0;
detect();
voiddetect()
{inti,j,x,y;
floatw[8],a[8][3],amp[8];
w[0]=2*cos(2*pi*11/125);
w[1]=2*cos(2*pi*12/125);
w[2]=2*cos(2*pi*13/125);
w[3]=2*cos(2*pi*15/125);
w[4]=2*cos(2*pi*19/125);
w[5]=2*cos(2*pi*21/125);
w[6]=2*cos(2*pi*23/125);
w[7]=2*cos(2*pi*26/125);
i<
8;
i++)
a[i][0]=0;
a[i][1]=0;
for(j=1;
j<
=125;
j++)
a[i][2]=w[i]*a[i][1]-a[i][0]+buffer[j-1];
a[i][0]=a[i][1];
a[i][1]=a[i][2];
//计算频谱的幅度平方值
amp[i]=a[i][1]*a[i][1]+a[i][0]*a[i][0]-w[i]*a[i][1]*a[i][0];
j=0;
i++)
if(amp[i]>
500)//门限设为500
{//printf("
Theamplitude%dis%f.\r\n"
i,amp[i]);
j++;
if(j==1)
{
x=i;
elseif(j==2)
y=i;
i=-1;
if(flag==0)
{
if(j==2)
if(x==0&
&
y==4)
{i='
1'
;
elseif(x==0&
y==5)
2'
y==6)
3'
elseif(x==1&
4'
5'
6'
elseif(x==2&
7'
8'
9'
elseif(x==3&
0'
y==7)
A'
B'
C'
D'
*'
#'
if(i!
=-1)
detect_result[l]=i;
l++;
if(l==100)
for(l=0;
l<
100;
l++)
printf("
TheDTMFsignalis%c.\r\n"
detect_result[l]);
flag++;
}
elseif(j==0)
flag=0;
voiddelay(intperiod)
(3)cmd源代码如下:
/*#############################################################################
##$Id:
$
##
###############################################################################
##Copyright(c)1999DNAEnterprises,Inc.
##RevisionHistory
##----------------
##$Log:
##XFERMAKE.CMD
##------------
##C54xLinkerCommandFilefor5402DSKMemoryTransferModule
#############################################################################*/
/*************************************************************************