使用python手写FFT算法

FFT(Fast Fourier Transform) 是 DFT(Discrete Fourier Transform)的快读实现,它在机理上没有改变DFT的算法,只是在实现上采用的巧妙的实现。 使 O ( N 2 ) O(N^2) O(N2)的实现变成了 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2N)的实现,优化算法的复杂度。

DFT 公式

DFT的公式我们先简单回忆一下:

DFT公式

DFT的python实现

def dft(x):
    x = np.asarray(x, dtype=float)
    N = x.shape[0]
    n = np.arange(N)
    k = n.reshape((N, 1))
    M = np.exp(-2j * np.pi * k * n / N)
    return np.dot(M, x)

x = np.random.random(1024)
np.allclose(dft(x), np.fft.fft(x))

FFT的思想其实分而治之,将整个DFT安装奇偶来分开计算

FFT之奇偶分治

首先根据DFT公式,将x分为odd(奇数),下标用2r+1表示;和even(偶数)下标用2r表示
X k = ∑ n = 0 N − 1 x n e − j 2 π k n N = ∑ n = 0 N 2 − 1 x 2 r + 1 e − j 2 π k ( 2 r + 1 ) N + ∑ n = 0 N 2 − 1 x 2 r e − j 2 π k ( 2 r ) N = ∑ n = 0 N 2 − 1 x 2 r + 1 e − j 4 π k r N e − j 2 π k N + ∑ n = 0 N 2 − 1 x 2 r e − j 4 π k r N = ∑ n = 0 N 2 − 1 x 2 r + 1 e − j 2 π k r N / 2 e − j 2 π k N + ∑ n = 0 N 2 − 1 x 2 r e − j 2 π k r N / 2 = e − j 2 π k N X o d d + X e v e n X_k = \sum_{n=0}^{N-1} x_n e^{\frac{-j2{\pi}kn}{N}} \newline = \sum_{n=0}^{\frac{N}{2}-1} x_{2r+1} e^{\frac{-j2{\pi}k(2r+1)}{N}} + \sum_{n=0}^{\frac{N}{2}-1} x_{2r} e^{\frac{-j2{\pi}k(2r)}{N}} \newline = \sum_{n=0}^{\frac{N}{2}-1} x_{2r+1} e^{\frac{-j4{\pi}kr}{N}} e^{\frac{-j2{\pi}k}{N}} + \sum_{n=0}^{\frac{N}{2}-1} x_{2r} e^{\frac{-j4{\pi}kr}{N}} \newline = \sum_{n=0}^{\frac{N}{2}-1} x_{2r+1} e^{\frac{-j2{\pi}kr}{N/2}} e^{\frac{-j2{\pi}k}{N}} + \sum_{n=0}^{\frac{N}{2}-1} x_{2r} e^{\frac{-j{2\pi}kr}{N/2}} \newline = e^{\frac{-j2{\pi}k}{N}} X_{odd} + X_{even} Xk=n=0N1xneNj2πkn=n=02N1x2r+1eNj2πk(2r+1)+n=02N1x2reNj2πk(2r)=n=02N1x2r+1eNj4πkreNj2πk+n=02N1x2reNj4πkr=n=02N1x2r+1eN/2j2πkreNj2πk+n=02N1x2reN/2j2πkr=eNj2πkXodd+Xeven

python实现

1. 根据奇偶分治和迭代的方式实现

def fft(x):
    x = np.asarray(x, dtype=float)
    N = x.shape[0]
    if N % 2 > 0:
        raise ValueError("must be a power of 2")
    elif N <= 2:
        return dft(x)
    else:
        X_even = fft(x[::2])
        X_odd = fft(x[1::2])
        terms = np.exp(-2j * np.pi * np.arange(N) / N)
        return np.concatenate([X_even + terms[:int(N/2)] * X_odd,
                               X_even + terms[int(N/2):] * X_odd])
x = np.random.random(1024)
np.allclose(fft(x), np.fft.fft(x))

2. 使用矩阵运算加速

def fft_v(x):
    x = np.asarray(x, dtype=float)
    N = x.shape[0]
    if np.log2(N) % 1 > 0:
        raise ValueError("must be a power of 2")
        
    N_min = min(N, 2)
    
    n = np.arange(N_min)
    k = n[:, None]
    M = np.exp(-2j * np.pi * n * k / N_min)
    X = np.dot(M, x.reshape((N_min, -1)))
	while X.shape[0] < N:
        X_even = X[:, :int(X.shape[1] / 2)]
        X_odd = X[:, int(X.shape[1] / 2):]
        terms = np.exp(-1j * np.pi * np.arange(X.shape[0])
                        / X.shape[0])[:, None]
        X = np.vstack([X_even + terms * X_odd,
                       X_even - terms * X_odd])
return X.ravel()

参考文档 How to implement the Fast Fourier Transform algorithm in Python from scratch

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值