DSP课程设计DTMF信号的产生及检测.docx

上传人:b****8 文档编号:11310549 上传时间:2023-02-26 格式:DOCX 页数:33 大小:555.54KB
下载 相关 举报
DSP课程设计DTMF信号的产生及检测.docx_第1页
第1页 / 共33页
DSP课程设计DTMF信号的产生及检测.docx_第2页
第2页 / 共33页
DSP课程设计DTMF信号的产生及检测.docx_第3页
第3页 / 共33页
DSP课程设计DTMF信号的产生及检测.docx_第4页
第4页 / 共33页
DSP课程设计DTMF信号的产生及检测.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

DSP课程设计DTMF信号的产生及检测.docx

《DSP课程设计DTMF信号的产生及检测.docx》由会员分享,可在线阅读,更多相关《DSP课程设计DTMF信号的产生及检测.docx(33页珍藏版)》请在冰豆网上搜索。

DSP课程设计DTMF信号的产生及检测.docx

DSP课程设计DTMF信号的产生及检测

 

DSP课程设计

实验报告

DTMF信号的产生及检测

 

院(系):

电子信息工程学院通信工程专业

设计人员:

宋佳阳学号:

08211042

 

 

一、设计任务书

设计要求及目标

基本部分:

(1)使用C语言编写DTMF信号的发生程序,要求循环产生0~9、*、#、A、B、C、D对应的DTMF信号,并且符合CCITT对DTMF信号规定的指标。

(2)使用C语言编写DTMF信号的检测程序,检测到的DTMF编码在屏幕上显示。

发挥部分:

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

二、设计内容

双音多频DTMF(DualToneMultiFrequency)是在按键式电话机上得到广泛应用的音频拨号信令,一个DTMF信号由两个频率的音频信号叠加构成。

这两个音频信号的频率分别来自两组预定义的频率组:

行频组和列频组。

每组分别包括4个频率,分别抽出一个频率进行组合就可以组成16种DTMF编码,分别记作0~9、*、#、A、B、C、D。

如图2-1所示。

图2-1DTMF信令的编码

要用DSP产生DTMF信号,只要产生两个正弦波叠加在一起即可;DTMF检测时采用改进的Goertzel算法,从频域搜索两个正弦波的存在。

三、设计方案、算法原理说明

1.DTMF信号的产生

DTMF发生器基于两个二阶数字正弦振荡器,一个用于产生行频,一个用于产生列频。

DSP只要装载相应的系数和初始条件,就可以只用两个振荡器产生所需的八种音频信号。

典型的DTMF信号频率范围是700~1700Hz,选取8000Hz作为采样频率,即可满足奈奎斯特定理。

正弦波是任何波形构成的基本元素,产生正弦波的方法一般有:

查表法和计算法(泰勒级数展开法或数字正弦振荡器法)。

这里我们使用计算法产生正弦波,有以下两种方案:

方案一:

使用数字正弦振荡器计算法产生正弦波

图3-1DTMF数字振荡器对

由图3-1所示数字振荡器对的框图,可以得到DTMF数字振荡器对的二阶系统函数的差分方程为:

其中

为采样频率,

为输出正弦波的频率,

为输出正弦波的幅度。

该式初值为

其中,上面一个数字振荡器用于产生行频,下面一个数字振荡器用于产生列频,将行频信号和列频信号通过加法器进行叠加即可产生DTMF信号。

方案二:

使用sin函数产生正弦波

直接利用sin函数生成离散的正弦值,其生成DTMF信号的方程为:

y[t]=sin(t*2*pi*f1/fs)+sin(t*2*pi*f2/fs)

其中t为采样序数,由0开始递增;f1,f2为生成DTMF信号的两个正弦波的频率;fs为采样频率,由前面的分析可知,采样频率应该设定为8000Hz。

将行频信号的采样值与列频信号的采样值进行叠加,即可得到序数为t时的采样值,即为y[t]。

将两种方案进行比较后,我们认为,使用正弦振荡器计算法这种方法计算时所需的计算量小,但是由于使用了迭代的方法产生样点值,所以当前时刻的输出序列需要反馈到输入端。

