基于Python實(shí)現(xiàn)DIT-FFT算法
自己寫函數(shù)實(shí)現(xiàn)FFT
使用遞歸方法
from math import log, ceil, cos, sin, pi import matplotlib.pyplot as plt import numpy as np # 這兩行代碼解決 plt 中文顯示的問題 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def fft(x, N=None): # DIT-FFT 函數(shù)說明 # x: 時域序列 # N: N點(diǎn)DFT, 理論上N=2**M # 返回值為序列x的DFT if N is None: N = len(x) elif N < len(x): N = len(x) if N == 2: return [x[0]+x[1], x[0]-x[1]] # 補(bǔ)0使得N=2**M M = ceil(log(N, 2)) N = 2**M x = x + [0] * (N-len(x)) # 遞歸地計(jì)算偶數(shù)項(xiàng)和奇數(shù)項(xiàng)的DFT X1 = fft(x[0::2]) X2 = fft(x[1::2]) X = [0] * N for i in range(N//2): # 蝶形計(jì)算 tmp = (cos(2*pi/N*i)-1j*sin(2*pi/N*i))*X2[i] X[i] = X1[i] + tmp X[i+N//2] = X1[i] - tmp return X if __name__ == '__main__': x = [1]*10 y = fft(x, 1024) # print(y) z = [abs(i) for i in y] # print(z) plt.plot(np.arange(len(z))*2/len(z), z, label='10點(diǎn)矩形窗函數(shù)的FFT') plt.title("幅度譜") plt.xlabel(r'單位:$\pi$') plt.ylabel(r'$|H(j\omega)|$') plt.grid(linestyle="-.") plt.legend() plt.show()
使用循環(huán),流式計(jì)算(極大地節(jié)省了內(nèi)存)
from math import log, ceil, cos, sin, pi import matplotlib.pyplot as plt import numpy as np # 這兩行代碼解決 plt 中文顯示的問題 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def fft(x, N=None): # DIT-FFT 函數(shù)說明 # x: 時域序列 # N: N點(diǎn)DFT, 理論上N=2**M # 返回值為序列x的DFT """ 采用流式計(jì)算方法,只用了一個N(N=2**M)點(diǎn)的數(shù)組內(nèi)存 """ if N is None: N = len(x) elif N < len(x): N = len(x) # 補(bǔ)0使得:N=2**M M = ceil(log(N, 2)) N = 2**M x = x + [0] * (N-len(x)) fm = "{:0"+f"{M}"+"b}" X = [0] * N for i in range(N//2): index1 = eval('0b'+fm.format(i*2)[::-1]) index2 = eval('0b'+fm.format(i*2+1)[::-1]) X[2*i] = x[index1] + x[index2] X[2*i+1] = x[index1] - x[index2] for i in range(1, M): # 第i步表示將2**i點(diǎn)DFT合成2**(i+1)點(diǎn)的DFT # 蝶形寬度width width = 2**i """ 將X(k)序列進(jìn)行分組,每組2**(i+1)個點(diǎn), 便于將每組中兩組2**i點(diǎn)DFT合成一組2**(i+1)點(diǎn)的DFT """ # num=2*width=2**(i+1), 表示每組點(diǎn)數(shù) num = 2*width # 組數(shù)groups groups = N//num for j in range(groups): # 對每組將2**i點(diǎn)DFT合成2**(i+1)=num點(diǎn)的DFT for k in range(num//2): # 旋轉(zhuǎn)因子 W = cos(2*pi/num*k) - 1j * sin(2*pi/num*k) # 第j組第k個 index = j*num + k tmp = W * X[index+width] # 每個蝶形一次復(fù)數(shù)乘法 X[index], X[index+width] = X[index]+tmp, X[index]-tmp return X if __name__ == '__main__': x = [1]*10 y = fft(x, 1024) # print(y) z = [abs(i) for i in y] # print(z) plt.plot(np.arange(len(z))*2/len(z), z, label='10點(diǎn)矩形窗函數(shù)的FFT') plt.title("幅度譜") plt.xlabel(r'單位:$\pi$') plt.ylabel(r'$|H(j\omega)|$') plt.grid(linestyle="-.") plt.legend() plt.show()
運(yùn)行結(jié)果:
# 說明:建議使用第二種方法實(shí)現(xiàn)FFT。第一種遞歸的方法在遞歸調(diào)用時也需要一定的成本,且使用的內(nèi)存較大;而第二種方法只使用了一個N(N=2**M)點(diǎn)的數(shù)組進(jìn)行計(jì)算,內(nèi)存可重用。
使用python的第三方庫進(jìn)行FFT
import numpy as np from numpy.fft import fft, ifft # from scipy.fftpack import fft, ifft import matplotlib.pyplot as plt # 這兩行代碼解決 plt 中文顯示的問題 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False if __name__ == '__main__': x = 2*np.sin(np.pi/2*np.arange(100))+np.sin(np.pi/5*np.arange(100)) z = [abs(i) for i in fft(x, 2048)] # print(z) L = len(z) plt.plot((np.arange(L)*2/L)[:L//2], z[:L//2], label='兩個不同頻率正弦信號相加的DFT') plt.title("幅度譜") plt.xlabel('$\pi$') plt.ylabel('$|H(j\omega)|$') plt.grid(linestyle="-.") plt.legend() plt.show() print('max(abs(ifft(fft(x))-x)) = ', end='') print(max(abs(ifft(fft(x))-x)))
運(yùn)行結(jié)果:
max(abs(ifft(fft(x))-x)) = 9.01467522361575e-16
以上就是基于Python實(shí)現(xiàn)DIT-FFT算法的詳細(xì)內(nèi)容,更多關(guān)于Python DIT-FFT算法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python+Matplotlib繪制發(fā)散條形圖的示例代碼
發(fā)散條形圖(Diverging Bar)是一種用于顯示數(shù)據(jù)分布的圖表,可以幫助我們比較不同類別或分組的數(shù)據(jù)的差異和相對性,本文介紹了Matplotlib繪制發(fā)散條形圖的函數(shù)源碼,需要的可以參考一下2023-06-06Python中urlencode()函數(shù)構(gòu)建URL查詢字符串的利器學(xué)習(xí)
這篇文章主要為大家介紹了Python中urlencode()函數(shù)構(gòu)建URL查詢字符串的利器學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10TensorFlow中關(guān)于tf.app.flags命令行參數(shù)解析模塊
這篇文章主要介紹了TensorFlow中關(guān)于tf.app.flags命令行參數(shù)解析模塊,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11線程和進(jìn)程的區(qū)別及Python代碼實(shí)例
這篇文章主要介紹了線程和進(jìn)程的區(qū)別及Python代碼實(shí)例,本文給出了一個python的腳本讓一個進(jìn)程中運(yùn)行兩個線程,需要的朋友可以參考下2015-02-02Python利用arcpy模塊實(shí)現(xiàn)柵格的創(chuàng)建與拼接
這篇文章主要為大家詳細(xì)介紹了如何基于Python語言arcpy模塊,實(shí)現(xiàn)柵格影像圖層建立與多幅遙感影像數(shù)據(jù)批量拼接(Mosaic)的操作,感興趣的可以了解一下2023-02-02Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換
使用opencv將圖片轉(zhuǎn)為灰度圖主要有兩種方法,第一種是將彩色圖轉(zhuǎn)為灰度圖,第二種是在使用OpenCV讀取圖片的時候直接讀取為灰度圖,今天通過實(shí)例代碼講解Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換,感興趣的朋友一起看看吧2023-02-02Python 支持向量機(jī)分類器的實(shí)現(xiàn)
這篇文章主要介紹了Python 支持向量機(jī)分類器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01