CUFFT |无法弄清楚一个简单的例子

时间:2013-10-05 16:10:29

标签: cuda fft cufft

我一直在苦苦挣扎,试图使一个基本的CUFFT示例正常工作。但是我遇到了一个我无法识别的小问题。基本上我有一个带x和y坐标的线性二维数组vx。然后我只计算一个向前然后向后的CUFFT(就地),就这么简单。然后我复制数组vx,将其标准化为NX * NY ,然后显示。

#define NX 32
#define NY 32
#define LX (2*M_PI)
#define LY (2*M_PI)
float *x = new float[NX*NY];
float *y = new float[NX*NY];
float *vx = new float[NX*NY];
for(int j = 0; j < NY; j++){
    for(int i = 0; i < NX; i++){
        x[j*NX + i] = i * LX/NX;
        y[j*NX + i] = j * LY/NY;
        vx[j*NX + i] = cos(x[j*NX + i]);
    }
}
float *d_vx;
CUDA_CHECK(cudaMalloc(&d_vx, NX*NY*sizeof(float)));
CUDA_CHECK(cudaMemcpy(d_vx, vx, NX*NY*sizeof(float), cudaMemcpyHostToDevice));
cufftHandle planr2c;
cufftHandle planc2r;
CUFFT_CHECK(cufftPlan2d(&planr2c, NY, NX, CUFFT_R2C));
CUFFT_CHECK(cufftPlan2d(&planc2r, NY, NX, CUFFT_C2R));
CUFFT_CHECK(cufftSetCompatibilityMode(planr2c, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftSetCompatibilityMode(planc2r, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftExecR2C(planr2c, (cufftReal *)d_vx, (cufftComplex *)d_vx));
CUFFT_CHECK(cufftExecC2R(planc2r, (cufftComplex *)d_vx, (cufftReal *)d_vx));
CUDA_CHECK(cudaMemcpy(vx, d_vx, NX*NY*sizeof(cufftReal), cudaMemcpyDeviceToHost));
for (int j = 0; j < NY; j++){
    for (int i = 0; i < NX; i++){
        printf("%.3f ", vx[j*NX + i]/(NX*NY));
    }
    printf("\n");
}

当vx定义为cos(x)或sin(x)时,它工作正常,但是当使用sin(y)或cos(y)时,它会返回正确的函数(sin或cos)但是有一半振幅(即在0.5和-0.5之间振荡而不是1和-1)!请注意,使用sin(2 * y)或cos(2 * y)(或sin(4 * y),cos(4 * y),...)可以正常工作。有什么想法吗?

1 个答案:

答案 0 :(得分:4)

这里的问题是就地实数到复数变换的输入和输出是一种复杂类型,其大小与输入的实际数据不同(它是两倍大)。您还没有分配足够的内存来保存真实到复杂变换的中间复杂结果。引自文档:

  

cufftExecR2C()(cufftExecD2Z())执行单精度   (双精度)实数到复数,隐式转发,CUFFT   转型计划。 CUFFT使用指向的GPU内存作为输入数据   idata参数。该函数存储非冗余傅立叶   odata数组中的系数。指向idata和odata的指针都是   需要以单精度对齐cufftComplex数据类型   以双精度转换和cufftDoubleComplex数据类型   变换。

解决方案是分配第二个设备缓冲区以保存中间结果或扩大就地分配,使其足够大以容纳复杂数据。所以核心转换代码改为:

float *d_vx;
CUDA_CHECK(cudaMalloc(&d_vx, NX*NY*sizeof(cufftComplex)));
CUDA_CHECK(cudaMemcpy(d_vx, vx, NX*NY*sizeof(cufftComplex), cudaMemcpyHostToDevice));
cufftHandle planr2c;
cufftHandle planc2r;
CUFFT_CHECK(cufftPlan2d(&planr2c, NY, NX, CUFFT_R2C));
CUFFT_CHECK(cufftPlan2d(&planc2r, NY, NX, CUFFT_C2R));
CUFFT_CHECK(cufftSetCompatibilityMode(planr2c, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftSetCompatibilityMode(planc2r, CUFFT_COMPATIBILITY_NATIVE));
CUFFT_CHECK(cufftExecR2C(planr2c, (cufftReal *)d_vx, d_vx));
CUFFT_CHECK(cufftExecC2R(planc2r, d_vx, (cufftReal *)d_vx));
CUDA_CHECK(cudaMemcpy(vx, d_vx, NX*NY*sizeof(cufftComplex), cudaMemcpyDeviceToHost));

[免责声明:用浏览器编写,绝不编译或测试,使用风险自负]

请注意,您需要调整主机代码以匹配输入和数据的大小和类型。

作为最后的评论,是否难以添加额外的8或10行所需的内容,以便将您发布的内容转换为有人试图帮助您使用的可编辑,可运行的示例?