听声音破解电话号码
?2012年9月的時(shí)候,一個(gè)南京的大學(xué)生從電視臺播放的一段記者采訪360總裁周鴻祎的視頻中破解了周鴻祎的手機(jī)號碼,一時(shí)間被網(wǎng)絡(luò)熱炒。后來,又聽說某人買車的時(shí)候使用電話銀行付款,結(jié)果被人錄下聲音,破解了銀行卡號和密碼,導(dǎo)致存款被盜。最近居委會在小區(qū)里散發(fā)傳單,提醒一種新的詐騙方式:電話聽音破密碼詐騙。各種網(wǎng)絡(luò)和媒體對這些事情炒作的很熱鬧,但是趨于兩種極端,要么將其說的出神入化,要么將其貶的一錢不值,唯獨(dú)缺少理性的聲音解釋一下到底是什么原理。貓貓一直想說,“其實(shí)就是離散傅立葉變換(DFT)嘛,至于嗎?”,這次就借著這種所謂的新型詐騙方式,一并說道說道。
??????? 在動筆寫這篇文章之前,貓貓上網(wǎng)Google了一下“電話號碼破解”,居然發(fā)現(xiàn)某寶上有人叫賣“電話撥號音破解器”,價(jià)格從幾百到上千大洋的都有,貓貓不說了,只笑笑。本文就準(zhǔn)備從理論上解釋一些破解電話撥號音的數(shù)學(xué)原理,看了本文的同學(xué),你有福了,只需要依照本文給出的百十行演示代碼,稍加改造,再加上一個(gè)麥克風(fēng),你就可以擁有自己的“電話撥號音破解器”了,廢話少說,現(xiàn)在就開始吧。
??????? 首先要說的是,根據(jù)電話撥號音破解電話號碼,只適用于使用“雙音多頻技術(shù)(DTMF)”的電話設(shè)備,老式的撥號盤電話(脈沖式電話機(jī))您就別試了(估計(jì)您也沒有這玩意了)。雙音多頻技術(shù)是貝爾實(shí)驗(yàn)室的發(fā)明,就是將電話機(jī)的撥號鍵盤分成4X4的矩陣,每一行對應(yīng)一個(gè)低頻信號,每一列對應(yīng)一個(gè)高頻信號,如圖(1)所示:
圖(1)電話鍵盤雙音頻對照表
?
其中低頻信號和高頻信號的頻率都在人耳可以識別的頻率范圍之內(nèi)。打電話撥號的時(shí)候,每按下一個(gè)鍵,就產(chǎn)生一個(gè)高頻信號和低頻信號的正弦信號組合,局端的電話交換機(jī)從這個(gè)組合信號中解出兩個(gè)頻率,就知道是那個(gè)按鍵被按下了。說到這里,您可能已經(jīng)猜到了,只要從按鍵音中解析出這兩個(gè)頻率,就能根據(jù)上表查出是對應(yīng)的哪個(gè)按鍵了。
??????? 現(xiàn)在該離散傅立葉變換(DFT)隆重登場了!關(guān)于離散傅立葉變換算法的來龍去脈,請上網(wǎng)Google之,這里只簡單介紹一下它的基本原理,以及它在電話號碼破解的過程中能做什么。
??????? 傅里葉是一位法國數(shù)學(xué)家和物理學(xué)家的名字,他于1807年在法國科學(xué)學(xué)會上發(fā)表了一篇論文,提到了一個(gè)觀點(diǎn):任何連續(xù)周期信號可以由一組適當(dāng)?shù)恼仪€組合而成,換言之,滿足一定條件的連續(xù)函數(shù)(周期函數(shù))都可以表示成一系列三角函數(shù)(正弦和/或余弦函數(shù))或者它們的積分的線性組合形式,這個(gè)轉(zhuǎn)換就被稱為“傅立葉轉(zhuǎn)換”。一般情況下,若“傅里葉變換”一詞的前面未加任何限定語,則指的是“連續(xù)傅里葉變換”,與之對應(yīng)的自然就是“離散傅立葉變換”。事實(shí)上,變換原始信號可以是周期的,也可以不是周期的,根據(jù)原始信號類型的不同,傅立葉變換可以分成四種形式,分別是“非周期性連續(xù)信號傅立葉變換”、“周期性連續(xù)信號傅立葉變換”、“非周期性離散信號傅立葉變換”和“周期性離散信號傅立葉變換”,其中“周期性連續(xù)信號傅立葉變換”實(shí)際上就是傅里葉級數(shù)的推廣,因?yàn)榉e分其實(shí)是一種極限形式的求和算子而已。
??????? 一維傅立葉變換的數(shù)學(xué)意義就是將時(shí)域信號轉(zhuǎn)換為頻域信號,當(dāng)然,也存在稱為傅立葉逆變換的變換,可以將頻域信號轉(zhuǎn)換成時(shí)域信號。連續(xù)時(shí)域信號以及對應(yīng)的連續(xù)傅里葉變換都是連續(xù)函數(shù)(且是無限長度的時(shí)域信號),但是用計(jì)算機(jī)進(jìn)行數(shù)字處理只能處理有限長度的離散信號,所以必須將原始信號離散化,同時(shí)建立對應(yīng)的離散信號傅里葉變換。所謂的“離散傅里葉變換(Discrete Fourier Transform,縮寫為DFT)”,是指傅里葉變換在時(shí)域和頻域上都以離散的形式呈現(xiàn)。原始信號離散化的過程其實(shí)就是以一定的周期對原始信號進(jìn)行采樣的過程,至于如何從連續(xù)傅立葉變換推導(dǎo)出離散傅立葉變換,不是本文的重點(diǎn),您可以Google之。因?yàn)殡x散傅立葉變換計(jì)算量相當(dāng)大,有很多提高效率的算法理論,其中應(yīng)用最廣泛的就是快速傅立葉變換(FFT),關(guān)于快速傅立葉變換的理論依據(jù),也不是本文的重點(diǎn),您可以Google之。總之,您只需要知道,存在一種方法,可以將基于時(shí)間軸的時(shí)域信號,轉(zhuǎn)換成基于頻率的頻域信號即可,本文的重點(diǎn)是這種轉(zhuǎn)換的物理意義,以及如何應(yīng)用這種轉(zhuǎn)換帶給我們的結(jié)果。
圖(2)440Hz正弦波在時(shí)域和頻域的形態(tài)
?
??????? 現(xiàn)在看幾個(gè)轉(zhuǎn)換對比圖,理解一下這種轉(zhuǎn)換的物理意義。首先看圖(2),圖(2-a)是440Hz的正弦波在時(shí)域中的形態(tài),采樣率是8000Hz。圖(2-b)就是通過離散傅立葉轉(zhuǎn)換后得到的頻域中的形態(tài),理想狀態(tài)下,圖(2-b)應(yīng)該在440Hz處一條直線,其他位置的值都是0,但是受原始信號雜波和轉(zhuǎn)換后的頻域分辨率影響,實(shí)際顯示的是一個(gè)呈金字塔形狀的圖形,不過還是可以明顯地看到在440Hz的時(shí)候功率(相對強(qiáng)度)值最大,其他位置的值都明顯小于440Hz位置的值。
圖(3)按鍵“1”對應(yīng)的音頻在時(shí)域和頻域的形態(tài)
?
??????? 圖(3-a)是電話按鍵“1”對應(yīng)的音頻波形,圖(3-b)是離散傅立葉轉(zhuǎn)換后得到的頻域形態(tài),雖然受錄音雜波影響很大,但是還是可以很明顯看到在697Hz和1209Hz位置上,相對能量強(qiáng)度達(dá)到了最大值。
??????? 前面提到過,原始信號離散化的過程其實(shí)就是以一定的周期對原始信號進(jìn)行采樣的過程,這里就提到了一個(gè)很重要的參數(shù),就是采樣率T。因?yàn)檫@個(gè)采樣率T決定了轉(zhuǎn)換成頻域信號后的分辨率,另外,每次進(jìn)行轉(zhuǎn)換的時(shí)域信號的個(gè)數(shù)N(也稱為離散傅立葉變換的點(diǎn)數(shù))不能小于T,否則無法完整映射到頻域信號。實(shí)際上,是T和N共同決定了轉(zhuǎn)換后的頻域信號的分辨率。以本文要用到的聲音信號為例,轉(zhuǎn)換前的數(shù)據(jù)是每個(gè)采樣點(diǎn)上的聲波的振幅(各個(gè)頻率疊加后的振幅),橫坐標(biāo)軸是T周期的時(shí)間點(diǎn),縱坐標(biāo)軸是振幅。轉(zhuǎn)換成頻域信號后,橫坐標(biāo)軸就是頻率,縱坐標(biāo)軸就是該頻率的產(chǎn)生強(qiáng)度,通過適當(dāng)?shù)霓D(zhuǎn)換,可以理解為該頻率的功率。剛才提到,時(shí)域信號的采樣率T和參與轉(zhuǎn)換的信號點(diǎn)數(shù)N決定了頻域信號的分辨率,這是因?yàn)殡x散傅立葉轉(zhuǎn)換會將時(shí)域信號一對一的轉(zhuǎn)換為頻域信號,也就是說,N個(gè)時(shí)域信號轉(zhuǎn)換后會得到N個(gè)頻域信號。但是傅立葉轉(zhuǎn)換有個(gè)特點(diǎn),就是時(shí)域信號的周期性和頻域信號的對稱性,所謂頻域信號的對稱性,是指轉(zhuǎn)換后的N個(gè)頻域信號在T/2位置呈現(xiàn)軸對稱特征,對信號分析有用的實(shí)際頻域信號點(diǎn)只有N/2 +1個(gè)。其中第一個(gè)點(diǎn)對應(yīng)的是0Hz,也就是時(shí)域信號中直流分量強(qiáng)度,其他N/2個(gè)點(diǎn)分別對應(yīng)(0,T/2]之間的頻率,頻率分辨率是T/N。由此可見,增加N可以提高頻域信號的分辨率,但是增加N會顯著增加每次傅立葉變換的計(jì)算量,因此對N的選擇需要做一個(gè)折衷。
??????? 使用離散傅立葉變換進(jìn)行信號分析的時(shí)候,一般都會采用快速傅立葉變換(FFT)算法,網(wǎng)上有很多高效的快速傅立葉變換算法,包括基于實(shí)數(shù)的快速傅立葉算法,大家可以參考。本文給出的算法是貓貓上學(xué)時(shí)寫的一個(gè)快速傅立葉變換算法,輸入和輸出參數(shù)都是復(fù)數(shù),算不上高效,但是很簡單,只有二十幾行代碼,適合研究原理使用。另外,這個(gè)算法采用原位變換的方式,可以減少傅立葉轉(zhuǎn)換算法使用過程中的數(shù)據(jù)復(fù)制操作。
| ?42?/* ?43?window = 1 -> hanning window ?44?*/ ?45?bool?InitFft(FFT_HANDLE?*hfft,?int?count,?int?window) ?46?{ ?47?????int?i; ?48? ?49???? hfft->count?=?count; ?50???? hfft->win?=?new?float[count]; ?51?????if(hfft->win?==?NULL) ?52?????{ ?53???? ????return?false; ?54?????} ?55???? hfft->wt?=?new?COMPLEX[count]; ?56?????if(hfft->wt?==?NULL) ?57?????{ ?58???? ????delete[]?hfft->win; ?59???? ????return?false; ?60?????} ?61?????for(i?=?0;?i?<?count;?i++) ?62?????{ ?63???? ??? hfft->win[i]?=?float(0.50?-?0.50?*?cos(2?*?M_PI?*?i?/?(count?-?1))); ?64?????} ?65?????for(i?=?0;?i?<?count;?i++) ?66?????{ ?67???? ????float?angle?=?-i?*?M_PI?*?2?/?count; ?68???? ??? hfft->wt[i].re?=?cos(angle); ?69???? ??? hfft->wt[i].im?=?sin(angle); ?70?????} ?71? ?72?????return?true; ?73?} ?74? ?75?void?FFT(FFT_HANDLE?*hfft,?COMPLEX?*TD2FD) ?76?{ ?77?????int?i,j,k,butterfly,p; ?78? ?79?????int?power?=?NumberOfBits(hfft->count); ?80? ?81?????/*蝶形運(yùn)算*/ ?82?????for(k?=?0;?k?<?power;?k++) ?83?????{ ?84???? ????for(j?=?0;?j?<?1<<k;?j++) ?85???? ????{ ?86???? ??? ??? butterfly?=?1<<(power-k); ?87???? ??? ????for(i?=?0;?i?<?butterfly/2;?i++) ?88???? ??? ????{ ?89???? ??? ??? ??? p=j?*?butterfly; ?90???? ??? ??? ??? COMPLEX t?=?TD2FD[i?+?p]?+?TD2FD[i?+?p?+?butterfly/2]; ?91???? ??? ??? ??? TD2FD[i?+?p?+?butterfly/2]?=?(TD2FD[i?+?p]?-?TD2FD[i?+?p?+butterfly/2])?*?hfft->wt[i*(1<<k)]; ?92???? ??? ??? ??? TD2FD[i?+?p]?=?t; ?93???? ??? ????} ?94???? ????} ?95?????} ?96? ?97?????/*重新排序*/ ?98?????for(i?=?1,j?=?hfft->count/2;i?<=?hfft->count-2;?i++) ?99?????{ 100???? ????if(i?<?j) 101???? ????{ 102???? ??? ??? COMPLEX t?=?TD2FD[j]; 103???? ??? ??? TD2FD[j]?=?TD2FD[i]; 104???? ??? ??? TD2FD[i]?=?t; 105???? ????} 106???? ??? k?=?hfft->count/2; 107???? ????while(k?<=?j) 108???? ????{ 109???? ??? ??? j?=?j?-?k; 110???? ??? ??? k?=?k?/?2; 111???? ????} 112???? ??? j?=?j?+?k; 113?????} 114?} |
?
??????? InitFft()函數(shù)初始化一個(gè)傅立葉轉(zhuǎn)換句柄,包括正/余弦系數(shù)表(wt)和窗口系數(shù)表(win),count參數(shù)是傅立葉轉(zhuǎn)換的點(diǎn)數(shù),就是一次能轉(zhuǎn)換的最大信號個(gè)數(shù),windows參數(shù)是決定使用什么窗函數(shù),這段代碼只支持漢寧窗(hanning window)。有關(guān)離散傅立葉變換中窗函數(shù)的作用將在后面介紹。FFT()函數(shù)就是快速傅立葉變換的實(shí)現(xiàn),TD2FD是個(gè)復(fù)數(shù)數(shù)組,每調(diào)用一次FFT()函數(shù)可以轉(zhuǎn)換count個(gè)數(shù)據(jù)。對于音頻數(shù)據(jù)這樣的實(shí)數(shù),只需使用COMPLEX結(jié)構(gòu)的實(shí)數(shù)分量,虛數(shù)分量可以置0。COMPLEX數(shù)據(jù)結(jié)構(gòu)定義如下:
| ?8?struct?COMPLEX ?9?{ 10?????float?re; 11?????float?im; 12?}; 13? |
COMPLEX數(shù)據(jù)結(jié)構(gòu)重載了+、-和*運(yùn)算符,所以FFT()函數(shù)的代碼看起來很簡練。
??????? 前文提到過,計(jì)算機(jī)不能處理無限長度的數(shù)據(jù),離散傅立葉變換算法只能對數(shù)據(jù)一批一批地進(jìn)行變換,每次只能對限時(shí)間長度的信號片段進(jìn)行分析。具體的做法就是從信號中截取一段時(shí)間的片段(比如本文對按鍵音頻文件的分析,從音頻文件中讀取的數(shù)據(jù)就可以看做是從無限長度信號中截取的一秒鐘音頻信號),然后對這個(gè)片段的信號數(shù)據(jù)進(jìn)行周期延拓處理,得到虛擬的無限長度的信號,再對這個(gè)虛擬的無限長度信號進(jìn)行傅立葉變換。但是信號被按照時(shí)間片截取成片段后,其頻譜就會發(fā)生畸變,這種情況也被稱之為頻譜能量泄露。
??????? 為了減少能量泄露,人們研究了很多截?cái)嗪瘮?shù)對信號進(jìn)行截取操作,這些截?cái)嗪瘮?shù)就被稱為窗函數(shù)。窗函數(shù)w(t)被設(shè)計(jì)成頻帶無限的函數(shù),所以即使原始信號是有限帶寬信號,被窗函數(shù)截取后得到的片段也會變成無限帶寬,也就是說,信號經(jīng)過窗函數(shù)處理后,在頻域的能量與分布都被擴(kuò)展了,有效地減少了頻譜能量泄露。
??????? 不同的窗函數(shù)對信號頻譜的影響是不一樣的,比如最簡單的矩形窗,實(shí)際上就是對信號不做任何處理,簡單地按照時(shí)間片段截取一定長度的信號進(jìn)行處理。本文的演示算法選用了漢寧窗(hanning window),漢寧窗的數(shù)學(xué)定義如下:
其中R(t)是原始信號,t的范圍是 0 <= t < N-1,對于其他范圍的值,w(t) = 0。圖(4)顯示了漢寧窗對信號截取的示意圖,以及對頻域轉(zhuǎn)換結(jié)果的影響,藍(lán)色區(qū)域是窗口覆蓋的數(shù)據(jù)部分。漢寧窗的作用是分析帶寬加寬,但是降低了頻率分辨率,不過撥號音的低頻和高頻組中,任意兩個(gè)頻率之間的間隔都超過了70Hz,所以犧牲這點(diǎn)分辨率對按鍵聲音的識別沒有影響。
圖(4)漢寧窗信號截取示意圖
?
??????? 使用了窗口,就需要討論窗口的滑動問題,也就是窗口重疊的處理。用漢寧窗截取的信號片段,可以看出來窗口中部分信號被削弱了(造成衰減),為了抵消部分窗口對信號造成的衰減,各種窗函數(shù)都需要對信號進(jìn)行相應(yīng)的重疊處理。本文選擇的重疊處理方式是選取信號時(shí)每次滑動半個(gè)窗口位置,使得每個(gè)窗口的后半個(gè)窗口的衰減在下個(gè)窗口的前半個(gè)窗口中的到一定的補(bǔ)償,這個(gè)在計(jì)算一段時(shí)間信號總的功率譜時(shí)會有相應(yīng)的體現(xiàn)。計(jì)算一段時(shí)域信號的總功率譜的函數(shù)代碼如下:
| 31?bool?PowerSpectrumT(FFT_HANDLE?*hfft,?short?*sampleData,?int?totalSamples,?intchannels,?float?*power) 32?{ 33?????int?i,j; 34? 35?????for(i?=?0;?i?<?hfft->count;?i++) 36???? ??? power[i]?=?(float)0.0; 37? 38???? COMPLEX?*inData?=?new?COMPLEX[hfft->count]; 39?????if(inData?==?NULL) 40???? ????return?false; 41? 42?????int?procSamples?=?0; 43?????short?*procData?=?sampleData; 44?????while((totalSamples?-?procSamples)?>=?hfft->count) 45?????{ 46???? ??? procData?=?sampleData?+?procSamples?*?channels; 47???? ????for(j?=?0;?j?<?hfft->count;?j++) 48???? ????{ 49???? ??? ??? SampleDataToComplex(procData,?channels,?&inData[j]); 50???? ??? ??? procData?+=?channels; 51???? ????} 52???? ??? procSamples?+=?(hfft->count?/?2);?/*每次向后移動半個(gè)窗口*/ 53? 54???? ??? FftWindowFunction(hfft,?inData); 55???? ??? FFT(hfft,?inData); 56? 57???? ????for(i?=?0;?i?<?hfft->count;?i++) 58???? ????{ 59???? ??? ??? power[i]?+=?float(20.0?*?log10(sqrt(inData[i].re?*?inData[i].re?+inData[i].im?*?inData[i].im)?/?(hfft->count?/?2))); 60???? ????} 61?????} 62? 63?????delete[]?inData; 64? 65?????return?true; 66?} |
??????? PowerSpectrumT()函數(shù)要做的事情很簡單,就是每次從采樣數(shù)據(jù)中選擇count個(gè),對其進(jìn)行窗口處理,然后用傅立葉轉(zhuǎn)換得到頻域信號,最后計(jì)算并累加各個(gè)頻率的相對功率。處理完一批采樣數(shù)據(jù)后,向后偏移 count/2 個(gè)采樣數(shù)據(jù)(相當(dāng)于滑動半個(gè)窗口),重復(fù)上述過程,直到剩余的采樣數(shù)據(jù)全部完成為止(剩余數(shù)據(jù)不足一個(gè)窗口時(shí)也退出計(jì)算)。sampleData參數(shù)是采樣數(shù)據(jù),本文處理的是16位音頻數(shù)據(jù),因此每個(gè)采樣的大小是兩個(gè)字節(jié),totalSamples是總的采樣數(shù)據(jù)的個(gè)數(shù),totalSamples必須大于count才能得到有意義的功率頻譜。channels是采樣數(shù)據(jù)的聲道數(shù),對于有兩個(gè)聲道的立體聲采樣數(shù)據(jù),則取兩個(gè)聲道的平均值做為采樣數(shù)據(jù)進(jìn)行傅立葉轉(zhuǎn)換。SampleDataToComplex()函數(shù)將采樣數(shù)據(jù)賦值給復(fù)數(shù)對象的實(shí)數(shù)部分,虛數(shù)部分置0,對于雙聲道,則取左右聲道的平均值賦值給復(fù)數(shù)對象的實(shí)數(shù)部分,其實(shí)現(xiàn)如下:
| 17?static?void?SampleDataToComplex(short?*sampleData,?int?channels,?COMPLEX?*cd) 18?{ 19?????if(channels?==?1) 20?????{ 21???? ??? cd->re?=?float(*sampleData?/?32768.0); 22???? ??? cd->im?=?0.0; 23?????} 24?????else 25?????{ 26???? ??? cd->re?=?float(*sampleData?+?*(sampleData?+?1)?/?65536.0); 27???? ??? cd->im?=?0.0; 28?????} 29?} |
??????? 現(xiàn)在來講一下對PowerSpectrumT()函數(shù)轉(zhuǎn)換結(jié)果的處理,PowerSpectrumT()函數(shù)的power參數(shù)返回最終計(jì)算好的功率譜,其分辨率是T/N。每個(gè)點(diǎn)對應(yīng)的頻率可使用以下公式計(jì)算:
?
Freq = n * (T / N)??????????????????????????????????????????????? (公式2)
?
以音頻信號采樣率8000Hz,傅立葉轉(zhuǎn)換的count是2048為例,其頻譜分辨率是3.90625Hz,power[0]是頻率0的相對功率,也就是直流信號的功率,power[1]是頻率3.9Hz對應(yīng)的相對功率,power[2]是頻率7.8Hz對應(yīng)的相對功率,對應(yīng)關(guān)系以此類推。如果在power[240]處出現(xiàn)頻率最大值,則其對應(yīng)的頻率應(yīng)該是(8000/2048)*240=937Hz。
??????? 雙音頻電話按鍵音中有兩個(gè)主頻率,因此轉(zhuǎn)換后的power數(shù)組中應(yīng)該存在兩個(gè)相對極大值,需要從power數(shù)組中找出這兩個(gè)相對極大值。從M個(gè)數(shù)中選最大的N個(gè)數(shù)是一個(gè)很常見的算法,其主要思想就是維護(hù)一個(gè)大小是N的有序組,然后從剩下的M-N個(gè)數(shù)中逐個(gè)與有序組中的最小值比較,如果小于有序組中的最小值,則繼續(xù)比較下一個(gè)數(shù),如果大于有序組中的最小值,則替換有序組中的最小值,并對有序組進(jìn)行適當(dāng)?shù)淖儞Q,使其保持有序。使用堆來維護(hù)有序組被認(rèn)為是最高效的方式,大家有興趣可以從網(wǎng)上找相關(guān)的代碼學(xué)習(xí)。本文設(shè)計(jì)的從power數(shù)組中選出最大的兩個(gè)值的算法也采用這種思想,但是有序表只有兩個(gè)元素,因此對有序表的維護(hù)不需要復(fù)雜的排序處理,如果有序性失效,只要交換兩個(gè)元素的位置即可,其具體算法如下:
| 290?void?ExchangeIndex(int?*index,?float?*power) 291?{ 292?????if(power[index[1]]?>?power[index[0]]) 293?????{ 294???? ????int?t?=?index[0]; 295???? ??? index[0]?=?index[1]; 296???? ??? index[1]?=?t; 297?????} 298?} 299? 300?void?SearchMax2FreqIndex(float?*power,?int?count,?int&?first,?int&?second) 301?{ 302?????int?max2Idx[2]?=?{?0?}; 303? 304???? ExchangeIndex(max2Idx,?power); 305?????for(int?i?=?2;?i?<?count;?i++) 306?????{ 307???? ????if(power[i]?>?power[max2Idx[1]]) 308???? ????{ 309???? ??? ??? max2Idx[1]?=?i; 310???? ??? ??? ExchangeIndex(max2Idx,?power); 311???? ????} 312?????} 313? 314???? first?=?min(max2Idx[0],?max2Idx[1]); 315???? second?=?max(max2Idx[0],?max2Idx[1]); 316?} |
??????? SearchMax2FreqIndex()函數(shù)從power數(shù)組中選擇最大的兩個(gè)值,并返回它們在power數(shù)組中的位置(power數(shù)組的下標(biāo)),并根據(jù)頻率排序,first總是較小的那個(gè)頻率的位置,second總是較大的那個(gè)頻率的位置。根據(jù)first和second指示的位置,利用“公式2”就可以計(jì)算出兩個(gè)頻率,但是因?yàn)轭l譜分辨率的關(guān)系,這兩個(gè)計(jì)算出來的頻率不會剛好就是圖(1)中所示的標(biāo)準(zhǔn)頻率,但是沒關(guān)系,它們與標(biāo)準(zhǔn)頻率差的不多,通過查表就可以確定是哪個(gè)標(biāo)準(zhǔn)頻率。
??????? 至此,所有的核心代碼都完成了,創(chuàng)建一個(gè)例子試試吧,我的例子很簡單,如圖(5)所示,就是打開按鍵音頻文件,然后顯示是哪個(gè)按鍵。您可以做的更復(fù)雜一些,直接從麥克風(fēng)獲得音頻數(shù)據(jù),實(shí)時(shí)分析按鍵聲音,這樣就可以實(shí)時(shí)破解電話號碼了。
圖(5)按鍵音識別實(shí)例程序
總結(jié)
- 上一篇: 语音识别技术构架
- 下一篇: 【技术+某度面经】Jenkins 内容+