DTMF信号的产生及检测 下载本文

实验名称:电工电子教学基地

DSP课程设计

实 验 报 告

DTMF信号的产生及检测

DTMF信号的产生及检测

一、实验设计内容

基本部分:

1.使用C语言编写DTMF信号的发生程序,可以通过键盘的输入产生0~9对应的DTMF信号,并且符合CCITT对DTMF信号规定的指标。

2.使用C语言编写DTMF信号的检测程序,检测到的DTMF编码在屏幕上显示。 发挥部分:

利用DTMF信号完成数据通讯的功能,并试改进DTMF信号的规定指标,使每秒内传送的DTMF编码越多越好。

二、实验目的

1、 了解、掌握DTMF的性质作用。 2、 掌握DTMF的产生和检测的思想和方法。 3、 了解Goertzel算法优化运算过程。

4、 熟练运用C语言进行编程实现DTMF的产生与检测。 5、 熟练使用CCS5402的操作方法和调试检验方式。

三、实验器材

DSP5402开发板两块,CCS软件环境

四、实验原理

双音多频DTMF(Dual Tone Multi-Frequency)信令,逐渐在全世界范围内使用在按键式电话机上,因其提供更高的拨号速率,迅速取代了传统转盘式电话机使用的拨号脉冲信令。近年来DTMF也应用在交互式控制中,诸如语言菜单、语言邮件、电话银行和ATM终端等。将DTMF信令的产生与检测集成到任一含有数字信号处理器(DSP)的系统中,是一项较有价值的工程应用。

DTMF编解码器在编码时将击键或数字信息转换成双音信号并发送,解码时在收到的DTMF信号中检测击键或数字信息的存在性。电话机键盘上每一个键通过由图1所示的行频与列频唯一确定。DTMF的编解码方案无需过多的计算量,可以很容易的在DSP系统里与其他任务并发执行。一个DTMF 信号由两个频率的音频信号叠加构成。这两个音频信号的频率分别来自两组预定义的频率组:行频组和列频组。每组分别包括4 个频率,分别抽出一个频率进行组合就可以组成16 种DTMF 编码,分别记作0~9、*、#、A、B、C、D。 1、 DTMF信号的产生

DTMF编码器基于两个二阶数字正弦波振荡器,一个用于产生行频,一个用于产生列频。向DSP装入相应的系数和初始条件,就可以只用两个振荡器产生所需的八个音频信号。典型的DTMF信号频率范围是700~1700Hz,选取8000Hz作为采样频率,即可满足Nyquist

条件。正弦波是任何波形构成的基本单元,产生正弦波的方法一般有:采样回放法、查表法、泰勒级数展开法、数字正弦振荡器法。

我们直接采用sin函数产生离散的正弦值,生成DTMF的公式为:buffer[t]=sin(t*2*pi*f1/fs)+sin(t*2*pi*f1/fs),其中t为采样序数,由0开始递增;f1,f2为生成DTMF信号的两个正弦波的频率;fs为采样频率;buffer[t]为序数t时的得出的采样值。将这些数据转换为Q15格式然后通过codec发送出去。

2、 DTMF信号的检测

在输入信号中检测DTMF信号,并将其转换为实际的数字,这一解码过程本质是连续的过程,需要在输入的数据信号流中连续地搜索DTMF信号频谱的存在。整个检测过程分两步:首先采用Goertzel算法在输入信号中提取频谱信息;接着作检测结果的有效性检查。

2.1 Goertzel算法

DTMF解码即是在输入信号中搜索出有效的行频和列频。计算数字信号的频谱可以采用DFT及其快速算法FFT,而在实现DTMF解码时,采用Goertzel算法要比FFT更快。通过FFT可以计算得到信号所有谱线,了解信号整个频域信息,而对于DTMF信号只用关心其8个行频/列频及其二次谐波信息即可(二次谐波的信息用于将DTMF信号与声音信号区别开)。此时Goertzel算法能更加快速的在输入信号中提取频谱信息。G直接计算DFT,需要很多复系数,即使只计算一点的DFT也需要N个复系数.采用数字信号处理中的Goertzel算法,则可明显地提高速度。

利用二阶复共轭极点可以得到只有一个实系数的差分方程:

