簡體   English   中英

Matlab FFT和自制FFT

[英]Matlab FFT and home brewed FFT

我正在嘗試驗證VS算法,該VS應該在Matlab上用於項目VS。 關鍵是,使用我自己的C FFT函數,我總是得到Matlab中評估的雙面FFT頻譜的正確部分(第二部分),而不是“期望”的第一部分。

例如,如果我的第三個bin的格式為a + i * b,則Matlab FFT的第三個bin的格式為ai * b。 A和B值相同,但我總是得到Matlab的復共軛。 我知道在振幅和功率方面沒有問題(因為有絕對值),但我想知道在相位方面我是否總是會讀取錯誤的角度。

我對Matlab不太了解(我在網上也沒有找到有用的信息)Matlab FFT是否可能先返回負頻率然后再返回正頻率的FFT頻譜...或者是否必須修復FFT算法...還是全部沒問題,因為無論FFT的哪個部分,相位都是不變的,我們選擇作為單邊頻譜(但我對最后一個選擇表示懷疑)。

例:

如果S是具有N = 512個樣本的樣本數組,則Matlab中的Y = fft(S)返回FFT為(該數組前半部分的虛部的符號是隨機的,只是為了顯示第二部分):

1   A1    +  i*B1     (DC, B1 is always zero)
2   A2    +  i*B2
3   A3    -  i*B3
4   A4    +  i*B4
5   A5    +  i*B5
...
253 A253  -  i*B253
254 A254  +  i*B254
255 A255  +  i*B255
256 A256  +  i*B256
257 A257  -  i*B257   (Nyquyst, B257 is always zero)
258 A256  -  i*B256
259 A255  -  i*B255
260 A254  -  i*B254
261 A253  +  i*B253
...
509 A5    -  i*B5
510 A4    -  i*B4
511 A3    +  i*B3
512 A2    -  i*B2

我的FFT實現在Y數組中僅返回256個值(沒關系),如下所示:

1   1    A1    +  i*B1     (A1 is the DC, B1 is Nyquist, both are pure Real numbers)
2   512  A2    -  i*B2
3   511  A3    +  i*B3
4   510  A4    -  i*B4
5   509  A5    +  i*B5
...
253 261  A253  +  i*B253
254 260  A254  -  i*B254
255 259  A255  -  i*B255
256 258  A256  -  i*B256

第一列是我的Y數組的正確索引,第二列只是Matlab FFT實現中相對行的引用。

如您所見,我的FFT實現(DC分開)返回FFT,就像 Matlab FFT的后 一半一樣 (以相反的順序)。

總結一下:即使我按照建議使用fftshift,似乎我的實現總是返回 Matlab FFT中應該被認為是頻譜負部分的內容。 錯誤在哪里???

這是我使用的代碼:

注1:此處未聲明FFT數組,並且在函數內部對其進行了更改。 最初,它包含N個樣本( 實際值), 最后包含單面FFT頻譜的N / 2 +1個單元。

注2:N / 2 + 1格存儲在N / 2個元素中,僅是因為DC分量始終是實數(並且存儲在FFT [0]中),而Nyquyst(它也存儲在FFT [1]中) ),則該例外情況除外,所有其他偶數元素K都擁有一個實數,而烤箱元素K + 1則擁有了虛部。

