【问题标题】:How to get the real and imaginary parts of a complex matrix separately in CUDA?如何在CUDA中分别获取复数矩阵的实部和虚部?
【发布时间】:2014-01-15 09:18:27
【问题描述】:

我正在尝试获取二维数组的 fft。输入是NxM 实矩阵,因此输出矩阵也是NxM 矩阵(复数的2xNxM 输出矩阵使用Hermitian 对称性属性保存在NxM 矩阵中)。

所以我想知道在 cuda 中是否有提取方法来分别提取实数和复数矩阵?在 opencv 中,拆分功能负责。所以我正在cuda中寻找类似的功能,但我还没有找到。

下面是我的完整代码

#define NRANK 2
#define BATCH 10

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cufft.h>
#include <stdio.h> 

#include <iostream>
#include <vector>

using namespace std;

int main()
    { 

    const size_t NX = 4;
    const size_t NY = 5;

    // Input array - host side
     float b[NX][NY] ={ 
        {0.7943 ,   0.6020 ,   0.7482  ,  0.9133  ,  0.9961},
        {0.3112 ,   0.2630 ,   0.4505  ,  0.1524  ,  0.0782},
        {0.5285 ,   0.6541 ,   0.0838  ,  0.8258  ,  0.4427},
        {0.1656 ,   0.6892 ,   0.2290  ,  0.5383  ,  0.1067}
    };


    // Output array - host side
    float c[NX][NY] = { 0 };

    cufftHandle plan;
    cufftComplex *data; // Holds both the input and the output - device side
    int n[NRANK] = {NX, NY};

    // Allocated memory and copy from host to device
    cudaMalloc((void**)&data, sizeof(cufftComplex)*NX*(NY/2+1));
    for(int i=0; i<NX; ++i){
        // Uses this because my actual array is a dynamically allocated. 
        // but here I've replaced it with a static 2D array to make it simple.
        cudaMemcpy(reinterpret_cast<float*>(data) + i*NY, b[i], sizeof(float)*NY, cudaMemcpyHostToDevice);
     }

    // Performe the fft
    cufftPlanMany(&plan, NRANK, n,NULL, 1, 0,NULL, 1, 0,CUFFT_R2C,BATCH);
    cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE);
    cufftExecR2C(plan, (cufftReal*)data, data);
    cudaThreadSynchronize();
    cudaMemcpy(c, data, sizeof(float)*NX*NY, cudaMemcpyDeviceToHost);


    // Here c is a NxM matrix. I want to split it to 2 seperate NxM matrices with each   
    // having the complex and real component of the output

    // Here c is in 
    cufftDestroy(plan);
    cudaFree(data);

    return 0;
    }

编辑

根据 JackOLanter 的建议,我将代码修改如下。但是问题还是没有解决。

 float  real_vec[NX][NY] = {0};       // host vector, real part
 float  imag_vec[NX][NY] = {0};       // host vector, imaginary part
cudaError  cudaStat1 = cudaMemcpy2D (real_vec, sizeof(real_vec[0]), data,  sizeof(data[0]),NY*sizeof(float2), NX, cudaMemcpyDeviceToHost);
cudaError  cudaStat2 = cudaMemcpy2D (imag_vec, sizeof(imag_vec[0]),data + 1,  sizeof(data[0]),NY*sizeof(float2), NX, cudaMemcpyDeviceToHost);

我得到的错误是“无效的音高参数错误”。但我不明白为什么。对于目的地,我使用“float”的音高大小,而对于源,我使用“float2”的大小

【问题讨论】:

标签: c++ matrix cuda fft


【解决方案1】:

你的问题和你的代码对我来说没有多大意义。

  1. 您正在执行批处理 FFT,但您似乎没有预见到输入和输出数据都没有足够的内存空间;
  2. cufftExecR2C的输出是NX*(NY/2+1)float2矩阵,可以解释为NX*(NY+2)float矩阵。因此,您没有为最后一个cudaMemcpy 分配足够的空间给c(仅是NX*NYfloat)。对于输出的连续分量,您仍需要一个复杂的内存位置;
  3. 您的问题似乎与cufftExecR2C 命令无关,但更为笼统:如何将复杂的NX*NY 矩阵拆分为包含实部和虚部的2NX*NY 实矩阵,分别。

