参考:https://baike.baidu.com/item/快速傅里叶变换/214957?fr=aladdin
https://blog.csdn.net/u012531536/article/details/82663818
什么是快速傅里叶变换
快速傅里叶变换 (fast Fourier transform), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少,特别是被变换的抽样点数N越多,FFT算法计算量的节省就越显著。
有限长序列可以通过离散傅里叶变换(DFT)将其频域也离散化
傅立叶原理表明:任何连续测量的时序或信号,都可以表示为不同频率的正弦波信号的无限叠加。而根据该原理创立的傅立叶变换算法利用直接测量到的原始信号,以累加方式来计算该信号中不同正弦波信号的频率、振幅和相位。如图1所示,即为时域信号与不同频率的正弦波信号的关系,这是最近翻阅文献看到的对于时域频域表示的最简单明了的图,原处为参考文献中的第二个链接,有兴趣的朋友可以去原文查阅。图中最右侧展示的是时域中的一个信号,这是一个近似于矩形的波,而图的正中间则是组成该信号的各个频率的正弦波。从图中我们可以看出,即使角度几乎为直角的正弦波,其实也是由众多的弧度圆滑的正弦波来组成的。在时域图像中,我们看到的只有一个矩形波,我们无从得知他是由这些正弦波组成。但当我们通过傅里叶变换将该矩形波转换到频域之后,我们能够很清楚的看到许多脉冲,其中频域图中的横轴为频率,纵轴为振幅。因此可以通过这个频域图像得知,时域中的矩形波是由这么多频率的正弦波叠加而成的。
# !/usr/bin/python
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def triangle_wave(size, T):
t = np.linspace(-1, 1, size, endpoint=False)
# where
# y = np.where(t < 0, -t, 0)
# y = np.where(t >= 0, t, y)
y = np.abs(t)
y = np.tile(y, T) - 0.5
x = np.linspace(0, 2*np.pi*T, size*T, endpoint=False)
return x, y
def sawtooth_wave(size, T):
t = np.linspace(-1, 1, size)
y = np.tile(t, T)
x = np.linspace(0, 2*np.pi*T, size*T, endpoint=False)
return x, y
def triangle_wave2(size, T):
x, y = sawtooth_wave(size, T)
return x, np.abs(y)
def non_zero(f):
f1 = np.real(f)
f2 = np.imag(f)
eps = 1e-4
return f1[(f1 > eps) | (f1 < -eps)], f2[(f2 > eps) | (f2 < -eps)]
if __name__ == "__main__":
mpl.rcParams['font.sans-serif'] = ['simHei']
mpl.rcParams['axes.unicode_minus'] = False
np.set_printoptions(suppress=True)
x = np.linspace(0, 2*np.pi, 16, endpoint=False)
print('时域采样值:', x)
y = np.sin(2*x) + np.sin(3*x + np.pi/4) + np.sin(5*x)
# y = np.sin(x)
N = len(x)
print('采样点个数:', N)
print('\n原始信号:', y)
f = np.fft.fft(y)
print('\n频域信号:', f/N)
a = np.abs(f/N)
print('\n频率强度:', a)
iy = np.fft.ifft(f)
print('\n逆傅里叶变换恢复信号:', iy)
print('\n虚部:', np.imag(iy))
print('\n实部:', np.real(iy))
print('\n恢复信号与原始信号是否相同:', np.allclose(np.real(iy), y))
plt.figure(facecolor='w')
plt.subplot(211)
plt.plot(x, y, 'go-', lw=2, mec='k')
plt.title('时域信号', fontsize=15)
plt.grid(b=True, ls=':', color='#404040')
plt.subplot(212)
w = np.arange(N) * 2*np.pi / N
print('频率采样值:', w)
plt.stem(w, a, linefmt='r-', markerfmt='ro')
plt.title('频域信号', fontsize=15)
plt.grid(b=True, ls=':', color='#404040')
plt.show()
# 三角/锯齿波
x, y = triangle_wave(20, 5)
# x, y = sawtooth_wave(20, 5)
N = len(y)
f = np.fft.fft(y)
# print '原始频域信号:', np.real(f), np.imag(f)
print('原始频域信号:', non_zero(f))
a = np.abs(f / N)
# np.real_if_close
f_real = np.real(f)
eps = 0.3 * f_real.max()
print('f_real = \n', f_real)
print(eps)
f_real[(f_real < eps) & (f_real > -eps)] = 0
f_imag = np.imag(f)
eps = 0.3 * f_imag.max()
print(eps)
f_imag[(f_imag < eps) & (f_imag > -eps)] = 0
f1 = f_real + f_imag * 1j
y1 = np.fft.ifft(f1)
y1 = np.real(y1)
# print '恢复频域信号:', np.real(f1), np.imag(f1)
print('恢复频域信号:', non_zero(f1))
plt.figure(figsize=(8, 8), facecolor='w')
plt.subplot(311)
plt.plot(x, y, 'g-', lw=2, mec='k')
plt.title('三角波', fontsize=15)
plt.grid(b=True, ls=':', color='#404040')
plt.subplot(312)
w = np.arange(N) * 2*np.pi / N
plt.stem(w, a, linefmt='r-', markerfmt='ro')
plt.title('频域信号', fontsize=15)
plt.grid(b=True, ls=':', color='#404040')
plt.subplot(313)
plt.plot(x, y1, 'b-', lw=2, markersize=4, markeredgecolor='k')
plt.title('三角波恢复信号', fontsize=15)
plt.grid(b=True, ls=':', color='#404040')
plt.tight_layout(1.5, rect=[0, 0.04, 1, 0.96])
plt.suptitle('快速傅里叶变换FFT与频域滤波', fontsize=17)
plt.show()
https://jingyan.baidu.com/article/84b4f56592d9b160f7da3271.html