其他分享
首页 > 其他分享> > 【数字信号】基于GUI DTMF信号生成与检测(带按键音)【Matlab 1086期】

【数字信号】基于GUI DTMF信号生成与检测(带按键音)【Matlab 1086期】

作者:互联网

一、DTMF简介

1 含义
双音多频 DTMF(Dual Tone Multi Frequency),双音多频,由高频群和低频群组成,高低频群各包含4个频率。一个高频信号和一个低频信号叠加组成一个组合信号,代表一个数字。DTMF信令有16个编码。利用DTMF信令可选择呼叫相应的对讲机。
双音多频信号(DTMF),电话系统中电话机与交换机之间的一种用户信令,通常用于发送被叫号码。

在使用双音多频信号之前,电话系统中使用一连串的断续脉冲来传送被叫号码,称为脉冲拨号。脉冲拨号需要电信局中的操作员手工完成长途接续。
双音多频信号是贝尔实验室发明的,其目的是为了自动完成长途呼叫。
双音多频的拨号键盘是4×4的矩阵,每一行代表一个低频,每一列代表一个高频。每按一个键就发送一个高频和低频的正弦信号组合,比如’1’相当于697和1209赫兹(Hz)。交换机可以解码这些频率组合并确定所对应的按键。

DTMF编解码器在编码时将击键或数字信息转换成双音信号并发送,解码时在收到的DTMF信号中检测击键或数字信息的存在性。一个DTMF信号由两个频率 的音频信号叠加构成。这两个音频信号的频率来自两组预分配的频率组:行频组或列频组。每一对这样的音频信号唯一表示一个数字或符号。电话机中通常有16个 按键,其中有10个数字键0~9和6个功能键*、#、A、B、C、D。由于按照组合原理,一般应有8种不同的单音频信号。因此可采用的频率也有8种,故称 之为多频,又因它采用从8种频率中任意抽出2种进行组合来进行编码,所以又称之为“8中取2”的编码技术。根据CCITT的建议,国际上采用的多种频率为 687Hz、770Hz、852Hz、941Hz、1209Hz、1336Hz、1477Hz和1633Hz等8种。用这8种频率可形成16种不同的组 合,从而代表16种不同的数字或功能键,具体组合见表1。

在很多应用中都要求进行音调检测,例如:双音多频信号 (DTMF)解码,呼叫过程(拨号音、忙音等)解码,频率响应测试(发送一个音调,同时将结果读回)。在频率响应测试中,如果在一定频率范围内进行测量, 那么得到的频响曲线中可能会包含丰富的信息,例如从电话线的频响曲线可以知道线上是否有负载线圈(电感)。
尽管针对以上应用均有专用IC,但采用软件来实现这些芯片的功能时所需成本比采用专用芯片低很多。然而,很多嵌入式系统都不具备进行连续实时FFT处理的能力,这时就适合采用Goertzel算法。本文将对Goertzel基本算法和Goertzel优化算法进行讨论。
采 用Goertzel基本算法能得出与常规离散傅立叶变换(DFT)或FFT相同的频率实部和虚部。如果需要的话,还可以从该频率实部和虚部中算出幅度和相 位信息。Goertzel优化算法则比Goertzel基本算法更快也更简单,但Goertzel优化算法并不给出频率实部和虚部分量,它只能给出相关的 幅度平方。如果需要幅度信息,可通过对该结果开方得到,但该方法无法得到相位信息。

2 Goertzel基本算法
Goertzel 基本算法在每次采样后立即进行处理,在每个第N次采样进行一次音调检测。在采用FFT算法时,我们要对成块的采样进行处理,但这并不意味着必须按块来处理 数据。数字处理的时间很短,因此如果每次采样都存在一次中断,那么这些数字处理完全可以在中断服务程序(ISR)内完成。或者,如果系统中存在采样缓存, 那么可以持续采样,然后进行批处理。
在真正运行Goertzel算法之前,必须进行下面的初步计算:

  1. 决定采样率;
  2. 选择块大小,即N;
  3. 预先进行一次余弦和正弦计算;
  4. 预先计算一个系数。
    这些计算均可以预先完成,然后硬编码到程序中,从而节省RAM和ROM空间,也可以动态方式计算。

