CUDA中 cuFFT的使用
1.流程
2.单个 1 维信号的 fft
假设要执行 fft的信号data_dev的长度为N,并且已经传输到 GPU显存中,data_dev数据的类型为cufftComplex,可以用一下方式产生主机段的data_dev,如下所示:
cufftComplex *data_Host = (cufftComplex*)malloc(NX*BATCH*sizeof(cufftComplex));// 主机端数据头指针
// 初始数据
for (int i =0; i < NX; i++)
{
data_Host[i].x =float((rand() *rand()) % NX) / NX;
data_Host[i].y =float((rand() *rand()) % NX) / NX;
}
然后用cudaMemcpy()将主机端的data_host拷贝到设备端的data_dev,即可用下述方法执行 fft :
cufftHandle plan;// 创建cuFFT句柄
cufftPlan1d(&plan, N, CUFFT_C2C, BATCH);
cufftExecC2C(plan, data_dev, data_dev, CUFFT_FORWARD);// 执行 cuFFT,正变换
cufftPlan1d():
cufftExecC2C():
需要注意的是,执行完逆 fft之后,要对信号中的每个值乘以 $\frac{1}{N}$
完整代码:GitHub
3. 多个 1维信号的 fft
要进行多个信号的 fft,就不得不使用 cufftPlanMany 函数,该函数的参数比较多,需要特别介绍,
cufftPlanMany(cufftHandle *plan,int rank, int *n,
int *inembed,int istride,int idist,
int *onembed,int ostride,int odist,
cufftType type,int batch);
为了叙述的更准确,此处先引入一个图,表示输入数据在内存中的布局,如下图所示,数据在内存中按行优先存储,但是现有的信号为一列表示一个信号,后四列灰白色的表示无关数据,要对前 12个彩色的列信号分别进行 fft。
如下所示:是第 b个信号的 [z][y][x](表示第 z 列,第 y 行,第 x页的元素)的索引(由于 c和 c++ 中数组的声明方式的问题,array[X][Y][Z]表示数组有 X页,Y 行,Z 列):
‣ 1D
input[ b * idist + x * istride ] output[ b * odist + x *ostride ]
‣ 2D
input[ b * idist + (x * inembed[1] + y) * istride ]output[ b * odist + (x * onembed[1] + y) * ostride ]
‣ 3D
input[b * idist + (x * inembed[1] * inembed[2] + y *inembed[2] + z) * istride] output[b * odist + (x * onembed[1] * onembed[2] + y* onembed[2] + z) * ostride]
/* 申请 cufft 句柄*/
cufftHandle plan_Nfft_Many;// 创建cuFFT句柄
constint rank =1; // 一维 fft
int n[rank] = { Nfft };// 进行 fft 的信号的长度为 Nfft
int inembed[1] = {0 }; // 输入数据的[页数,列数,行数](3维);[列数,行数](2维)
int onembed[1] = { 0 };// 输出数据的[页数,列数,行数];[列数,行数](2维)
int istride = NXWITH0;// 每个输入信号相邻两个元素的距离
int idist =1; // 每两个输入信号第一个元素的距离
int ostride = NXWITH0;// 每个输出信号相邻两个元素的距离
int odist =1; // 每两个输出信号第一个元素的距离
int batch = NX; // 进行 fft 的信号个数
cufftPlanMany(&plan_Nfft_Many, rank, n, inembed, istride, idist,onembed, ostride, odist, CUFFT_C2C, batch);
/* 核心部份 */
cudaMemcpy(data_dev, data_Host, Nfft * NXWITH0 *sizeof(cufftComplex), cudaMemcpyHostToDevice);
cufftExecC2C(plan_Nfft_Many, data_dev, data_dev, CUFFT_FORWARD);// 执行 cuFFT,正变换
cufftExecC2C(plan_Nfft_Many, data_dev, data_dev, CUFFT_INVERSE);// 执行 cuFFT,逆变换
CufftComplexScale<<
cudaMemcpy(resultIFFT, data_dev, Nfft * NXWITH0 *sizeof(cufftComplex), cudaMemcpyDeviceToHost);
完整代码:GitHub
参考