如何快速获得cufftcomplex幅度和相位

时间:2013-08-29 04:03:19

标签: cuda fft

我有一个cufftcomplex数据块,这是cuda fft(R2C)的结果。我知道数据被保存为一个带有实数后跟图像编号的结构。现在我想通过快速方式(不是循环)获得每个复杂元素的幅度= sqrt(R * R + I * I)和相位= arctan(I / R)。有没有好办法呢?或任何图书馆可以做到这一点?

1 个答案:

答案 0 :(得分:2)

由于cufftExecR2C对GPU上的数据进行操作,因此结果已经在GPU上(如果您正在执行此操作,则将它们复制回主机之前。)

编写自己的cuda内核来完成此任务应该是直截了当的。您描述的幅度是cuCabscuCabsf cuComplex.h头文件中返回的值。通过查看该头文件中的函数,您应该能够找出如何编写自己的函数来计算相位角。您会注意到cufftComplexjust a typedef of cuComplex

假设您的cufftExecR2C调用在大小为cufftComplex的数组data中留下了sz类型的一些结果。你的内核可能如下所示:

#include <math.h>
#include <cuComplex.h>
#include <cufft.h>
#define nTPB 256    // threads per block for kernel
#define sz 100000   // or whatever your output data size is from the FFT
...

__host__ __device__ float carg(const cuComplex& z) {return atan2(cuCimagf(z), cuCrealf(z));} // polar angle

__global__ void magphase(cufftComplex *data, float *mag, float *phase, int dsz){
  int idx = threadIdx.x + blockDim.x*blockIdx.x;
  if (idx < dsz){
    mag[idx]   = cuCabsf(data[idx]);
    phase[idx] = carg(data[idx]);
  }
}

...
int main(){
...
    /* Use the CUFFT plan to transform the signal in place. */
    /* Your code might be something like this already:      */
    if (cufftExecR2C(plan, (cufftReal*)data, data) != CUFFT_SUCCESS){
      fprintf(stderr, "CUFFT error: ExecR2C Forward failed");
      return;   
    }
    /* then you might add:                                  */
    float *h_mag, *h_phase, *d_mag, *d_phase;
    // malloc your h_ arrays using host malloc first, then...
    cudaMalloc((void **)&d_mag, sz*sizeof(float));
    cudaMalloc((void **)&d_phase, sz*sizeof(float));
    magphase<<<(sz+nTPB-1)/nTPB, nTPB>>>(data, d_mag, d_phase, sz);
    cudaMemcpy(h_mag, d_mag, sz*sizeof(float), cudaMemcpyDeviceToHost);
    cudaMemcpy(h_phase, d_phase, sz*sizeof(float), cudaMemcpyDeviceToHost);

您也可以使用thrust为幅度和相位函数创建仿函数,并将这些仿函数与datamagphase一起传递给{{{} 3}}

我确信你也可以使用thrust::transform,使用矢量加法和向量乘法运算的组合。

CUBLAS也可能会引起关注。我从那里解除了相位函数carg