[英]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.