CUDA中3D矩阵的列和行的1D FFT

时间:2014-11-13 20:47:27

标签: cuda cufft

我正在尝试使用cufftPlanMany计算批量1D FFT。数据集来自3D场,存储在一维阵列中,我想在xy方向计算一维FFT。数据存储如下图所示;继续x然后y然后z

x方向进行批量FFT是(我相信)直截了当;输入stride=1distance=nxbatch=ny * nz,它计算元素{0,1,2,3}{4,5,6,7}...{28,29,30,31}上的FFT。但是,我想不出一种方法可以在y方向上实现相同的FFT。每个xy平面的批次也很简单(输入stride=nxdist=1batch=nx会产生超过{0,4,8,12}的FFT,{1,5,9,13}等。 )。但是batch=nx * nz{3,7,11,15}转到{16,20,24,28},距离大于1。这可以用cufftPlanMany以某种方式完成吗?

enter image description here

2 个答案:

答案 0 :(得分:4)

我认为您的问题的简短答案(使用单个cufftPlanMany执行3D矩阵列的一维FFT的可能性)是否定的。

确实,根据cufftPlanMany执行的转换,您称之为

cufftPlanMany(&handle, rank, n, 
              inembed, istride, idist,
              onembed, ostride, odist, CUFFT_C2C, batch);

必须遵守Advanced Data Layout。特别是,根据以下布局计算出1D FFT

input[b * idist + x * istride]

其中b处理b - th信号,istride是同一信号中两个连续项之间的距离。如果3D矩阵具有维度M * N * Q,并且如果要沿列执行1D变换,则两个连续元素之间的距离将为M,而两个连续信号之间的距离将为{{1} }}。此外,批量执行的数量必须设置为1。使用这些参数,您只能覆盖3D矩阵的一个切片。实际上,如果你尝试增加M,那么cuFFT将开始尝试从第二行开始计算新的逐列FFT。解决此问题的唯一方法是迭代调用M以覆盖所有cufftExecC2C切片。

为了记录,以下代码提供了关于如何对3D矩阵的列执行1D FFT的完整工作示例。

Q

当您想要执行行的1D变换时,情况会有所不同。在这种情况下,两个连续元素之间的距离为#include <thrust/device_vector.h> #include <cufft.h> /********************/ /* CUDA ERROR CHECK */ /********************/ #define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); } inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true) { if (code != cudaSuccess) { fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line); if (abort) exit(code); } } int main() { const int M = 3; const int N = 4; const int Q = 2; thrust::host_vector<float2> h_matrix(M * N * Q); for (int k=0; k<Q; k++) for (int j=0; j<N; j++) for (int i=0; i<M; i++) { float2 temp; temp.x = (float)(j + k * M); //temp.x = 1.f; temp.y = 0.f; h_matrix[k*M*N+j*M+i] = temp; printf("%i %i %i %f %f\n", i, j, k, temp.x, temp.y); } printf("\n"); thrust::device_vector<float2> d_matrix(h_matrix); thrust::device_vector<float2> d_matrix_out(M * N * Q); // --- Advanced data layout // input[b * idist + x * istride] // output[b * odist + x * ostride] // b = signal number // x = element of the b-th signal cufftHandle handle; int rank = 1; // --- 1D FFTs int n[] = { N }; // --- Size of the Fourier transform int istride = M, ostride = M; // --- Distance between two successive input/output elements int idist = 1, odist = 1; // --- Distance between batches int inembed[] = { 0 }; // --- Input size with pitch (ignored for 1D transforms) int onembed[] = { 0 }; // --- Output size with pitch (ignored for 1D transforms) int batch = M; // --- Number of batched executions cufftPlanMany(&handle, rank, n, inembed, istride, idist, onembed, ostride, odist, CUFFT_C2C, batch); for (int k=0; k<Q; k++) cufftExecC2C(handle, (cufftComplex*)(thrust::raw_pointer_cast(d_matrix.data()) + k * M * N), (cufftComplex*)(thrust::raw_pointer_cast(d_matrix_out.data()) + k * M * N), CUFFT_FORWARD); cufftDestroy(handle); for (int k=0; k<Q; k++) for (int j=0; j<N; j++) for (int i=0; i<M; i++) { float2 temp = d_matrix_out[k*M*N+j*M+i]; printf("%i %i %i %f %f\n", i, j, k, temp.x, temp.y); } } ,而两个连续信号之间的距离为1。这允许您设置多个M转换,然后只调用N * Q一次。为了记录,下面的代码提供了3D矩阵行的1D变换的完整示例。

cufftExecC2C

答案 1 :(得分:-1)

我猜,idist = nx * nz也可以跳过整个平面,然后batch = nz会覆盖一个yx平面。应根据nx或nz是否更大来做出决定。