算法导论FFT代码

《算法导论》是我目前为止看到的最好的有关于写FFT的书,虽然和信号处理一类的树不太相同,算法导论对于FFT的出发点更加纯粹一点,那就是如果快速计算DFT,而并不深究DFT的物理意义,切入点也是多项式乘法。说实话,这个算法很难,并不是很直观,理解困难的很大原因是算法构造的如此精妙,以至于让人迷失了究竟算法的目的在何处,当然,现在很多库集成的FFT高效且稳定,不过深入学习一下FFT的原理我认为还是有必要的。


详细的原理就不说了,直接上python实现的代码

python由于支持了复数运算,所以和书中的伪代码基本差不多,无须做更多修改,计算结果和numpy中自带的FFT函数完全一致,当然,此算法只能应用于输入时2的幂次的时候。

其中第一个函数是递归版本的FFT,第二个则是迭代版本的FFT。

def recursiveFFT(a):
    n = len(a)
    if n == 1:
        return a
    wm = np.exp((2*np.pi*1j)/n) #旋转因子
    #wm = np.cos(2*np.pi/n)+1j*np.sin(2*np.pi/n) # 欧拉展开后的旋转因子,与上式相同
    w = 1
    a0 = a[[x for x in range(0,n) if x%2 == 0]] # 提取出下标为偶数的系数
    a1 = a[[x for x in range(0,n) if x%2 == 1]] # 提取出下标为奇数的系数
    y0 = recursiveFFT(a0) # 递归调用
    y1 = recursiveFFT(a1)
    y = np.empty(n,dtype=complex) #注意这里类型必须声明为complex型,否则运算时会自动舍去虚部
    for k in range(0,n/2):  # 归一
        #t = w*y1[k]
        y[k] = y0[k]+(w*y1[k])
        y[k+n/2] = y0[k] - w*y1[k]
        w = w*wm
    return y

def rev(x,num):
    n = int(np.log2(num)) # 求出最大的二进制位数
    ans = []
    while x!= 0:
        ans.append(x%2)
        x /= 2
    while len(ans)!= n:
        ans.append(0)   # 空位补零
    reval = 0
    for index,i in enumerate(ans):
        reval += np.power(2,n-index-1)*i  #二进制转十进制
    return reval

def bitReserveCopy(a):
    n = len(a)
    newA = np.empty(n,dtype=complex) # 此处必须声明类型为complex,否则下面的FFT运算会自动舍去虚部
    for k in range(0,n):
        newA[rev(k,n)] = a[k]  # 二进制逆序排列
    return newA

def MyFFT(a):
    A = bitReserveCopy(a)
    n = len(a)
    for s in range(1,int(np.log2(n))+1): # 遍历树的所有层
        m = np.power(2,s) # m很关键,代表了接下来n次单位根中的n,也表示接下来遍历新序列时的步长
        wm = np.exp((2*np.pi*1j)/m)
        for k in range(0,n,m):
            w = 1
            for j in range(0,m/2):
                t = w*A[k+j+m/2] # 蝶形运算
                u = A[k+j]
                A[k+j] = u+t
                A[k+j+m/2] = u-t
                w = w*wm
    return A


x = np.random.rand(8)
print x
my1 = recursiveFFT(x)
print my1
my2 = MyFFT(x)
print my2
y = np.fft.fft(x)
print y



你可能感兴趣的:(算法导论FFT代码)