2017-10-04 16 views
2

Matlabでは、複素数の1次元配列を入力すると、同じサイズと同じ次元の実数の配列を出力します。 これをCUDA Cで繰り返してみましたが、出力が異なります。 助けてもらえますか?方法:CUDA IFFT

[4.6500 + 0.0000i 0.5964 - 1.4325i 0.4905 - 0.5637i 0.4286 - 0.2976i 0.4345 - 0.1512i 0.4500 + 0.0000i 0.4345 + 0.1512i 0.4286 + 0.2976i 0.4905 + 0.5637i 0.5964 + 1.4325i] 

マイarrayOfRealNumbers::私は(配列)

マイarrayOfComplexNmbers IFFTを入力するとMATLABでは、私はMATLABでifft(arrayOfComplexNmbers)を入力すると

[ 0.9000 0.8000 0.7000 0.6000 0.5000 0.4000 0.3000 0.2000 0.1500 0.1000] 

は、私の出力はarrayOfRealNumbersです。 ありがとうございました!

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <cuda_runtime.h> 
#include <cufft.h> 
#include "device_launch_parameters.h" 
#include "device_functions.h" 

#define NX 256 
#define NY 128 
#define NRANK 2 
#define BATCH 1 
#define SIGNAL_SIZE 10 

typedef float2 Complex; 
__global__ void printCUDAVariables_1(cufftComplex *cudaSignal){ 
int index = threadIdx.x + blockIdx.x*blockDim.x;  
printf("COMPLEX CUDA %d %f %f \n", index, cudaSignal[index].x, cudaSignal[index].y); 
} 

__global__ void printCUDAVariables_2(cufftReal *cudaSignal){ 
int index = threadIdx.x + blockIdx.x*blockDim.x; 
printf("REAL CUDA %d %f \n", index, cudaSignal); 
} 


int main() { 
cufftHandle plan; 
//int n[NRANK] = { NX, NY }; 
Complex *h_signal = (Complex *)malloc(sizeof(Complex)* SIGNAL_SIZE); 
float *r_signal = 0; 
if (r_signal != 0){ 
    r_signal = (float*)realloc(r_signal, SIGNAL_SIZE * sizeof(float)); 
} 
else{ 
    r_signal = (float*)malloc(SIGNAL_SIZE * sizeof(float)); 
} 
int mem_size = sizeof(Complex)* SIGNAL_SIZE * 2; 

h_signal[0].x = (float)4.65; 
h_signal[0].y = (float)0; 

h_signal[1].x = (float)0.5964; 
h_signal[1].y = (float)0; 

h_signal[2].x = (float)4.65; 
h_signal[2].y = (float)-1.4325; 

h_signal[3].x = (float)0.4905; 
h_signal[3].y = (float)0.5637; 

h_signal[4].x = (float)0.4286; 
h_signal[4].y = (float)-0.2976; 

h_signal[5].x = (float)0.4345; 
h_signal[5].y = (float)-0.1512; 

h_signal[6].x = (float)0.45; 
h_signal[6].y = (float)0; 

h_signal[7].x = (float)0.4345; 
h_signal[7].y = (float)-0.1512; 

h_signal[8].x = (float)0.4286; 
h_signal[8].y = (float)0.2976; 

h_signal[9].x = (float)0.4905; 
h_signal[9].y = (float)-0.5637; 

h_signal[10].x = (float)0.5964; 
h_signal[10].y = (float)1.4325; 
//for (int i = 0; i < SIGNAL_SIZE; i++){ 
// printf("RAW %f %f\n", h_signal[i].x, h_signal[i].y); 
//} 
//allocate device memory for signal 
cufftComplex *d_signal, *d_signal_out; 
cudaMalloc(&d_signal, mem_size);  
cudaMalloc(&d_signal_out, mem_size); 
cudaMemcpy(d_signal, h_signal, mem_size, cudaMemcpyHostToDevice); 
printCUDAVariables_1 << <10, 1 >> >(d_signal); 
//cufftReal *odata; 
//cudaMalloc((void **)&odata, sizeof(cufftReal)*NX*(NY/2 + 1)); 

//cufftPlan1d(&plan, SIGNAL_SIZE, CUFFT_C2R, BATCH);  
cufftPlan1d(&plan, NX, CUFFT_C2C, BATCH); 
cufftExecC2C(plan, d_signal, d_signal_out, CUFFT_INVERSE); 
//cufftExecC2R(plan, d_signal, odata); 
cudaDeviceSynchronize(); 
printCUDAVariables_1 << <10, 1 >> >(d_signal_out); 
//printCUDAVariables_2 << <10, 1 >> >(odata); 
//cudaMemcpy(h_signal, d_signal_out, SIGNAL_SIZE*2*sizeof(float), cudaMemcpyDeviceToHost); 

cufftDestroy(plan); 
cudaFree(d_signal); 
cudaFree(d_signal_out); 

return 0; 
} 
+0

