CUFFT: Как рассчитать FFT, когда входной сигнал представляет собой тональный массив

Я пытаюсь найти FFT динамически распределенного массива. Входной массив копируется с хоста на устройство с помощью cudaMemcpy2D, Затем берется fft (cufftExecR2C) и результаты копируются обратно с устройства на хост.

Поэтому моя первоначальная проблема заключалась в том, как использовать информацию о высоте тона в FFT. Тогда я нашел ответ здесь — CUFFT: Как рассчитать FFT наклонного указателя?

Но, к сожалению, это не работает. Результаты, которые я получаю, являются значениями мусора. Ниже приведен мой код.

#define NRANK 2
#define BATCH 10

#include "cuda_runtime.h"#include "device_launch_parameters.h"#include <cufft.h>
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <vector>

using namespace std;

const size_t NX = 4;
const size_t NY = 6;

int main()
{
// Input array (static) - host side
float h_in_data_static[NX][NY] ={
{0.7943 ,   0.6020 ,   0.7482  ,  0.9133  ,  0.9961 , 0.9261},
{0.3112 ,   0.2630 ,   0.4505  ,  0.1524  ,  0.0782 ,  0.1782},
{0.5285 ,   0.6541 ,   0.0838  ,  0.8258  ,  0.4427,  0.3842},
{0.1656 ,   0.6892 ,   0.2290  ,  0.5383  ,  0.1067,  0.1712}
};

// --------------------------------
// Input array (dynamic) - host side
float *h_in_data_dynamic = new float[NX*NY];

// Set the values
size_t h_ipitch;
for (int r = 0; r < NX; ++r)  // this can be also done on GPU
{
for (int c = 0; c < NY; ++c)
{   h_in_data_dynamic[NY*r + c] = h_in_data_static[r][c];   }
}
// --------------------------------

// Output array - host side
float2 *h_out_data_temp = new float2[NX*(NY/2+1)] ;// Input and Output array - device side
cufftHandle plan;
cufftReal *d_in_data;
cufftComplex * d_out_data;
int n[NRANK] = {NX, NY};

//  Copy input array from Host to Device
size_t ipitch;
cudaError  cudaStat1 =  cudaMallocPitch((void**)&d_in_data,&ipitch,NY*sizeof(cufftReal),NX);
cout << cudaGetErrorString(cudaStat1) << endl;
cudaError  cudaStat2 =  cudaMemcpy2D(d_in_data,ipitch,h_in_data_dynamic,NY*sizeof(float),NY*sizeof(float),NX,cudaMemcpyHostToDevice);
cout << cudaGetErrorString(cudaStat2) << endl;

//  Allocate memory for output array - device side
size_t opitch;
cudaError  cudaStat3 =  cudaMallocPitch((void**)&d_out_data,&opitch,(NY/2+1)*sizeof(cufftComplex),NX);
cout << cudaGetErrorString(cudaStat3) << endl;

//  Performe the fft
int rank = 2; // 2D fft
int istride = 1, ostride = 1; // Stride lengths
int idist = 1, odist = 1;     // Distance between batches
int inembed[] = {ipitch, NX}; // Input size with pitch
int onembed[] = {opitch, NX}; // Output size with pitch
int batch = 1;
cufftPlanMany(&plan, rank, n, inembed, istride, idist, onembed, ostride, odist, CUFFT_R2C, batch);
//cufftPlan2d(&plan, NX, NY , CUFFT_R2C);
cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE);
cufftExecR2C(plan, d_in_data, d_out_data);
cudaThreadSynchronize();

// Copy d_in_data back from device to host
cudaError  cudaStat4 = cudaMemcpy2D(h_out_data_temp,(NY/2+1)*sizeof(float2), d_out_data, opitch, (NY/2+1)*sizeof(cufftComplex), NX, cudaMemcpyDeviceToHost);
cout << cudaGetErrorString(cudaStat4) << endl;

// Print the results
for (int i = 0; i < NX; i++)
{
for (int j =0 ; j< NY/2 + 1; j++)
printf(" %f + %fi",h_out_data_temp[i*(NY/2+1) + j].x ,h_out_data_temp[i*(NY/2+1) + j].y);
printf("\n");
}
cudaFree(d_in_data);

return 0;
}

Я думаю, что проблема в cufftPlanMany, Как я могу решить эту проблему?

2

Решение

Вы можете изучить расширенный раздел макета данных документации тщательно.

Я думаю, что предыдущий вопрос, который был связан, несколько сбивает с толку, потому что этот вопрос проходит width а также height параметры в обратном порядке для того, что я ожидал бы для 2D плана плана. Однако тогда ответ имитирует этот порядок, поэтому он по меньшей мере последовательный.