3 选择合适的采样率
实际上,采样率可能已经由应用本身决定了。例如,在电信应用中普遍采用8kHz的采样率,即每秒8,000个采样。又如,模数转换器(或编解码器)的工作频率可能是由一个我们无法控制的外部时钟或外部晶振决定。
但如果我们可以选择采样率,那么就必须遵循奈奎斯特采样定理:采样率至少不低于最高信号频率的两倍。这是是因为如果我们要检测多个频率,那么采用更高的采样率可能会得到更好的结果。而且我们都希望采样率与每一个感兴趣的频率之间均呈整数倍关系。

4 块大小的设置
Goertzel算法中的块大小N与相应的FFT中的点数类似,它控制了频率分辨率的大小。例如,若采样率为8kHz,而N为100个采样,那么频率分辨率就是80Hz。
这就可能使我们为了获取最大的频率分辨率而尽量将N取高。然而N越大,检测到每个音调所需的时间就越多,因为我们必须等所有这N个采样都完成后才能开始处理。例如,采样率为8kHz时,累积800个采样需要100ms。若想缩短检测音调的时间,就必须适当调整N的值。
影响N的选择的另一个因素是采样率和目标频率之间的关系。比较理想情况是目标频率在相应的频率分辨率的中点范围内,也就是说,我们希望目标频率是sample_rate/N比值的整数倍。值得庆幸的是,Goertzel算法中的N与FFT中不同,不必是2的整数次幂。

5 预计算常数
在采样率和块大小确定之后,只须通过下面5个简单的计算来得出处理时所需要的常数:
k = (Ntarget_freq)/sample_tate
w = (2
π/N)*k
cosine = cos w
sine = sin w
coeff = 2 * cosine
每一次采样处理中都需要3个变量,我们称其为Q0’、Q1’和Q2。Q1是前一次采样处理的Q0值,Q2是在两次采样前的Q0值(或Q1在本次采样前的值)。
在每个采样块的开始时,都必须将Q1和Q2初始化为0。每个采样都需要按照下面三个等式进行计算:
Q0 = coeff * Q1 - Q2 + sample
Q2 = Q1
Q1 = Q0
在进行N次预采样计算之后,可以检测到音调是否存在。
real = (Q1 - Q2 * cosine)
imag = (Q2 * sine)
magnitude2 = real2 + imag2
这时只需进行一次简单的幅度门限测试就可以判断出是否有音调存在。之后,将Q2和Q1复位到0,开始下一个块的处理。

6 Goertzel优化算法
Goertzel优化算法比Goertzel基本算法所需的计算量小,但这是以损失相位信息为代价。
在 Goertzel优化算法中每个采样处理完全一样,但处理的结果与Goertzel基本算法不同。在Goertzel基本算法中,通常需要计算信号的实部 和虚部,然后将实部和虚部的计算结果转换为相应的幅度平方。而在优化Goertzel算法中则不需计算实部和虚部,直接计算下式:
magnitude2 = Q12 + Q22-Q1Q2coeff

二、部分源代码

function varargout = GUI(varargin)
%          GUI Application M-file for GUI.fig
%        FIG = GUI launch GUI GUI.
%              GUI('callback_name', ...) invoke the named callback.
%
%  Date: 21/05/04     Time: 17:50          
%  Email: pranamjanney@yahoo.com

if nargin == 0  % LAUNCH GUI

	fig = openfig(mfilename,'reuse');

	% Use system color scheme for figure:
	set(fig,'Color',get(0,'defaultUicontrolBackgroundColor'));

	% Generate a structure of handles to pass to callbacks, and store it. 
	handles = guihandles(fig);
    
    % Initialising structure variables to be used in program
    handles.data = 0;           % used for storing the Num_of_samples value
    handles.data1 = 0;          % used for storing the Slider values
    handles.data3 = 0;          % used for storing the number of times the push button is pressed
    handles.data4(1,8) = ' ';       % Array to store the numbers dialled 
	handles.chk = 0;            %  To check if the Number of samples is used or not
    
    guidata(fig, handles);

	if nargout > 0
		varargout{1} = fig;
	end

elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK

	try
		if (nargout)
			[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
		else
			feval(varargin{:}); % FEVAL switchyard
		end
	catch
		disp(lasterr);
	end

end

% --------------------------------------------------------------------
function varargout = pushbutton1_Callback(h, eventdata, handles, varargin)

% To check for N
if handles.chk == 0
    N = 205;
else
    N = handles.data;           %  Number of samples
end

NP = handles.data1;         % Noise Power
handles.data3 = handles.data3 + 1;  % to keep track of number of times push buttons are used

% Generator
[x,v,snr] = generator(1,N,NP);
size(x);

% Display SNR
set(handles.edit3,'String',snr)

% To plot on GUI
f = 1:N;
axes(handles.Out_dtmf) % Select the proper axes
plot(f,x(1:N))
set(handles.Out_dtmf,'XMinorTick','on')
grid on

% Decoder
[D,m] = decoder(x,N);
size(m);

% To append each dialled digit into an array (max 8 numbers)
[handles.data4,handles.data3] = StringNum(handles.data4,D,handles.data3);

% After 8th digit the next number is put into first digit place
if handles.data4 == ' ' 
    handles.data4(handles.data3) = D;
end

% To display the dialled numbers 
set(handles.edit2,'String',handles.data4);         % The dialled number as decoded by the decoder
                                       % is displayed on the edit text

% To plot the output                                       
f = 1 : length(m);
axes(handles.G_output) % Select the proper axes
plot(f,m)
set(handles.G_output,'XMinorTick','on')
grid on
guidata(h,handles);



% --------------------------------------------------------------------
function varargout = pushbutton2_Callback(h, eventdata, handles, varargin)

% To check for N
if handles.chk == 0
    N = 205;
else
    N = handles.data;           %  Number of samples
end       %  Number of samples

NP = handles.data1;         % Noise Power
handles.data3 = handles.data3 + 1;  % to keep track of number of times push buttons are used

% Generator
[x,v,snr] = generator(2,N,NP);
size(x);

% Display SNR
set(handles.edit3,'String',snr)

% To plot on GUI
f = 1:N;
axes(handles.Out_dtmf) % Select the proper axes
plot(f,x(1:N))
set(handles.Out_dtmf,'XMinorTick','on')
grid on

% Decoder
[D,m] = decoder(x,N);
size(m);

% To append each dialled digit into an array (max 8 numbers)
[handles.data4,handles.data3] = StringNum(handles.data4,D,handles.data3);

% After 8th digit the next number is put into first digit place
if handles.data4 == ' ' 
    handles.data4(handles.data3) = D;
end

% To display the dialled numbers 
set(handles.edit2,'String',handles.data4);         % The dialled number as decoded by the decoder
                                       % is displayed on the edit text

% To plot the output                                       
f = 1 : length(m);
axes(handles.G_output) % Select the proper axes
plot(f,m)
set(handles.G_output,'XMinorTick','on')
grid on
guidata(h,handles);



% --------------------------------------------------------------------
function varargout = pushbutton3_Callback(h, eventdata, handles, varargin)

% To check for N
if handles.chk == 0
    N = 205;
else
    N = handles.data;           %  Number of samples
end


NP = handles.data1;         % Noise Power
handles.data3 = handles.data3 + 1;  % to keep track of number of times push buttons are used

% Generator
[x,v,snr] = generator('A',N,NP);
size(x);

% Display SNR
set(handles.edit3,'String',snr)

% To plot on GUI
f = 1:N;
axes(handles.Out_dtmf) % Select the proper axes
plot(f,x(1:N))
set(handles.Out_dtmf,'XMinorTick','on')
grid on

% Decoder
[D,m] = decoder(x,N);
size(m);

% To append each dialled digit into an array (max 8 numbers)
[handles.data4,handles.data3] = StringNum(handles.data4,D,handles.data3);

% After 8th digit the next number is put into first digit place
if handles.data4 == ' ' 
    handles.data4(handles.data3) = D;
end

% To display the dialled numbers 
set(handles.edit2,'String',handles.data4);         % The dialled number as decoded by the decoder
                                       % is displayed on the edit text

% To plot the output                                       
f = 1 : length(m);
axes(handles.G_output) % Select the proper axes
plot(f,m)
set(handles.G_output,'XMinorTick','on')
grid on
guidata(h,handles);



% --------------------------------------------------------------------
function varargout = pushbutton4_Callback(h, eventdata, handles, varargin)

% To check for N
if handles.chk == 0
    N = 205;
else
    N = handles.data;           %  Number of samples
end

三、运行结果

在这里插入图片描述

四、matlab版本及参考文献

1 matlab版本
2014a

2 参考文献
[1] 沈再阳.精通MATLAB信号处理[M].清华大学出版社,2015.
[2]高宝建,彭进业,王琳,潘建寿.信号与系统——使用MATLAB分析与实现[M].清华大学出版社,2020.
[3]王文光,魏少明,任欣.信号处理与系统分析的MATLAB实现[M].电子工业出版社,2018.

标签:采样,1086,GUI,DTMF,Goertzel,handles,算法,data4,data3
来源: https://blog.csdn.net/m0_54742769/article/details/120375078