python实现离散傅里叶变换

初步认识傅里叶变换:
认识傅里叶变换
讲的较为通俗,图文并茂

离散傅里叶变换(DFT)的推导:
DFT推导

关于SDFT,mSDFT的推导:
SDFT,mSDFT

下面用python实现DFT:
首先,导入需要的包

import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft, ifft

接着,定义自己实现的DFT函数:

def myDFT(ys, k, N, fs):
     '''
     :param ys:离散时域信号
     :param k:频域索引
     :param N:采样点数
     :param fs:采样信号
     :return:
     '''
     Xk = []
     for i in range(k):
        X = 0. + 0j
        for j in range(N):
            X += ys[j]*(np.cos(2*np.pi/N *j *i)-1j*np.sin(2*np.pi/N *j *i))
        Xk.append(X)

     A = abs(np.array(Xk))        # 计算模值
     amp_x = A / N * 2            # 纵坐标变换
     label_x = np.linspace(0, int(N / 2) - 1, int(N / 2))    # 生成频率坐标
     amp = amp_x[0:int(N / 2)]    # 选取前半段计算结果即可,幅值  对称
     fs = fs                      # 计算采样频率
     fre = label_x / N * fs       # 频率坐标变换

     return Xk, A, amp, fre

使用scipy.fftpack的fft用于比较,验证自己实现的DFT算法的正确性

# 简单定义一个FFT函数
def myfft(x, t, fs):
    fft_x = fft(x)                                            # fft计算
    amp_x = abs(fft_x)/len(x)*2                               # 纵坐标变换  abs:求模长
    label_x = np.linspace(0,int(len(x)/2)-1,int(len(x)/2))    # 生成频率坐标
    amp = amp_x[0:int(len(x)/2)]                              # 选取前半段计算结果即可  对称
    # amp[0] = 0                                              # 可选择是否去除直流量信号
    fre = label_x/len(x)*fs                                   # 频率坐标变换
    pha = np.unwrap(np.angle(fft_x))                          # 计算相位角并去除2pi跃变
    return amp,fre,pha                                        # 返回幅度和频率

最后,生成一个信号用于验证

Ts = 1    # 采样时间
fs = 1400  # 采样频率
N = Ts * fs  # 采样点数
# 在Ts内采样N个点
xs = np.linspace(0, Ts, int(N))

# 生成采样信号 由180Hz,390Hz和600Hz的正弦波叠加
ys = 7.0*np.sin(2*np.pi*180*xs) + 2.8*np.sin(2*np.pi*390*xs) + 5.1*np.sin(2*np.pi*600*xs)

amp, fre, pha = myfft(ys, xs, fs)  # 调用scipy.fftpack里的fft
Xk, A, amp2, fre2 = myDFT(ys, int(N), int(N), fs)

# 绘图
plt.subplot(221)
plt.plot(xs, ys)
plt.title('OriSignal')
plt.xlabel('Time / s')
plt.ylabel('Intencity / cd')

# 反傅里叶变换
ys390 = 2.8*np.sin(2*np.pi*390*xs)
H = np.zeros((int(N)))
H[390-50:390+50] = 1
H[1400-390-50:1400-390+50] = 1  # 将390Hz附近的频率获取
IFFT = ifft(H*Xk)
plt.subplot(223)
plt.plot(xs, IFFT, alpha=0.75, color='r')
plt.plot(xs, ys390, alpha=0.75, color='g')
plt.legend(['IFFT', 'ys390'])
plt.title('IFFT Filter')

plt.subplot(222)
plt.plot(fre, amp)
plt.title("'fft's Amplitute-Frequence-Curve")
plt.ylabel('Amplitute / a.u.')
plt.xlabel('Frequence / Hz')

plt.subplot(224)
plt.plot(fre2, amp2)
plt.title("myDFT's Amplitute-Frequence-Curve")
plt.ylabel('DFT Amplitute / a.u.')
plt.xlabel('DFT Frequence / Hz')
plt.show()

实验结果如下:
python实现离散傅里叶变换_第1张图片
图1是原始信号,图2是python封装好的fft的试验结果,图4是自定义的DFT,从试验结果来看,自己实现的DFT可以正确分解原始信号。

你可能感兴趣的:(python,开发语言)