逆DTMF变换(Demonstrate the DFT-based DTMF detection algorithm.)

一,逆DTMF说明即思路

DTMF的方法,思路即代码在上文已经提到

DTMFmatlab实现

由上文可知,一个按键中包含着两个频率的信号,为了将按键区分,可以对按键声音进行fft即傅里叶变换(不严谨,应该叫dft变换),将变换后的结果与表中预设相比对可以得出按键的种类。

代码的实现在预先知道按键的持续时间和间隔时间的情况下,对声音数据进行分段,对一段声音进行IFFT变换,由于DTMF行频率和列频率以1000Hz为界,可以在进行完IFFT变换后,以1000Hz为界将频谱分为两部分,与预设的频率进行比对。

在得到IFFT频率时,由于存在噪声和频谱泄漏现象,所以并不能得到理想的频谱,所以可以使用Max函数,找寻频谱范围内频率的最大值。

二,代码

1,读取声音文件

先确定声音序列和按键持续时间和空白时间

[h,Fs]=audioread('my_phone_number_sound_test.wav');%读出信号,采样率和采样位数。
keytime=0.5;%按键持续时间
zerotime=0.5;%中间为零的时间
n=keytime*Fs;%按键摁下时的点数
n1=zerotime*Fs;%无按键时的点数

2,对数据进行IFFT变换

y=h(1+n1*(i-1)+n*(i-1):n+n1*(i-1)+n*(i-1));%确定声音处理的区间
H=fft(y);%快速傅里叶变换
h_d=abs(H/n);%求fft的幅值,并转变为双边谱的幅值(fft的幅值与输入的点数有关,除于n保证原来的幅值)
h_d1= h_d(1:n/2+1);%将双边谱变为单边谱
h_d1(2:end-1)=2*h_d1(2:end-1);%双边谱变为单边谱幅度乘2
f=Fs*(0:n/2)/n;%求归一化后的频率

3,频率获取

 f=Fs*(0:n/2)/n;%求归一化后的频率
 h_d2=h_d1(1:n/8);%由f可知,f的范围为0到4000,n/8的范围为0到1000
 [M,I] = max(h_d2);
 I=Fs*I/n;%求出最大值所对应的频率
 h_d3=h_d1(n/8:n/4-1);%频率范围为1000到2000
 [A,B] = max(h_d3);
 B=Fs*B/n+1000;

 注意:最大值或者数据位置并不代表着所对应的频率,要进行f=Fs*(0:n/2)/n的处理。

4,很简单的但很繁琐频率判断

if I>=690&&I<=700&&B>=1200&&B<=1300
        disp(1);
    end
    if I>=690&&I<=700&&B>=1300&&B<=1400
        disp(2);
    end
    if I>=690&&I<=700&&B>=1400&&B<=1500
        disp(3);
    end
    if I>=690&&I<=700&&B>=1600&&B<=1700
        disp(A);
    end
    if I>=700&&I<=800&&B>=1200&&B<=1300
        disp(4);
    end
    if I>=700&&I<=800&&B>=1300&&B<=1400
        disp(5);
    end
    if I>=700&&I<=800&&B>=1400&&B<=1500
        disp(6);
    end
    if I>=700&&I<=800&&B>=1600&&B<=1700
        disp(B);
    end
    if I>=800&&I<=900&&B>=1200&&B<=1300
        disp(7);
    end
    if I>=800&&I<=900&&B>=1300&&B<=1400
        disp(8);
    end
    if I>=800&&I<=900&&B>=1400&&B<=1500
        disp(9);
    end
    if I>=800&&I<=900&&B>=1600&&B<=1700
        disp(C);
    end
    if I>=900&&I<=1000&&B>=1200&&B<=1300
        disp('*');
    end
    if I>=900&&I<=1000&&B>=1300&&B<=1400
        disp(0);
    end
    if I>=900&&I<=1000&&B>=1400&&B<=1500
        disp('#');
    end
    if I>=900&&I<=1000&&B>=1600&&B<=1700
        disp(D);
    end

5,总代码

%-----------------------------------------------------------------------
%clc
[h,Fs]=audioread('my_phone_number_sound_test.wav');%读出信号,采样率和采样位数。
keytime=0.5;%按键持续时间
zerotime=0.5;%中间为零的时间
n=keytime*Fs;%按键摁下时的点数
n1=zerotime*Fs;%无按键时的点数
for i=1:11
    y=h(1+n1*(i-1)+n*(i-1):n+n1*(i-1)+n*(i-1));%确定声音处理的区间
    H=fft(y);%快速傅里叶变换
    h_d=abs(H/n);%求fft的幅值,并转变为双边谱的幅值(fft的幅值与输入的点数有关,除于n保证原来的幅值)
    h_d1= h_d(1:n/2+1);%将双边谱变为单边谱
    h_d1(2:end-1)=2*h_d1(2:end-1);%双边谱变为单边谱幅度乘2
    f=Fs*(0:n/2)/n;%求归一化后的频率
    h_d2=h_d1(1:n/8);%由f可知,f的范围为0到4000,n/8的范围为0到1000
    [M,I] = max(h_d2);
    I=Fs*I/n;%求出最大值所对应的频率
    h_d3=h_d1(n/8:n/4-1);%频率范围为1000到2000
    [A,B] = max(h_d3);
    B=Fs*B/n+1000;
    if I>=690&&I<=700&&B>=1200&&B<=1300
        disp(1);
    end
    if I>=690&&I<=700&&B>=1300&&B<=1400
        disp(2);
    end
    if I>=690&&I<=700&&B>=1400&&B<=1500
        disp(3);
    end
    if I>=690&&I<=700&&B>=1600&&B<=1700
        disp(A);
    end
    if I>=700&&I<=800&&B>=1200&&B<=1300
        disp(4);
    end
    if I>=700&&I<=800&&B>=1300&&B<=1400
        disp(5);
    end
    if I>=700&&I<=800&&B>=1400&&B<=1500
        disp(6);
    end
    if I>=700&&I<=800&&B>=1600&&B<=1700
        disp(B);
    end
    if I>=800&&I<=900&&B>=1200&&B<=1300
        disp(7);
    end
    if I>=800&&I<=900&&B>=1300&&B<=1400
        disp(8);
    end
    if I>=800&&I<=900&&B>=1400&&B<=1500
        disp(9);
    end
    if I>=800&&I<=900&&B>=1600&&B<=1700
        disp(C);
    end
    if I>=900&&I<=1000&&B>=1200&&B<=1300
        disp('*');
    end
    if I>=900&&I<=1000&&B>=1300&&B<=1400
        disp(0);
    end
    if I>=900&&I<=1000&&B>=1400&&B<=1500
        disp('#');
    end
    if I>=900&&I<=1000&&B>=1600&&B<=1700
        disp(D);
    end
end

  就每个频率对比就完事了,给每个频率一个范围,我上面给的范围很宽,可以是适当的压缩。

三,结果分析

就用上篇文章产生的音频,按键持续时间为0.5s,空白时间为0.5s

与产生的结果相同。

四,函数用法

audioread

posted @ 2019-01-15 18:16  孤独野猪骑士  阅读(1057)  评论(0编辑  收藏  举报