DSP课程设计---DTMF信号的产生及检测_第1页
DSP课程设计---DTMF信号的产生及检测_第2页
DSP课程设计---DTMF信号的产生及检测_第3页
DSP课程设计---DTMF信号的产生及检测_第4页
DSP课程设计---DTMF信号的产生及检测_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、;.DSP课程设计实 验 报 告DTMF信号的产生及检测院(系): 电子信息工程学院通信工程专业设计人员:宋佳阳 学号:08211042目录一、设计任务书- 3 -二、设计内容- 3 -三、设计方案、算法原理说明- 4 -1.DTMF信号的产生- 4 -2.DTMF信号的检测- 5 -四、程序设计、调试与结果分析- 7 -1.程序设计部分:- 7 -2.调试与结果分析部分:- 28 -五、设计(安装)与调试的体会- 33 -六、参考文献- 33 -一、 设计任务书设计要求及目标基本部分:(1)使用C语言编写DTMF信号的发生程序,要求循环产生09、*、#、A、B、C、D对应的DTMF信号,并且

2、符合CCITT对DTMF信号规定的指标。(2)使用C语言编写DTMF信号的检测程序,检测到的DTMF编码在屏幕上显示。发挥部分:利用DTMF信号完成数据通讯的功能,并试改进DTMF信号的规定指标,使每秒内传送的DTMF编码越多越好。二、 设计内容双音多频DTMF(Dual Tone Multi Frequency)是在按键式电话机上得到广泛应用的音频拨号信令,一个DTMF信号由两个频率的音频信号叠加构成。这两个音频信号的频率分别来自两组预定义的频率组:行频组和列频组。每组分别包括4个频率,分别抽出一个频率进行组合就可以组成16种DTMF编码,分别记作09、*、#、A、B、C、D。如图2-1所示

3、。图2-1 DTMF信令的编码要用DSP产生DTMF信号,只要产生两个正弦波叠加在一起即可;DTMF检测时采用改进的Goertzel算法,从频域搜索两个正弦波的存在。三、 设计方案、算法原理说明1. DTMF信号的产生DTMF发生器基于两个二阶数字正弦振荡器,一个用于产生行频,一个用于产生列频。DSP只要装载相应的系数和初始条件,就可以只用两个振荡器产生所需的八种音频信号。典型的DTMF信号频率范围是7001700Hz,选取8000Hz作为采样频率,即可满足奈奎斯特定理。正弦波是任何波形构成的基本元素,产生正弦波的方法一般有:查表法和计算法(泰勒级数展开法或数字正弦振荡器法)。 这里我们使用计

4、算法产生正弦波,有以下两种方案:方案一:使用数字正弦振荡器计算法产生正弦波图3-1 DTMF数字振荡器对由图3-1所示数字振荡器对的框图,可以得到DTMF数字振荡器对的二阶系统函数的差分方程为:其中 , , , 为采样频率, 为输出正弦波的频率, 为输出正弦波的幅度。该式初值为 , 。 其中,上面一个数字振荡器用于产生行频,下面一个数字振荡器用于产生列频,将行频信号和列频信号通过加法器进行叠加即可产生DTMF信号。方案二:使用sin函数产生正弦波直接利用sin函数生成离散的正弦值,其生成DTMF信号的方程为:yt=sin(t*2*pi*f1/fs)+sin(t*2*pi*f2/fs)其中t为采

5、样序数,由0开始递增;f1,f2为生成DTMF信号的两个正弦波的频率;fs为采样频率,由前面的分析可知,采样频率应该设定为8000Hz。将行频信号的采样值与列频信号的采样值进行叠加,即可得到序数为t时的采样值,即为yt。 将两种方案进行比较后,我们认为,使用正弦振荡器计算法这种方法计算时所需的计算量小,但是由于使用了迭代的方法产生样点值,所以当前时刻的输出序列需要反馈到输入端。在程序中实现,就需要不断对y(n-1)和y(n-2)的值进行更新。同时,当前时刻的输出序列也会影响下一时刻和下两个时刻的输出。因此,如果用这种方法来产生长时间连续的正弦信号和余弦信号,则累积误差较大。 直接使用sin函数

