浅谈快速离散傅里叶变换的实现

在运用之前我们需要知道他是什么?是怎么来的?怎么去应用。

傅立叶变换是一种分析信号的方法,它可分析信号的组成成分,也可用这些成分合成信号。许多波形可作为信号的成分,比如正弦波、方波、锯齿波等,傅立叶变换用正弦波作为信号的组成成分,在时域他们是相互重叠在一起的,我们需要运用傅里叶变换把他们分开并在频域显示出来。

连续傅里叶变换(Fourier Transform)如下:

          

连续傅里叶变换的反变换为:

         

满足傅里叶变换的条件是f(t)在整个定义域是绝对可积的(不发散),只有这样积分才有效。

快速傅里叶变换归属于离散傅里叶变换,理论部分大家可以自行百度。

那下面我们直接上代码:

 1 import numpy as np
 2 import time as tm
 3 import math
 4 #********************************************
 5 #这个函数的作用是输入转换点数,然后求出多少次方
 6 #********************************************
 7 def __fft_inpute(x):
 8     for i in range(11):
 9         if(2**i == x):
10             return i
11     return -1
12 #************************
13 #这个函数是把输入倒序排列
14 #************************
15 def __fft_daoxu(x):
16     if(x == -1):
17         return -1
18     daoxu = []
19     for i in range(2**x):
20         d = 0
21         for j in range(x):
22             if i & 1 == 1:
23                 i >>= 1
24                 d <<= 1
25                 d += 1
26             else:
27                 i >>= 1
28                 d <<= 1
29         daoxu.append(d)
30     return daoxu
31 #****************************
32 #快速傅里叶运算 基于时域的分解
33 #参数:
34 #    data:是输入数据,以列表的形式传入
35 #    N:输入链表data的长度
36 #****************************
37 def fft(data,N):
38     _data =[]
39     _post_n = __fft_inpute(N)#判断运算级数
40     if(_post_n == -1):    
41         return -1
42 
43 
44     daoxu_post = __fft_daoxu(_post_n)
45     print("原序列的倒置:",daoxu_post)
46     for i in daoxu_post:
47         _data.append(data[i])
48 
49 
50     #蝶形运算,按时间抽选(DIT)的基-2 fft算法(库里-图基算法)
51     for i in range(_post_n):#第一次循环把就是各级运算分开
52         step = 1 << (i+1)#确定运算几大步,
53        
54         Wn = 1.0 + 0.0j; #给定第一次旋转因子的值
55 
56         print("第%d次蝶形运算"%(i))
57         
58 
59         for j in range(int(step/2)):#不相同的Wn的个数
60             for x1 in range(j,N,step):#把同级的相同的Wn全部运算完
61                 x2 = x1 + int(step / 2)
62                 print(x1,x2)
63                 
64                 #下面是两点傅里叶变换
65                 tem_variable = 0 + 0j
66                 tem_variable = (_data[x1].real + _data[x2].real*Wn.real - _data[x2].imag*Wn.imag) + (_data[x1].imag + _data[x2].real*Wn.imag + _data[x2].imag*Wn.real)*1j
67                 _data[x2] = (_data[x1].real - _data[x2].real*Wn.real + _data[x2].imag*Wn.imag) + (_data[x1].imag - _data[x2].real*Wn.imag - _data[x2].imag*Wn.real)*1j
68                 _data[x1] = tem_variable
69 
70             
71             Wn = (math.cos(2 * math.pi*(j +1) / (N >> (_post_n - (i + 1))))) - (math.sin(2 * math.pi*(j+1 )/ (N >> (_post_n - (i + 1)))))*1j#欧拉公式求旋转因子
72 
73         
74     return _data
75 
76 num =[i for i in range(8)]   
77 print("参与傅里叶变换的序列:",num)  
78 star = tm.perf_counter()
79 print("我的fft:",fft(num,len(num)),len(num))     
80 end1 = tm.perf_counter()
81 print("numpy的fft:",np.fft.fft(num))
82 end2 = tm.perf_counter()
83 print("自带库fft的运行时间:",end2 - end1,"我的fft的运行时间:",end1 - star)

下面我讲解下旋转因子:

 Wn = (math.cos(2 * math.pi*(j +1) / (N >> (_post_n - (i + 1))))) - (math.sin(2 * math.pi*(j+1 )/ (N >> (_post_n - (i + 1)))))*1j#欧拉公式求旋转因子

旋转因子为: ,所以Wnk经过欧拉公式为:

首先我们看一张图这个旋转因子是怎么变化的:

是不是恍然大悟,N的变化是从2开始,往右依次增加,增加的倍数是以前的两倍。所以我们可以写成如下形式变化:

 1 (N >> (_post_n - (i + 1)) 

N的右移一次表现的效果就是除以一次2。

接下来看看我们的运行结果:

 1 参与傅里叶变换的序列: [0, 1, 2, 3, 4, 5, 6, 7]
 2 原序列的倒置: [0, 4, 2, 6, 1, 5, 3, 7]
 3 第0次蝶形运算
 4 0 1
 5 2 3
 6 4 5
 7 6 7
 8 第1次蝶形运算
 9 0 2
10 4 6
11 1 3
12 5 7
13 第2次蝶形运算
14 0 4
15 1 5
16 2 6
17 3 7
18 我的fft: [(28+0j), (-3.9999999999999996+9.65685424949238j), (-4+4j), (-4+1.6568542494923797j), (-4+0j), (-4-1.6568542494923806j), (-3.9999999999999996-4j), (-3.9999999999999987-9.65685424949238j)] 8
19 numpy的fft: [28.+0.j         -4.+9.65685425j -4.+4.j         -4.+1.65685425j
20  -4.+0.j         -4.-1.65685425j -4.-4.j         -4.-9.65685425j]
21 自带库fft的运行时间: 0.00610923200000002 我的fft的运行时间: 0.003303109999999998

经过测试,长序列的傅里叶变换numpy自带的fft要快得多,这里只是验证程序的可行性。

posted @ 2019-09-29 18:10  闪——灵  阅读(1164)  评论(0编辑  收藏  举报