傅立葉變換是一種從完全不同的角度查看數(shù)據(jù)的強(qiáng)大方法:從時(shí)域到頻域。 但是這個(gè)強(qiáng)大的運(yùn)算用它的數(shù)學(xué)方程看起來很可怕。 將時(shí)域波變換為頻域的公式如下: 下圖很好地說明了傅立葉變換:將一個(gè)復(fù)雜的波分解成許多規(guī)則的正弦波。 這是完整的動(dòng)畫,解釋了將時(shí)域波數(shù)據(jù)轉(zhuǎn)換為頻域視圖時(shí)會(huì)發(fā)生什么。 我們可以輕松地處理頻域中的數(shù)據(jù),例如:去除噪聲波。 之后,我們可以使用這個(gè)逆方程將頻域數(shù)據(jù)轉(zhuǎn)換回時(shí)域波: 讓我們暫時(shí)忽略 FT 方程的復(fù)雜性。 假設(shè)我們已經(jīng)完全理解數(shù)學(xué)方程的含義,讓我們使用傅立葉變換在 Python 中做一些實(shí)際工作。 理解任何事物的最好方法就是使用它,就像學(xué)習(xí)游泳的最好方法是到進(jìn)入到泳池中。 將干凈的數(shù)據(jù)與噪聲混合創(chuàng)建兩個(gè)正弦波并將它們合并為一個(gè)正弦波,然后故意用 np.random.randn(len(t)) 生成的數(shù)據(jù)污染干凈的波。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['figure.figsize'] = [16,10]plt.rcParams.update({'font.size':18})#Create a simple signal with two frequenciesdata_step = 0.001t = np.arange(start=0,stop=1,step=data_step)f_clean = np.sin(2*np.pi*50*t) + np.sin(2*np.pi*120*t)f_noise = f_clean + 2.5*np.random.randn(len(t))plt.plot(t,f_noise,color='c',Linewidth=1.5,label='Noisy')plt.plot(t,f_clean,color='k',Linewidth=2,label='Clean')plt.legend() (將兩個(gè)信號(hào)組合成第三個(gè)信號(hào)也稱為卷積或信號(hào)卷積。這是另一個(gè)有趣的話題,現(xiàn)在在神經(jīng)網(wǎng)絡(luò)模型中被大量使用) 帶有帶噪音的波浪,黑色是我們想要的波浪,綠線是噪音。 如果我隱藏圖表中的顏色,我們幾乎無法將噪聲從干凈的數(shù)據(jù)中分離出來,但是 傅立葉變換在這里可以提供幫助。我們需要做的就是將數(shù)據(jù)轉(zhuǎn)換到另一個(gè)角度,從時(shí)間視圖(x 軸)到頻率視圖(x 軸將是波頻率)。 從時(shí)域到頻域的轉(zhuǎn)換這里可以使用 numpy.fft 或 scipy.fft(pytorch1.8以后也增加了torch.fft這里就不詳細(xì)說了)。 我發(fā)現(xiàn) scipy.fft 非常方便且功能齊全,所以在本文中使用 scipy.fft,但是如果想使用其他模塊或者根據(jù)公式構(gòu)建自己的一個(gè)也是沒問題的(代碼見最后)。
在代碼中,我使用 rfft 而不是 fft。 r 意味著reduce(我認(rèn)為)只計(jì)算正頻率。 所有負(fù)鏡像頻率將被省略。 因?yàn)樗乃俣雀臁?rfft 函數(shù)的 yf 結(jié)果是一個(gè)復(fù)數(shù),形式類似于 a+bj。 np.abs() 函數(shù)將為復(fù)數(shù)計(jì)算 √(a2 + b2)。 這是我們?cè)疾ǖ纳衿娴念l域視圖。x軸表示頻率。 一些在時(shí)域看起來很復(fù)雜的東西現(xiàn)在被轉(zhuǎn)換成非常簡(jiǎn)單的頻域數(shù)據(jù)。這兩個(gè)峰代表兩個(gè)正弦波的頻率。一種波是50Hz,另一種是120Hz。再回顧一下生成正弦波的代碼。 f_clean = np.sin(2*np.pi*50*t) + np.sin(2*np.pi*120*t) 其他頻率就是噪音,并且在下一個(gè)步驟中很容易去除。 去除噪聲頻率在Numpy的幫助下,我們可以很容易地將這些頻率數(shù)據(jù)設(shè)置為0,除了50Hz和120Hz。
現(xiàn)在,所有的噪音都被清除了。 回到時(shí)域數(shù)據(jù)最后一步就是逆轉(zhuǎn)換了,將頻域數(shù)據(jù)轉(zhuǎn)換回時(shí)域數(shù)據(jù) from scipy.fft import irfftnew_f_clean = irfft(yf_clean)plt.plot(t,new_f_clean)plt.ylim(-6,8) 結(jié)果表明,所有的噪聲波都被去除了。 這種轉(zhuǎn)變是如何進(jìn)行的回到變換方程: 原始時(shí)域信號(hào)由小寫 x 表示。 x[n] 表示第 n 個(gè)位置(時(shí)間)的時(shí)域數(shù)據(jù)點(diǎn)。 假設(shè)有10個(gè)數(shù)據(jù)點(diǎn)。
N 應(yīng)該是 10,所以,n 的范圍是 0 到 9,10 個(gè)數(shù)據(jù)點(diǎn)。 k代表頻率#,它的范圍是0到9,為什么? 極端情況是每個(gè)數(shù)據(jù)點(diǎn)代表一個(gè)獨(dú)立的正弦波。 在傳統(tǒng)的編程語言中,它將需要兩個(gè) for 循環(huán),一個(gè)循環(huán)用于 k,另一個(gè)用于 n。 在 Python 中(其實(shí)使用了numpy)可以進(jìn)行矢量化的操作替代循環(huán)。 Python 對(duì)復(fù)數(shù)的原生支持非常棒。 讓我們構(gòu)建傅立葉變換函數(shù)。 import numpy as npfrom scipy.fft import fftdef DFT_slow(x):x = np.asarray(x, dtype=float)# ensure the data typeN = x.shape[0] # get the x array lengthn = np.arange(N) # 1d arrayk = n.reshape((N, 1)) # 2d array, 10 x 1, aka column arrayM = np.exp(-2j * np.pi * k * n / N)return np.dot(M, x) # [a,b] . [c,d] = ac + bd, it is a sumx = np.random.random(1024)np.allclose(DFT_slow(x), fft(x)) 與來自numpy或scipy的函數(shù)相比,這個(gè)函數(shù)相對(duì)較慢,但對(duì)于理解FFT函數(shù)的工作原理來說已經(jīng)足夠了。 進(jìn)一步的思考傅立葉變換的思想是如此的深刻。它提醒我世界可能不是你所看到的,你的生活可能有一個(gè)完全不同的新面貌,只能通過一種變換才能看到,比如傅立葉變換。 你不僅可以轉(zhuǎn)換聲音數(shù)據(jù),還可以轉(zhuǎn)換圖像,視頻,電磁波,甚至股票交易數(shù)據(jù)(Kondratiev波)。 傅立葉變換也可以用描述運(yùn)動(dòng)來解釋。 大圈就是我們的國(guó)家或者這個(gè)時(shí)代。 我們的個(gè)體是微小的內(nèi)圈。 沒有驅(qū)動(dòng)一切的大圈,我們能做的很少。 工業(yè)革命發(fā)生在英國(guó)而不是其他國(guó)家不僅僅是因?yàn)檎羝麢C(jī),還有很多其他原因。 - 為什么英國(guó)首先工業(yè)化?因?yàn)楫?dāng)時(shí)的大圈只在英國(guó)出現(xiàn)了。 我們的成功可能并不全是因?yàn)樽约旱膬?yōu)點(diǎn),而主要是因?yàn)槟阏驹诹孙L(fēng)口上、你周圍的人、你合作的好公司等等。 沒有那些推動(dòng)你前進(jìn)的大圈子,小圈子再怎么轉(zhuǎn)也是微乎其微的。 對(duì)傅里葉變換了解得越多,就越會(huì)覺得約瑟夫·傅里葉在 1822 年提出了這個(gè)令人難以置信的方程是有史以來最偉大的數(shù)學(xué)發(fā)現(xiàn)之一。 附錄:四種傅里葉變換本文中提到的所有傅里葉變換都是指離散傅里葉變換: ![]() |
|