1st Harmonics (N = 205) fs = 8 ksps 2nd Harmonics (N=201) fs = 8 ksps k 18 20 22 24 31 34 38 42 frequency (k/N)fs/Hz 702 780 858 936 1210 1326 1483 1639 coefficient cos(2pi k/N) 0.85162 0.81793 0.78115 0.74142 0.58157 0.50442 0.39505 0.27972 k 35 39 43 47 61 67 74 82 frequency (k/N)fs/Hz 1393 1552 1711 1871 2428 2667 2945 3264 coefficient cos(2pi k/N) 0.45886 0.34445 0.22470 0.10141 -0.32974 -0.50000 -0.67606 -0.83740 ?vk(n)?2cos(2k)?vk(n?1)?vk(n?2)?x(n)Nwhere vk(?1)?0 vk(?2)?0 x(n)?input

在实际的DTMF检测中,只需DFT的幅度(本算法为平方幅度)信息就足够了,因此在Goertzel滤波器中,当N点(相当于DFT数据块的长度)样值输入滤波器后,滤波器输出伪DFT值vk(n),由vk(n)即可确定频谱的平方幅度。

2?kkX(k)?y(N)y(N)22? ?vk(N)?vk(N?1)?2cos(2Nk)vk(N)vk(N?1)

Goertzel算法的特点

? Goertzel算法的IIR滤波器结构涉及两个复共轭极点,但对于实际的DTMF音频检

测,只要有幅度信息就够了(实际上使用幅度平方),从而简化为只需要一个实系数参与计算。

? Goertzel算法要比FFT快得多,因为只需要提供8个行/列频和它们的二次谐

波的信息(二次谐波的信息用于将DTMF与话音或音乐区别开来)。

2.2 DTMF检测器流程

把检测程序作为C54x的McBsp接收中断服务子程序,在每一个接收中断到来时,表明采到一个新样点。样点值代入式(2),迭代计算8个行频/列频的中间变量vk(n)(k为8个行频/列频分别对应的数字频率),直到采到N=125个样点(在8kHz采样频率下,约为15ms)。此时再按式(4)计算8个行频/列频的幅度平方|X(k)|2。接下来将|X(k)|2与门限作比较,并作二次谐波检测,判决出有效的音频信号。将音频信号映射为数字信号后,再与上一个检测到的数字信号比较,最终判决出有效的数字信号。

五、实验程序及注释:

1、DTMF信号的产生和发送程序:

/*****************************************************************/

/* DTMFsignal 发送程序 send.c */ /*****************************************************************/ #include #include #include #include #include #include

void send(int num);

HANDLE hHandset; s16 out_buffer[256]; float buffer[256]; s16 n=0; int c=0,a;

float pi=3.1415926;

void main() {

if(brd_init(100)) {

return; }

/* Open Handset Codec */

hHandset = codec_open(HANDSET_CODEC); /* Acquire handle to codec */ /* Set codec parameters */

codec_dac_mode(hHandset, CODEC_DAC_15BIT); /* DAC in 15-bit mode */ codec_adc_mode(hHandset, CODEC_ADC_15BIT); /* ADC in 15-bit mode */

codec_ain_gain(hHandset, CODEC_AIN_6dB); /* 6dB gain on analog input to ADC */

codec_aout_gain(hHandset, CODEC_AOUT_MINUS_12dB); /* -12dB gain on analog output from DAC */

codec_sample_rate(hHandset,SR_8000); /* 8KHz sampling rate */ send(n); }

