DTMF信号的产生及检测要点
- 格式:doc
- 大小:241.50 KB
- 文档页数:18
DSP课程设计实验报告DTMF信号的产生及检测院(系):电子信息工程学院-通信工程设计人员:周钰哲学号:08211052苗祚雨08212075目录一、设计任务书 (2)二、设计内容 (2)三、设计方案、算法原理说明 (3)四、程序设计、调试与结果分析 (6)五、设计(安装)与调试的体会 (16)六、参考文献 (16)一设计任务要求双音多频DTMF(Dual Tone Multi Frequency)是在按键式电话机上得到广泛应用的音频拨号信令,一个DTMF信号由两个频率的音频信号叠加构成。
这两个音频信号的频率分别来自两组预定义的频率组:行频组和列频组。
每组分别包括4个频率,分别抽出一个频率进行组合就可以组成16种DTMF编码,分别记作0~9、*、#、A、B、C、D。
如下图1所示。
图1 DTMF信令的编码要用DSP产生DTMF信号,只要产生两个正弦波叠加在一起即可;DTMF检测时采用改进的Goertzel算法,从频域搜索两个正弦波的存在。
1、基本部分:(1)使用C语言编写DTMF信号的发生程序,要求循环产生0~9、*、#、A、B、C、D对应的DTMF信号,并且符合CCITT对DTMF信号规定的指标。
(2)使用C语言编写DTMF信号的检测程序,检测到的DTMF编码在屏幕上显示。
2、发挥部分:利用DTMF信号完成数据通讯的功能,并试改进DTMF信号的规定指标,使每秒内传送的DTMF编码越多越好。
3、要求完成的任务(1)编写C语言程序,并在CCS集成开发环境下调试通过。
(2)实现设计所要求的各项功能。
(3)按要求撰写设计报告。
二、设计内容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的采样频率(电话信号f=8kHZ),即1秒采样8000个点,则100ms采样800个点,的典型抽样频率为sam我们设置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 可以只计算感兴趣的频率点.如果要计算的频率点数少于log 2N(N 为输入信号点数),采用DFT 的计算速度比FFT 更快。
直接计算DFT ,需要很多复系数,即使只计算一点的DFT 也需要N 个复系数.采用数字信号处理中的Goertzel 算法,如图2,则可明显地提高速度。
图2 Goertzel 算法原理框图input n x v v n x n v n v k n v k k k k N k ==-=-+---⋅=)( 0)2( 0)1( )()2()1()cos(2)(2π在实际的DTMF 检测中,只需DFT 的幅度(本算法为平方幅度)信息就足够了,因此在Goertzel 滤波器中,当N 点(相当于DFT 数据块的长度)样值输入滤波器后,滤波器输出伪DFT 值vk (n ),由vk (n )即可确定频谱的平方幅度。
)1()()cos(2)1()( )()()(2222---+==*N v N v k N v N v N y N y k X k k Nk k k k π其中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.109375 0.57899% 1336 20.875 21 0.125 0.59880% 1477 23.078125 23 0.078125 0.33852% 163325.515625250.5156252.02082%表1一旦得到行/列频率的频谱平方幅度信息,就可以通过一系列的判决来确定音频及数字结果的有效性。
首先,检测可能DTMF 信号的强度是否足够大。
行频率分量和列频率分量的平方幅度和应高于某一确定门限。
注意与DTMF 频率相符的正弦波的能量集中在频域内一段很窄的范围当中,所以门限取值应占动态范围的大部分。
第二,如果DTMF 信号存在,由于构成DTMF 信号的行频都低于列频,因此从小到大依次判断各个频率点的频谱幅度,得到的第一个达到门限要求的的频率点即为行频,第二个即为列频,综合行频和列频即可得出检测到的按键信息。
检测流程图:图3 检测流程图四、程序设计、调试与结果分析(1)发送源程序代码如下:/*****************************************************************//* DTMFsignal 发送程序 send.c */ /*****************************************************************/#include <stdio.h>#include <math.h>#include <type.h>#include <board.h>#include <codec.h>#include <mcbsp54.h>void delay(int period);void generate(int num);HANDLE hHandset;float buffer[800];s16 num=0;int count=0;float freq[16][2]={ 941,1336, //键值0对应的行频列频697,1209, //1697,1336, //2697,1477, //3770,1209, //4770,1336, //5770,1477, //6852,1209, //7852,1336, //8852,1477, //9697,1633, //A770,1633, //B852,1633, //C941,1633, //D941,1209, //*941,1477 //#};float pi=3.1415926;void main(){int cnt=2;if(brd_init(100)){return;}/* blink the leds a couple times */while ( cnt-- ) /* 二极管闪两次 */{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);}/* 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 */generate(num);}void generate(int num){f32 x,y;int k=0;int i;i=0;while(1){// Wait for sample from handsetwhile (!MCBSP_XRDY(HANDSET_CODEC)) {};*(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=buffer[i];i++;if(i==800){i=0;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;}}}}void delay(int period) /*延时子程序 */{int i, j;for(i=0; i<period; i++){for(j=0; j<period>>1; j++);}}(2)检测源程序代码如下:/*****************************************************************//* DTMFsignal 检测程序 receive.c */ /*****************************************************************/#include <stdio.h>#include <math.h>#include <type.h>#include <board.h>#include <codec.h>#include <mcbsp54.h>HANDLE hHandset;float buffer[125];float pi=3.1415926;s16 receive[125];s16 dacdata;int k=0;int detect_result[100]={0};int l=0;int flag=0;void delay(int period);void detect();void main(){int cnt=2;/********************************************Description:* vk(n) = 2*coef*vk(n-1) - vk(n-2) + x(n)** Coefficients are in w[8]* x(n) is in buffer[256]* vk(n-2) is a[i][0]* vk(n-1) is a[i][1] ....* vk(n) is a[i][2]*********************************************/if(brd_init(100)){return;}// blink the leds a couple timeswhile ( cnt-- ){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);}/* 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_6dB);/* -6dB gain on analog output from DAC */codec_sample_rate(hHandset,SR_8000); /* 8KHz sampling rate */while(1){while (!MCBSP_RRDY(HANDSET_CODEC)) {};dacdata = *(volatile u16*)DRR1_ADDR(HANDSET_CODEC);receive[k]=dacdata;buffer[k]=dacdata/16384.0;k++;if(k==125){k=0;detect();}}}void detect(){ int i,j,x,y;float w[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);for(i=0;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;for(i=0;i<8;i++) {if(amp[i]>500) //门限设为500{ //printf("The amplitude %d is %f.\r\n",i,amp[i]);j++;if(j==1){x=i;}else if(j==2){y=i;}}}i=-1;if(flag==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'; }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){ i='A'; }else if(x==1 && y==7){ i='B'; }else if(x==2 && y==7){ i='C'; }else if(x==3 && y==7){ i='D'; }else if(x==3 && y==4){ i='*'; }else if(x==3 && y==6){ i='#'; }}if(i!=-1){detect_result[l]=i;l++;if(l==100){for(l=0;l<100;l++)printf("The DTMF signal is %c.\r\n ",detect_result[l]);}flag++;}}else if(j==0)flag=0;}void delay(int period){int i, j;for(i=0; i<period; i++){for(j=0; j<period>>1; j++);}}(3)cmd源代码如下:/*############################################################################# ## $Id: $################################################################################# ## Copyright (c) 1999 DNA Enterprises, Inc.############################################################################### ## Revision History## ----------------## $Log: $################################################################################################################################################################## XFERMAKE.CMD## ------------## C54x Linker Command File for 5402 DSK Memory Transfer Module###############################################################################*//*****************************************************************************//* Object Files *//*****************************************************************************//*****************************************************************************//* Linker Options *//*****************************************************************************//*****************************************************************************//* C5402 DSK DSP Memory Map *//* *//*****************************************************************************/MEMORY{PAGE 0: VECS: origin = 0080h, length = 0080h /* Internal Program RAM */PRAM: origin = 0100h, length = 8000h /* Internal Program RAM */PAGE 1: SCRATCH: origin = 0060h, length = 0020h /* Scratch Pad Data RAM */DMARAM: origin = 0C00h, length = 0300h /* DMA buffer */DATA: origin = 1100h, length = 0080h /* Internal Data RAM */STACK: origin = 1180h, length = 0560h /* Stack Memory Space */INRAM: origin = 1900h, length = 0100h /* Internal Data RAM */HPRAM0: origin = 1A00h, length = 0002h /* HPI memory accessible by Host and DSP */HPRAM1: origin = 1A02h, length = 0280h /* HPI memory accessible by Host and DSP */HPRAM2: origin = 1C82h, length = 0280h /* HPI memory accessible by Host and DSP */EXRAM: origin = 1F10h, length = 4000h /* External Data RAM */}/*****************************************************************************//* DSP Memory Allocation *//*****************************************************************************/SECTIONS{.cinit > PRAM PAGE 0.text > PRAM PAGE 0.vectors > VECS PAGE 0init_var > PRAM PAGE 0detect > PRAM PAGE 0vrcprg > PRAM PAGE 0matprg > PRAM PAGE 0.stack > STACK PAGE 1.trap > SCRATCH PAGE 1.const > EXRAM PAGE 1.data > EXRAM PAGE 1.bss > EXRAM PAGE 1.cio > EXRAM PAGE 1.switch > EXRAM PAGE 1tables > EXRAM PAGE 1var > EXRAM PAGE 1svctab > EXRAM PAGE 1 /* SS_V LSP table */vctab > EXRAM PAGE 1 /* V LSP table */uvctab > EXRAM PAGE 1 /* UV LSP table */cuvtab > EXRAM PAGE 1 /* Stochastic codebook */cdbktab > EXRAM PAGE 1 /* various codebook tables*/logtab > EXRAM PAGE 1 /* table for log2 */powtab > EXRAM PAGE 1 /* table for pow2 */hamtab > EXRAM PAGE 1 /* table for hamming */lgwtab > EXRAM PAGE 1 /* table for lag window */acostab > EXRAM PAGE 1 /* table for arccos */sqrtab > EXRAM PAGE 1 /* table for square root */acbtab > EXRAM PAGE 1 /* table for thresholds in acb */pm03tab > EXRAM PAGE 1 /* table for x^(-0.3) computation */ costab > EXRAM PAGE 1 /* table for cosine */V23 > INRAM PAGE 1FSK > INRAM PAGE 1hpibuff0 > HPRAM0 PAGE 1hpibuff1 > HPRAM1 PAGE 1hpibuff2 > HPRAM2 PAGE 1dma_buff > DMARAM PAGE 1}(4)调试与结果分析发送端的频域图形如图4所示:接收端的频域图形接受判决结果如图5所示:图5(5)调试过程中产生的问题及解决方案1、起初采用每检测到一次字符便用printf()函数输出,而printf()函数占用DSP的处理时间过多,因此丢失了很多的DTMF样点,致使很多数字按键信息无法被检测出来,因而不仅产生字符丢失的情况,也达不到每秒10个字符的传送标准。