FFT快速傅里葉變換算法


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算法移植:

未完待續


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM