DTMF信号的产生与检测-实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
DSP课程设计实验报告DTMF信号的产生与检测
指导老师:
时间:
1 设计任务书
双音多频DTMF(Dual Tone Multi Frequency)信号是在按键式电话机上得到广泛应用的音频拨号信令,一个DTMF信号由两个频率的音频信号叠加构成。
这两个音频信号的频率分别来自两组预定义的频率组:行频组和列频组。
每组分别包括4个频率,据CCITT的建议,国际上采用的这些频率为697Hz、770Hz、852Hz、941Hz、1209Hz、1336Hz、1477Hz 和1633Hz等8种。
在每组频率中分别抽出一个频率进行组合就可以组成16种DTMF编码,从而代表16种不同的数字或功能键,分别记作0~9、*、#、A、B、C、D。
如下图所示。
图1-1 双音多频信号编码示意图
要用DSP产生DTMF信号,只要产生两个正弦波叠加在一起即可;DTMF检测时采用改进的Goertzel算法,从频域搜索两个正弦波的存在。
1.1 实验目的
掌握DTMF信号的产生和检测的DSP设计可使学生更加透彻的理解和应用奈奎斯特采样定理,与实际应用相结合,提高学生系统地思考问题和解决实际问题的能力。
通过对DSP 信号处理器及D/A和A/D转换器的编程,可以培养学生C语言编程能力以及使用DSP硬件平台实现数字信号处理算法的能力。
1.2 技术指标及设计要求
1.2.1 基本部分
1)使用C语言编写DSP下DTMF信号的产生程序,要求循环产生0~9、*、#、A、B、C、
D对应的DTMF信号,并且符合CCITT对DTMF信号规定的指标。
2)使用C语言编写DSP下DTMF信号的检测程序,检测到的DTMF编码在CCS调试窗口
中显示,要求既不能漏检,也不能重复检出。
3) DTMF 信号的发送与接收分别使用不同的实验板完成。
1.2.2 发挥部分
1) 使用一个DSP 工程同时实现DTMF 信号的发送和检测功能。
2) 改进DTMF 信号的规定指标,使每秒内可传送的DTMF 编码加倍。
3)发送的DTMF 信号的幅度在一定范围内可调,此时仍能完成DTMF 信号的正常检测。
1.3 方案完成情况
在实现基本要求的基础上,我们又完成了发挥部分的全部要求:能够实现在一个DSP 实验箱上同时实现自发自收,基本能实现无差错传输。
通过改变处理信号的点数N 的数值实现了DTMF 信号编码加倍,能够在一秒内传送够多的数据。
通过gel 添加滑动条的方法实现输入信号幅度可调,并实现判决门限的自适应处理,能随着幅度的变化自动调整门限的值,进而了判决传输信号的正确性。
2 设计内容
2.1 DTMF 信号的的定义
双音多频(DTMF)信号是由两个不同频率的信号叠加而成,设V(t)为DTMF 信号、()t V H 和()t V L 分别为构成V(t)的两个信号,则它们应满足关系式(1)。
V(t)= ()t V H +()t V L
(1)
根据CCITT 建议,国际上采用697Hz 、770Hz 、852Hz 、941Hz 、1209Hz 、1336Hz 、1477Hz 、1633Hz8个频率,并将其分成两个群,即低频群和高频群。
从低频群和高频群中任意抽出一个频率进行叠加组合,具有16种组合形式,让其代表数字和功率,如表3-1所列,则有关系式(2)。
V(t)=Asin H ωt+Bsin L ωt
(2)
其中Asin H ωt 为低频群的值,Bsin L ωt 为高频组的值,A 、B 分别为低频群和高频群样值的量化基线,具体见表2-1。
表2-1 DTMF频率及其对应的键值
2.2 DTMF信号生成方法
2.2.1 利用math.h采用数学方法产生DTMF信号
buffer[k]= sin(2*pi*k *f0/fs)+ sin(2*pi*k *f1/fs) (式2-1)f0为行频频率,f1为列频频率,fs为8000采样频率,k为对信号的采样。
2.2.2 利用两个二阶数字正弦波振荡器产生DTMF信号(本
课程设计实际采用方法)
DTMF 编码器基于两个二阶数字正弦波振荡器,一个用于产生行频,一个用于产生列频。
向DSP装入相应的系数和初始条件,就可以只用两个振荡器产生所需的八个音频信号。
典型的DTMF信号频率范围是700~1700Hz,选取8000Hz 作为采样频率,即可满足Nyquist 条件。
由数字振荡器对的框图,可以得到该二阶系统函数的差分方程
(式2-2)其中a1=-2cosω0,a2=1,ω0=2πf0 /fs,fs为采样频率,f0 为输出正弦波的频率,A 为输出正弦波的幅度。
该式初值为y(-1)=0,y(-2)=-Asinω0。
CCITT 对DTMF 信号规定的指标是,传送/ 接收率为每秒10个数字,即每个数字100ms。
代表数字的音频信号必须持续至少45ms,但不超过55ms。
100ms 内其他时间为静音,以便区别连续的两个按键信号。
编程的流程如图1所示,由CCITT 的规定,数字之间必须有适当长度的静音,因此编码器有两个任务,其一是音频信号任务,产生双音样本,其二是静音任务,产生静音样本。
每个任务结束后,启动下一个任务前(音频信号任务或静音任务),都必须复位决定其持续时间的定时器变量。
在静音任务结束后,DSP 从数字缓存中调出下一个数字, 判决该数字信号所对应的行频和列频信号,并根据不同频率确定其初始化参数a1=-2cosω0 与y(-2)=-Asinω0。
该流程图可采用C 语言实现,双音信号的产生则由54x汇编代码实现。
整个程序作为C 5 4 x 的多通道缓冲串口(McBsp)的发射串口中断服务子程序,由外部送入的16000Hz串口时钟触发中断,可实时处理并通过D / A 转换器输出DTMF 信令信号。
图2-1 DTMF编码流程
2.3 DTMF信号的检测方法
DTMF信号的检测方法可以有多种。
主要分为从信号时间域处理和从信号频率域处理两大类。
前一种方法包括:过零点位置检测法、信号峰值位置检测法、过零点位置及信号幅值检测法。
其特点是实现简单,可以通过MT8880等芯片加上外围电路实现,易于集成化。
缺点是易受干扰,对信噪比要求高。
现在广泛应用于一般的脉冲拨号电话机。
通过神经网络等辅助判别方法可以大大提高信号的识别率。
后一种方法包括:频率判断、能量判断两类。
频率判断主要通过滤波器提取DTMF相应的频率信号进行比较判断,滤波器可以用窄带、低通、高通滤波器,应用方式可以有并联、级联、混合联接等方式。
能量判断是直接对DTMF信号相应的能量进行计算,找出高、低频率群中最强的信号,进行判断,包括有DFT法(Discrete Fourier Transform)、FFT(Fast Fourier Transform)、Goertzel法等。
本次实验我们采用的是能量判断法,并采用了Goertzel算法。
3 设计方案、算法原理说明
3.1 Goertzel 算法原理
Goertzel 算法信号解码是将两个音频信号提取出来,并通过他们的频率,确定所接受的DTMF 数字。
原来使用模拟技术音频信号频率进行检测,一般通过模拟电路进行过零点检测,通过零点计数完成对输入信号的频率检测。
在数字信号检测电路中,一般使用频域计算技术代替时域信号处理。
我们可以直接通过付立叶变换,直接得到输入的信号频率。
信号各个频率分量的幅值直接计算可以使用DFT 。
对于N 点数据序列{x(n)}的DFT 为:
()()1N ,...,1,0k ,W n x k X nk
N 1
N 0n -==∑-=
(式 3-1)
如果用FFT 算法来实现DFT 计算,计算将涉及复数乘法和加法,并且计算量为N Nlog 2。
虽然我们可以得到DFT 的所有N 个值,然而,如果希望计算DFT 的M 个点,并且M<N log 2时,可以看到,直接计算DFT 则更加有效。
下面我们用到Goertzel 法,是一种直接计算DFT 有效的方法。
我们应用Goertzel 算法对DTMF 信号的检测,并且对其进行改进。
Goertzel 算法,从根本上说,是计算DFT 的一种线性滤波算法,它可以通过调整滤波器的中心频率和带宽,直接计算出DFT 的系数。
Goertzel 算法利用相位因子{}
k
N W 的周期性。
我们可以同时将DFT 运算表示为线性滤波运算,由于kN N W -=1,我们可以用该因子对公式(4) (DFT 表达式)两边相乘,得到:
()()()()()
m N k N 1
N 0
m kN N
nk N
1N 0
n kN
N
W m x W
W n x k X k X W
---=--=-∑∑=*== (式 3-2) 我们注意到,上式就是卷积形式。
可以定义序列()n Y K 为:
()()()
m N k N
1
N 0m k W m x n Y ---=∑= (式 3-3) 显然,Yk (n)就是长度为N 的有限长输入序列()n Y K 与具有如下单位脉冲响应的滤波器的卷积:
()()n u W n h kn
N k -= (式 3-4)
可以看到,当n=N 时,该滤波器的输出就是DFT 在频点k N
2k π
=ω值 即
()()N n K n Y k X == (式 3-5)
我们可以通过比较式(6)和式(7) 来验证上式。
对于单位脉冲响应为()n h k 的滤波器来说,其系统函数为:
()1
k N k z
W 11
z H ---=
(式 3-6) 这个滤波器只有一个位于单位圆上的极点,其频率为k N
2K π
=
ω。
因此,可以使用输入数据块通过N 个并行的单极点滤波器或者谐振器组来计算全部的DFT,其中每个滤波器有一个位于DFT 响应频率的极点。
因此,对于式(7)的卷积计算,我们可以使用差分方程形式来表示用式(9)给出的滤波器,通过迭代的方法计算()n Y K ,从而得出DFT 的计算结果:
()()()()01y ,n x 1n y W n y k k k
N k =-+-=- (式 3-7)
计算涉及复数加法和复数乘法,计算量大。
由于我们只需要计算幅值信息,而不关心相位信息。
我们在单位圆上另外引入一个极点,与原有的极点形成一对共扼极点。
将两个滤波器组成一对复数共轭极点的谐振器。
原有的单极点滤波器计算方式变成形如式(10)的方式。
其系统函数为:
()()2
11
k N z z
z N k 2cos 21z
W 1z H ---+π--= (式 3-8) 上式中:N /k j2K
N e W π=,为差分方程的系数。
由于引入了复数共扼极点,避免了式(9)
中复杂的复数加法和复数乘法。
显然,对式(10)无法进行直接计算。
为了便于计算实现,我们引入中间变量()n Q k ,将式(9)表示为差分方程形式:
()()()()n x 2n Q 1n Q N k 2cos 2n Q k k k +---⨯⎪⎭
⎫
⎝⎛π⨯= (式 3-9)
式中,初始条件为: ()()N ,...,1,0n ,02Q 1Q k k ==-=-
()()()()1N Q W N Q N Y k X k k
N k k -⨯-== (式 3-10)
其中,N
k
2k N
e
W π-=
3.2 Goertzel 算法改进与实现
Goertzel 算法是计算离散傅立叶变换的方法,需要计算的频率点数不超过21092 N 时Goertzel 算法将比FFT(Fast Fourier Transform)更为有效。
Goertzel 算法相当于一个二阶IIR 滤波器,(10)式是它的转移函数我们可以根据(10)式画出改进Goertzel 算法的模拟框图,如图 3-1所示
(n x -1
()
n k
图 3-1 Goertzel 算法的模拟框图
图2中可看到,整个计算过程分为两部分:前向通路式(11)和反馈通路式(12)。
显然,对于式(11)的递推关系计算需要重复N=1,⋯,N 重复N+1次,但是式(12)中的反向计算只需要在n=N 时计算一淡。
每次计算只需要计算一次实数乘法和两次实数加法。
所以,对实数序列x (n), 由于对称性,用这种算法求出X(k)和X(N-k)的值需要N+1次实数乘法运算。
我们现在可应用Goertzel 算法完成实现DTMF 解码器了。
由于有8种可能的音频信号需要检测。
所以需要至少8个由式(9)给出的滤波器,将每个滤波器调谐到这8个频率值上。
在完成信号判决时,我们并不需要相位信息,只需要幅值信息|X(k)| 。
因此,对式(12)两边进行平方,计算幅度的平方值|X(k)|2。
我们将递推方程式(9,11, 12)进一步简化,得到滤波器计算的前向部分的简化表达方式,即滤波表达式的分子项部分:
由于我们只需要幅值信息,不需要相位信息,因此,对前向部分进行改进,输出幅度平
方值。
()()()()()()()1N Q N Q N
k
2cos
21N Q N Q N y N y k X k k 2
k 2k k k 2
-π-+==* (式 3-1) 3.3 改进Goertzel 算法原理小结
在式(12)中可以使用A, B 分别代替递归项,令()1N Q A k -=,()2N Q B k -=将离散付里叶变换DFT 的改进计算过程总结写为:
()k 222
k ABcoef B A N y -+= (式 3-2)
其中 ⎪⎭
⎫
⎝⎛π=k N 2cos 2coef k ,()()22k k X N y = 可以看到,由于上面两式中:
忽略相位信息,使用实数运算,无复数运算。
等式右边全部是实数运算,大大提高了运算速度,降低计算量。
3.4 实际实现中误差分析
3.4.1 舍入误差问题
我们再次回到公式 3-1 进行分析:
()()()()()()1N Q N Q N
k
22cos
1N Q N y N y k X K K 2K k k 2
-π--==*
(式 3-1) 简单地说,在实际的DSP 实现中将使用(4)式和(6)式来得到DTMF 信号的频谱信息,(4)式实际就是一个递归线性滤波器的表达式,它在n=0…N 之间进行循环。
每N 个样点对公式(6)进行了一次计算。
在这个算法中,DTMF 频率(f i )变换成了离散傅立叶系数(k ),它们之间存在如下关系:
,N
k
f f s i = 这里,N 是滤波器的长度,f s 是采样频率。
在给定的采样频率下,我们可以通过调整N 和K 值,得到相应的DTMF 频率(i f )上的能量幅值。
但是,由于k 和N 是整数,有可能不能取到合适的DTMF 频率(f i )。
实际上,计算时如果采用FFT 变换,计算字长N 将被限定为2得n 次方,每次计算可以同时得到N/2个频率点的幅度值。
而对于DFT 或Goertzel 算法来说,对于N 长度的算法,其可以分辨的最高频率为采样频率的一半。
其输出序列为
{X(0)、X(1)……,X(N)}
对应的信号计算频率为f i ,i=0,1,…,N 。
所以,我们可以知道,可计算的信号频率存在一定的限制。
式(4-12)给出了Goertzel 算法的频率分辨率。
对于不是正好在输出序列计算点上的信号频率,其计算结果分布在相近的频率值上,将会出现泄漏,这不是我们所期望的。
3.4.2 计算字长N 的问题提出
N 和k 的选择不同,计算的误差会有很大不同。
缩小N 值,将显著减少计算量,所以N 值的选取,是完成实时计算的核心。
在相关文献中,N 值的选取也有很大的不同。
有使用16个106字长计算完成信号监测及语音检测的,也有使用105字长或205字长完成Goertzel 算法完成检测的,由此我们提出这样一个问题,在文所利用的Goertzel 算法中,进行DTMF 信号检测的最佳字长是多少?
由采样频率公式可知,在采样率一定的情况下,N 值的取值同时决定Goertzel 算法计算时对应的频率,即Goertzel 滤波器的中心频率。
通过改变N 值,计算出我们感兴趣的对应一组k 值,即完成DTMF 频率检测。
但是,由式(14)可知k 取整数,计算中心频率的位置与实际的DTMF 频率必然会产生一定的舍入误差。
我们将Goertzel 算法中的中心频率与实际的DTMF 频率的差值定义为D 。
可以计算出D 的最大值为
Dmax =
2N f s ,当k 的误差k =0.5时,对应的频率百分比为:dtmf
s
2Nf f ,dtmf f 为所需计算的DTMF 频率。
这实际上是DTMF 频率位于“所计算的信号窗口的边缘”。
当N 值取较大值时,同时采取较高的采样频率可以取得较准确的检测结果,但是也加大了计算量。
由于N 的取值,影响了计算时的Goertzel 滤波器的中心频率的位置。
实际应用中,首先需要确定N ,同时对应不同的DTMF 频率,取相应的k 值,通过Goertzel 算法,得到相应的X(k)。
可以看到,N 的取值是Goertzel 算法设计DTMF 信号检测器的关键,它直接决定了检测器的性
能及对ITU 建议的满足性。
以下讨论在满足ITU 要求的情况下,寻找的N 值的过程,同时,我们在这里讨论的是误差的百分比,因此,可以通过计算点数的误差百分比来估计频率的百分比。
3.4.3 Goertzel 算法中N 的选择要求
N 的选择应考虑如下的因素:
频率偏移度不但要求主瓣宽度存在一定的范围之内,同时也和计算窗口中心频率有关。
Goertzel 算法种计算长度N 的取值也影响到计算窗口中心频率的取值。
例如,如果N=125,f s =8000Hz,对于770Hz 信号的完成检测,频域分辨率为
8000/125=64Hz,ITU 规定的对于频率误差大于3.5%的信号拒识,即对于770Hz 信号为中心,宽度为743.05到769.95。
39.0Hz 的频率分辨率将矗立的信号为780.488Hz 为中心,其他范围的频率则不满足规定要求。
3.4.4 舍入误差的寻优
根据s
i
f f N k ⨯
=,在Goertzel 算法进行递归计算时k 要取整数,因而存在舍入误差。
舍入误差是随机和离散的,不同的N 值和不同的f i 舍入误差是不同的,因此造成的频率的偏移也是不同的。
由于k 的舍入误差反映的是频率的偏移,因此必须兼顾每个频率,选择k 舍入误差小得N 值。
表3-1列出了当N=125时,不同的频率k 值的舍入误差,表3-2列出了当N=205时,不同的频率k 值的舍入误差.
表3-1 N=125时不同的频率值k的舍入误差
表3-2 N=205时不同的频率值k的舍入误差
由于k的舍入误差反映的是频率的偏移,因此必须选择k舍入误差小的N值。
同时还要兼顾每个频率,每个频率k舍入误差都比较小,或者尽可能的都取“舍”或者都取“入”,这样就会使偏移比较小或者都向同一个方向偏移。
3.4.5 复杂度比较
直接计算离散傅里叶变换,对于每一个k值,需要4N次实数乘法及4N-2次的实数加法,4N次实数乘法及N(4N-2)次实数加法,因此,采用直接法计算的计N点的傅里叶变换需要2
N)。
算复杂度为O(2
对于Goertzel算法来说。
其输入的X(n),Wk,是复数,每计算一个新输出Y值需要做四次实数加法和四次实数乘法。
由于我们只需要幅值信息,对于相位信息可以忽略,通过变换得到
N)。
幅值信息。
因此,共需要N+l次实数乘法,计算复杂度为O(M
对于单个解码器来说,对于每次成功完成DTMF信号解码的时间估计十分重要。
通过对解码器的处理时间估计,我们可以得到其处理性能,通过对处理性能评价,就可以预计单个解码器工作时可以承载的最大信道个数。
在这里,定义DTMF解码器成功完成两个DTMF信
号解码之间所耗费的时间可以这样估算:
每处理一个采样样本的时间间隔允许的最大值为:
==
s
s f 1
T 125s μ (式3-3) 前向计算所需的时间为:s T N *
可以看到,计算时间主要决定于计算字长N 。
对于每一个需要检测的频率,都必须进行(N+4)次实数乘法和(N 十2)次加法。
检测8个DTMF 频率需要的总共的计算量为:(8N+ 32)次乘法与(16N 十16)次实数加法。
4 算法流程图
图4-1 程序算法流程图
5 源程序注释
5.1 初始化程序
//*****************************初始化********************************** // Initialize CSL library - This is REQUIRED !!! CSL_init();
// The main frequency of system is 240MHz
// 该频率是为了设置IIC模块的需要设置的,为了使用I2C_setup函数PLL_setFreq(1, 0xC, 0, 1, 3, 3, 0);
//EMIF初始化
Emif_Config();
// Open McBSP port 1 and get a McBSP type handle
hMcbsp = MCBSP_open(MCBSP_PORT1,MCBSP_OPEN_RESET);
// Config McBSP port 1 by use previously defined structure
Mcbsp_Config(hMcbsp);
//I2C初始化
I2C_cofig();
//CODEC寄存器初始化
inti_AIC();
5.2 二极管闪烁程序
//*******************程序正常执行:二极管闪烁两次***********************
while(cnt--)
{
asm(" BCLR XF"); // ; Clear XF
delay(3000);
asm(" BSET XF"); // ; Set XF
delay(3000);
}
5.3 DTMF信号产生,发送与接收
//**********************DTMF信号产生,发送,接收*************************
for(i=0;i<16;i++)
{
f0=freq[i][0]; //顺序获取各符号低频数据
row_freq[i][0]=cos(2*pi*f0/fs);
row_freq[i][1]=sin(2*pi*f0/fs);
}
for(i=0;i<16;i++)
{
f0=freq[i][1]; //顺序获取各符号高频数据
column_freq[i][0]=cos(2*pi*f0/fs);
column_freq[i][1]=sin(2*pi*f0/fs);
}
for(k=0;k<16;) //基于两个二阶数字正弦振荡器,产生DTMF信号
{
ax1=row_freq[k][0];
x_n_2= -row_freq[k][1];
ay1=column_freq[k][0];
y_n_2= -column_freq[k][1];
x_n_1=0;
y_n_1=0;
for(j=0;j<200;j++) //传输信号采样值,设产生信号的持续时间为50ms,所以j为200。
{
x_n=2*ax1*x_n_1-x_n_2;
y_n=2*ay1*y_n_1-y_n_2;
z_n=x_n+y_n;
x_n_2=x_n_1;
x_n_1=x_n;
y_n_2=y_n_1;
y_n_1=y_n;
dtmf[j]=z_n*gain; //gain(可变)改变产生信号的幅度,使之在一定范围内可调,
while(!MCBSP_xrdy(hMcbsp)) {}; //左声道信号发送
MCBSP_write16(hMcbsp,dtmf[j]); //采样值的装入,前二百
个点为双音信号采样值
while(!MCBSP_xrdy(hMcbsp)) {}; //右声道信号发送
MCBSP_write16(hMcbsp,dtmf[j]); //采样值的装入,前二百个点为双音信号采样值
while(!MCBSP_rrdy(hMcbsp)){}; //左声道信号接收
dtmfr[j]=MCBSP_read16(hMcbsp);
while(!MCBSP_rrdy(hMcbsp)){}; //右声道信号接收
dtmfr[j]=MCBSP_read16(hMcbsp);
}
for(j=0;j<200;j++) //传输静音信号,设产生信号的持续时间为50ms,所以j为200。
{
dtmf[j+200]=0; //后二百个点为0(即静音信号)。
while(!MCBSP_xrdy(hMcbsp)) {}; //左声道信号发送
MCBSP_write16(hMcbsp,0);
while(!MCBSP_xrdy(hMcbsp)) {}; //右声道信号发送
MCBSP_write16(hMcbsp,0);
while(!MCBSP_rrdy(hMcbsp)){}; //左声道信号接收
dtmfr[j+200]=MCBSP_read16(hMcbsp);
while(!MCBSP_rrdy(hMcbsp)){}; //右声道信号接收
dtmfr[j+200]=MCBSP_read16(hMcbsp);
}
detect(); //接收信号判决检测与显示
k++;
if(k==16) //控制16个符号循环发送
k=0;
}
5.4 延时子程序
//********************************延时子程序******************************
void delay(int period)
{
int i, j;
for(i=0; i<period; i++)
{
for(j=0; j<period>>1; j++);
}
}
5.5 接收信号判决检测与显示子程序
//***********************接收信号判决检测与显示子程序*********************
void detect()
{
w[0]=2*cos(2*pi*K[0]/N); //采用Goertzel算法检测DTMT信号
w[1]=2*cos(2*pi*K[1]/N);
w[2]=2*cos(2*pi*K[2]/N);
w[3]=2*cos(2*pi*K[3]/N);
w[4]=2*cos(2*pi*K[4]/N);
w[5]=2*cos(2*pi*K[5]/N);
w[6]=2*cos(2*pi*K[6]/N);
w[7]=2*cos(2*pi*K[7]/N);
for(i=0;i<8;i++) //i表示有8个频率点。
{
bb[i][0]=0;
bb[i][1]=0;
for(j=0;j<N;j++)
{
bb[i][2]=w[i]*bb[i][1]-bb[i][0]+dtmfr[j+50]/8192.0; //DFT在8个频率点的值
bb[i][0]=bb[i][1]; //迭代算法
bb[i][1]=bb[i][2];
}
result[i]=bb[i][1]*bb[i][1]+bb[i][0]*bb[i][0]-w[i]*bb[i][1]*bb[i][0]; //每一段的8个频率点的幅度平方值
}
j=0;
for(i=0;i<8;i++)
{
if(result[i]>thresh) //对result中的值进行检测,与域值比较,当超过域值时,判断此频率点上信号存在
{
j++;
printf("dtmf[%d]:%f\r\n",i,result[i]);
if(j==1) //j=1时i的值赋给x,代表检测符号含
有的低频信息
{
X=i;
}
else if(j==2) //j=2时i的值赋给y,代表检测符号含有的高频信息
{
Y=i;
}
}
}
threshold(); //根据当前8个频率点的幅度平方值自适应更新域值
ch='e';
if(j==2)
{
if(X==0 && Y==4) //若x=0,y=4,则表示低频为697Hz,高频为1209Hz
{
ch='1'; //这两个频率所对应的数为"1"
}
else if(X==0 && Y==5) //若x=0,y=5,则表示低频为697Hz,高频为1336Hz
{
ch='2'; //这两个频率所对应的数为"2"
}
else if(X==0 && Y==6) //以下都依次类推
{
ch='3';
}
else if(X==1 && Y==4)
{
ch='4';
}
else if(X==1 && Y==5)
{
ch='5';
}
else if(X==1 && Y==6)
{
ch='6';
}
else if(X==2 && Y==4)
{
ch='7';
}
else if(X==2 && Y==5)
{
ch='8';
}
else if(X==2 && Y==6)
{
ch='9';
}
else if(X==3 && Y==5)
{
ch='0';
}
else if(X==3 && Y==4)
{
ch='*';
}
else if(X==3 && Y==6)
{
ch='#';
}
else if(X==0 && Y==7)
{
ch='A';
}
else if(X==1 && Y==7)
{
ch='B';
}
else if(X==2 && Y==7)
{
ch='C';
}
else if(X==3 && Y==7)
{
ch='D';
}
}
if(ch!='e') //满足以上一种情况,则输出检测的信号{
printf("The DTMF signal is \"%c\".\r\n",ch);
}
else //以上情况都不满足,则输出错误信息提示{
printf("The number inputted in is wrong!\n");
}
}
5.6 自适应域值更新子程序
//******************************自适应域值更新子程序**********************
void threshold()
{
for(c=0;c<8;c++) //传递当前8个频率点的幅度平方值,便于自适应域值更新处理
{
linshi[c]=result[c];
}
for(b=0;b<2;b++) //寻找八个频点中第二大频点的幅度平方值{
for(a=b;a<8;a++)
{
if(linshi[b]<=linshi[a])
{
temp=linshi[b];
linshi[b]=linshi[a];
linshi[a]=temp;
}
}
}
thresh=thresh*0.3+0.7*(linshi[1]*0.5); //自适应更新域值(原域值30%+0.7倍第二大频点的幅度平方值70%)
}
6 程序设计、调试与结果分析
6.1 调试过程
6.1.1 CCS的启动
双击桌面上的Setup CC3.3 运行CCS 设置程序。
单击Import Configuration 对话框中的Clear,删除原先定义的设置。
从Available Configurations列表中,选择C5502 SEEDXDS510PLUS Emulator,单击Import,单击save and quit。
图6-1 硬件环境设置
6.1.2 工程建立、加载与程序运行
(1)创建名为DTMF-SEND&RECEIVE的工程
通过project的new来建立一个名为DTMF-SEND&RECEIVE的新工程,过程如下图所示:
图6-2 新建工程
(2)向工程中添加文件
从file中的new—source建立c程序和cmd文件,编写完成后保存,然后从project—add files to project添加c程序和cmd文件,库文件,头文件可以通过扫描相关性(Scan All
Dependencies)自动加入到工程中。
头文件路径可以通过project中build options的compiler 中的processes进行设置,最终编译环境如下图所示:
图6-3 添加源文件
图6-4 添加cmd文件
图6-5 添加库文件
图6-6 添加头文件(使用浏览文件相关性选项)
图6-7 设置头文件路径
图6-8 设置数据大小端模式(大端模式)
图6-9 添加宏定义
(3)编译与运行程序
选择Project/Rebuild All或单击(Rebuild All)菜单条按钮,CCS重新进行编辑、汇编、连接工程里的所有文件。
选择File/Load Program.选中DTMF-SEND&RECEIVE,双击,即可加载.out文件。
CCS将程序装载到目标DSP上,打开显示程序反汇编指令的Disassembly窗口。
选择Debug/Go Main,从主程序开始执行。
最后单击Debug-Run(或按F5键)运行程序。
图6-10下载gel文件
图6-11程序编译成功
图6-12将程序下载到实验箱
图6-13程序运行
图6-13打开gel文件滚动条
6.2 实验结果及图像
本次实验中,我们通过一台电脑循环产生0——9、A、B、C、D、*、#,在另一台电脑上会循环显示检测到的DTMF信号,即循环显示0——9、A、B、C、D、*、#。
下面我们从时域和频域两个角度观察一下检测信号的波形:
6.2.1 使用CCS中Graph显示
发送端的时域图形参数设置及显示结果如下所示:
图6-14发送缓存区图形参数设置(时域及频域)
图6-15 发送缓存区时域图形显示
检测端的时域图形参数设置及显示结果如下所示:
图4-17 检测缓存区图形参数设置(时域及频域)
图6-18 发送缓存区时域图形显示
6.2. 2 使用虚拟仪器显示
图6-20 发送端信号时域波形
图6-21 发送端信号频谱
7. 遇到的问题及解决方法
【问题一】
新建工程时头文件路径不匹配,文件编译出错。
解决方法:在菜单栏中选中Project-Build Options-Compiler-preprocessor-Include Search Path,添加正确路径即可。
【问题二】
数据类型定义不当导致cmd文件中,内存分配不足,文件编译出错。
解决方法:打开Debug中的.map文件,观察缓存溢出情况,修改cmd文件内存分配。
【问题三】
声卡抽样频率设置有误,导致虚拟仪器观察输出波形时,出现多余频谱分量。
解决方法:打开AIC23.c,更改波特率设置,即采样频率设置为8K后,输出信号频谱正常。
【问题四】
信号幅度控制与自适应阈值选取衔接有误。
解决方法:算法有误,后采取合理算法即原域值30%+0.7倍第二大频点的幅度平方值70% (thresh=thresh*0.3+0.7*(linshi[1]*0.5) ),信号检测正常。
【问题五】
阈值选取不当,无法正常检测输出信号。
解决方法:经过多次尝试并修改阈值,最终选取合理阈值,正常判决、检测以及显示结果。
8. 心得体会
刘璐:
双音多频DTMF信号是在按键式电话机上广泛应用的的音频信号,由于我家里最早接触的就是固话,一开始对这个题目比较感兴趣,就选择了这个题目。
通过看课件与查阅资料逐渐懂得了DTMF信号产生与检测的原理,熟悉了利用CSS这款软件和DSK板调试的过程。
刚开始只知道按部就班的把过程操作一遍,后来通过学习也渐渐知道添加的*.lib,*.h这些文件的意义所在,比如rts.lib(支持C语言运行的库)、dsk5402.lib、drv5402.lib(是使用dsk板所需的库),c5400/cgtools/include里面含有dsp通用头文件,与硬件无关,而c5400/dsk5402/include中是硬件专用头文件等等。
还有关于C语言在DSP课程设计中的应用和以前大一所学习的简单常用的C语言还是很有些区别,要掌握好编程还需要学习和努力。
还有一个体会就是最后几天要接到实验板实在很困难,早上起的很早可能也没法借到板子来调试。
这次实验收获很大,掌握了一些对于CCS的运用,学习了DTMF信号的产生与检测的原理,学习了C语言的编程在dsp中的应用,真正体会到了DSP芯片强大的运算和处理能力,并且这次的课程设计不仅仅让我们学会如何使用DSP芯片以及应用,更是给我们今后在实际解决或系统设计时提供了一种设计思路,可根据不同系统的设计要求采用性能要求不同的DSP处理芯片来解决实际问题,同时有效地锻炼和提高了我们的软件编程能力。
总之,此次的课程设计使我收获颇丰,不仅掌握了DTMF信号的相关知识与CCS的操作,更锻炼了我处理问题的实际能力和思考问题的方法,这也必将对日后的科研相关工作奠定积极的意义。
最后感谢老师对我的耐心细致的指导,谢谢老师。
9. 参考文献
[1]高海林钱满义编写《DSP技术及其应用》清华大学出版社
[2] 陈后金等《信号分析与处理实验》高等教育出版社
[3] DTMF Tone Generation and Detection:An Implementation Using the TMS320C54x.
SPRA096a ,TI.Inc.2000
[4]唐达强.双音多频信号接收器的设计与实现(硕士学位论文).北京:北方交通大学.1990
[5]陈通,曹小强. 基于NDFT Goertzel滤波器的DTMF信号检测的改进方法.西南大学
学报.2008
[6]李义府.双音多频信号检测在DSP中的实现.中南大学信息科学与工程学院.2006
[7]薛曼芳.基于改进的Goertzel算法的双音多频检测器的设计.甘肃:兰州工业高等专科
学校.2008。