【问题标题】:About cufft R2C and C2R关于袖带 R2C 和 C2R
【发布时间】:2017-01-16 04:58:46
【问题描述】:

我已经使用袖带进行研究,但是使用它时遇到了一些问题。我的步骤如下:

  1. 使用 R2C 对图像进行正向 FFT
  2. 将核系数与复数结果相乘
  3. 使用 C2R 对乘法结果进行逆 FFT

但是,当我使用复数结果乘核时,出现了一个严重的问题,cufft复数结果不等于fftw的结果,结果中有很多零。我知道 R2C 的结果大小是 N1(N2/2+1),但我想得到完整的复杂结果。如何解决这个问题呢?即如何恢复 R2C 结果?以及如何将相乘的结果放入C2R并得到正确答案?

我的实现程序代码如下:

__global__ void MultiplyKernel(cufftComplex *data, float *data1,cufftComplex *data2, unsigned vectorSize) {
    unsigned idx = blockIdx.x*blockDim.x+threadIdx.x;
    if (idx < vectorSize){
        data[idx].x = data2[idx].x*data1[idx];
        data[idx].y = data2[idx].y*data1[idx];
    }
}

__global__ void Scale(cufftReal *data, unsigned vectorSize) {
    unsigned idx = blockIdx.x*blockDim.x+threadIdx.x;
    if (idx < vectorSize){
        data[idx] = data[idx]/vectorSize;
    }
}

void ApplyKernel1(cufftReal *data2, float *ImageBuffer, float *KernelBuffer, unsigned int NX, unsigned int NY,unsigned int NZ)
{
      float *Akernel;
      cufftComplex *data_dev1, *data_dev2;
      cufftReal *data_dev3, *data_dev;
      cudaMalloc((void **)&Akernel, NX * NY * NZ * sizeof(float));
      cudaMalloc((void **)&data_dev3, NX * NY * NZ * sizeof(cufftReal));
      cudaMalloc((void **)&data_dev, NX * NY * NZ * sizeof(cufftComplex));
      cudaMalloc((void **)&data_dev1, NX * NY * NZ * sizeof(cufftComplex));
      cudaMalloc((void **)&data_dev2, NX * NY * NZ * sizeof(cufftComplex));
      cudaMemset(data_dev, 0, NX * NY * NZ * sizeof(cufftReal));
      cudaMemset(data_dev1, 0, NX * NY * NZ * sizeof(cufftComplex));
      cudaMemset(data_dev2, 0, NX * NY * NZ * sizeof(cufftComplex));
      //cufftComplex *resultFFT = (cufftComplex*)malloc(NX * NY * NZ * sizeof(cufftComplex));
      //cufftReal *resultIFFT = (cufftReal*)malloc(NX * NY * NZ * sizeof(cufftReal));

      cudaMemcpy(data_dev, ImageBuffer, NX * NY * NZ * sizeof(cufftReal), cudaMemcpyHostToDevice);

      cufftHandle plan;
      cufftPlan3d(&plan, NZ, NY, NX, CUFFT_R2C);
      cufftExecR2C(plan, data_dev, data_dev1);

      //Multiply kernel
      cudaMemcpy(Akernel, KernelBuffer, NX * NY * NZ * sizeof(float), cudaMemcpyHostToDevice);
      static const int BLOCK_SIZE = 1000;
      const int blockCount = (NX*NY*NZ+BLOCK_SIZE-1)/BLOCK_SIZE;
      MultiplyKernel <<<blockCount, BLOCK_SIZE>>> (data_dev2, Akernel, data_dev1, NX*NY*NZ);


      cufftDestroy(plan);
      //cufftPlan3d(&plan, NZ, NY, NX, CUFFT_C2R);
      cufftPlan3d(&plan, NZ,NY,NX, CUFFT_C2R);
      cufftExecC2R(plan, data_dev2, data_dev3 );
      Scale <<<blockCount, BLOCK_SIZE>>> (data_dev3, NX*NY*NZ);
      cudaMemcpy(data2, data_dev3, NZ * NY * NX * sizeof(cufftReal), cudaMemcpyDeviceToHost);

      cufftDestroy(plan);
      cudaFree(data_dev);
      cudaFree(data_dev1);
      cudaFree(data_dev2);
      cudaFree(data_dev3);
      cudaFree(Akernel);


}

【问题讨论】:

  • 您不明白 R2C 和 C2R 变换是对称的,因此 CUFFT 只计算了一半的解?
  • 为什么不把所有事情都用 C2C 操作来做?
  • 是的,我使用 C2C 通过将 data.y 设置为 0 来进行正向变换,并得到了正确的结果。但是,最后在乘以系数之后,我想进行反向变换以获得真正的结果,即 C2R(backward),我如何使用 cufft 库得到正确的答案? (注:我在C2C结果上乘了一些系数。)

标签: c++ cuda cufft


【解决方案1】:

当您将 R2C fft 的结果乘以复数时,结果不再对应于对称数组。

【讨论】:

  • 感谢您的回答,我问的是如何从R2C结果中得到与C2C结果相等的完整结果。我想要整个结果,因为我想将它乘以一些系数,你能帮帮我吗?
  • @KwuJohn 复数的个数是实数的一半,因为如果输入数组是实数,频率 n-k 的响应是频率 k 的响应的复共轭。如果您的过滤器不保留此属性,则过滤后的信号将不是纯真实的,使用 C2R 回到现实世界似乎有缺陷!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-21
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多