網站首頁 編程語言 正文
自己寫函數實現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 函數說明
# x: 時域序列
# N: 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]]
# 補0使得N=2**M
M = ceil(log(N, 2))
N = 2**M
x = x + [0] * (N-len(x))
# 遞歸地計算偶數項和奇數項的DFT
X1 = fft(x[0::2])
X2 = fft(x[1::2])
X = [0] * N
for i in range(N//2):
# 蝶形計算
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點矩形窗函數的FFT')
plt.title("幅度譜")
plt.xlabel(r'單位:$\pi$')
plt.ylabel(r'$|H(j\omega)|$')
plt.grid(linestyle="-.")
plt.legend()
plt.show()
使用循環,流式計算(極大地節省了內存)
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 函數說明
# x: 時域序列
# N: N點DFT, 理論上N=2**M
# 返回值為序列x的DFT
"""
采用流式計算方法,只用了一個N(N=2**M)點的數組內存
"""
if N is None:
N = len(x)
elif N < len(x):
N = len(x)
# 補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點DFT合成2**(i+1)點的DFT
# 蝶形寬度width
width = 2**i
"""
將X(k)序列進行分組,每組2**(i+1)個點,
便于將每組中兩組2**i點DFT合成一組2**(i+1)點的DFT
"""
# num=2*width=2**(i+1), 表示每組點數
num = 2*width
# 組數groups
groups = N//num
for j in range(groups):
# 對每組將2**i點DFT合成2**(i+1)=num點的DFT
for k in range(num//2):
# 旋轉因子
W = cos(2*pi/num*k) - 1j * sin(2*pi/num*k)
# 第j組第k個
index = j*num + k
tmp = W * X[index+width] # 每個蝶形一次復數乘法
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點矩形窗函數的FFT')
plt.title("幅度譜")
plt.xlabel(r'單位:$\pi$')
plt.ylabel(r'$|H(j\omega)|$')
plt.grid(linestyle="-.")
plt.legend()
plt.show()
運行結果:
# 說明:建議使用第二種方法實現FFT。第一種遞歸的方法在遞歸調用時也需要一定的成本,且使用的內存較大;而第二種方法只使用了一個N(N=2**M)點的數組進行計算,內存可重用。
使用python的第三方庫進行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)))
運行結果:
max(abs(ifft(fft(x))-x)) = 9.01467522361575e-16
原文鏈接:https://blog.csdn.net/weixin_51613747/article/details/127418030
相關推薦
- 2023-01-20 Python-with?open()?as?f的用法及說明_python
- 2022-05-27 C++?超詳細分析多態的原理與實現_C 語言
- 2022-07-14 python?udp如何實現同時收發信息_python
- 2022-03-26 jquery對元素的基本操作實例分析_jquery
- 2022-09-08 Tomcat安裝shell腳本的方法步驟_Tomcat
- 2023-12-12 線程并發協作(生產者/消費者模式)
- 2022-07-18 使用d2l包和相關環境配置的一些血淚心得
- 2022-03-15 const定義簡單數據類型修改會報錯,而復雜數據類型則不會
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支