6、产生正弦波的方法,其计算时所需的计算量与方案一相当,并且也能达到误差要求。同时,由于使用方案二的方法产生正弦波,其当前时刻的输出序列只与当前时刻行频和列频的输入有关,所以不会产生累积误差,适合用来产生长时间连续的DTMF信号。 综上所述,我们使用方案二来产生DTMF信号。根据CCITT的规定,数字之间必须有适当长度的静音,因此编码器有两个任务,一是产生双音频信号的任务,二是静音任务。由于采样频率为8000Hz,所以DSP有足够的计算时间,可以使用查询模式通过D/A转换器输出DTMF信号。CCITT规定每秒传送/接收10个数字,即每个数字持续100ms。由于1秒采样8000个点,则每个数字采样8

7、00个点。由于代表数字的音频信号必须持续至少45ms,但不超过55ms。100ms内其他时间为静音,以便区别连续的两个按键信号。所以,需要设置800个点的缓存,其中400个点用于产生DTMF信号中的音频信号,另外400个点用于产生DTMF信号中的静音信号。根据这样的设计,音频信号的持续时间为50ms,在45ms和55ms之间,满足CCITT的规定。静音信号的持续时间为50ms。2. DTMF信号的检测DTMF检测是对进入解码端的信号进行检测,并把双音频信号转换成对应的数字信息。由于数据流是连续的,为了保证DTMF检测的实时性,因此要求检测过程必须是实时连续的。在输入信号中检测DTMF 信号,需

8、要在输入的数据信号流中连续地搜索DTMF 信号频谱的存在。检测过程有两部分的任务,一是在输入信号中提取频谱信息;二是检查检测结果的有效性。任务一:在输入信号中提取频谱信息DTMF 解码时在输入信号中搜索出有效的行频和列频。计算数字信号的频谱可以采用DFT 及其快速算法FFT,而在实现DTMF 解码时,采用Goertzel 算法要比FFT 更快。通过FFT 可以计算得到信号所有谱线,了解信号整个频域信息,而对于DTMF 信号只需关心其8 个行频/列频及其二次谐波信息即可,二次谐波的信息用于将DTMF 信号与声音信号区别开。此时Goertzel 算法能更加快速的在输入信号中提取频谱信息。Goert

9、zel 算法实质是一个两极点的IIR 滤波器,其算法原理框图如图3-2所示。图3-2 Goertzel算法原理框图 其传递函数为:DTMF检测器的核心是Goertzel算法。该算法利用二极点的IIR滤波器计算离散傅立叶变换值,能够快速高效地提取输入信号的频谱信息。由于IIR滤波器是一个递归结构,它利用只有一个实系数的差分方程进行操作,并不像DFT或FFT算法那样需要计算数据块,而是每输入一个样值就执行一次算法。DFT计算可以等价为:在实际的DTMF检测中,只需DFT的幅度(本算法为平方幅度)信息就足够了,因此在Goertzel滤波器中,当N点(相当于DFT数据块的长度)样值输入滤波器后,滤波器

10、输出伪DFT值vk(n),由vk(n)即可确定频谱的幅度平方。其中k=f*N/fs,f为输入信号的频率,N为样值的个数,fs为抽样频率。任务二:检查检测结果的有效性严格来讲,DTMF信号的有效性检验应该包括几项内容,在此不一一赘述。由于严格意义上DTMF信号有效性的检查实现起来比较困难,所以在这里我们只是进行了简单的有效性检测。 当得到频谱的幅度平方之后,将幅度平方与门限作比较。门限的设定,应该保证能够检测到DTMF发送信号,同时应该保证不产生误判漏判的情况。所以,门限的设定至关重要。在我们看来,门限的取值应该满足下面两点要求:一是门限的大小应该小于DTMF发送信号行频分量和列频分量的幅度平方

11、,这样才能够有效地检测到信号;二是门限的取值也不能太小,否则噪声会对判决产生很大的影响。同时,为了防止重复检测,下一个判决必须在检测到静音信号后才能有效。四、 程序设计、调试与结果分析 1.程序设计部分:DTMF信号产生流程图如图4-1所示。 开始DSK板初始化对DA转换和输入输出增益进行设置调用gets()函数键入要输入的字符调用send()判决函数对要发送的字符进行判定,返回num根据num,查表得要发送的行频列频将要发送的音频信号和400个点的静音信号存入buffer采足样点值后发送,将每个信号发送20次结束16个信号是否发完是否图4-1 信号产生流程图DTMF信号产生程序如下:#inc

12、lude /程序头文件#include #include #include #include #include void delay(int period); /延时子程序delayvoid send(int j); /判决子程序sendHANDLE hHandset; /codec句柄变量s16 out_buffer800; /输出缓冲区,数据类型为S16 float buffer800; /缓冲区,数据类型为floats16 num=0; /定义num,用于查询频率表int count=0; /定义count,用于控制发送的次数int k=0; /定义k,用于控制采样点数int i;int

