|
基于python(scipy和numpy)的快速傅里叶变换FFT
- import numpy as np
- from scipy.fftpack import fft, ifft
- import matplotlib.pyplot as plt
- from matplotlib.pylab import mpl
- # 基于python(scipy)的快速傅里叶变换FFT
- mpl.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文
- mpl.rcParams['axes.unicode_minus'] = False # 显示负号
- # fft简单滤波的步骤:
- # 1、将原信号进行FFT
- # 2、去掉需要滤波的频率
- # 3、逆变换得到信号数据
- # FFT——离散傅里叶变换(DFT)的快速算法。它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的
- # 采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性
- # 由于FFT结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果
- # 采样点选择1400个,因为设置的信号频率分量最高为600赫兹,根据采样定理知采样频率要大于信号频率2倍,所以这里设置采样频率为1400赫兹(即一秒内有1400个采样点,一样意思的)
- # 一般实际应用中保证采样频率为信号最高频率的2.56~4倍
- N = 1400
- x_time = np.linspace(0, 1, N, endpoint=True)
- # x_time = np.arange(0, 1, 1/N)
- # 设置需要采样的信号,频率分量有200,400和600
- y = 7 * np.sin(2 * np.pi * 200 * x_time) + 5 * np.sin(2 * np.pi * 400 * x_time) + 3 * np.sin(2 * np.pi * 600 * x_time)
- print("变换之前,看看原始值:", y[:5])
- fft_y = fft(y) # 快速傅里叶变换
- yreal = fft_y.real # 获取实数部分
- yimag = fft_y.imag # 获取虚数部分
- print("快速傅里叶变换后的长度=%d;看看前面的值=" % len(fft_y), fft_y[:5])
- # 变换之后的结果数据长度和原始采样信号是一样的
- # 每一个变换之后的值是一个复数,为a+bj的形式 复数具有模和角度
- # “振幅谱”“相位谱”,它其实就是通过对快速傅里叶变换得到的复数结果进一步求出来的
- # FFT得到的复数的模(即绝对值)就是对应的“振幅谱”,复数所对应的角度,就是所对应的“相位谱”
- x = np.arange(N) # 频率个数
- half_x = x[range(int(N / 2))] # 取一半区间
- abs_y = np.abs(fft_y) # 取复数的绝对值,即复数的模(双边频谱) 振幅谱
- angle_y = np.angle(fft_y) # 取复数的角度 相位谱
- # 我们发现,振幅谱的纵坐标很大,而且具有对称性
- # 关键:关于振幅值很大的解释以及解决办法——归一化和取一半处理
- normalization_y = abs_y / N # 归一化处理(双边频谱)
- normalization_half_y = normalization_y[range(int(N / 2))] # 由于对称性,只取一半区间(单边频谱)
- plt.figure(figsize=(16, 8))
- plt.subplot(231)
- plt.plot(x_time, y)
- plt.title('原始波形')
- plt.xlabel('time')
- # plt.plot(x_time[:50], y[:50])
- # plt.title('原始波形(前50组样本)')
- plt.subplot(232)
- plt.plot(x, fft_y, 'black')
- plt.title('双边振幅谱(未求振幅绝对值)', fontsize=9, color='black')
- plt.subplot(233)
- plt.plot(x, abs_y, 'r')
- plt.title('双边振幅谱(未归一化)', fontsize=9, color='red')
- plt.subplot(234)
- plt.plot(x, angle_y, 'violet')
- plt.title('双边相位谱(未归一化)', fontsize=9, color='violet')
- plt.subplot(235)
- plt.plot(x, normalization_y, 'g')
- plt.title('双边振幅谱(归一化)', fontsize=9, color='green')
- plt.subplot(236)
- plt.plot(half_x, normalization_half_y, 'blue')
- plt.title('单边振幅谱(归一化)', fontsize=9, color='blue')
- # plt.savefig('fft.png', dpi=200)
- plt.show()
复制代码
|
|