Во-вторых, в предыдущем вопросе вы пропустили, что передаваемые параметры «основного тона» inembed а также onembed являются не то же самое в качестве параметров высоты тона, которые вы получите от cudaMallocPitch операция. Они должны быть масштабированы по количеству байтов на элемент данных во входных и выходных наборах данных. Я на самом деле не совсем уверен, что это предполагаемое использование inembed а также onembed параметры, но похоже на работу.

Когда я настраиваю ваш код для учета двух вышеупомянутых изменений, я, кажется, получаю действительные результаты, по крайней мере, они находятся в разумных пределах. Вы опубликовали несколько вопросов о 2D БПФ, в которых вы сказали, что результаты неверны. Я не могу сделать эти 2D БПФ в моей голове, поэтому я предлагаю вам в будущем указать, какие данные вы ожидаете.

Это имеет изменения, которые я сделал:

#define NRANK 2
#define BATCH 10

#include "cuda_runtime.h"#include "device_launch_parameters.h"#include <cufft.h>
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <vector>

using namespace std;

const size_t NX = 4;
const size_t NY = 6;

int main()
{
// Input array (static) - host side
float h_in_data_static[NX][NY] ={
{0.7943 ,   0.6020 ,   0.7482  ,  0.9133  ,  0.9961 , 0.9261},
{0.3112 ,   0.2630 ,   0.4505  ,  0.1524  ,  0.0782 ,  0.1782},
{0.5285 ,   0.6541 ,   0.0838  ,  0.8258  ,  0.4427,  0.3842},
{0.1656 ,   0.6892 ,   0.2290  ,  0.5383  ,  0.1067,  0.1712}
};

// --------------------------------
// Input array (dynamic) - host side
float *h_in_data_dynamic = new float[NX*NY];

// Set the values
size_t h_ipitch;
for (int r = 0; r < NX; ++r)  // this can be also done on GPU
{
for (int c = 0; c < NY; ++c)
{   h_in_data_dynamic[NY*r + c] = h_in_data_static[r][c];   }
}
// --------------------------------
int owidth = (NY/2)+1;

// Output array - host side
float2 *h_out_data_temp = new float2[NX*owidth] ;// Input and Output array - device side
cufftHandle plan;
cufftReal *d_in_data;
cufftComplex * d_out_data;
int n[NRANK] = {NX, NY};

//  Copy input array from Host to Device
size_t ipitch;
cudaError  cudaStat1 =  cudaMallocPitch((void**)&d_in_data,&ipitch,NY*sizeof(cufftReal),NX);
cout << cudaGetErrorString(cudaStat1) << endl;
cudaError  cudaStat2 =  cudaMemcpy2D(d_in_data,ipitch,h_in_data_dynamic,NY*sizeof(float),NY*sizeof(float),NX,cudaMemcpyHostToDevice);
cout << cudaGetErrorString(cudaStat2) << endl;

//  Allocate memory for output array - device side
size_t opitch;
cudaError  cudaStat3 =  cudaMallocPitch((void**)&d_out_data,&opitch,owidth*sizeof(cufftComplex),NX);
cout << cudaGetErrorString(cudaStat3) << endl;

//  Performe the fft
int rank = 2; // 2D fft
int istride = 1, ostride = 1; // Stride lengths
int idist = 1, odist = 1;     // Distance between batches
int inembed[] = {NX, ipitch/sizeof(cufftReal)}; // Input size with pitch
int onembed[] = {NX, opitch/sizeof(cufftComplex)}; // Output size with pitch
int batch = 1;
if ((cufftPlanMany(&plan, rank, n, inembed, istride, idist, onembed, ostride, odist, CUFFT_R2C, batch)) != CUFFT_SUCCESS) cout<< "cufft error 1" << endl;
//cufftPlan2d(&plan, NX, NY , CUFFT_R2C);
if ((cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE)) != CUFFT_SUCCESS) cout << "cufft error 2" << endl;
if ((cufftExecR2C(plan, d_in_data, d_out_data)) != CUFFT_SUCCESS) cout << "cufft error 3" << endl;
cudaDeviceSynchronize();

// Copy d_in_data back from device to host
cudaError  cudaStat4 = cudaMemcpy2D(h_out_data_temp,owidth*sizeof(float2), d_out_data, opitch, owidth*sizeof(cufftComplex), NX, cudaMemcpyDeviceToHost);
cout << cudaGetErrorString(cudaStat4) << endl;

// Print the results
for (int i = 0; i < NX; i++)
{
for (int j =0 ; j< owidth; j++)
printf(" %f + %fi",h_out_data_temp[i*owidth + j].x ,h_out_data_temp[i*owidth + j].y);
printf("\n");
}
cudaFree(d_in_data);

return 0;
}
7

Другие решения

Других решений пока нет …