电话拨键号码(DTMF信号)识别

1、流程

电话拨键号码(DTMF信号)识别_第1张图片 图1 流程图

2、MATLAB实现

(1)主程序

clear all
clc
[x0,Fs]=audioread('1234567890.wav');
%sound(x0,Fs);
N=length(x0);                              %采样点
k=(0:N-1);
f=(k/N-1/2)*Fs;
X0=fft(x0);
figure
subplot(2,1,1),plot(x0)
title('原始按键音(时域)'),xlabel('t'),ylabel('振幅')
subplot(2,1,2),plot(f,abs(fftshift(X0)));xlim([0,4000])
title('原始按键音(频域)'),xlabel('f/Hz'),ylabel('幅度')                                 
% -----------------------------------------带通滤波 
Hd=band_pass;                              %带通滤波器
x1=filter(Hd,x0);                          %滤波
%sound(x1,Fs)
X1=fft(x1);
figure
subplot(2,1,1),plot(x1)
title('滤波后的按键音(时域)'),xlabel('t'),ylabel('振幅')
subplot(2,1,2),plot(f,abs(fftshift(X1))),xlim([0,2000])
title('滤波后的按键音(频域)'),xlabel('f/Hz'),ylabel('幅度') 
% -------------------------------------------过零率与短时能量
len=2000;                                   %帧长
d=50;                                       %帧重叠样点长
s=fra(len,len-d,x1);                        %分帧,s为帧数
es=s.^2;                                    %一帧内各样点能量
energy=sum(es,2);                           %一帧的能量,行求和
zcr=zcro(s);                                %求过零率
figure
subplot(3,1,1),plot(x1)
title('按键音1234567890'),ylabel('幅度')
subplot(3,1,2),plot(energy)
title('短时能量'),xlabel('帧编号'),ylabel('E')
subplot(3,1,3),plot(zcr)
title('信号过零率'),xlabel('帧编号'),ylabel('过零次数')
%-------------------------------------------端点检测
flag=energy;                                %有效信号标志
Ethresh=0.02;                               %短时能量阈值
flag(find(energy>Ethresh))=1;
flag(find(energy<=Ethresh))=0;                         
desired_signal=[];                          %有效信号标志
desired_signal(1)=0;                       
for i=1:length(flag)
    for j=2:i
        if flag(j-1)*flag(j)==0
            desired_signal(i)=0;
        else
            desired_signal(i)=1;
        end
    end
end 
figure,plot(desired_signal),ylim([0,1.2])
title('有效信号标志(0无效,1有效)'),xlabel('帧编号'),ylabel('y')
for i=2:length(desired_signal)
    if desired_signal(i)-desired_signal(i-1)==1
        left(i)=i;                      %左端点
    elseif desired_signal(i)-desired_signal(i-1)==-1
        right(i)=i;                     %右端点
    end
end
left_end=find(left~=0);                 %左端点
right_end=find(right~=0);               %右端点
%---------------------------------------分帧后的恢复,分割信号
[leftend1,leftend2]=inverse_fra(left_end,len-d,len);
[rightend1,rightend2]=inverse_fra(right_end,len-d,len);
figure
subplot(3,1,1),plot(x1)
title('按键音1234567890'),ylabel('幅度'),xlabel('t')
for i=1:length(leftend1)
    line([leftend1(i) leftend1(i)],[-0.1 0.1],'Color','red')
    line([rightend1(i) rightend1(i)],[-0.1 0.1],'Color','red')
end
subplot(3,1,2),plot(energy),ylim([-0.1,0.6])
title('短时能量'),xlabel('帧编号'),ylabel('E')
for i=1:length(left_end)
    line([left_end(i) left_end(i)],[-0.1 1],'Color','red')
    line([right_end(i) right_end(i)],[-0.1 1],'Color','red')
end
subplot(3,1,3),plot(zcr)
for i=1:length(left_end)
    line([left_end(i) left_end(i)],[-200,200],'Color','red')
    line([right_end(i) right_end(i)],[-200,200],'Color','red')