void send(int n) {

int k=0; int i;

float f1,f2,ff;

ff=2*pi/8000;

i=k;

//键盘输入DTMF信号,每个信号发送40次

while(1)

{ while (!MCBSP_XRDY(HANDSET_CODEC)) {};////如果D/A未准备好,则等待

*(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=buffer[i];//从读取A/D转换数据 i++; if(i==256) { i=0; c++; if(c==40) { c=0;

scanf(\键盘输入要发送的号

switch (a)

{

case 0 : f1=ff*941; f2=ff*1336; break; case 1 : f1=ff*697; f2=ff*1209; break; case 2 : f1=ff*697; f2=ff*1336; break; case 3 : f1=ff*697; f2=ff*1477; break; case 4 : f1=ff*770; f2=ff*1209; break; case 5 : f1=ff*770; f2=ff*1336; break; case 6 : f1=ff*770; f2=ff*1477; break; case 7 : f1=ff*852; f2=ff*1209; break; case 8 : f1=ff*852; f2=ff*1336; break; case 9 : f1=ff*852; f2=ff*1477; break; } }

for(k=0;k<=255;k++)

{

buffer[k]=(0.65*sin(f1*k)+0.8*sin(f2*k))*16384; out_buffer[k]=buffer[k]; //强制类型转换 } } } }

用Graph窗口观察到的图形为:

2、DTMF信号的接收程序

/*****************************************************************/

/* DTMFsignal 检测程序 detector.c */ /*****************************************************************/ #include #include #include #include #include #include HANDLE hHandset; float buffer[256]; float pi=3.1415926; s16 receive[256]; s16 dacdata; int k=0;

void delay(int period); void detect(); void main() {

int k,cnt=2;

if(brd_init(100))

{return;}

// blink the leds a couple times while ( cnt-- ) { }

/* Open Handset Codec */

brd_led_toggle(BRD_LED0); //brd_delay_msec(1000); delay(1000);

brd_led_toggle(BRD_LED1); //brd_delay_msec(1000); delay(1000);

brd_led_toggle(BRD_LED2); //brd_delay_msec(1000); delay(1000);

hHandset = codec_open(HANDSET_CODEC); /* Acquire handle to codec */

/* Set codec parameters */

codec_dac_mode(hHandset, CODEC_DAC_15BIT); /* DAC in 15-bit mode */ codec_adc_mode(hHandset, CODEC_ADC_15BIT); /* ADC in 15-bit mode */

codec_ain_gain(hHandset, CODEC_AIN_6dB); /* 6dB gain on analog input to ADC */ codec_aout_gain(hHandset, CODEC_AOUT_MINUS_6dB); /* -6dB gain on analog output from DAC */

codec_sample_rate(hHandset,SR_8000); /* 8KHz sampling rate */ while(1) {

while (!MCBSP_XRDY(HANDSET_CODEC)) {};

dacdata = *(volatile u16*)DRR1_ADDR(HANDSET_CODEC);

receive[k]=dacdata;

buffer[k]=dacdata/16384.0;

} }

k++;

if(k==256) {

k=0; detect(); }

*(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=receive[k];

//信号检测函数 void detect() {int i,j,x,y;

float w[8],a[8][3],amp[8],temp; //Goertzel算法 w[0]=2*cos(2*pi*18/205);

w[1]=2*cos(2*pi*20/205); w[2]=2*cos(2*pi*22/205); w[3]=2*cos(2*pi*24/205); w[4]=2*cos(2*pi*31/205); w[5]=2*cos(2*pi*34/205); w[6]=2*cos(2*pi*38/205); w[7]=2*cos(2*pi*42/205); for(i=0;i<8;i++) {

a[i][0]=0; a[i][1]=0;

for(j=1;j<=205;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];}

//printf(\用于调试门限参数用 k=0;

for(i=0;i<8;i++) {if(amp[i]<11.00) k++; }

if(k<3) //取行频率号 {temp=amp[0]; x=0;

for(i=1;i<4;i++) {

if(amp[i]>temp) {temp=amp[i]; x=i; } j=0; }

temp=amp[4]; //取列频率号

y=4;

for(i=5;i<8;i++) {

if(amp[i]>temp) {temp=amp[i]; y=i; } j=0; } j=0; i=-1;

//判断号码

if(j==0) {

if(x==0 && y==4) { i=1; }

else if(x==0 && y==5) { i=2; }

else if(x==0 && y==6) { i=3; }

else if(x==1 && y==4)

}

{ i=4; }

else if(x==1 && y==5) { i=5; }

else if(x==1 && y==6) { i=6; }

else if(x==2 && y==4) { i=7; }

else if(x==2 && y==5) { i=8; }

else if(x==2 && y==6) { i=9; }

else if(x==3 && y==5) { i=0; }

else if(x==0 && y==7)

{ printf(\else if(x==1 && y==7)

{ printf(\else if(x==2 && y==7)

{ printf(\else if(x==3 && y==7)

{ printf(\else if(x==3 && y==4)

{ printf(\else if(x==3 && y==6)

{ printf(\

}

if(i!=-1)

{ printf(\

} }

void delay(int period) {

int i, j;

for(i=0; i

{

for(j=0; j

用Graph窗口观察到的图形为:

3、 关于cmd文件的几点解释:

.cmd文件类型及作用:

.cmd是链接器命令文件,用于存储器配置。 .cmd文件结构:

.cmd由两条链接伪指令来描述:MEMORY 和SECTIONS,其中: MEMORY定义用户目标系统存储器的配置; SECTIONS控制段的构建和存储器的分配。

六、 调试心得及实验心得

通过此次DSP课程设计,使我对上课学过的知识有了进一步的认识,特别是我们硬件用到了codec,对这方面的内容有了更深的理解。DTMF信号即电话拨号信令是我们平时经常

用到的,原来通信概论里面接触过一点这个,学了DSP后,发现可以用板子来实现这个,所以我们就选了这个题目,在做课程设计时,参考了图书馆的一些书籍以及网上查的资料,从而对双音多频的产生与检测机理有了初步的掌握,然后在CCS编程调试过程中不断实践,改进程序。在调试程序的过程中,遇到了一些困难,首先是信号产生的样点要送到Codec输出,开始输出的数据格式不正确,所以输出波形不正确,而且每次在运行这个程序之前都得先用别的程序在板子上运行一下;其次在双机通信中检测时不准确,通过请教老师定点运算和浮点运算的差别之后,知道了该怎样调试,就是先看有没有收到数据,然后看检测算法是否正确,通过用两个信号源叠加输入到检测端将检测程序调试好了。总之,我们在做课程设计时,可以有很多时间接触有关DSP的硬件及软件知识,有些上课时没明白的地方,现在弄懂了,也使自己增加了许多调试经验,对数字信号处理有了更深的掌握。――秦志勇

通过此次DSP课程设计,使我们对DSP及其相关的知识有了更深入的理解,在当今这个器械小型化的时代,可编程软硬件的应用越来越广泛了,DSP的学习扩宽了我们的视野,使我们对很多看似高深莫测的东西有了基本的了解,并加以研究。例如我们这次实验做的双音多频信号的产生和接受其实是我们生活中经常用到的技术,经过此次试验,我们对双音多频有了深入的了解,并通过自己的努力,完美的实现了预期的结果。同时也掌握了DSK开发环境的使用方法及过程。例如新的工程的建立、文件的加载、头文件库文件的加载及其使用这些文件的意义,它们对编程起着十分关键的作用,同时也简化了用户的编程,使我们能够在掌握基本C语言的编程的前提下,加以实际题目的研究就可以实现其功能。在实验中我们也遇到了很多问题,例如头文件无法加入,始终显示未加入,后来才发现经过编译之后才能生效,还有断点的设置给我们的编程带来了很大的帮助,是我们查找错误的有力帮手。具体接板子时也遇到很多问题,我们都耐心的一一解决了,在此也谢谢老师的辛勤指导。经过几天的努力,我们完成了自己的课程设计,虽然这个实验的功能很简单,但我相信我们在实验中已经掌握了最基本的实验思路,为我们后续实验打下了很好的基础。同时,从中也提高了自己的自学能力,收益很大。――银燕

七、 参考文献:

1、唐达强.双音多频信号接收器的设计与实现(硕士学位论文).北京:北方交通大学.1990 2、郑红,吴冠.TMS320C54xDSP应用系统设计.北京:北京航空航天大学出版社.2002 3、戴明桢,周建江.TMS320C54xDSP结构、原理及应用. 北京:北京航空航天大学出版社.2002

4、薛曼芳.基于改进的Goertzel算法的双音多频检测器的设计.甘肃:兰州工业高等专科学校.2008

5、苑毅.双音多频DTMF信号的产生与检测.北京:大众科技.2008

6、陈通,曹小强. 基于NDFT Goertzel滤波器的DTMF信号检测的改进方法.西南大学学报.2008

7、张俊,孙学康.双音多频接收系统分析及其FPGA设计.北京:北京邮电大学.2007 8、李义府. 双音多频信号检测在DSP中的实现.中南大学信息科学与工程学院.2006 9、网络资料的检索。