在程序中实现,就需要不断对y(n-1)和y(n-2)的值进行更新。

同时,当前时刻的输出序列也会影响下一时刻和下两个时刻的输出。

因此,如果用这种方法来产生长时间连续的正弦信号和余弦信号,则累积误差较大。

直接使用sin函数产生正弦波的方法,其计算时所需的计算量与方案一相当,并且也能达到误差要求。

同时,由于使用方案二的方法产生正弦波,其当前时刻的输出序列只与当前时刻行频和列频的输入有关,所以不会产生累积误差,适合用来产生长时间连续的DTMF信号。

综上所述,我们使用方案二来产生DTMF信号。

根据CCITT的规定,数字之间必须有适当长度的静音,因此编码器有两个任务,一是产生双音频信号的任务,二是静音任务。

由于采样频率为8000Hz,所以DSP有足够的计算时间,可以使用查询模式通过D/A转换器输出DTMF信号。

CCITT规定每秒传送/接收10个数字,即每个数字持续100ms。

由于1秒采样8000个点,则每个数字采样800个点。

由于代表数字的音频信号必须持续至少45ms,但不超过55ms。

100ms内其他时间为静音,以便区别连续的两个按键信号。

所以,需要设置800个点的缓存,其中400个点用于产生DTMF信号中的音频信号,另外400个点用于产生DTMF信号中的静音信号。

根据这样的设计,音频信号的持续时间为50ms,在45ms和55ms之间,满足CCITT的规定。

静音信号的持续时间为50ms。

2.DTMF信号的检测

DTMF检测是对进入解码端的信号进行检测,并把双音频信号转换成对应的数字信息。

由于数据流是连续的,为了保证DTMF检测的实时性,因此要求检测过程必须是实时连续的。

在输入信号中检测DTMF信号,需要在输入的数据信号流中连续地搜索DTMF信号频谱的存在。

检测过程有两部分的任务,一是在输入信号中提取频谱信息;二是检查检测结果的有效性。

任务一:

在输入信号中提取频谱信息

DTMF解码时在输入信号中搜索出有效的行频和列频。

计算数字信号的频谱可以采用DFT及其快速算法FFT,而在实现DTMF解码时,采用Goertzel算法要比FFT更快。

通过FFT可以计算得到信号所有谱线,了解信号整个频域信息,而对于DTMF信号只需关心其8个行频/列频及其二次谐波信息即可,二次谐波的信息用于将DTMF信号与声音信号区别开。

此时Goertzel算法能更加快速的在输入信号中提取频谱信息。

Goertzel算法实质是一个两极点的IIR滤波器,其算法原理框图如图3-2所示。

图3-2Goertzel算法原理框图

其传递函数为:

DTMF检测器的核心是Goertzel算法。

该算法利用二极点的IIR滤波器计算离散傅立叶变换值,能够快速高效地提取输入信号的频谱信息。

由于IIR滤波器是一个递归结构,它利用只有一个实系数的差分方程进行操作,并不像DFT或FFT算法那样需要计算数据块,而是每输入一个样值就执行一次算法。

DFT计算可以等价为:

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

其中k=f*N/fs,f为输入信号的频率,N为样值的个数,fs为抽样频率。

任务二:

检查检测结果的有效性

严格来讲,DTMF信号的有效性检验应该包括几项内容,在此不一一赘述。

由于严格意义上DTMF信号有效性的检查实现起来比较困难,所以在这里我们只是进行了简单的有效性检测。

当得到频谱的幅度平方

之后,将幅度平方与门限作比较。

门限的设定,应该保证能够检测到DTMF发送信号,同时应该保证不产生误判漏判的情况。

所以,门限的设定至关重要。

在我们看来,门限的取值应该满足下面两点要求:

一是门限的大小应该小于DTMF发送信号行频分量和列频分量的幅度平方,这样才能够有效地检测到信号;二是门限的取值也不能太小,否则噪声会对判决产生很大的影响。

同时,为了防止重复检测,下一个判决必须在检测到静音信号后才能有效。

 

四、程序设计、调试与结果分析

1.程序设计部分:

