cufftHandle
创建句柄cufftPlan1d()
,cufftPlan3d()
,cufftPlan3d()
,cufftPlanMany()
对句柄进行配置,主要是配置句柄对应的信号长度,信号类型,在内存中的存储形式等信息。 cufftPlan1d()
:针对单个 1 维信号cufftPlan2d()
:针对单个 2 维信号cufftPlan3d()
:针对单个 3 维信号cufftPlanMany()
:针对多个信号同时进行 fftcufftExec()
函数执行 fftcufftDestroy()
函数释放 GPU 资源假设要执行 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()
:
CUFFT_C2C
为要执行 fft 的信号输入类型及输出类型都为复数;CUFFT_C2R
表示输入复数,输出实数;CUFFT_R2C
表示输入实数,输出复数;CUFFT_R2R
表示输入实数,输出实数;BATCH
表示要执行 fft 的信号的个数,新版的已经使用cufftPlanMany()
来同时完成多个信号的 fft。cufftExecC2C()
:
CUFFT_FORWARD
表示执行的是 fft 正变换;CUFFT_INVERSE
表示执行 fft 逆变换。需要注意的是,执行完逆 fft 之后,要对信号中的每个值乘以 1N
完整代码:GitHub
要进行多个信号的 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句柄
const int 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<<>>(data_dev, data_dev, 1.0f / Nfft); // 乘以系数
cudaMemcpy(resultIFFT, data_dev, Nfft * NXWITH0 * sizeof(cufftComplex), cudaMemcpyDeviceToHost);
完整代码:GitHub