一,逆DTMF说明即思路
DTMF的方法,思路即代码在上文已经提到
由上文可知,一个按键中包含着两个频率的信号,为了将按键区分,可以对按键声音进行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
与产生的结果相同。