DTMF信号产生流程图如图4-1所示。

 

图4-1信号产生流程图

 

DTMF信号产生程序如下:

#include//程序头文件

#include

#include

#include

#include

#include

voiddelay(intperiod);//延时子程序delay

voidsend(intj);//判决子程序send

HANDLEhHandset;//codec句柄变量

s16out_buffer[800];//输出缓冲区,数据类型为S16

floatbuffer[800];//缓冲区,数据类型为float

s16num=0;//定义num,用于查询频率表

intcount=0;//定义count,用于控制发送的次数

intk=0;//定义k,用于控制采样点数

inti;

intj;

f32x,y;//定义x和y,用于存放发送的行频和列频

floatfs=8000;//定义fs为抽样频率8000Hz

floatpi=3.1415926;//定义PI的值

 

chartelephonenumber[18];//定义字符型数组telephonenumber

//用于存放键入的字符

floatfreq[16][2]={941,1336,//定义16行2列的二维数组,第一列用于

697,1209,//存放行频,第二列用于存放列频

697,1336,

697,1477,

770,1209,

770,1336,

770,1477,

852,1209,

852,1336,

852,1477,

697,1633,

770,1633,

852,1633,

941,1633,

941,1209,

941,1477

};

voidmain()//主程序main

{

intcnt=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亮

delay(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);//模拟输入增益为6dB

codec_aout_gain(hHandset,CODEC_AOUT_MINUS_12dB);//模拟输出增益为

//-12dB

codec_sample_rate(hHandset,SR_8000);//D/A转换频率为8kHz

gets(telephonenumber);//gets函数,用于将键入的字符存入数组

j=0;

send(j);//调用send函数对发送的第一个字符进行判定

x=freq[num][0]/fs;//查表得行频,并赋给x

y=freq[num][1]/fs;//查表得列频,并赋给y

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

{//前400个点为音频信号,存入buffer

buffer[k]=(0.65*sin(2*pi*y*k)+0.8*sin(2*pi*x*k))*16384;

out_buffer[k]=buffer[k];//将float型强行转化为s16型

//后400个点为静音信号,存入buffer

buffer[k+400]=0;

out_buffer[k+400]=buffer[k];//将float型强行转化为s16型

}

i=0;

j=0;

while

(1)

{

while(!

MCBSP_XRDY(HANDSET_CODEC)){};//等待D/A转换器准备好

//发送

*(volatileu16*)DXR1_ADDR(HANDSET_CODEC)=buffer[i];

i++;

if(i==400)//采足400个样值点,完成第一次发送

{

i=0;

count++;

if(count==20)//控制每一个数反复发送20次

{

count=0;

j++;

if(j==16)//如果发送完16个字符,则返回

return;

send(j);//调用send函数,对发送的字符进行判定,返回num

x=freq[num][0]/fs;//查表得行频,并赋给x

y=freq[num][1]/fs;//查表得列频,并赋给y

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

{//前400个点为音频信号,存入buffer

buffer[k]=(0.65*sin(2*pi*y*k)+0.8*sin(2*pi*x*k))*16384;

out_buffer[k]=buffer[k];

//后400个点为静音信号,存入buffer

buffer[k+400]=0;

out_buffer[k+400]=buffer[k];

}

}

}

}

}

voidsend(intj)//判决子程序send,输入j的值,输出num的值

{

switch(telephonenumber[j])

{

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=11;break;

case'C':

num=12;break;

case'0':

num=0;break;

case'D':

num=13;break;

case'*':

num=14;break;

case'#':

num=15;break;

}

}

voiddelay(intperiod)//延时子程序delay,运用了指令循环的原理,延时