void Fft::FastFourierTransform( bool inverseFft ) {
   double twr, twi, twpr, twpi, twtemp, ttheta;
   int i, i1, i2, i3, i4, c1, c2;
   double h1r, h1i, h2r, h2i, wrs, wis;
   int nn, ii, jj, n, mmax, m, j, istep, isign;
   double wtemp, wr, wpr, wpi, wi;    
   double theta, tempr, tempi;

   // NS is the number of samples and it must be a power of two
   if( NS == 1 )
      return;

   if( !inverseFft ) {
      ttheta = 2.0 * PI / NS;
      c1 = 0.5;
      c2 = -0.5;
   }
   else {
      ttheta = 2.0 * PI / NS;
      c1 = 0.5;
      c2 = 0.5;
      ttheta = -ttheta;
      twpr = -2.0 * Pow( Sin( 0.5 * ttheta ), 2 );
      twpi = Sin(ttheta);
      twr = 1.0+twpr;
      twi = twpi;
      for( i = 2; i <= NS/4+1; i++ ) {
         i1 = i+i-2;
         i2 = i1+1;
         i3 = NS+1-i2;
         i4 = i3+1;
         wrs = twr;
         wis = twi;
         h1r = c1*(FFT[i1]+FFT[i3]);
         h1i = c1*(FFT[i2]-FFT[i4]);
         h2r = -c2*(FFT[i2]+FFT[i4]);
         h2i = c2*(FFT[i1]-FFT[i3]);
         FFT[i1] = h1r+wrs*h2r-wis*h2i;
         FFT[i2] = h1i+wrs*h2i+wis*h2r;
         FFT[i3] = h1r-wrs*h2r+wis*h2i;
         FFT[i4] = -h1i+wrs*h2i+wis*h2r;
         twtemp = twr;
         twr = twr*twpr-twi*twpi+twr;
         twi = twi*twpr+twtemp*twpi+twi;
      }
      h1r = FFT[0];
      FFT[0] = c1*(h1r+FFT[1]);
      FFT[1] = c1*(h1r-FFT[1]);
   }
   if( inverseFft )
      isign = -1;
   else
      isign = 1;
   n = NS;
   nn = NS/2;
   j = 1;
   for(ii = 1; ii <= nn; ii++) {
      i = 2*ii-1;
      if( j>i ) {
         tempr = FFT[j-1];
         tempi = FFT[j];
         FFT[j-1] = FFT[i-1];
         FFT[j] = FFT[i];
         FFT[i-1] = tempr;
         FFT[i] = tempi;
      }
      m = n/2;
      while( m>=2 && j>m ) {
         j = j-m;
         m = m/2;
      }
      j = j+m;
   }
   mmax = 2;
   while(n>mmax) {
      istep = 2*mmax;
      theta = 2.0 * PI /(isign*mmax);
      wpr = -2.0 * Pow( Sin( 0.5 * theta ), 2 );
      wpi = Sin(theta);
      wr = 1.0;
      wi = 0.0;
      for(ii = 1; ii <= mmax/2; ii++) {
         m = 2*ii-1;
         for(jj = 0; jj <= (n-m)/istep; jj++) {
            i = m+jj*istep;
            j = i+mmax;
            tempr = wr*FFT[j-1]-wi*FFT[j];
            tempi = wr*FFT[j]+wi*FFT[j-1];
            FFT[j-1] = FFT[i-1]-tempr;
            FFT[j] = FFT[i]-tempi;
            FFT[i-1] = FFT[i-1]+tempr;
            FFT[i] = FFT[i]+tempi;
         }
         wtemp = wr;
         wr = wr*wpr-wi*wpi+wr;
         wi = wi*wpr+wtemp*wpi+wi;
      }
      mmax = istep;
   }
   if( inverseFft )
      for(i = 1; i <= 2*nn; i++)
         FFT[i-1] = FFT[i-1]/nn;
   if( !inverseFft ) {
      twpr = -2.0 * Pow( Sin( 0.5 * ttheta ), 2 );
      twpi = Sin(ttheta);
      twr = 1.0+twpr;
      twi = twpi;
      for(i = 2; i <= NS/4+1; i++) {
         i1 = i+i-2;
         i2 = i1+1;
         i3 = NS+1-i2;
         i4 = i3+1;
         wrs = twr;
         wis = twi;
         h1r = c1*(FFT[i1]+FFT[i3]);
         h1i = c1*(FFT[i2]-FFT[i4]);
         h2r = -c2*(FFT[i2]+FFT[i4]);
         h2i = c2*(FFT[i1]-FFT[i3]);
         FFT[i1] = h1r+wrs*h2r-wis*h2i;
         FFT[i2] = h1i+wrs*h2i+wis*h2r;
         FFT[i3] = h1r-wrs*h2r+wis*h2i;
         FFT[i4] = -h1i+wrs*h2i+wis*h2r;
         twtemp = twr;
         twr = twr*twpr-twi*twpi+twr;
         twi = twi*twpr+twtemp*twpi+twi;
      }
      h1r = FFT[0];
      FFT[0] = h1r+FFT[1];  // DC
      FFT[1] = h1r-FFT[1];  // FS/2 (NYQUIST)
   }            
   return;
}

在Matlab中嘗試使用fftshift(fft(...))。 Matlab在調用FFT后不會自動移動頻譜,這就是為什么他們實現了fftshift()函數。

這只是一個matlab格式化的東西。 基本上,matlab按以下順序安排傅立葉變換

DC, (DC-1), .... (Nyquist-1), -Nyquist, -Nyquist+1, ..., DC-1

假設您有一個8點序列:[1 2 3 1 4 5 1 3]

在您的信號處理課程中,您的教授可能會基於笛卡爾系統繪制傅立葉頻譜(負-> x軸為正); 因此,您的DC應該位於x軸上的0(在fft序列中的第4個位置,假設此處的位置索引是從0開始的)。

在matlab中,DC是fft序列中的第一個元素,因此您需要fftshit()交換fft序列的前一半和后一半,以使DC位於第4個位置(位置從0開始索引)

我在這里附上一張圖,這樣您就可以看到視覺效果:

在此處輸入圖片說明

其中a是原始的8點序列; FT(a)是a的傅立葉變換。

Matlab代碼在這里:

a = [1 2 3 1 4 5 1 3];
A = fft(a);

N = length(a);
x = -N/2:N/2-1;

figure
subplot(3,1,1), stem(x, a,'o'); title('a'); xlabel('time')
subplot(3,1,2), stem(x, fftshift(abs(A),2),'o'); title('FT(a) in signal processing'); xlabel('frequency')
subplot(3,1,3), stem(x, abs(A),'o'); title('FT(a) in matlab'); xlabel('frequency')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM