1、FFT算法概要:

 FFT(Fast Fourier Transformation)是离散傅氏变换(DFT)的快速算法。即为快速傅氏变换。它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。

2、FFT算法原理:

离散傅里叶变换DFT公式:

 

FFT算法(Butterfly算法)

        设x(n)为N项的复数序列,由DFT变换,任一X(m)的计算都需要N次复数乘法和N-1次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N项复数序列的X(m),即N点DFT变换大约就需要N^2次运算。当N=1024点甚至更多的时候,需要N2=1048576次运算,在FFT中,利用WN的周期性和对称性,把一个N项序列(设N=2k,k为正整数),分为两个N/2项的子序列,每个N/2点DFT变换需要(N/2)2次运算,再用N次运算把两个N/2点的DFT变换组合成一个N点的DFT变换。这样变换以后,总的运算次数就变成N+2*(N/2)^2=N+(N^2)/2。继续上面的例子,N=1024时,总的运算次数就变成了525312次,节省了大约50%的运算量。而如果我们将这种“一分为二”的思想不断进行下去,直到分成两两一组的DFT运算单元,那么N点的DFT变换就只需要N/2log2N次的运算,N在1024点时,运算量仅有5120次,是先前的直接算法的近1/200,点数越多,运算量的节约就越大,这就是FFT的优越性。

3、FFT算法官方实现:

       

搭建FFTW库并生成所需要的lib文件:

Step1:从官网下载对应的.zip文件,例如我是win10_x86的操作系统,下载64bit的安装包:

Step2:下载完成之后解压到你希望安装的FFTW库的位置

Step3:打开CMD命令操作行,切换到Step2中的安装目录下,执行下面的指令代码生成.lib文件(需要安装Visual Studio,用VC++中的lib命令生成系统能够使用的.lib文件)

  打开的方式为,按下window键,输入vs,小娜会自动帮你查找对应的File。

   切换到对应的路径之后就可以使用lib命令来生成.lib文件了:

1 lib /def:libfftw3-3.def
2 lib /def:libfftw3f-3.def
3 lib /def:libfftw3l-3.def

  查看对应的目录,我们就能看到生成的.lib文件:

 

在工程中使用FFTW库

首先在VS2017中创建一个工程命名为FFTW_Test

FFTW_Test.cpp文件内容如下:

 1 #include <stdio.h>
 2 #include <iostream>
 3 
 4 #include "fftw3.h"
 5 #pragma comment(lib, "libfftw3-3.lib")
 6 
 7 using namespace std;
 8 
 9 int main(void)
10 {
11     /*
12     *fftw_complex 是FFTW自定义的复数类
13     *引入<complex>则会使用STL的复数类
14     */
15     fftw_complex x[5];
16     fftw_complex y[5];
17 
18     for (int i = 0; i < 5; i++) {
19         x[i][REAL] = i;
20         x[i][IMAG] = 0;
21     }
22 
23     //定义plan,包含序列长度、输入序列、输出序列、变换方向、变换模式
24     fftw_plan plan = fftw_plan_dft_1d(5, x, y, FFTW_FORWARD, FFTW_ESTIMATE);
25 
26     //对于每个plan,应当"一次定义 多次使用",同一plan的运算速度极快
27     fftw_execute(plan);
28 
29     for (int i = 0; i < 5; i++) {
30         cout << y[i][REAL] << "  " << y[i][IMAG] << endl;
31     }
32 
33     //销毁plan
34     fftw_destroy_plan(plan);      
35 }

将FFTW相关的库文件拷贝到FFTW_Test工程目录下,拷贝的位置需要和FFTW_Test.cpp在同一个目录当中!

拷贝的文件如下图所示(只需要将FFTW安装目录下的这三个文件拷贝过去即可):

程序运行结果:

参考资料

4、FFT算法C/C++/Python代码:

Code1(DFT):

 1 char DFT_Alg(float *Signal, float *Fre, int L)
 2 {
 3     long long i,j;
 4     float real, imag, coff1, coff2;
 5     coff1 = -2*pi/L;
 6     for(i=0;i<L;i++){
 7         for(j=0;j<L;j++){
 8             coff2 = coff1*i*j;
 9             real += Signal[j]*cos(coff2);
10             imag += Signal[j]*sin(coff2);
11         }
12         printf("Processing:%d\n",i);
13         Fre[i] = real*real + imag*imag;
14     }
15     return 1;
16 }

