簡體   English   中英

用袖帶實現實到復 FFT

[英]In place real to complex FFT with cufft

我正在嘗試使用 cufft 執行就地真實到復雜的 FFT。 我知道類似的問題How to perform a Real to Complex Transformation with cuFFT 但是,我在嘗試重現相同的方法時遇到問題。

如果我做一個不合適的轉換,沒有問題,但是一旦我做到位,我在 FFT 中沒有正確的值(用 python 檢查,在兩者之間使用二進制文件)。 我沒有錯誤,只是不正確的值。

這是我的代碼:

void fftCuda2d(mat3d* scene)
{
    cufftResult resultStatus;
    cudaError_t cuda_status;

    cufftHandle plan_forward;

    resultStatus = cufftPlan2d(&plan_forward, scene->_height, scene->_width, CUFFT_R2C);
    cout << "Creating plan forward: " << _cudaGetErrorEnum(resultStatus) << endl;

    cufftComplex *d_fft, *d_scene, *h_fft;

    size_t size_fft = (int(scene->_width/2)+1)*scene->_height;

    cudaMalloc((void**)&d_scene, sizeof(cufftComplex)*size_fft);
    cudaMalloc((void**)&d_fft, sizeof(cufftComplex)*size_fft);


    h_fft = (cufftComplex*) malloc(sizeof(cufftComplex)*size_fft);

    cuda_status = cudaMemcpy(d_scene, scene->_pData, sizeof(cufftReal) * scene->_height * scene->_width, cudaMemcpyHostToDevice);

    resultStatus = cufftExecR2C(plan_forward, (cufftReal*) d_scene, d_scene);

    cuda_status = cudaMemcpy(h_fft, d_scene, sizeof(cufftReal)*scene->_height*scene->_width, cudaMemcpyDeviceToHost);

    FILE* *pFileTemp;

    pFileTemp = fopen("temp.bin", "wb");

    check = fwrite(h_fft, sizeof(cufftComplex), sizeFft, pFileTemp);

}

如果我使用resultStatus = cufftExecR2C(plan_forward, (cufftReal*) d_scene, d_fft); 並保存 d_fft 的d_fft我得到了正確的結果。 所以你在這里看到我的任何錯誤嗎?

PS Mat3d 是一個結構,其中 _width 和 _height 包含矩陣的大小,而 pData 是指向數據的指針,但這沒有問題。

(看起來這應該是一個重復的問題,但我無法找到重復的問題。)

使用就地轉換時,您的輸入數據需要以不同方式組織(填充)。 這在 2D 情況下尤其明顯,因為必須填充每一行數據。

在非就地 R2C 變換中,輸入數據是實數值的,大小為高*寬(例如 R=4,C=4 的情況):

X X X X
X X X X
X X X X
X X X X

上述數據將恰好占據16*sizeof(cufftReal) (假設float輸入數據,維度 R = 4,C = 4),並且它將在 ZCD69B4957F06CD818D143E1257Z = 4 中以這種方式組織,190DE 沒有間隙2 但是,當我們切換到就地變換時,輸入緩沖區的大小會發生變化。 這種大小的變化對數據排列產生了影響。 具體來說,輸入緩沖區的大小為R*(C/2 + 1)*sizeof(cufftComplex) 對於 R=4, C=4 示例情況,即12*sizeof(cufftComplex)24*sizeof(cufftReal) ,但它仍被組織為 4 行數據。 因此,每一行的長度為 6(如果在cufftReal中測量)或 3(如果在cufftComplex中測量)。 將其視為cufftReal ,那么當我們創建輸入數據時,我們必須像這樣組織它:

X X X X P P
X X X X P P
X X X X P P
X X X X P P

其中P位置是“填充”數據,而不是您的輸入數據。 如果我們在 memory 中線性查看,它看起來像:

X X X X P P X X X X P P X X X X P P X X X X P P

這就是 CUFFT 的期望/要求(我相信 FFTW 也是如此)。 但是,由於您沒有更改存儲數據的方式,因此您提供的數據如下所示:

X X X X X X X X X X X X X X X X P P P P P P P P 

