双音多频

双音多频信号（英語：Dual-Tone Multi-Frequency，簡稱：DTMF），电话系统中电话机与交换机之间的一种信令，最常用于撥號時发送被叫号码。不過雙音多頻的發明，除了縮短撥號時間，也擴展了撥號之外的功能，例如自動總機、互動式語音應答。 在双音多频信号普及之前，电话系统中使用一连串的断续脉冲来传送被叫号码，称为脉冲拨号。脉冲拨号需要电信局中的操作员手工完成长途接续。由脈衝撥號到雙音複頻這幾年轉換期當中，新設計的電話機為了能相容於兩種系統，大都設計為複頻/脈衝(TONE / PULSE)兩用。 双音多频信号是贝尔实验室发明的，其目的是为了自动完成长途呼叫。 因為傳統的脉冲拨号，只能把信號送到電話接上的這一台電信交換機，但長距通話時，往往必須經由多台電信交換機才能完成，雙音多頻信號可以克服這個障礙，利用本來就用來傳送聲音的電話線傳送使用者的按鍵信號。 因為雙音多頻的發明，讓自動總機與互動式語音應答得以發展，此類設備可以在接聽電話後自動宣讀預錄的語音，再依據發話端的按鍵信號做相對回應。 DTMF拨号 DTMF拨号音 播放此文件有问题？请参见媒體幫助。 双音多频的拨号键盘是 4 ∗ 4 {\displaystyle {\color {Red}4*4}} 的矩阵，有 10 {\displaystyle {\color {RoyalBule}10}} 個數字鍵和 6 {\displaystyle {\color {RubineRed}6}} 個字符鍵，每個數字或字符都是由兩個單頻信號的組合來進行傳輸，因此鍵盤上每個按鍵所對應的信號都可以表示為 x ( t ) = A sin ⁡ ( 2 π f L t ) + B cos ⁡ ( 2 π f H t ) {\displaystyle {\mathcal {x}}(t)=\mathrm {A} \sin(2\pi f_{\color {Maroon}L}t)+\mathrm {B} \cos(2\pi f_{\color {Maroon}H}t)} ，其中 f L {\displaystyle f_{\color {Maroon}L}} 和 f H {\displaystyle f_{\color {Maroon}H}} 分別表示按鍵所在的行和列對應的頻率值。換句話說每一行代表一个高频，每一列代表一个低频。也就是說每按一个键就发送一个高频和低频的正弦信号组合，比如'1'相当于697和1209赫兹（Hz）。交换机可以解码这些频率组合並确定所对应的按键。 AT&T貝爾實驗室提出用DTMF信號作為音頻電話的撥號信號，因為這種方式可以提供更高的撥號速率，且容易被自動檢測和識別。但反之，DTMF信號的這個優點也很容易變成致命的缺點，因為容易被交換機檢測和識別，也就意味著容易被意圖為之第三方破解。破解的原理很簡單，只要能估計出DTMF信號中兩個單頻信號的頻率值，再根據底下電話機鍵盤的頻率陣列表格的對應關係就可以反推出按鍵值。 注意：ABCD四個字母並不使用於撥號鍵盤，但常做為機器對機器的控制信號，例如DTMF格式的來話顯示。 根據撥號音識別號碼的關鍵就在於準確估計出DTMF信號的頻率值。有很多種方法可以估計DTMF信號的頻率值，在此舉例兩種實現方法，一種是基於"帶通濾波器"的方法，另一種方法為基於"格策爾演算法(Goertzel algorithm)"。 1.帶通濾波器算法: 濾波器算法識別按鍵的關鍵是設計8個帶通濾波器，每個帶通濾波器的中心頻率對應著低/高頻組的各個頻率點。將待識別的撥號音也就是DTMF的信號波型依次通過這8個帶通濾波器。理論上只有頻率成分與濾波器中心頻率一致的信號才會通過，在濾波器輸出端檢測能量最大者即可判斷出低/高頻序號，最後再通過電話機鍵盤的頻率陣列表格的對應關係即可反推出按鍵值。 以下展示使用帶通濾波器算法應用於MATLAB程式碼: clear clc fs=8000; t=(0:800)/fs; fcolumns1 = 697;fcolumns2 = 770;fcolumns3 = 852;fcolumns4 = 941; frow1 = 1209;frow2 = 1336;frow3 = 1477; num0 = sin(2*pi*fcolumns4*t)+sin(2*pi*frow2*t); %數字0 num1 = sin(2*pi*fcolumns1*t)+sin(2*pi*frow1*t); %數字1 num2 = sin(2*pi*fcolumns1*t)+sin(2*pi*frow2*t); %數字2 num3 = sin(2*pi*fcolumns1*t)+sin(2*pi*frow3*t); %數字3 num4 = sin(2*pi*fcolumns2*t)+sin(2*pi*frow1*t); %數字4 num5 = sin(2*pi*fcolumns2*t)+sin(2*pi*frow2*t); %數字5 num6 = sin(2*pi*fcolumns2*t)+sin(2*pi*frow3*t); %數字6 num7 = sin(2*pi*fcolumns3*t)+sin(2*pi*frow1*t); %數字7 num8 = sin(2*pi*fcolumns3*t)+sin(2*pi*frow2*t); %數字8 num9 = sin(2*pi*fcolumns3*t)+sin(2*pi*frow3*t); %數字9 numStar = sin(2*pi*fcolumns4*t)+sin(2*pi*frow1*t); %符號* numJin = sin(2*pi*fcolumns4*t)+sin(2*pi*frow3*t); %符號# blank = zeros(size(num1)); %間隔 f = [fcolumns1 fcolumns2 fcolumns3 fcolumns4 frow1 frow2 frow3]; f_Low = [fcolumns1 fcolumns2 fcolumns3 fcolumns4]; f_High = [frow1 frow2 frow3]; %設計帶通濾波器(low frequency) N = 400; Bandwidth = 70; B_Low = zeros(4,N+1); %存放低頻組的濾波器係數 for i = 1:4 Wo = f_Low(i); wc1 = ( Wo - Bandwidth/2 ) * 2* pi/fs; wc2 = ( Wo + Bandwidth/2 ) * 2* pi/fs; B_Low(i, :) = fir2(N,[0,wc1/pi,wc2/pi,1],[0,1,1,0]); end %設計帶通濾波器(high frequency) N = 200; Bandwidth = 110; B_High = zeros(3,N+1); %存放高頻組的濾波器係數 for i = 1:3 Wo = f_High(i); wc1 = ( Wo - Bandwidth/2 ) * 2* pi/fs; wc2 = ( Wo + Bandwidth/2 ) * 2* pi/fs; B_High(i, :) = fir2(N,[0,wc1/pi,wc2/pi,1],[0,1,1,0]); end DialNum = num1; %DTMF訊號 sound(DialNum); %計算當前信號與各個頻率點的距離(low frequency) Diatance_Low = zeros(1,4); for i = 1:4 Output = filter(B_Low(i, :),1,DialNum); Diatance_Low(1,i) = max(abs(fft(Output))); end [maxnum_low,index_low] = max(Diatance_Low(1, :)); %計算當前信號與各個頻率點的距離(high frequency) Diatance_High = zeros(1,3); for i = 1:3 Output = filter(B_High(i, :),1,DialNum); Diatance_High(1,i) = max(abs(fft(Output))); end [maxnum_high,index_high] = max(Diatance_High(1, :)); %判斷按鍵 if index_low == 1 && index_high == 1 keynum = '1'; elseif index_low == 1 && index_high == 2 keynum = '2'; elseif index_low == 1 && index_high == 3 keynum = '3'; elseif index_low == 2 && index_high == 1 keynum = '4'; elseif index_low == 2 && index_high == 2 keynum = '5'; elseif index_low == 2 && index_high == 3 keynum = '6'; elseif index_low == 3 && index_high == 1 keynum = '7'; elseif index_low == 3 && index_high == 2 keynum = '8'; elseif index_low == 3 && index_high == 3 keynum = '9'; elseif index_low == 4 && index_high == 2 keynum = '0'; elseif index_low == 4 && index_high == 1 keynum = '*'; elseif index_low == 4 && index_high == 3 keynum = '#'; end keynum 2.格策爾演算法(Goertzel algorithm): 理論上DTMF信號只會在兩個固定的頻率點上出現能量，如何準確又高效地估計這兩個頻率值(低/高頻組)是識別撥號音的關鍵。傳統的頻譜估計方法得到的是一個頻率區間內所有頻率點的估計結果，而對於DTMF信號我們只在乎那8個固定頻率點上的功率譜估計值。而Goertzel算法就是估計DTMF信號功率譜最經典又實用的方法，這個算法只估計DTMF信號特定頻率點上的功率譜。 以下展示MATLAB利用Goertzel演算法估計DTMF信號的範例: clear clc fs=8000; t=(0:2000)/fs; fcolumns1=697;fcolumns2=770;fcolumns3=852;fcolumns4=941; frow1=1209;frow2=1336;frow3=1477; num0=sin(2*pi*fcolumns4*t)+sin(2*pi*frow2*t); %數字0 num1=sin(2*pi*fcolumns1*t)+sin(2*pi*frow1*t); %數字1 num2=sin(2*pi*fcolumns1*t)+sin(2*pi*frow2*t); %數字2 num3=sin(2*pi*fcolumns1*t)+sin(2*pi*frow3*t); %數字3 num4=sin(2*pi*fcolumns2*t)+sin(2*pi*frow1*t); %數字4 num5=sin(2*pi*fcolumns2*t)+sin(2*pi*frow2*t); %數字5 num6=sin(2*pi*fcolumns2*t)+sin(2*pi*frow3*t); %數字6 num7=sin(2*pi*fcolumns3*t)+sin(2*pi*frow1*t); %數字7 num8=sin(2*pi*fcolumns3*t)+sin(2*pi*frow2*t); %數字8 num9=sin(2*pi*fcolumns3*t)+sin(2*pi*frow3*t); %數字9 numStar=sin(2*pi*fcolumns4*t)+sin(2*pi*frow1*t); %符號* numJin=sin(2*pi*fcolumns4*t)+sin(2*pi*frow3*t); %符號# blank=zeros(size(num1)); %間隔 f=[fcolumns1 fcolumns2 fcolumns3 fcolumns4 frow1 frow2 frow3]; freq_indices=round(f/fs*length(t))+1; %DTMF信號% CellPhoneNum=[num1 blank num3 blank num9 blank num8 blank num0 blank num7 blank num6 blank num6 blank num5 blank num2 blank num4]; CellPhoneNum=0.2*randn(size(CellPhoneNum))+CellPhoneNum; sound(CellPhoneNum); for i=1:2:21 DialNumber=CellPhoneNum(((i-1)*length(t)+1):i*length(t)); dft_data=goertzel(DialNumber,freq_indices); temp = sort(abs(dft_data),'descend'); %找最大的兩個頻率點數值 temp_index1 = find(abs(dft_data) == temp(1)); temp_inedx2 = find(abs(dft_data) == temp(2)); if temp_index1 < temp_inedx2 %保證 temp_index1代表低頻,temp_index2代表高頻 index_low = temp_index1; index_high = temp_inedx2; else index_low = temp_inedx2; index_high = temp_index1; end %判斷按鍵 if index_low == 1 && index_high == 5 keynum = '1'; elseif index_low == 1 && index_high == 6 keynum = '2'; elseif index_low == 1 && index_high == 7 keynum = '3'; elseif index_low == 2 && index_high == 5 keynum = '4'; elseif index_low == 2 && index_high == 6 keynum = '5'; elseif index_low == 2 && index_high == 7 keynum = '6'; elseif index_low == 3 && index_high == 5 keynum = '7'; elseif index_low == 3 && index_high == 6 keynum = '8'; elseif index_low == 3 && index_high == 7 keynum = '9'; elseif index_low == 4 && index_high == 6 keynum = '0'; elseif index_low == 4 && index_high == 5 keynum = '*'; elseif index_low == 4 && index_high == 7 keynum = '#'; end PhoneCell_Indent(round(i/2)) = keynum; end display(PhoneCell_Indent) %顯示識別結果 欧式音调： 星號 井號 Z., Dodd, Annabel. The essential guide to telecommunications 5th. Upper Saddle River, NJ: Prentice Hall. 2012. ISBN 9780137058914. OCLC 779863446.