Code2(FFT):

 1 typedef float FFT_TYPE;
 2 
 3 #ifndef PI
 4     #define PI (3.14159265f)
 5 #endif
 6 
 7 typedef struct complex_st {
 8     FFT_TYPE real;
 9     FFT_TYPE img;
10 } complex;
11 
12 static void BitReverse(complex *x, complex *r, int n, int l)
13 {
14     int i = 0;
15     int j = 0;
16     short stk = 0;
17     static complex *temp = 0;
18 
19     temp = (complex *)malloc(sizeof(complex) * n);
20     if (!temp) {
21         return;
22     }
23 
24     for(i=0; i<n; i++) {
25         stk = 0;
26         j = 0;
27         do {
28             stk |= (i>>(j++)) & 0x01;
29             if(j<l)
30             {
31                 stk <<= 1;
32             }
33         }while(j<l);
34 
35         if(stk < n) {             /* 满足倒位序输出 */
36             temp[stk] = x[i];
37         }
38     }
39     /* copy @temp to @r */
40     for (i=0; i<n; i++) {
41         r[i] = temp[i];
42     }
43     free(temp);
44 }
45 
46 int fft(complex *x, int N)
47 {
48     int i,j,l,ip;
49     static int M = 0;
50     static int le,le2;
51     static FFT_TYPE sR,sI,tR,tI,uR,uI;
52 
53     M = (int)(log(N) / log(2));
54 
55     BitReverse(x,x,N,M);
56 
57     for (l=1; l<=M; l++) {
58         le = (int)pow(2,l);
59         le2 = (int)(le / 2);
60         uR = 1;
61         uI = 0;
62         sR = cos(PI / le2);
63         sI = -sin(PI / le2);
64         for (j=1; j<=le2; j++) {
65             //jm1 = j - 1;
66             for (i=j-1; i<=N-1; i+=le) {
67                 ip = i + le2;
68                 tR = x[ip].real * uR - x[ip].img * uI;
69                 tI = x[ip].real * uI + x[ip].img * uR;
70                 x[ip].real = x[i].real - tR;
71                 x[ip].img = x[i].img - tI;
72                 x[i].real += tR;
73                 x[i].img += tI;
74             }
75             tR = uR;
76             uR = tR * sR - uI * sI;
77             uI = tR * sI + uI *sR;
78         }
79     }
80     return 0;
81 }
82 int ifft(complex *x, int N)
83 {
84     int k = 0;
85     for (k=0; k<=N-1; k++) {
86         x[k].img = -x[k].img;
87     }
88     fft(x, N);    /* using FFT */
89     for (k=0; k<=N-1; k++) {
90         x[k].real = x[k].real / N;
91         x[k].img = -x[k].img / N;
92     }
93     return 0;
94 }

View Code

Code3(DFT-Python):

 1 def DFT(x):
 2     """
 3     Input:
 4         x (numpy array) = input sequence of length N
 5     Output:
 6         The function should return a numpy array of length N
 7         X (numpy array) = The N point DFT of the input sequence x
 8     """
 9     N = len(x)
10     real = np.zeros(N)
11     imag = np.zeros(N)
12     for i in range(N):
13         for j in range(N):
14             real[i] += x[j]*np.cos(-2*np.pi*i*j/N)
15             imag[i] += x[j]*np.sin(-2*np.pi*i*j/N)
16     Res = 1j*imag + real
17     return Res
18 def IDFT(X):
19     """
20     Input:
21         X (numpy array) = frequency spectrum (length N)
22     Output:
23         The function should return a numpy array of length N 
24         x (numpy array) = The N point IDFT of the frequency spectrum X
25     """
26     N = len(X)
27     real = np.zeros(N)
28     imag = np.zeros(N)
29     for i in range(N):
30         for k in range(N):
31             param1 = X[k].real
32             param2 = X[k].imag
33             sin = np.sin(2*np.pi*i*k/N)
34             cos = np.cos(2*np.pi*i*k/N)
35             real[i] += param1*cos-param2*sin
36             imag[i] += param1*sin+param2*cos
37     Res = 1j*imag/N + real/N
38     return Res

 

5、多种平台的FFT算法移植:

未完待续

版权声明:本文为uestc-mm原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/uestc-mm/p/10683367.html