13、 j;f32 x,y; /定义x和y,用于存放发送的行频和列频float fs=8000; /定义fs为抽样频率8000Hzfloat pi=3.1415926; /定义PI的值char telephonenumber18; /定义字符型数组telephonenumber/用于存放键入的字符float freq162= 941,1336, /定义16行2列的二维数组,第一列用于 697,1209,/存放行频,第二列用于存放列频 697,1336, 697,1477, 770,1209, 770,1336, 770,1477, 852,1209, 852,1336, 852,1477, 697,

14、1633, 770,1633, 852,1633, 941,1633, 941,1209, 941,1477 ; void main() /主程序main int cnt=3; /cnt=3控制亮灯的次数为3次 if(brd_init(100) /初始化DSK板 return; while ( cnt- ) brd_led_toggle(BRD_LED0); /LED0亮delay(1000); /延时1000个时间单位brd_led_toggle(BRD_LED1);/LED1亮delay(1000); /延时1000个时间单位brd_led_toggle(BRD_LED2);/LED2亮d

15、elay(1000); /延时1000个时间单位/ 打开codec,获取DAC的句柄hHandset = codec_open(HANDSET_CODEC); /设置DAC的工作参数 codec_dac_mode(hHandset, CODEC_DAC_15BIT); /D/A工作在15bit模式codec_adc_mode(hHandset, CODEC_ADC_15BIT); /A/D工作在15bit模式 codec_ain_gain(hHandset, CODEC_AIN_6dB); /模拟输入增益为6dBcodec_aout_gain(hHandset, CODEC_AOUT_MINU

16、S_12dB); /模拟输出增益为 /-12dBcodec_sample_rate(hHandset,SR_8000); /D/A转换频率为8kHz gets(telephonenumber); /gets函数,用于将键入的字符存入数组 j=0;send(j); /调用send函数对发送的第一个字符进行判定 x=freqnum0/fs;/查表得行频,并赋给x y=freqnum1/fs;/查表得列频,并赋给y for(k=0;k400;k+)/前400个点为音频信号,存入buffer bufferk=(0.65*sin(2*pi*y*k)+0.8*sin(2*pi*x*k)*16384; ou

17、t_bufferk=bufferk;/将float型强行转化为s16型 /后400个点为静音信号,存入buffer bufferk+400=0; out_bufferk+400=bufferk; /将float型强行转化为s16型 i=0; j=0; while(1)while (!MCBSP_XRDY(HANDSET_CODEC) ;/等待D/A转换器准备好 /发送 *(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=bufferi; i+; if(i=400) /采足400个样值点,完成第一次发送 i=0; count+; if(count=20) /控制每一

18、个数反复发送20次 count=0; j+; if(j=16) /如果发送完16个字符,则返回 return; send(j); /调用send函数,对发送的字符进行判定,返回num x=freqnum0/fs; /查表得行频,并赋给x y=freqnum1/fs; /查表得列频,并赋给y for(k=0;k400;k+) /前400个点为音频信号,存入buffer bufferk=(0.65*sin(2*pi*y*k)+0.8*sin(2*pi*x*k)*16384; out_bufferk=bufferk; /后400个点为静音信号,存入buffer bufferk+400=0; out_

19、bufferk+400=bufferk; void send(int j) /判决子程序send,输入j的值,输出num的值switch(telephonenumberj) case 1:num=1;break; case 2:num=2;break; case 3:num=3;break; case 4:num=4;break; case 5:num=5;break; case 6:num=6;break; case 7:num=7;break; case 8:num=8;break; case 9:num=9;break; case A:num=10;break; case B:num=1

20、1;break; case C:num=12;break; case 0:num=0;break; case D:num=13;break; case *:num=14;break; case #:num=15;break; void delay(int period) /延时子程序delay,运用了指令循环的原理,延时 /时间的长短由输入period决定 int i, j; for(i=0; iperiod; i+) for(j=0; j1; j+); DTMF信号检测流程图如下:开始DSK板初始化设置A/D转换器和转换速率A/D转换器输出数据准备好?是是否否采集满256样点值?调用DTMF

21、_detect检测判决程序开始计算vk(n)的系数存入W8设置vk(n-2), vk(n-1)的值为0计算vk(n)的值,并对vk(n-2), vk(n-1)的值进行更新计算8个的值并存入数组result中是否有两个幅度达标的频率?返回是否显示接收到的值DTMF信号检测程序基本部分如下:#include /头文件#include #include #include #include #include HANDLE hHandset; /codec句柄变量float buffer256; /DTMF样点缓冲区,定义其容量为256float pi=3.1415926;s16 test256; /定

22、义数组tests16 data;int k=0;int detect_result256=0; /缓存DTMF检测结果int l=0;void delay(int period); /延时子程序delayvoid DTMF_detect(void); /检测子程序DTMF_detectvoid main() /主函数mainint cnt=3; /控制灯闪烁的次数为3次,如果灯循环 /亮三次,则程序运行正常 if(brd_init(100) /初始化DSK板return;while(cnt-)brd_led_toggle(BRD_LED0);delay(1000);brd_led_toggle

23、(BRD_LED1);delay(1000);brd_led_toggle(BRD_LED2);delay(1000); / 打开codec,获取ADC的句柄hHandset = codec_open(HANDSET_CODEC);/设置D/A工作在15bit模式codec_dac_mode(hHandset, CODEC_DAC_15BIT);/设置A/D工作在15bit模式codec_adc_mode(hHandset, CODEC_ADC_15BIT); /设置输入增益为6dB codec_ain_gain(hHandset, CODEC_AIN_6dB);/设置输出增益为-6dB co

24、dec_aout_gain(hHandset, CODEC_AOUT_MINUS_6dB); /设置取样频率为8000Hzcodec_sample_rate(hHandset,SR_8000);while(1)while (!MCBSP_RRDY(HANDSET_CODEC) ;/等待A/D转换器输出数据data=*(volatile u16*)DRR1_ADDR(HANDSET_CODEC);testk=data;将A/D的输出存入数组testbufferk+=data/16384.0;将16进制整数转化为浮点数存入数组bufferif(k=256) k=0; /当采集满256个样点值后,调

25、用DTMF_detect对采集DTMF_detect(); /到的信号进行判决void DTMF_detect(void) float w8,a83;/数组w8用于存放的系数 float result8; /数组result8用于存放判决后的输出结果 int i,j,x,y; /k=f*N/fs,N为DFT数据块的长度,这里取N=205,k的计算结果取整数w0=2*cos(2*pi*18/205); /f=697Hz,k=18w1=2*cos(2*pi*20/205); /f=770Hz,k=20w2=2*cos(2*pi*22/205); /f=852Hz,k=22w3=2*cos(2*pi

26、*24/205); /f=941Hz,k=24w4=2*cos(2*pi*31/205); /f=1209Hz,k=31w5=2*cos(2*pi*34/205); /f=1336Hz,k=34w6=2*cos(2*pi*37/205); /f=1477Hz,k=37w7=2*cos(2*pi*42/205); /f=1633Hz,k=42for(i=0;i8;i+) ai0=0; /vk(n-2)=0 ai1=0; / vk(n-1)=0 for(j=0;j205;j+) ai2=wi*ai1-ai0+bufferj;/对vk(n)的值进行计算ai0=ai1; /对vk(n-2)的值进行更新

27、ai1=ai2; /对vk(n-1)的值进行更新resulti=ai1*ai1+ai0*ai0-wi*ai1*ai0;/计算的值j=0;for(i=0;i1500) /判决门限设置为1500j+;if(j=1) /第一个大于门限的是行频信号x=i; /将行频信号的编号赋给xelse if(j=2) /第二个大于门限的是列频信号y=i; /将列频信号的编号赋给xi=-2; if(j=2) /利用行频信号的编号x和列频信号的y确定接收到的字 /符,并将其输出。 if(x=3 & y=5)i=0;else if(x=0 & y=4)i=1;else if(x=0 & y=5)i=2;else if(

28、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=0 & y=7)printf(The DTMF signal is An);else if(x=1 & y=7)printf(The DTMF signal is Bn);else if(x=2 & y=7)printf(The DTMF signal is Cn);else if(x=

29、3 & y=7)printf(The DTMF signal is Dn);else if(x=3 & y=4)printf(The DTMF signal is *n);else if(x=3 & y=6)printf(The DTMF signal is #n);if(i!=-2)printf(The DTMF signal is %d.rn ,i); void delay(int period) /延时子程序 int i, j; for(i=0; iperiod; i+) for(j=0; j1; j+); CMD文件如下: MEMORY PAGE 0: VECS: origin = 0

30、080h, length = 0080h PRAM: origin = 7600h, length = 8000h PAGE 1: SCRATCH: origin = 0060h, length = 0020h DMARAM: origin = 0C00h, length = 0300h DATA: origin = 1100h, length = 0080h STACK: origin = 1180h, length = 0560h INRAM: origin = 1900h, length = 0100h HPRAM0: origin = 1A00h, length = 0002h HPR

31、AM1: origin = 1A02h, length = 0280h HPRAM2: origin = 1C82h, length = 0280h EXRAM: origin = 1F10h, length = 4000h SECTIONS .cinit PRAM PAGE 0 .text PRAM PAGE 0 .vectors VECS PAGE 0 init_var PRAM PAGE 0 detect PRAM PAGE 0 vrcprg PRAM PAGE 0 matprg PRAM PAGE 0 .stack STACK PAGE 1 .trap SCRATCH PAGE 1 .

32、const EXRAM PAGE 1 .data EXRAM PAGE 1 .bss EXRAM PAGE 1 .cio EXRAM PAGE 1 .switch EXRAM PAGE 1 tables EXRAM PAGE 1 var EXRAM PAGE 1 svctab EXRAM PAGE 1 vctab EXRAM PAGE 1 uvctab EXRAM PAGE 1 cuvtab EXRAM PAGE 1 cdbktab EXRAM PAGE 1 logtab EXRAM PAGE 1 powtab EXRAM PAGE 1 hamtab EXRAM PAGE 1 lgwtab E

33、XRAM PAGE 1 acostab EXRAM PAGE 1 sqrtab EXRAM PAGE 1 acbtab EXRAM PAGE 1 pm03tab EXRAM PAGE 1 costab EXRAM PAGE 1 V23 INRAM PAGE 1 FSK INRAM PAGE 1 hpibuff0 HPRAM0 PAGE 1 hpibuff1 HPRAM1 PAGE 1 hpibuff2 HPRAM2 PAGE 1 dma_buff DMARAM PAGE 1DTMF信号检测程序发挥部分: 由于在做接收实验时,发现发送端每发送一个DTMF信号,接收端总会重复输出几次接收到的DTM

34、F信号。我希望能够对程序进行改进,使发送端每发送一个信号,接收端只对接收到的DTMF信号进行一次输出。 对基本检测程序的改动如下:(与基本检测程序相同的部分用省略号代替)char num_150;char num_216;int m=0;int n=0;if(j=2)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; els

35、e 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) num_1m=A;m+;else if(x=1 & y=7) num_1m=B;m+ ;else if(x=2 & y=7) num_1m=C;m+ ; else if(x=3 & y=7) num_1m=D;m+ ; else if(x=3 & y=4) num_1m=*;m+;else if(x=3 & y=6) num_1m=#;m+; if(i!=-1) num_1m=i; m+ ; if(m=1) num_20

36、=num_10; /将num_1m中的第一个数送入 num_2n中。 n+; if(m1) if(num_1m-1!=num_1m-2) /将num_1m中的后一个元素与前一个元素比较 num_2n=num_1m-1; /若两者不相同,则将元素存入num_2n n+; for(n=0;n16;n+) /将num_2中的元素输出 printf(The DTMF signal is %s.rn ,num_2n); 由上述程序可以很容易看出,我们对于接收程序的输出进行了判别控制,将接收到信号先存入数组num_1m,再对数组num_1m中的元素进行比较。若num_1m+1与num_1m不相同,则将nu

37、m_1m+1中的元素送入num_2n;反之,则不进行操作。这样就能够保证接收到相同信号时只进行一次输出。但是,由此也带来一点点小的问题,就是如果发送端发送两个相同的信号时,接收端也只是输出一个信号,所以此时要求发送的前后两个信号不能相同,这会给实际应用带来一定的麻烦。2.调试与结果分析部分:调试步骤:1. 启动CCS软件;2. 新建工程;3. 向工程中添加源文件、cmd文件、库文件和头文件;4. 编译并运行程序;5. 待运行无错后,将第四步生成的.out文件下载到DSK板中,并点击run,开始在DSK板中运行程序。(注意在进行DTMF双机通信时,应该先运行接收程序,等待接收,然后再运行发送程序,这样才能保证完整接收到发送信号。)结果与结果分析:1.运行发送端程序后,发送端的LED灯循环亮三次,证明程序正常运行。之后,发送端电脑屏幕上出现如下所示的对话框,通过键盘输入要发送的按键信号,注意不要超过16位。2要观测发送端信号的时域波形,需要对CCS软件的Graph Property Dialog的参数进行如下图所示的设置。设置的具体含义如下,Single Time是指观察时域波形,out_buffer是发送程序的输出缓冲区,其数据类型为是s16,所以下面应该相应设定为16-bit signed intege

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论