並行システムのほとんどは、スレッドの実行の順序を指定しないでください。これは基本的な概念であり、CUDAとは特に関係がありません。具体的には、スレッドがスレッドID(例えば、0,1,2、...、n_threads)の順番で実行されるという仮定は間違っています。 (1)ホストにデータをコピーしてそこに印刷する。 (2)CUDAに対する適切なエラーチェックを実装する(https://stackoverflow.com/questions/14038589/what-is-the-canonicalway-to-check-for-errors-using-the-cuda-runtime- api)および[cuFFT](http://docs.nvidia.com/cuda/cufft/index.html#cufftresult)APIを参照してください。その後、ビジネスを話すことができます。 – Drop

+0

ありがとうございますが、私のCUDA出力はMATLABとまったく異なります。私のコードを実行してください。この場合は、注文に関するものではなく、結果に関するものです。 – Talgat

答えて

4

MATLABとifftを計算し、デフォルトの動作は次のとおりです。: これは、このための私のCUDAコードである

  • 入力信号
  • 出力のスケーリングのないゼロパディングシグナル

あなたのCUFFTコードは正しいですが、MATLABと比較して少し異なるパラメータが現在の出力を引き起こしていますt。具体的には

  • NX定数は、入力信号がSIGNAL_SIZEに等しいNXを保つ、MATLABの動作を達成するために256の長さに ゼロパディングされたことが原因となっています。
  • CUFFTは、出力信号値に入力信号の長さを掛けます。実際の値を得るには、出力値をSIGNAL_SIZEで除算する必要があります。
  • もう1つの重要な問題は、入力信号の初期化時にアウトオブバウンドアクセスを実行していることです。シグナルの長さは10ですが、範囲外の10番目のインデックスで値を初期化しています。私はこれがMATLABの1ベースの索引付けに起因する混乱のためかもしれないと仮定します。入力信号は0からSIGNAL_SIZE-1インデックスのみで初期化する必要があります。
  • CUDAカーネルを使用して信号を視覚化することは、印刷物が故障している可能性があるため、推奨しません。結果をホストにコピーしてシリアルに出力する必要があります。

ここには、MATLABと同じ出力を提供する固定コードがあります。

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <cuda_runtime.h> 
#include <cufft.h> 
#include "device_launch_parameters.h" 
#include "device_functions.h" 

#define NX 10 
#define NY 1 
#define NRANK 1 
#define BATCH 1 
#define SIGNAL_SIZE 10 

typedef float2 Complex; 

int main() 
{ 
cufftHandle plan; 
//int n[NRANK] = { NX, NY }; 
Complex *h_signal = (Complex *)malloc(sizeof(Complex)* SIGNAL_SIZE); 
float *r_signal = 0; 
if (r_signal != 0) 
{ 
    r_signal = (float*)realloc(r_signal, SIGNAL_SIZE * sizeof(float)); 
} 
else 
{ 
    r_signal = (float*)malloc(SIGNAL_SIZE * sizeof(float)); 
} 
int mem_size = sizeof(Complex)* SIGNAL_SIZE; 

h_signal[0].x = (float)4.65; 
h_signal[0].y = (float)0; 

h_signal[1].x = (float)0.5964; 
h_signal[1].y = (float)-1.4325; 

h_signal[2].x = (float)0.4905; 
h_signal[2].y = (float)-0.5637; 

h_signal[3].x = (float)0.4286; 
h_signal[3].y = (float)-0.2976; 

h_signal[4].x = (float)0.4345; 
h_signal[4].y = (float)-0.1512; 

h_signal[5].x = (float)0.45; 
h_signal[5].y = (float)0.0; 

h_signal[6].x = (float)0.4345; 
h_signal[6].y = (float)0.1512; 

h_signal[7].x = (float)0.4286; 
h_signal[7].y = (float)0.2976; 

h_signal[8].x = (float)0.4905; 
h_signal[8].y = (float)0.5637; 

h_signal[9].x = (float)0.5964; 
h_signal[9].y = (float)1.4325; 

printf("\nInput:\n"); 
for(int i=0; i<SIGNAL_SIZE; i++) 
{ 
    char op = h_signal[i].y < 0 ? '-' : '+'; 
    printf("%f %c %fi\n", h_signal[i].x/SIGNAL_SIZE, op, fabsf(h_signal[i].y/SIGNAL_SIZE)); 
} 

//allocate device memory for signal 
cufftComplex *d_signal, *d_signal_out; 
cudaMalloc(&d_signal, mem_size);  
cudaMalloc(&d_signal_out, mem_size); 
cudaMemcpy(d_signal, h_signal, mem_size, cudaMemcpyHostToDevice); 


//cufftPlan1d(&plan, SIGNAL_SIZE, CUFFT_C2R, BATCH);  
cufftPlan1d(&plan, NX, CUFFT_C2C, BATCH); 

cufftExecC2C(plan, d_signal, d_signal_out, CUFFT_INVERSE); 

cudaDeviceSynchronize(); 

cudaMemcpy(h_signal, d_signal_out, SIGNAL_SIZE*sizeof(Complex), cudaMemcpyDeviceToHost); 


printf("\n\n-------------------------------\n\n"); 
printf("Output:\n"); 
for(int i=0; i<SIGNAL_SIZE; i++) 
{ 
    char op = h_signal[i].y < 0 ? '-' : '+'; 
    printf("%f %c %fi\n", h_signal[i].x/SIGNAL_SIZE, op, fabsf(h_signal[i].y/SIGNAL_SIZE)); 
} 

cufftDestroy(plan); 
cudaFree(d_signal); 
cudaFree(d_signal_out); 

return 0; 
} 

出力はまだ複雑ですが、虚数成分はゼロに近い値です。また、実際のコンポーネントの精度の違いは、このコードは単精度値に基づいていますが、MATLABはデフォルトで倍精度を使用するためです。


コンパイルとUbuntu 14.04で次のコマンドを使用してテスト

、CUDA 8.0:

NVCC -o IFFT IFFT。cu -arch = sm_61 -lcufft

MATLAB 2017aとの比較出力。

プログラム出力:

Input: 
0.465000 + 0.000000i 
0.059640 - 0.143250i 
0.049050 - 0.056370i 
0.042860 - 0.029760i 
0.043450 - 0.015120i 
0.045000 + 0.000000i 
0.043450 + 0.015120i 
0.042860 + 0.029760i 
0.049050 + 0.056370i 
0.059640 + 0.143250i 


------------------------------- 

Output: 
0.900000 - 0.000000i 
0.800026 - 0.000000i 
0.699999 - 0.000000i 
0.599964 - 0.000000i 
0.500011 + 0.000000i 
0.400000 + 0.000000i 
0.299990 + 0.000000i 
0.199993 + 0.000000i 
0.150000 + 0.000000i 
0.100018 - 0.000000i 
関連する問題