這兩種模式的差異是導致結果 output 差異的原因。 有多種方法可以解決此問題。 我將選擇演示使用cudaMemcpy2D在就地情況下填充設備輸入緩沖區,這將為我們提供所需的模式。 這可能不是最好/最快的方式,具體取決於您的應用程序需求。

您也沒有將正確大小的結果數據從設備復制回主機。

這是一個固定的例子:

$ cat t1589.cu
#include <cufft.h>
#include <iostream>
#include <cstdlib>

struct mat3d{
  int _width;
  int _height;
  cufftReal *_pData;
};


void fftCuda2d(mat3d* scene)
{
    cufftResult resultStatus;
    cudaError_t cuda_status;

    cufftHandle plan_forward;

    resultStatus = cufftPlan2d(&plan_forward, scene->_height, scene->_width, CUFFT_R2C);
    std::cout << "Creating plan forward: " <<  (int)resultStatus << std::endl;

    cufftComplex *d_fft, *d_scene, *h_fft;

    size_t size_fft = (int(scene->_width/2)+1)*scene->_height;

    cudaMalloc((void**)&d_scene, sizeof(cufftComplex)*size_fft);
    cudaMalloc((void**)&d_fft, sizeof(cufftComplex)*size_fft);


    h_fft = (cufftComplex*) malloc(sizeof(cufftComplex)*size_fft);

#ifdef USE_IP
    cuda_status = cudaMemcpy2D(d_scene, ((scene->_width/2)+1)*sizeof(cufftComplex), scene->_pData, (scene->_width)*sizeof(cufftReal), sizeof(cufftReal) * scene->_width, scene->_height, cudaMemcpyHostToDevice);
    resultStatus = cufftExecR2C(plan_forward, (cufftReal*) d_scene, d_scene);
    cuda_status = cudaMemcpy(h_fft, d_scene, sizeof(cufftComplex)*size_fft, cudaMemcpyDeviceToHost);
#else
    cuda_status = cudaMemcpy(d_scene, scene->_pData, sizeof(cufftReal) * scene->_height * scene->_width, cudaMemcpyHostToDevice);
    resultStatus = cufftExecR2C(plan_forward, (cufftReal*) d_scene, d_fft);
    cuda_status = cudaMemcpy(h_fft, d_fft, sizeof(cufftComplex)*size_fft, cudaMemcpyDeviceToHost);
#endif
    std::cout << "exec: " <<  (int)resultStatus << std::endl;

    for (int i = 0; i < size_fft; i++)
      std::cout << h_fft[i].x << " " << h_fft[i].y << ",";
    std::cout << std::endl;
}
const int dim = 4;
int main(){

  mat3d myScene;
  myScene._pData  = new cufftReal[dim*dim];
  myScene._width  = dim;
  myScene._height = dim;
  for (int i = 0; i < dim*dim; i++) myScene._pData[i] = rand()/(float)RAND_MAX;
  fftCuda2d(&myScene);
  std::cout << cudaGetErrorString(cudaGetLastError()) << std::endl;
}
$ nvcc -lineinfo -o t1589 t1589.cu -lcufft
t1589.cu(15): warning: variable "cuda_status" was set but never used

$ ./t1589
Creating plan forward: 0
exec: 0
9.71338 0,-0.153554 1.45243,0.171302 0,0.878097 0.533959,0.424595 -0.834714,0.858133 -0.393671,-0.205139 0,-0.131513 -0.494514,-0.165712 0,0.878097 -0.533959,0.0888268 1.49303,0.858133 0.393671,
no error
$ nvcc -lineinfo -o t1589 t1589.cu -lcufft -DUSE_IP
t1589.cu(15): warning: variable "cuda_status" was set but never used

$ ./t1589
Creating plan forward: 0
exec: 0
9.71338 0,-0.153554 1.45243,0.171302 0,0.878097 0.533959,0.424595 -0.834714,0.858133 -0.393671,-0.205139 0,-0.131513 -0.494514,-0.165712 0,0.878097 -0.533959,0.0888268 1.49303,0.858133 0.393671,
no error
$

暫無
暫無

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

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