2017-08-07 2 views
0

J'ai un problème. J'essaie d'apprendre OpenCl, donc j'ai essayé d'implémenter l'algorithme FFT avec OpenCl. Je tentais de recréer ceci:Les résultats de l'implémentation de l'algorithme OpenCl diffèrent

void FFT (cmplx* data, int dataSize){ 
    if(dataSize == 1){ 
     return; 
    }else{ 
     cmplx* even = (cmplx*)malloc(dataSize/2*sizeof(cmplx)); 
     cmplx* odd = (cmplx*)malloc(dataSize/2*sizeof(cmplx)); 
     for (int i = 0;i<dataSize;i+=2){ 
      even[i/2] = data[i]; 
      odd[i/2] = data[i+1]; 
     } 

     FFT(even,dataSize/2); 
     FFT(odd,dataSize/2); 

     for (int i = 0;i<dataSize;i++){ 
      cmplx C = cmplx(-2*M_PI/dataSize*i); 
      data[i].real = even[i].real + C.real*odd[i].real - C.imag*odd[i].imag; 
      data[i].imag = even[i].imag + C.real*odd[i].imag + C.imag*odd[i].real; 
     } 
    } 
} 

CMPLX est juste une classe qui détient deux flotteurs parties réelles et imaginaires de nombre complexe et a un constructeur qui crée nombre complexe avec l'équation d'Euler. et tout le reste est tout à fait tout droit

Je probablement ne sais pas une petite nuance, dans ma compréhension, je peux faire le calcul du cycle dans des threads indépendants afin cycles comme ceci:

for (int i = 0;i<dataSize;i++){ 
    cmplx C = cmplx(-2*M_PI/dataSize*i); 
    data[i].real = even[i].real + C.real*odd[i].real - C.imag*odd[i].imag; 
    data[i].imag = even[i].imag + C.real*odd[i].imag + C.imag*odd[i].real; 
} 

Avec le code OpenCL comme ceci:

__kernel void FFTComplexSum(__global float *evenReal,__global float *evenImag, 
         __global float *oddReal,__global float *oddImag, 
         __global float *real,__global float *imag, 
         __global float *C){ 
    int gid = get_global_id(0); 
    real[gid] = evenReal[gid] + cos(C[gid])*oddReal[gid] - sin(C[gid])*oddImag[gid]; 
    imag[gid] = evenImag[gid] + cos(C[gid])*oddImag[gid] + sin(C[gid])*oddReal[gid]; 
} 

Mais si exécuter ce:

.... // instantiating stuff like platform, device_id, kernel, program... 
    size_t buffer_size; 
    cl_mem evenReal_mem, evenImag_mem, oddReal_mem, oddImag_mem, real_mem, imag_mem, c_mem; 

    float evenReal[dataSize]; 
    float evenImag[dataSize]; 
    float tReal[dataSize]; 
    float tImag[dataSize]; 
    float oddReal[dataSize]; 
    float oddImag[dataSize]; 
    float C[dataSize]; 

    for (int i = 0;i<dataSize;i+=2){ 
     evenReal[i/2] = real[i]; 
     evenImag[i/2] = imag[i]; 
     oddReal[i/2] = real[i+1]; 
     oddImag[i/2] = imag[i+1]; 
     C[i] = -2*M_PI/dataSize*i; 
     C[i+1] = -2*M_PI/dataSize*(i+1); 
    } 

    doubleArray(evenReal,dataSize); // doubleArray function just makes array to loop 
    doubleArray(evenImag,dataSize); 

    doubleArray(oddReal,dataSize); 
    doubleArray(oddImag,dataSize); 

    buffer_size = sizeof(float) * dataSize; 

    evenReal_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, evenReal_mem, CL_TRUE, 0, buffer_size,(void*)evenReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    evenImag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, evenImag_mem, CL_TRUE, 0, buffer_size,(void*)evenImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    oddReal_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, oddReal_mem, CL_TRUE, 0, buffer_size,(void*)oddReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    oddImag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, oddImag_mem, CL_TRUE, 0, buffer_size,(void*)oddImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    real_mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, real_mem, CL_TRUE, 0, buffer_size,(void*)real, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    imag_mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, imag_mem, CL_TRUE, 0, buffer_size,(void*)imag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    c_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float), NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, c_mem, CL_TRUE, 0, sizeof(float),(void*)C, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    clFinish(cmd_queue); 

    err = clSetKernelArg(kernel[0], 0, sizeof(cl_mem), &evenReal_mem); 
    err = clSetKernelArg(kernel[0], 1, sizeof(cl_mem), &evenImag_mem); 
    err = clSetKernelArg(kernel[0], 2, sizeof(cl_mem), &oddReal_mem); 
    err = clSetKernelArg(kernel[0], 3, sizeof(cl_mem), &oddImag_mem); 
    err = clSetKernelArg(kernel[0], 4, sizeof(cl_mem), &real_mem); 
    err = clSetKernelArg(kernel[0], 5, sizeof(cl_mem), &imag_mem); 
    err = clSetKernelArg(kernel[0], 6, sizeof(cl_mem), &c_mem); 
    assert(err == CL_SUCCESS); // Fail check 

    size_t global_work_size = dataSize; 
    err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 1, NULL, &global_work_size, NULL, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 

    printf("test data:\n"); 

    for (int i = 0;i<dataSize;i++){ 
     float r,I; 
     r = evenReal[i] + cos(C[i])*oddReal[i] - sin(C[i])*oddImag[i]; 
     I = evenImag[i] + cos(C[i])*oddImag[i] + sin(C[i])*oddReal[i]; 
     printf("%f + %f\n",r,I); 
    } 

    err = clEnqueueReadBuffer(cmd_queue, real_mem, CL_TRUE, 0, buffer_size, tReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 
    err = clEnqueueReadBuffer(cmd_queue, imag_mem, CL_TRUE, 0, buffer_size, tImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 

    clReleaseMemObject(evenReal_mem); 
    clReleaseMemObject(evenImag_mem); 
    clReleaseMemObject(oddReal_mem); 
    clReleaseMemObject(oddImag_mem); 
    clReleaseMemObject(real_mem); 
    clReleaseMemObject(imag_mem); 
    clReleaseMemObject(c_mem); 

    prinf("data:"); 

    for (int i = 0;i<dataSize;i++){ 
     printf("%f + %f\n",tReal[i],tImag[i]); 
    } 

Il r Je répète:

test data: 
1.000000 + 0.000000 
0.000000 + 1.000000 
-1.000000 + 0.000000 
-0.000000 + -1.000000 
data: 
1.000000 + 0.000000 
-1.000000 + 0.000000 
1.000000 + 0.000000 
-1.000000 + 0.000000 

Suis-je vraiment confus pourquoi je reçois des mauvaises réponses. Il me manque quelque chose de vraiment évident?

Désolé pour une longue question.

Répondre

0

c_mem a le problème.

Vous accédez à C comme C[gid] dans le noyau mais vous l'avez créé avec la taille de sizeof(float) uniquement. Les données principales ne peuvent donc pas tenir dans cet espace mémoire (4 octets) et vous n'écrivez que 4 octets. Multiplier à la fois sa taille de création et sa taille d'écriture avec data_size devrait suffire.

C'est pourquoi les valeurs réelles obtiennent 1 et -1 tandis que les imaginaires obtiennent zéro (sin (0)). Si vous aviez de la chance, le débordement de C donnerait des ordures et donnerait à la fois des éléments réels et imaginaires, ce qui montrerait immédiatement la source de l'erreur.

+0

Omg ... Je suis gêné de ne pas voir ça ... Merci. –