end
title('信号过零率'),xlabel('帧编号'),ylabel('过零次数')
%------------------------------------提取信号,识别号码
Ass=15;                                       %单个检测阈值
ferror=-10:10;                                %频率误差
fsL=[697 770 852 941];                        %信号低频
fsH=[1209 1336 1477];                         %信号高频
number=zeros(1,length(leftend1));             %存号码
figure
for i=1:length(leftend1)
    x=x1(leftend1(i):rightend1(i));
    N=length(x);
    fk=(0:N-1)/N*Fs;
    X=abs(fft(x));
    if max(X(floor(N*(fsL(1)+ferror)/Fs)))>Ass & max(X(floor(N*(fsH(1)+ferror)/Fs)))>Ass
        number(i)=1;
    elseif max(X(floor(N*(fsL(1)+ferror)/Fs)))>Ass & max(X(floor(N*(fsH(2)+ferror)/Fs)))>Ass
        number(i)=2;
    elseif max(X(floor(N*(fsL(1)+ferror)/Fs)))>Ass & max(X(floor(N*(fsH(3)+ferror)/Fs)))>Ass
        number(i)=3;
    elseif max(X(floor(N*(fsL(2)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(1)+ferror)/Fs)))>Ass
        number(i)=4;
    elseif max(X(floor(N*(fsL(2)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(2)+ferror)/Fs)))>Ass
        number(i)=5;
    elseif max(X(floor(N*(fsL(2)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(3)+ferror)/Fs)))>Ass
        number(i)=6;
    elseif max(X(floor(N*(fsL(3)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(1)+ferror)/Fs)))>Ass
        number(i)=7;
    elseif max(X(floor(N*(fsL(3)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(2)+ferror)/Fs)))>Ass
        number(i)=8;
    elseif max(X(floor(N*(fsL(3)/Fs)+ferror)))>Ass & max(X(floor(N*(fsH(3)+ferror)/Fs)))>Ass
        number(i)=9;
    elseif X(floor(N*(fsL(4)/Fs)+ferror))>Ass & X(floor(N*(fsH(2)+ferror)/Fs))>Ass
        number(i)=0;
    end
    subplot(3,4,i),plot(fk,X),title('按键音(频域)'),xlim([500,1500])
end
disp('该号码为:')
disp(num2str(number))                        %转换为字符串输出

(2)带通滤波器,此滤波器是使用fdatool生成

function Hd = band_pass
%BAND_PASS Returns a discrete-time filter object.

% MATLAB Code

% Butterworth Bandpass filter designed using FDESIGN.BANDPASS.

% Generated by MATLAB(R) 9.0 and the Signal Processing Toolbox 7.2.
% Generated on: 18-Dec-2019 14:51:03
% All frequency values are in Hz.
Fs = 44100;  % Sampling Frequency

Fstop1 = 500;         % First Stopband Frequency
Fpass1 = 697;         % First Passband Frequency
Fpass2 = 1477;        % Second Passband Frequency
Fstop2 = 1600;        % Second Stopband Frequency
Astop1 = 20;          % First Stopband Attenuation (dB)
Apass  = 1;           % Passband Ripple (dB)
Astop2 = 30;          % Second Stopband Attenuation (dB)
match  = 'stopband';  % Band to match exactly

% Construct an FDESIGN object and call its BUTTER method.
h  = fdesign.bandpass(Fstop1, Fpass1, Fpass2, Fstop2, Astop1, Apass, ...
                      Astop2, Fs);
Hd = design(h, 'butter', 'MatchExactly', match);

% [EOF]

(3)分帧

function [f] = fra(len,inc,x)
%fra 对语音信号分帧
%   len-帧长,inc-非重叠样点长度,x-语音信号
fh=fix((size(x,1)-len+inc)/inc);  %计算帧数
f=zeros(fh,len);                  %行为帧长,列为帧数
i=1;n=1;
while i

(4)过零率

function [f] = zcro(x)
%zcro 计算过零率
%   f-过零率,x-帧长
f=zeros(size(x,1),1);
for i=1:size(x,1)
    z=x(i,:);
    for j=1:(length(z)-1)
        if z(j)*z(j+1)<0
            f(i)=f(i)+1;
        end
    end
end
end

(5)分帧后的复原

function [end1,end2] = inverse_fra(k,inc,len)
%inverse_fra 将帧数编号时,还原到原始语音部分
%输出   end1-起始端点,end2-结束端点
%输入   k-帧编号,inc-帧非重叠样点长度,len-帧长
end1=(k-1)*inc+1;
end2=(k-1)*inc+len;
end

3、程序结果

电话拨键号码(DTMF信号)识别_第2张图片 图2 原始按键音
电话拨键号码(DTMF信号)识别_第3张图片 图3 滤波后的按键音
电话拨键号码(DTMF信号)识别_第4张图片 图4 短时能量与过零率
电话拨键号码(DTMF信号)识别_第5张图片 图5 有效信号区域
电话拨键号码(DTMF信号)识别_第6张图片 图6 分割信号
电话拨键号码(DTMF信号)识别_第7张图片
图7 各按键音频率

       

电话拨键号码(DTMF信号)识别_第8张图片 图8 识别结果

        在此程序中,端点检测并未用到短时过零率,是通过短时能量进行判断的,短时过零率仅仅是用来辅助判断。由于本人录音时间较长,且每段信号所含信息相同,因此可以用短时能量进行糙的端点检测,若进行更细致的检测则需要使用双门限检测,甚至是多门限检测法。由于电话号码当中并未出现A、B、C、D四个信号,因此滤波时可将高于1477Hz的频率滤除,滤波是为了排除杂波的影响。

识别结果如图8所示,录音顺序确为“1234567890”,表明该程序是正确的。

你可能感兴趣的:(信号(语音,图像,其他)处理)