簡體   English   中英

3D 陣列的 1D 實數 FFT 和 IFFT

[英]1D real FFT and IFFT of a 3D array

我有一個具有維度(Nx,Ny,Nz)的 3D 數組。

我想使用 FFTW3 庫沿 z 軸應用真正的 FFT 和 IFFT。

這里,'z' 是變化最快的索引。

我已經使用 python 編寫了相同的功能代碼

numpy.fft.rfft 和 numpy.fft.irfft。 它完全按照我的預期工作。

但它太慢了。 所以我嘗試用C語言寫代碼。

我試圖比較 IFFT(FFT(f)) 和 f 的結果,其中 f 是一個任意數組。

我使用 fft_plan_many_dft_r2c / fft_plan_many_dft_c2r 進行前向/后向 FFT。

這是我的代碼。

(使用 gcc 和 -lfftw3 -lm 選項在 Ubuntu 16.04 中編譯)

#include <stdio.h>
#include <stdlib.h>
#include <fftw3.h>

void rfft_1d_of_3d(int Nx, int Ny, int Nz, double* input, double* output);

int main(){

    double* input;
    double* output;

    int Nx=2, Ny=4, Nz=8;
    int i,j,k,idx;

    input  = (double*) malloc(Nx*Ny*Nz*sizeof(double));
    output = (double*) malloc(Nx*Ny*Nz*sizeof(double));

    for(i=0; i<Nx; i++){
        for(j=0; j<Ny; j++){
            for(k=0; k<Nz; k++){

                idx = k + j*Nz + i*Nz*Ny;
                input[idx] = idx;
                output[idx] = 0.;
            }
        }   
    }   

    rfft_1d_of_3d(Nx, Ny, Nz, input, output);

    for(i=0; i<Nx; i++){
        for(j=0; j<Ny; j++){
            for(k=0; k<Nz; k++){
                idx = k + j*Nz + i*Nz*Ny;
                printf("%f, %f\n", input[idx], output[idx]);
            }
        }
    }   

    return 0;
}

void rfft_1d_of_3d(int Nx, int Ny, int Nz, double* input, double* output){

    int i,j,k,idx;

    // Allocate memory space.
    fftw_complex *FFTz = fftw_alloc_complex(Nx*Ny*(Nz/2+1));

    // Set forward FFTz parameters
    int rankz = 1;
    int nz[] = {Nz};
    const int *inembedz = NULL, *onembedz = NULL;
    int istridez = 1, ostridez = 1;
    int idistz = Nz, odistz= (Nz+2)/2;
    int howmanyz = (Nx*Ny);

    // Setup Forward plans.
    fftw_plan FFTz_for_plan = fftw_plan_many_dft_r2c(rankz, nz, howmanyz, input, inembedz, istridez, idistz, FFTz, onembedz, ostridez, odistz, FFTW_ESTIMATE);

    // Set backward FFTz parameters
    int rankbz = 1;
    int nbz[] = {(Nz+2)/2};
    const int *inembedbz = NULL, *onembedbz = NULL;
    int istridebz = 1, ostridebz = 1;
    int idistbz = (Nz+2)/2, odistbz = Nz;
    int howmanybz = (Nx*Ny);

    // Setup Backward plans.
    fftw_plan FFTz_bak_plan = fftw_plan_many_dft_c2r(rankbz, nbz, howmanybz, FFTz, inembedbz, istridebz, idistbz, output, onembedbz, ostridebz, odistbz, FFTW_ESTIMATE);

    fftw_execute(FFTz_for_plan);
    fftw_execute(FFTz_bak_plan);
    fftw_free(FFTz);

    return;
}

輸入和輸出結果應該是相同的,但事實並非如此。

輸入數組是一個 3D 數組(Nx=2,Ny=4,Nz=8),

[[[  0.   1.   2.   3.   4.   5.   6.   7.]
  [  8.   9.  10.  11.  12.  13.  14.  15.]
  [ 16.  17.  18.  19.  20.  21.  22.  23.]
  [ 24.  25.  26.  27.  28.  29.  30.  31.]]

 [[ 32.  33.  34.  35.  36.  37.  38.  39.]
  [ 40.  41.  42.  43.  44.  45.  46.  47.]
  [ 48.  49.  50.  51.  52.  53.  54.  55.]
  [ 56.  57.  58.  59.  60.  61.  62.  63.]]]

我把它弄平了,

