Как получить реальные и мнимые части сложной матрицы отдельно в CUDA?

0

Я пытаюсь получить fft двумерного массива. Вход представляет собой реальную матрицу NxM, поэтому выходная матрица также является матрицей NxM (2xNxM вывода 2xNxM которая является сложной, сохраняется в матрице 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",

  • 0
    Проще обдумать это, начав с комплексного преобразования, которое сохраняет размеры изображения: stackoverflow.com/questions/52744818/…
Теги:
matrix
cuda
fft

1 ответ

1
Лучший ответ

Ваш вопрос и ваш код не имеют для меня большого смысла.

  1. Вы выполняете пакетный FFT, но, похоже, вы не предвидели достаточного объема памяти ни для ввода, ни для выходных данных;
  2. Выход cufftExecR2C является NX*(NY/2+1) - NX*(NY+2) float NX*(NY/2+1) float2 матрица, которая может быть интерпретирована как NX*(NY+2) - NX*(NY+2) float матрицы. Соответственно, вы не выделяете достаточно места для c (который является только NX*NY float) для последнего cudaMemcpy. Вам понадобится еще одна сложная ячейка памяти для непрерывного компонента вывода;
  3. Ваш вопрос, похоже, не связан с командой cufftExecR2C, но является гораздо более общим: как я могу разбить сложную матрицу NX*NY на 2 реальные матрицы NX*NY содержащие соответственно действительную и мнимую части.

Если я правильно интерпретирую ваш вопрос, то решение, предложенное @njuffa at

Копирование данных в структуру данных "cufftComplex"?

может быть хорошей подсказкой для вас.

РЕДАКТИРОВАТЬ

Ниже приводится небольшой пример того, как "собрать" и "разобрать" реальную и мнимую части сложных векторов при копировании их с/на хост на/с устройства. Добавьте свою собственную проверку ошибок 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;
 } 
  • 0
    Как вы и предложили, я попробовал метод, предложенный по ссылке, которую вы дали. Я заменил устройство для размещения cudamemcpy. Я вошел как РЕДАКТИРОВАТЬ на мой вопрос. Но как только я это сделаю, я получу «Ошибка аргумента неверного тона» .....
  • 0
    Ваша претензия № 1: неверный размер входных данных? Ввод NX х NY матрицы с плавающей запятой. Поэтому sizeof (cufftComplex) * NX * (NY / 2 + 1) даст достаточно памяти, так как sizeof (cufftComplex) = 2 * sizeof (float). Не так ли? Я принимаю, что распределение памяти на выходе является неправильным.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню