1. 程式人生 > >數字訊號處理公式變程式(一)——DFT、FFT

數字訊號處理公式變程式(一)——DFT、FFT

之前搞了一些數字訊號處理演算法程式設計(OC),一直沒來得及整理,現在整理一下。陸續會更新,包括FFT、巴特沃斯濾波器(高低帶通、高低帶阻)、資料差值(線性、sinc、三次樣條*)、資料壓縮(等距、平均、峰值檢測)和模仿matlab的STFT功能(spectrogram函式三維繪圖)。

注:我比較喜歡使用matlab(也喜歡自己修改matlab的原始碼做測試,所以重灌了好幾次了,囧。。。),有部分參考matlab的演算法進行(或者直接翻譯為OC),演算法的執行結果經常會跟matlab運算結果進行比較,演算法只做學習用,轉載請註明。

另外可能會有不足或者理解偏差的地方,路過的高人請不吝賜教。

好啦,進入正題。

---------------------------------------------------------------------------------------

在數字世界中FFT的意義不言而喻(我曾轉載一篇文章有提到:http://blog.csdn.net/shengzhadon/article/details/40539101),這裡就不再贅述了。FFT(快速傅立葉變換)是DFT的一種特殊情況,就是當運算點的個數是2的整數次冪的時候進行的運算(不夠用0補齊),那就先從DFT開始吧。

一、DFT(本部分就是翻譯公式)

定義(來自百科):離散傅立葉變換(Discrete Fourier Transform,縮寫為DFT),是傅立葉變換在時域和頻域上都呈離散的形式,將訊號的時域取樣變換為其DTFT的頻域取樣。在形式上,變換兩端(時域和頻域上)的序列是有限長的,而實際上這兩組序列都應當被認為是離散週期訊號的主值序列。即使對有限長的離散訊號作DFT,也應當將其看作其週期延拓的變換。在實際應用中通常採用快速傅立葉變換計算DFT。

DFT的公式是:設x(n)為M點的有限長序列,即在0≤n≤M-1內有值,則定義x(n)的N點(N≥M。當N>M時,補N-M個零值點),離散傅立葉變化定義為

其中,為旋轉因子(為方便編輯後續記作W(N, nk),特此說明),其計算公式為,具有以下性質:

①週期性:W(N, nk) = W(N, (n+rN)k) = W(N, n(k+rN)),其中r問整數。

②共軛對稱性:(W(N, nk))* = W(N, -nk)。

③可約性:W(N, nk) = W(mN, mnk),W(N, nk) = W(N/m, nk/m),其中m為整數,N/m為整數。

④特殊值:

W(N, N/2) = -1;  W(N, (k+N/2)) = -W(N, k);  W(N, (N-k)n) = W(N, (N-n)k) = W(N, -nk)。

所以,在計算旋轉因子的過程中可以適當的使用特殊值來提高運算的效率。

在計算DFT時,如果資料的點數夠計算的點數,則擷取計算點數長的資料進行DFT運算,否則將資料點個數補0至計算點個數,然後進行計算,舉例如下(舉例只是為了說明問題,沒有按照程式語言的書寫格式)。

比如:資料點陣列為 dataArray = {1, 2, 3, 4,5},可以看出資料長度為5。

   如果要求做4點DFT運算,則只需擷取前4個數作為運算陣列進行運算即可,即為{1, 2, 3, 4};

   如果要求做8點DFT運算,則需在原陣列後補三個0,使長度為8後再進行計算,計算陣列為{1, 2, 3, 4,5,0,0,0}。

旋轉因子計算程式碼如下:

注:①傳入值格式為W(N, p);②為了提高效率,當旋轉因子p = 0時,直接返回  result = 1+0*j = 1;③返回值為負數形式;④利用尤拉公式求負數的指數運算。

/*======================================================================
 * 方法名:  twiddleFactor
 * 方法功能:求FFT計算過程中的旋轉因子 - W(N,p)
 * 說明:    Euler(尤拉)公式  exp(iθ) = cos(θ) - i*sin(θ)
 *
 * 變數名稱:
 *          N   - FFT計算點數
 *          p   - 旋轉因子的階數
 *
 * 返回值:  旋轉因子的複數表示
 *=====================================================================*/
+ (ComplexStruct *)twiddleFactor:(int)N andP:(int)p
{
    ComplexStruct *twiddle = [[ComplexStruct alloc] init];
    
    if(p==0)
    {
        [twiddle setReal:1 andSetImg:0];
    }
    else
    {
        float tempx = PI_x_2 * p/N;
        float real = cos(tempx); //計算複數的實部與虛部
        float img = -1 * sin(tempx);
    
        [twiddle setReal:real andSetImg:img]; //呼叫賦值方法
    }

    return twiddle;
}

DFT流程圖和程式碼如下:


/*======================================================================
 * 方法名:  dft
 * 方法功能:計算陣列的DFT,非2的整數次冪的FFT
 *                N-1
 * 公式說明:X(k) =  ∑  [x(n)*W(N,nk)],其中,W(N,nk)為旋轉因子,k = 0,1,...,N-1
 *                n=0
 *
 * 
 *          yVector   - 原始資料
 *          length    - 原始資料長度
 *          N         - FFT計算點數
 *          fftYreal  - FFT後的實部
 *          fftYImg   - FFT後的虛部
 *
 * 返回值:  是否成功的標誌,若成功返回true,否則返回false
 *=====================================================================*/
+ (BOOL)dft:(float *)yVector andOriginalLength:(NSInteger)length andFFTCount:(NSInteger)N andFFTReal:(float *)fftYReal andFFTYImg:(float *)fftYImg
{
    // 標誌
    BOOL isFFTOK = false;
    
    // 旋轉因子指數
    NSInteger p;
    
    // N點運算的原始資料
    float yVectorN[N];
    
    for (int i = 0; i < N; i++)
    {
        yVectorN[i] = 0.0;
    }
    
    // 定義計算過程中用到的複數變數
    ComplexStruct *tempFFTY, *yFFT1, *yFFT2;
    
    // 初始化複數變數
    yFFT1 = [[ComplexStruct alloc]init];
    yFFT2 = nil;
    
    // 判斷點數是否夠FFT運算點數,並確定最終用於計算的點的值
    if (length <= N)
    {
        // 如果N至少為length,先把yVector全部賦值
        for (NSInteger i = 0; i < length; i++)
        {
            yVectorN[i] = yVector[i];
        }
        
        // 如果 N > length,後面補零
        if (length < N)
        {
            for (NSInteger i = length; i < N; i++)
            {
                yVectorN[i] = 0.0;
            }
        }
    }
    else
    {
        // 如果 N < length 擷取相應長度的資料進行運算
        for (NSInteger i = 0; i < N; i++)
        {
            yVectorN[i] = yVector[i];
        }
    }
    
    // 計算結果初始化
    for (NSInteger i = 0; i < N; i++)
    {
        fftYReal[i] = 0.0;
        fftYImg[i]  = 0.0;
    }
    
    // 運用公式計算
    for (NSInteger i = 0; i < N; i++)
    {
        for (NSInteger j = 0; j < N; j++)
        {
            p = i*j;
            tempFFTY = [FFT twiddleFactor:N andP:p];
            [yFFT1 setReal:yVectorN[j] andSetImg:0.0];
            yFFT2 = [ComplexStruct complexMul:yFFT1 and:tempFFTY];
            fftYReal[i] += [yFFT2 getReal];
            fftYImg[i] += [yFFT2 getImg];
        }
    }
    
    return isFFTOK;
}

二、FFT

1.DFT的運算量

複數乘法次數為N*N,複數加法次數為N(N-1),若N>>1,則這兩者都近似為N*N,它隨N增大為急速增大。

改進途徑:①利用旋轉因子性質減小計算量;②由於運算量和N*N成正比,因而可將N點DFT分解成小點數的DFT,以減少運算量(點數越小,計算量越小);③改為用FFT計算,複數乘法次數為(N/2)*log(2,N)。

2.FFT可分為按照時間抽選的基-2演算法(庫利-圖基演算法DIT-FFT)和按頻率抽選的基-2演算法(桑德-圖基演算法DIF-FFT)。本文采用DIT-FFT演算法。

3.FFT計算原理及流程圖

FFT的計算要求點數必須為2的整數次冪,如果點數不夠用0補齊。例如計算{2,3,5,8,4}的8點FFT,需要補3個0後進行計算,如果計算該陣列的5點FFT,則先計算8點FFT後擷取前5個值即可(不提倡)。

(1)原理

公式推導

設序列x(n)點數為N=2^L,L為整數。將N=2^L,先按照n的奇偶分為兩組,其中r = 0, 1, ..., N/2-1

x(2r) = x1(r)

x(2r-1) = x2(r)

則可將DFT化為(式1)


由上式可以看出一個N點的DFT可以分為兩個N/2點的DFT,按照上式右組合成N點DFT。但是這裡的x1(r)、x2(r)以及X1(k)、X2(k)都是N/2點的序列,即r,k滿足r,k=0, 1, ..., N/2-1。而X(k)卻有N點,上式計算的只是X(k)的前半項數的結果,因此還需要計算後半項的值。


將①②③代入(式1),就可將X(k)表達為前後兩部分:

前半部分,X(k),當k=0, 1, ..., N/2-1


後半部分,X(k),當k=N/2, ..., N-1


蝶形運算說明

蝶形運算,符號表示如下圖所示:


所以,FFT的蝶形運算圖表示為(8點,2^3 = 8,運算級數最大為L=3)


在蝶形運算中變化規律由W(N, p)推導,其中N為FFT計算點數,J為下角標的值

L = 1時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0;

L = 2時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0, 1;

L = 3時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0, 1, 2, 3;

所以,W(N, p) = W(2^L, J),其中J = 0, 1, ..., 2^(L-1)-1

又因為2^L = 2^M*2^(L-M) = N*2^(L-M),這裡N為2的整數次冪,即N=2^M,

W(N, p) = W(2^L, J) = W(N*2^(L-M), J) = W(N, J*2^(M-L))

所以,p = J*2^(M-L),此處J = 0, 1, ..., 2^(L-1)-1,當J遍歷結束但計算點數不夠N時,J=J+2^L,後繼續遍歷,直到計算點數為N時不再迴圈。

舉例:N=8點的FFT計算

當L=2時,J = 0, 1兩個值,因此p = J*2^(M-L) = 0, 2兩個值,即旋轉因子有兩個值W(8, 0)和W(8, 2),計算中兩行之間的距離B = 2^(L-1)=2^(2-1)=2,


代入J=0, 1可求得X(0)、X(0+2)和X(1)、X(1+2),即可求出第2級蝶形運算的X(0), X(1), X(2), X(3),也就是求出一半,此時J加步進2^L=4,即J=J+2^L=4, 5,

再代入J=4, 5可求出X(4), X(4+2)和X(5), X(5+2),即可求出第2級蝶形運算的X(4), X(5), X(6), X(7),已經全部求出,J迴圈結束。

二進位制倒序說明

前面數的排列順序是進行二進位制倒序後的排序。二進位制倒序是指將某數轉化為二進位制表示,將最高位看做最低位、次高位看做次低位...以此類推,計算後的紙進行排序。例如3的二進位制表示為011b(3=0*2^2+1*2+1),二進位制倒序值為6(011b,最高位看做最低位...即6=0+1*2+1*2^2)

即0到7的二進位制排序是:

       0,                4,                 2,                6,                 1,                5,                3,                7

000→000    001→100    010→010    011→110    100→001    101→101    110→011    111→111

(2)流程圖及程式碼

①FFT運算總流程圖,包括


②二進位制倒序程式碼(過程見程式碼註釋,可用其他方式實現)

// 二進位制倒序說明:
//    二進位制倒序是指將數二進位制表示後,把最高位當做最低位(以此類推)排序,最高位向次高位進位
//    如倒序後 0 = 000,1 = 100(最高位+1),2 = 010(最高位向次高位進1)
//------------------------------------------------------------------------
//       倒序前              高位->低位    低位->高位               倒序後
//
//        0                   0 0 0  ---  0 0 0                   0
//        1                   0 0 1  ---  1 0 0                   4
//        2    轉化為二進位制     0 1 0  ---  0 1 0    轉化為十進位制     2
//        3   ===========>    0 1 1  ---  1 1 0   ===========>    6
//        4                   1 0 0  ---  0 0 1                   1
//        5                   1 0 1  ---  1 0 1                   5
//        6                   1 1 0  ---  0 1 1                   3
//        7                   1 1 1  ---  1 1 1                   7
//------------------------------------------------------------------------


/**
 *  @brief        對陣列vector進行二進位制倒序處理,按位計算
 *                實現原理:將原陣列下角標倒序後賦值給倒序後陣列
 *  @param[in]    vector             原陣列
 *  @param[in]    N                  陣列的長度
 *  @param[out]   inverseOrderVector 倒序後的陣列
 */
+ (void)inverseOrder:(float *)vector andN:(NSInteger)N andInverseOrderVector:(float *)inverseOrderVector
{
    // 求對數,即求出二進位制表示時N的位數
    NSInteger k = log2(N);
    
    // 按位處理
    for (NSInteger i = 0; i < N; i++)
    {
        // 下角標號
        NSInteger temp_i    = i;
        
        // 計算後的下角標
        NSInteger foot      = 0;
        
        // 計算過程中,當前所在的位
        NSInteger j         = 0;
        
        // 第j位上的數
        NSInteger temp_foot = 0;
        
        // 每次取低位,變為對應高位,迴圈求和
        while (temp_i)
        {
            // 取出最後一位
            temp_foot = temp_i % 2;
            
            // 計算將最後一位轉化為高位的十進位制值,並與之前值累加
            foot = foot + temp_foot * powf(2, (k - 1 - j));
            
            // 將數右移一位,最右位捨棄
            temp_i = temp_i * 0.5;
            
            // 下一位
            j++;
        }
        
        // 根據下角標取值
        inverseOrderVector[i] = vector[foot];
    }
}

③根據(1)中推導的內容,FFT的流程圖可化為


說明:蝶形運算中又三層迴圈

第一層(最外層),完成M次迭代過程,即算出A0(k), A1(k), ..., Am(k),其中k=0, 1, ..., N;A2(k)為蝶形運算第2級的結果,如A0(k)=x(k), Am(k)=X(k);

第二層(中間層),完成旋轉因子的變化,步進為2^L;

第三層(最裡層),完成相同旋轉因子的蝶形運算。

FFT實現的程式碼如下:

/*======================================================================
 * 方法名:  fft
 * 方法功能:計算陣列的FFT,運用蝶形運算
 *
 * 變數名稱:
 *          yVector   - 原始資料
 *          length    - 原始資料長度
 *          N         - FFT計算點數
 *          fftYreal  - FFT後的實部
 *          fftYImg   - FFT後的虛部
 *
 * 返回值:  是否成功的標誌,若成功返回true,否則返回false
 *=====================================================================*/

+ (BOOL)fft:(float *)yVector andOriginalLength:(NSInteger)length andFFTCount:(NSInteger)N andFFTReal:(float *)fftYReal andFFTYImg:(float *)fftYImg
{
    // 確保計算時時2的整數冪點數計算
    NSInteger N1 = [self nextNumOfPow2:N];
    
    // 定義FFT運算是否成功的標誌
    BOOL isFFTOK = false;
    
    // 判斷計算點數是否為2的整數次冪
    if (N != N1)
    {
        // 不是2的整數次冪,直接計算DFT
        isFFTOK = [self dft:yVector andOriginalLength:length andFFTCount:N andFFTReal:fftYReal andFFTYImg:fftYImg];
        
        // 返回成功標誌
        return isFFTOK;
    }
    
    
    // 如果計算點數位2的整數次冪,用FFT計算,如下
    // 定義變數
    float yVectorN[N1];             // N點運算的原始資料
    NSInteger powOfN = log2(N1);    // N = 2^powOfN,用於標記最大運算級數(公式中表示為:M)
    NSInteger level = 1;            // 運算級數(第幾次運算),最大為powOfN,初值為第一級運算(公式中表示為:L)
    NSInteger lineNum;              // 行號,倒序排列後的蝶形運算行號(公式中表示為:k)
    float inverseOrderY[N1];        // yVector倒序x
    NSInteger distanceLine = 1;     // 行間距,第level級運算每個蝶形的兩個節點距離為distanceLine = 2^(L-1)(公式中表示為:B)
    NSInteger p;                    // 旋轉因子的階數,旋轉因子表示為 W(N, p),p = J*2^(M-L)
    NSInteger J;                    // 旋轉因子的階數,旋轉因子表示為 W(2^L, J),J = 0, 1, 2,..., 2^(L-1) - 1 = distanceLine - 1
    float realTemp, imgTemp, twiddleReal, twiddleImg, twiddleTheta, twiddleTemp = PI_x_2/N1;
    NSInteger N_4 = N1/4;
    
    // 判斷點數是否夠FFT運算點數
    if (length <= N1)
    {
        // 如果N至少為length,先把yVector全部賦值
        for (NSInteger i = 0; i < length; i++)
        {
            yVectorN[i] = yVector[i];
        }
        
        if (length < N1)
        {
            // 如果 N > length 後面補零
            for (NSInteger i = length; i < N1; i++)
            {
                yVectorN[i] = 0.0;
            }
        }
    }
    else
    {
        // 如果 N < length 擷取相應長度的資料進行運算
        for (NSInteger i = 0; i < N1; i++)
        {
            yVectorN[i] = yVector[i];
        }
    }
    
    // 呼叫倒序方法
    [self inverseOrder:yVectorN andN:N1 andInverseOrderVector:inverseOrderY];

    // 初始值
    for (NSInteger i = 0; i < N1; i++)
    {
        fftYReal[i] = inverseOrderY[i];
        fftYImg[i] = 0.0;
    }
    
    // 三層迴圈
    //     第三層(最裡):完成相同旋轉因子的蝶形運算
    //     第二層(中間):完成旋轉因子的變化,步進為2^level
    //     第一層(最外):完成M次迭代過程,即計算出x(k) = A0(k), A1(k),...,Am(k) = X(k)
    
    // 第一層迴圈
    while (level <= powOfN)
    {
        distanceLine = powf(2, level - 1); // 初始條件 distanceLine = 2^(level-1)
        J = 0;
        NSInteger pow2_Level = distanceLine * 2;   // 2^level
        NSInteger pow2_NSubL = N1/pow2_Level;      // 2^(M-L)
        
        // 第二層迴圈
        while (J < distanceLine)
        {
            p = J * pow2_NSubL;
            lineNum = J;
            NSInteger stepCount = 0; // J運算的步進計數
            
            // 求旋轉因子
            if (p==0)
            {
                twiddleReal = 1.0;
                twiddleImg = 0.0;
            }
            else if (p == N_4)
            {
                twiddleReal = 0.0;
                twiddleImg = -1.0;
            }
            else
            {
                // 計算尤拉公式中的θ
                twiddleTheta = twiddleTemp * p;
                
                // 計算複數的實部與虛部
                twiddleReal = cos(twiddleTheta);
                twiddleImg = -1 * sin(twiddleTheta);
            }
            
            // 第三層迴圈
            while (lineNum < N1)
            {
                // 計算下角標
                NSInteger footNum = lineNum + distanceLine;
                
                /*---------------------------------------
                 * 用複數運算計算每級中各行的蝶形運算結果
                 * X(k) = X(k) + X(k+B)*W(N,p)
                 * X(k+B) = X(k) - X(k+B)*W(N,p)
                 *---------------------------------------*/
                realTemp = fftYReal[footNum] * twiddleReal - fftYImg[footNum] * twiddleImg;
                imgTemp  = fftYReal[footNum] * twiddleImg + fftYImg[footNum] * twiddleReal;
                
                // 將計算後的實部和虛部分別存放在返回陣列中
                fftYReal[footNum] = fftYReal[lineNum] - realTemp;
                fftYImg[footNum]  = fftYImg[lineNum] - imgTemp;
                fftYReal[lineNum] = fftYReal[lineNum] + realTemp;
                fftYImg[lineNum]  = fftYImg[lineNum] + imgTemp;
                
                stepCount += pow2_Level;
                
                // 行號改變
                lineNum = J + stepCount;
            }
            
            // 旋轉因子的階數變換,達到旋轉因子改變的效果
            J++;
        }
        
        // 運算級數加一
        level++;
    }
    
    isFFTOK = true;
    return isFFTOK;
}


三、DFT、FFT測試結果

本文開頭就已經說了,我個人比較喜歡使用matlab,所以我程式的對比物件當然是matlab。給定t1[8] = {0,1,2,3,4,5,6,7};signal=sin(t1);對signal進行8、16、4、13、6點FFT/DFT計算輸出的結果和給定128點資料進行128點FFT計算結果如下圖所示:


複製一遍:

FFT8點計算結果

0.553733 + 0.000000i   2.394647 - 2.097012i   -1.386684 + 0.915560i   -0.881042 + 0.280414i   -0.807574 + 0.000000i   -0.881042 - 0.280414i   -1.386684 - 0.915560i   2.394647 + 2.097012i   

FFT16點計算結果

0.553733 + 0.000000i   1.431957 + 0.493527i   2.394647 - 2.097012i   -1.786256 - 2.899550i   -1.386684 + 0.915560i   0.105162 - 0.495158i   -0.881042 + 0.280414i   0.249137 - 0.129291i   -0.807574 + 0.000000i   0.249137 + 0.129291i   -0.881042 - 0.280414i   0.105162 + 0.495158i   -1.386684 - 0.915560i   -1.786256 + 2.899551i   2.394647 + 2.097012i   1.431957 - 0.493527i   

FFT4點計算結果

1.891888 + 0.000000i   -0.909297 - 0.700351i   -0.073294 + 0.000000i   -0.909297 + 0.700351i   

FFT13點計算結果

0.553733 + 0.000000i   1.898167 + 0.288124i   0.803761 - 3.465451i   -2.328951 + 0.137430i   0.200269 - 0.367077i   -0.688243 + 0.477332i   -0.161869 - 0.528187i   -0.161868 + 0.528186i   -0.688245 - 0.477332i   0.200271 + 0.367075i   -2.328952 - 0.137428i   0.803762 + 3.465451i   1.898167 - 0.288123i   

FFT6點計算結果

0.176162 + 0.000000i   -0.276095 - 3.002073i   0.123599 - 0.116304i   0.128828 + 0.000000i   0.123600 + 0.116302i   -0.276092 + 3.002073i   

FFT128點計算結果

0.699691 + 0.000000i   0.704772 + 0.010352i   0.719298 + 0.021364i   0.739474 + 0.033697i   0.749607 + 0.047746i   0.679161 + 0.061398i   0.105405 + 0.050647i   -6.945906 - 0.423135i   54.641422 + 5.062080i   -57.156776 - 6.630915i   9.187446 + 1.338868i   0.342783 + 0.093026i   -0.288066 - 0.020889i   -0.353394 - 0.043726i   -0.328844 - 0.047995i   -0.290196 - 0.047167i   -0.253328 - 0.044825i   -0.221405 - 0.042109i   -0.194470 - 0.039423i   -0.171855 - 0.036897i   -0.152811 - 0.034570i   -0.136679 - 0.032440i   -0.122920 - 0.030495i   -0.111105 - 0.028715i   -0.100891 - 0.027084i   -0.092007 - 0.025581i   -0.084229 - 0.024193i   -0.077390 - 0.022905i   -0.071342 - 0.021706i   -0.065971 - 0.020587i   -0.061182 - 0.019537i   -0.056895 - 0.018550i   -0.053044 - 0.017619i   -0.049575 - 0.016737i   -0.046441 - 0.015901i   -0.043601 - 0.015106i   -0.041024 - 0.014347i   -0.038679 - 0.013621i   -0.036542 - 0.012927i   -0.034593 - 0.012260i   -0.032808 - 0.011617i   -0.031181 - 0.010997i   -0.029686 - 0.010398i   -0.028318 - 0.009818i   -0.027066 - 0.009256i   -0.025917 - 0.008710i   -0.024865 - 0.008177i   -0.023903 - 0.007660i   -0.023024 - 0.007153i   -0.022220 - 0.006657i   -0.021489 - 0.006172i   -0.020825 - 0.005695i   -0.020224 - 0.005227i   -0.019682 - 0.004767i   -0.019197 - 0.004313i   -0.018766 - 0.003867i   -0.018383 - 0.003419i   -0.018055 - 0.002986i   -0.017772 - 0.002551i   -0.017534 - 0.002121i   -0.017342 - 0.001693i   -0.017193 - 0.001268i   -0.017087 - 0.000845i   -0.017025 - 0.000423i   -0.017003 + 0.000000i   -0.017025 + 0.000422i   -0.017087 + 0.000845i   -0.017193 + 0.001268i   -0.017342 + 0.001693i   -0.017534 + 0.002121i   -0.017772 + 0.002551i   -0.018055 + 0.002986i   -0.018383 + 0.003425i   -0.018766 + 0.003866i   -0.019197 + 0.004314i   -0.019682 + 0.004767i   -0.020224 + 0.005227i   -0.020825 + 0.005695i   -0.021489 + 0.006172i   -0.022220 + 0.006656i   -0.023024 + 0.007153i   -0.023902 + 0.007659i   -0.024865 + 0.008177i   -0.025917 + 0.008710i   -0.027066 + 0.009256i   -0.028318 + 0.009818i   -0.029686 + 0.010398i   -0.031179 + 0.010998i   -0.032808 + 0.011617i   -0.034592 + 0.012259i   -0.036542 + 0.012927i   -0.038679 + 0.013621i   -0.041024 + 0.014347i   -0.043601 + 0.015106i   -0.046441 + 0.015901i   -0.049574 + 0.016737i   -0.053044 + 0.017619i   -0.056894 + 0.018549i   -0.061182 + 0.019537i   -0.065971 + 0.020587i   -0.071342 + 0.021706i   -0.077390 + 0.022905i   -0.084229 + 0.024193i   -0.092005 + 0.025579i   -0.100891 + 0.027084i   -0.111107 + 0.028715i   -0.122921 + 0.030496i   -0.136679 + 0.032441i   -0.152811 + 0.034570i   -0.171855 + 0.036897i   -0.194470 + 0.039423i   -0.221401 + 0.042109i   -0.253328 + 0.044825i   -0.290195 + 0.047166i   -0.328844 + 0.047996i   -0.353394 + 0.043726i   -0.288066 + 0.020889i   0.342783 - 0.093026i   9.187446 - 1.338871i   -57.156776 + 6.630923i   54.641422 - 5.062086i   -6.945903 + 0.423136i   0.105404 - 0.050648i   0.679161 - 0.061398i   0.749607 - 0.047746i   0.739474 - 0.033698i   0.719298 - 0.021364i   0.704768 - 0.010354i 

測試結果顯示:iOS程式與MATLAB程式運算結果一致,但是MATLAB運算效率高。以下是多次比較求平均後的時間值


為了更直觀的觀察,將其他的訊號(幾個訊號疊加後的訊號)通過fft計算後並作頻域處理匯入matlab,繪製圖如下:



===================================================================

OK,FFT隨筆一份,方便自己以後查閱。其中一定會有很多不足,望路過的大神訂正。謝過