如果我正确解释了您的问题,那么@njuffa 提出的解决方案在

Copying data to “cufftComplex” data struct?

对你来说可能是一个很好的线索。

编辑

下面是一个小例子,说明在将复向量从主机复制到主机或从设备复制它们时如何“组装”和“分解”复矢量的实部和虚部。 请添加您自己的 CUDA 错误检查

#include <stdio.h>

#define N 16

int main() { 

    // Declaring, allocating and initializing a complex host vector
    float2* b = (float2*)malloc(N*sizeof(float2));
    printf("ORIGINAL DATA\n");
    for (int i=0; i<N; i++) {
        b[i].x = (float)i;
        b[i].y = 2.f*(float)i;
        printf("%f %f\n",b[i].x,b[i].y);
    }
    printf("\n\n");

    // Declaring and allocating a complex device vector
    float2 *data; cudaMalloc((void**)&data, sizeof(float2)*N);

    // Copying the complex host vector to device
    cudaMemcpy(data, b, N*sizeof(float2), cudaMemcpyHostToDevice);

    // Declaring and allocating space on the host for the real and imaginary parts of the complex vector
    float* cr = (float*)malloc(N*sizeof(float));       
    float* ci = (float*)malloc(N*sizeof(float));       

    /*******************************************************************/
    /* DISASSEMBLING THE COMPLEX DATA WHEN COPYING FROM DEVICE TO HOST */
    /*******************************************************************/
    float* tmp_d = (float*)data;

    cudaMemcpy2D(cr,        sizeof(float), tmp_d,    2*sizeof(float), sizeof(float), N, cudaMemcpyDeviceToHost);
    cudaMemcpy2D(ci,        sizeof(float), tmp_d+1,  2*sizeof(float), sizeof(float), N, cudaMemcpyDeviceToHost);

    printf("DISASSEMBLED REAL AND IMAGINARY PARTS\n");
    for (int i=0; i<N; i++)
        printf("cr[%i] = %f; ci[%i] = %f\n",i,cr[i],i,ci[i]);
    printf("\n\n");

    /******************************************************************************/
    /* REASSEMBLING THE REAL AND IMAGINARY PARTS WHEN COPYING FROM HOST TO DEVICE */
    /******************************************************************************/
    cudaMemcpy2D(tmp_d,     2*sizeof(float), cr, sizeof(float), sizeof(float), N, cudaMemcpyHostToDevice);
    cudaMemcpy2D(tmp_d + 1, 2*sizeof(float), ci, sizeof(float), sizeof(float), N, cudaMemcpyHostToDevice);

    // Copying the complex device vector to host
    cudaMemcpy(b, data, N*sizeof(float2), cudaMemcpyHostToDevice);
    printf("REASSEMBLED DATA\n");
    for (int i=0; i<N; i++) 
        printf("%f %f\n",b[i].x,b[i].y);
    printf("\n\n");

    getchar();

    return 0;
 } 

【讨论】:

  • 按照您的建议,我尝试了您提供的链接建议的方法。我更换了设备来托管 cudamemcpy。我已作为编辑输入我的问题。但是一旦我这样做了,我就会得到“无效的音高参数错误”.....
  • 您的第 1 项声明:输入数据大小是否错误?输入是 NX x NY 浮点矩阵。因此 sizeof(cufftComplex)*NX*(NY/2+1) 将提供足够的内存,因为 sizeof(cufftComplex) = 2*sizeof(float)。不是吗?我接受输出内存分配错误。
  • @Optimus 我添加了一个小示例,说明在将复杂数据从主机复制到主机或从设备复制时如何“组装”和“分解”复杂数据。希望对你有用。
  • 我的问题是关于二维数组。但是,通过幻灯片修改,这也可以用于 2D 数组。所以我把它标记为正确答案。
  • @Optimus 您可能希望注意,二维数组在存储到内存时会变平。所以,我认为你应该能够通过考虑N=NX*(NY/2+1),在上面为一维数组制定的答案中应用相同的方案。
猜你喜欢
  • 2016-02-20
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 2014-08-26
  • 2019-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多