[  0.   1.   2.   3.   4.   5.   6.   7.  8.   9.  10.  11.  12.  13.  14.  15. 16.  17.  18.  19.  20.  21.  22.  23. 24.  25.  26.  27.  28.  29.  30.  31. 32.  33.  34.  35.  36.  37.  38.  39. 40.  41.  42.  43.  44.  45.  46.  47. 48.  49.  50.  51.  52.  53.  54.  55. 56.  57.  58.  59.  60.  61.  62.  63.]

我預計輸出將與輸入相同,但實際結果是

0.000000, 12.000000
1.000000, 8.929290
2.000000, 28.256139
3.000000, 35.743861
4.000000, 55.070710
5.000000, 0.000000
6.000000, 0.000000
7.000000, 0.000000
8.000000, 76.000000
9.000000, 72.929290
10.000000, 92.256139
11.000000, 99.743861
12.000000, 119.070710
13.000000, 0.000000
14.000000, 0.000000
15.000000, 0.000000
16.000000, 140.000000
17.000000, 136.929290
18.000000, 156.256139
19.000000, 163.743861
20.000000, 183.070710
21.000000, 0.000000
22.000000, 0.000000
23.000000, 0.000000
24.000000, 204.000000
25.000000, 200.929290
26.000000, 220.256139
27.000000, 227.743861
28.000000, 247.070710
29.000000, 0.000000
30.000000, 0.000000
31.000000, 0.000000
32.000000, 268.000000
33.000000, 264.929290
34.000000, 284.256139
35.000000, 291.743861
36.000000, 311.070710
37.000000, 0.000000
38.000000, 0.000000
39.000000, 0.000000
40.000000, 332.000000
41.000000, 328.929290
42.000000, 348.256139
43.000000, 355.743861
44.000000, 375.070710
45.000000, 0.000000
46.000000, 0.000000
47.000000, 0.000000
48.000000, 396.000000
49.000000, 392.929290
50.000000, 412.256139
51.000000, 419.743861
52.000000, 439.070710
53.000000, 0.000000
54.000000, 0.000000
55.000000, 0.000000
56.000000, 460.000000
57.000000, 456.929290
58.000000, 476.256139
59.000000, 483.743861
60.000000, 503.070710
61.000000, 0.000000
62.000000, 0.000000
63.000000, 0.000000

左邊是輸入數組的元素,右邊是輸出數組的元素。

我在哪里做錯了?

對於fftw_plan_many_dft_c2r()nbz ,變換的大小,將設置為Nz實際輸出數組的大小。 fftw_plan_dft_c2r_1d()可能類似。

// Set backward FFTz parameters
int rankbz = 1;
int nbz[1] = {(Nz)}; // here !!!
const int *inembedbz = NULL, *onembedbz = NULL;
//int inembedbz[1]={Nz/2+1};
//int onembedbz[1]={Nz};
int istridebz = 1, ostridebz = 1;
int idistbz = (Nz/2+1), odistbz = (Nz);
int howmanybz = (Nx*Ny);

// Setup Backward plans.
fftw_plan FFTz_bak_plan = fftw_plan_many_dft_c2r(rankbz, nbz, howmanybz, FFTz, inembedbz, istridebz, idistbz, output, onembedbz, ostridebz, odistbz, FFTW_ESTIMATE);

由於 FFTW 變換使用inputoutput數組,因此建議使用fftw_malloc()或類似函數來分配它們,就像您對FFTz所做的FFTz 這些函數確保滿足有關內存對齊的要求。 請參閱*X(kernel_malloc)(size_t n) -3.3.6-pl2/kernel/kalloc.c 中的函數*X(kernel_malloc)(size_t n) 它調用諸如memalign()_aligned_malloc()等函數。 如果失敗,這兩個都返回NULL就像malloc()一樣。

有規模差異。 實際上,鏈接長度的向前和向后FFTW變換Nz導致由縮放Nz

最后,允許某些 FFTW 轉換,例如 c2r,覆蓋其輸入數組,除非添加了標志 FFTW_PRESERVE_INPUT

FFTW_PRESERVE_INPUT 指定異地變換不得更改其輸入數組。 這通常是默認值,除了 FFTW_DESTROY_INPUT 是默認值的 c2r 和 hc2r(即復數到實數)轉換。 在后一種情況下,傳遞 FFTW_PRESERVE_INPUT 將嘗試使用不會破壞輸入的算法,代價是性能更差; 然而,對於多維 c2r 變換,沒有實現輸入保留算法,如果需要,規划器將返回 NULL。

暫無
暫無

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

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