2016-04-10 9 views
1

Ich mache 2D FFT auf 128 Bilder der Größe 128 x 128 mit CUFFT-Bibliothek. Die Art, wie ich die Bibliothek verwendet wird, ist der folgende:CUDA Cuff-Bibliothek 2D FFT nur die linke Halbebene korrekt

unsigned int nx = 128; unsigned int ny = 128; unsigned int nz = 128; 
// Make 2D fft batch plan 
int n[2] = {nx, ny}; 
int inembed[] = {nx, ny}; 
int onembed[] = {nx, ny}; 

cufftPlanMany(&plan, 
      2, // rank 
      n, // dimension 
      inembed, 
      1, // istride 
      nx * ny, // idist 
      onembed, 
      1, //ostride 
      nx * ny, // odist 
      CUFFT_D2Z, 
      nz); 
cufftSetCompatibilityMode(plan,CUFFT_COMPATIBILITY_NATIVE) 

// Create output array 
complex<double>* out_complex = new complex<double>[nx * ny * nz]; 
// Initialize output array 
for (unsigned int i = 0; i < nx * ny * nz; i++) { 
    out_complex[i].real(0); 
    out_complex[i].imag(0); 
} 
cudaMalloc((void**)&idata, sizeof(cufftDoubleReal) * nx * ny * nz); 
cudaMalloc((void**)&odata, sizeof(cufftDoubleComplex) * nx * ny * nz); 
cudaMemcpy(idata, in_real, nx * ny * nz * sizeof(cufftDoubleReal), 
            cudaMemcpyHostToDevice) ); 
cudaMemcpy(odata, out_complex, nx * ny * nz * sizeof(cufftDoubleComplex), 
            cudaMemcpyHostToDevice) ); 

cufftExecD2Z(plan, idata, odata); 

cudaMemcpy(out_complex, odata, nx * ny * nz * sizeof(cufftDoubleComplex), 
            cudaMemcpyDeviceToHost)); 

Der Eingang in_real auf dem Host ist ein großes Array von 3D-Bildern gehalten wird, die eine doppelte Array ist. Ich denke, dass es kein Problem geben sollte, zu/von double von/in cammettDoubleReal und komplex von/in cammettDoubleComplex zu konvertieren? Ich bin ein wenig misstrauisch gegenüber der Art, wie der Plan gemacht wurde, und den Parametern, die ich versucht habe, ein Beispiel online zu finden, aber sie sind nicht so hilfreich oder konsistent. Dann setze ich einfach die Parameter über die programming guide nach meinem eigenen Verständnis.

Wie durch den Titel angezeigt, ist die Ausgabe teilweise korrekt (die linke Halbebene), mit der rechten Hälfte Ebene Nullen, die mich so verwirrt. Ich habe versucht, verschiedene Arten von Kompatibilitätsmodus einzustellen, aber es war nicht so hilfreich. Die Version, mit der ich vergleiche, ist MATLAB fft2().

Antwort

3

Sie müssen die documentation für echte bis komplexe Transformationen (wieder) lesen. Zitieren:

In vielen praktischen Anwendungen ist der Eingabevektor real-value. Es kann leicht gezeigt werden, dass in diesem Fall die Ausgabe Hermitian Symmetrie (X k = X N - k *, wobei der Stern Komplex Konjugation bedeutet) erfüllt. Das Umgekehrte ist auch wahr: Für den komplex-hermiteschen Eingang wird die inverse Transformation rein reellwertig sein. cuFFT nimmt Vorteil dieser Redundanz und arbeitet nur auf der ersten Hälfte des Hermitian Vektor

dh die Ausgabe eines Echt komplexe Transformation ist symmetrisch, und cuFFT nutzt dies, indem nicht die redundante (symmetrisch) Koeffizienten-Berechnungs . Daher ist es normal, nur die "Hälfte" der Transformationsausgabe zu erhalten, weil die andere "Hälfte" identisch ist. Dies ist nicht einzigartig für cuFFT, FFTW und die meisten anderen Hochleistungs-FFT-Bibliotheken funktionieren auf diese Weise für reale bis komplexe Transformationen und komplexe bis echte inverse Transformationen.

+0

Danke @talonmies. Ich denke dann habe ich dann eine Frage, die CUDA nicht wirklich angeht. Angenommen, ich transformiere im1 und hole im1_fft, und ich habe ein anderes Bild in der Fourier-Domäne, nicht symmetrisch. Dann dotte ich diese zwei Bilder und bekomme ein Produktbild, das aufgrund der Eingabe halbiert ist. Wie wird CUDA IFFT dann die Information der Halbebenen-Pixel beibehalten, die Null war (in diesem Fall nicht symmetrisch)? Oder verwende ich in diesem Fall die vollständige Z2Z-Transformation für beide Bilder in CUDA? Das hört sich an wie CUDA Z2Z und D2Z Betrieb nicht wirklich miteinander kompatibel? –