CUDA 中 FFT 的使用
CUDA 中 FFT 的使用
@(10.CUDA)[CUDA,并行,fft]
1. 流程
- cufftPlan1d():針對單個 1 維信號
- cufftPlan2d():針對單個 2 維信號
- cufftPlan3d():針對單個 3 維信號
- cufftPlanMany():針對多個信號同時進行 fft
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():
- 第一個參數就是要配置的 cuFFT 句柄;
- 第二個參數為要進行 fft 的信號的長度;
- 第三個CUFFT_C2C為要執行 fft 的信號輸入類型及輸出類型都為復數;CUFFT_C2R表示輸入復數,輸出實數;CUFFT_R2C表示輸入實數,輸出復數;CUFFT_R2R表示輸入實數,輸出實數;
- 第四個參數BATCH表示要執行 fft 的信號的個數,新版的已經使用cufftPlanMany()來同時完成多個信號的 fft。
cufftExecC2C():
- 第一個參數就是配置好的 cuFFT 句柄;
- 第二個參數為輸入信號的首地址;
- 第三個參數為輸出信號的首地址;
- 第四個參數CUFFT_FORWARD表示執行的是 fft 正變換;CUFFT_INVERSE表示執行 fft 逆變換。
需要注意的是,執行完逆 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。
- plan:表示 cufft 句柄
- rank:表示進行 fft 的每個信號的維度數,一維信號為 1,二維信號為2,三維信號為 3 ,針對上圖,rank = 1
- n:表示進行 fft 的每個信號的行數,列數,頁數,必須用數組形式表示,例如假設要進行 fft 的每個信號的行、列、頁為(m, n, k),則 int n[rank] = {m, n, k};針對上圖,int n[1] = {5}
- inembed:表示輸入數據的[頁數,列數,行數],這是三維信號的情況;二維信號則為[列數,行數];一維信號為[行數];inembed[0] 這個參數會被忽略,也就是此處 inembed 可以為{0},{1},{2}等等。
- istride:表示每個輸入信號相鄰兩個元素的距離,在此處 istride = 16(每個信號相鄰兩個元素間的距離為16)
- idist:表示兩個連續輸入信號的起始元素之間的間隔,在此處為 idist = 1(第一個信號的第一個元素與第二個信號的第一個元素的間隔為1);如果把上圖數據的每一行看成一個信號,那么應該為 idist = 16;
- onembed:表示輸出數據的[頁數,列數,行數],這是三維信號的情況;二維信號則為[列數,行數];一維信號為[行數];onembed[0] 這個參數會被忽略,也就是此處 onembed 可以為{0},{1},{2}等等。
- ostride:表示每個輸出信號相鄰兩個元素的距離,在此處 ostride = 16(每個信號相鄰兩個元素間的距離為16)
- odist:表示兩個連續信號的起始元素之間的間隔,在此處為 odist = 1(第一個信號的第一個元素與第二個信號的第一個元素的間隔為1);如果把上圖數據的每一行看成一個信號,那么應該為 odist = 16;
如下所示:是第 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; // 一維 fftint n[rank] = { Nfft }; // 進行 fft 的信號的長度為 Nfftint 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<<<dimGrid2D_NXWITH0_Nfft, dimBlock2D>>>(data_dev, data_dev, 1.0f / Nfft); // 乘以系數cudaMemcpy(resultIFFT, data_dev, Nfft * NXWITH0 * sizeof(cufftComplex), cudaMemcpyDeviceToHost);完整代碼:GitHub
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的CUDA 中 FFT 的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java xml dom4j 解析_Ja
- 下一篇: Hibert变换