Cuda 如何快速获得复振幅和相位

Cuda 如何快速获得复振幅和相位,cuda,fft,Cuda,Fft,我有一个CuftComplex数据块,它是cuda fft(R2C)的结果。我知道数据保存为一个结构,后面跟一个实数,后面跟一个图像编号。现在我想用一种快速的方法(不是循环)得到每个复元素的振幅=sqrt(R*R+i*i),相位=arctan(i/R)。有什么好办法吗?或者任何库都可以这样做?因为cufftExecR2C对GPU上的数据进行操作,所以结果已经在GPU上了(在您将它们复制回主机之前,如果您这样做的话) 编写自己的cuda内核来实现这一点应该很简单。您描述的振幅是cuCabs或cuC

我有一个CuftComplex数据块,它是cuda fft(R2C)的结果。我知道数据保存为一个结构,后面跟一个实数,后面跟一个图像编号。现在我想用一种快速的方法(不是循环)得到每个复元素的振幅=sqrt(R*R+i*i),相位=arctan(i/R)。有什么好办法吗?或者任何库都可以这样做?

因为
cufftExecR2C
对GPU上的数据进行操作,所以结果已经在GPU上了(在您将它们复制回主机之前,如果您这样做的话)

编写自己的cuda内核来实现这一点应该很简单。您描述的振幅是
cuCabs
cuCabsf
cuComplex.h
头文件中返回的值。通过查看该头文件中的函数,您应该能够了解如何编写自己的计算相位角的函数。您会注意到
cufftComplex
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);
#包括
#包括
#包括
#为内核定义每个块的nTPB 256//线程
#定义sz 100000//或FFT输出数据的大小
...
__主机设备浮点数(const-cuComplex&z){return atan2(cuCimagf(z),cucreaf(z))}//极角
__全局无效磁相(袖口复杂*数据、浮点*磁相、浮点*相位、整数dsz){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
if(idx
您还可以使用为幅值和相位函数创建函子,并将这些函子与
数据
mag
相位
一起传递到

我相信您也可以使用向量加法和向量乘法操作的组合来完成


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

因为
cufftExecR2C
对GPU上的数据进行操作,所以结果已经在GPU上了(如果您这样做的话,在将它们复制回主机之前)

编写自己的cuda内核来实现这一点应该很简单。您描述的振幅是
cuCabs
cuCabsf
cuComplex.h
头文件中返回的值。通过查看该头文件中的函数,您应该能够弄清楚如何编写自己的值来计算p相位角。您会注意到
cuftcomplex
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);
#包括
#包括
#包括
#为内核定义每个块的nTPB 256//线程
#定义sz 100000//或FFT输出数据的大小
...
__主机设备浮点数(const-cuComplex&z){return atan2(cuCimagf(z),cucreaf(z))}//极角
__全局无效磁相(袖口复杂*数据、浮点*磁相、浮点*相位、整数dsz){
int idx=threadIdx.x+blockDim.x*blockIdx.x;
if(idx
您还可以使用为幅值和相位函数创建函子,并将这些函子与
数据
mag
相位
一起传递到

我相信您也可以使用向量加法和向量乘法操作的组合来完成


这可能也是一个有趣的问题。我从那里提取了相位函数
carg

这不是一个写得很清楚的问题。你说“我有一个cofftcomplex | sic]块数据”是什么意思?这是否意味着您的内核在共享内存中具有块作用域某些数据,并且您想要一个用于计算相位和幅度的设备函数?或者其他东西?很抱歉让您感到困惑。这是设备内存中的袖口复杂数据块,是cuda fft(R2C)的结果.我想计算相位和幅度。这不是一个写得很清楚的问题。你说的“我有一个cofftcomplex | sic]块数据”是什么意思?这是否意味着你有一个内核,它在共享内存中有块作用域一些数据,你想要一个de