【问题标题】:how to get cufftcomplex magnitude and phase fast如何快速获得 cufftcomplex 幅度和相位
【发布时间】:2013-08-30 06:05:41
【问题描述】:

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

【问题讨论】:

  • 这不是一个写得很清楚的问题。 “我有一个 cofftcomplex|sic] 块数据”是什么意思?这是否意味着您有一个内核,它在共享内存中具有块范围的一些数据,并且您想要一个设备函数来计算相位和幅度?还是别的什么?
  • 抱歉让您感到困惑。它是设备内存中的 cufftcomplex 数据块,是 cuda fft(R2C) 的结果。我想计算相位和幅度。

标签: cuda fft


【解决方案1】:

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

编写您自己的 cuda 内核来完成此操作应该很简单。您描述的幅度是cuCabscuCabsfcuComplex.h 头文件中返回的值。通过查看该头文件中的函数,您应该能够弄清楚如何编写自己的函数来计算相位角。你会注意到cufftComplexjust a typedef of cuComplex

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

#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 一起传递给thrust::transform

我相信您也可以使用CUBLAS 来实现,结合使用向量加法和向量乘法运算。

这个question/answer 可能也很有趣。我从那里提升了我的相位函数carg

【讨论】:

  • 只是好奇。实函数的傅里叶变换是 Hermitian。为了利用这种相似性,cufftExecR2C 函数仅在输出数组中存储非冗余傅里叶变换。您是否应该在内核启动大小sz 中考虑到这一点?
  • 可能。是不是没有计算在内?我没有在任何地方指定袖带计划的细节,这将确定 FFT 的输入和输出大小之间的关系。我只是说“在data 中留下大小sz 的结果”。你会怎么说呢?我应该删除#define sz 行以使其更清晰吗?随意编辑我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多