{//时间的长短由输入period决定

inti,j;

for(i=0;i

{

for(j=0;j>1;j++);

}

}

DTMF信号检测流程图如下:

 

 

 

DTMF信号检测程序基本部分如下:

#include//头文件

#include

#include

#include

#include

#include

HANDLEhHandset;//codec句柄变量

floatbuffer[256];//DTMF样点缓冲区,定义其容量为256

floatpi=3.1415926;

s16test[256];//定义数组test

s16data;

intk=0;

intdetect_result[256]={0};//缓存DTMF检测结果

intl=0;

voiddelay(intperiod);//延时子程序delay

voidDTMF_detect(void);//检测子程序DTMF_detect

voidmain()//主函数main

{

intcnt=3;//控制灯闪烁的次数为3次,如果灯循环

//亮三次,则程序运行正常

if(brd_init(100))//初始化DSK板

return;

while(cnt--)

{

brd_led_toggle(BRD_LED0);

delay(1000);

brd_led_toggle(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

codec_aout_gain(hHandset,CODEC_AOUT_MINUS_6dB);

//设置取样频率为8000Hz

codec_sample_rate(hHandset,SR_8000);

while

(1)

{

while(!

MCBSP_RRDY(HANDSET_CODEC)){};//等待A/D转换器输出数据

data=*(volatileu16*)DRR1_ADDR(HANDSET_CODEC);

test[k]=data;将A/D的输出存入数组test

buffer[k++]=data/16384.0;将16进制整数转化为浮点数存入数组buffer

if(k==256)

{k=0;//当采集满256个样点值后,调用DTMF_detect对采集

DTMF_detect();}//到的信号进行判决

}

}

voidDTMF_detect(void)

{

floatw[8],a[8][3];//数组w[8]用于存放

的系数

floatresult[8];//数组result[8]用于存放判决后的输出结果

inti,j,x,y;

//k=f*N/fs,N为DFT数据块的长度,这里取N=205,k的计算结果取整数

w[0]=2*cos(2*pi*18/205);//f=697Hz,k=18

w[1]=2*cos(2*pi*20/205);//f=770Hz,k=20

w[2]=2*cos(2*pi*22/205);//f=852Hz,k=22

w[3]=2*cos(2*pi*24/205);//f=941Hz,k=24

w[4]=2*cos(2*pi*31/205);//f=1209Hz,k=31

w[5]=2*cos(2*pi*34/205);//f=1336Hz,k=34

w[6]=2*cos(2*pi*37/205);//f=1477Hz,k=37

w[7]=2*cos(2*pi*42/205);//f=1633Hz,k=42

for(i=0;i<8;i++)

{a[i][0]=0;//vk(n-2)=0

a[i][1]=0;//vk(n-1)=0

for(j=0;j<205;j++)

{

a[i][2]=w[i]*a[i][1]-a[i][0]+buffer[j];//对vk(n)的值进行计算

a[i][0]=a[i][1];//对vk(n-2)的值进行更新

a[i][1]=a[i][2];//对vk(n-1)的值进行更新

}

result[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(result[i]>1500)//判决门限设置为1500

{

j++;

if(j==1)//第一个大于门限的是行频信号

x=i;//将行频信号的编号赋给x

elseif(j==2)//第二个大于门限的是列频信号

y=i;//将列频信号的编号赋给x

}

}

i=-2;

if(j==2)//利用行频信号的编号x和列频信号的y确定接收到的字

//符,并将其输出。

{

if(x==3&&y==5)

i=0;

elseif(x==0&&y==4)

i=1;

elseif(x==0&&y==5)

i=2;

elseif(x==0&&y==6)

i=3;

elseif(x==1&&y==4)

i=4;

elseif(x==1&&y==5)

i=5;

elseif(x==1&&y==6)

i=6;

elseif(x==2&&y==4)

i=7;

elseif(x==2&&y==5)

i=8;

elseif(x==2&&y==6)

i=9;

elseif(x==0&&y==7)

printf("TheDTMFsignalisA\n");

elseif(x==1&&y==7)

printf("TheDTMFsignalisB\n");

elseif(x==2&&y==7)

printf("TheDTMFsignalisC\n");

elseif(x==3&&y==7)

printf("TheDTMFsignalisD\n");

elseif(x==3&&y==4)

printf("TheDTMFsignalis*\n");

elseif(x==3&&y==6)

printf("TheDTMFsignalis#\n");

}

if(i!

=-2)

{

printf("TheDTMFsignalis%d.\r\n",i);

}

}

voiddelay(intperiod)//延时子程序

{

inti,j;

for(i=0;i

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1