Main Content

FFT の例

この例では、2 次元フーリエ変換を光マスクに対して使用して、その回折パターンを計算する方法について説明します。小さな円形の開口部を持つ光マスクを定義する logical 配列を作成します。

n = 2^10;                 % size of mask
M = zeros(n);
I = 1:n; 
x = I-n/2;                % mask x-coordinates 
y = n/2-I;                % mask y-coordinates
[X,Y] = meshgrid(x,y);    % create 2-D mask grid
R = 10;                   % aperture radius
A = (X.^2 + Y.^2 <= R^2); % circular aperture of radius R
M(A) = 1;                 % set mask elements inside aperture to 1
figure
imagesc(M)                % plot mask
axis image

DP = fftshift(fft2(M));
imagesc(abs(DP))
axis image

カーネル作成用の myFFT の準備

関数 fft2 を使用してマスクの 2 次元フーリエ変換を計算するエントリポイント関数 myFFT を作成します。関数 fftshift を使用して、ゼロ周波数成分が中央になるように出力を再配列します。この関数を GPU カーネルにマッピングするには、coder.gpu.kernelfun プラグマをこの関数内に配置します。

function [DP] = myFFT(M)

coder.gpu.kernelfun();

DP = fftshift(fft2(M));

生成された CUDA コード

CUDA® コードを生成すると、GPU Coder™ は cuFFT ライブラリを初期化する関数呼び出し (cufftEnsureInitialization) を作成し、FFT 演算を実行して、cuFFT ライブラリで使用されたハードウェア リソースを解放します。生成された CUDA コードのスニペットは次のとおりです。

void myFFT(myFFTStackData *SD, const real_T M[1048576], creal_T DP[1048576])
 {
  ...
  cudaMemcpy((void *)gpu_M, (void *)M, 8388608ULL, cudaMemcpyHostToDevice);
  myFFT_kernel1<<<dim3(2048U, 1U, 1U), dim3(512U, 1U, 1U)>>>(gpu_M, gpu_b);
  cufftEnsureInitialization(1024, CUFFT_D2Z, 1024, 1024);
  cufftExecD2Z(*cufftGlobalHandlePtr, (cufftDoubleReal *)&gpu_b[0],
               (cufftDoubleComplex *)&gpu_y1[0]);
  ...
  myFFT_kernel2<<<dim3(2048U, 1U, 1U), dim3(512U, 1U, 1U)>>>(gpu_y1, gpu_y);
  cufftEnsureInitialization(1024, CUFFT_Z2Z, 1024, 1024);
  cufftExecZ2Z(*cufftGlobalHandlePtr, (cufftDoubleComplex *)&gpu_y[0],
               (cufftDoubleComplex *)&gpu_DP[0], CUFFT_FORWARD);
  ...
  cufftEnsureDestruction();
  ...
 }

1 番目の関数 cudaMemcpy の呼び出しは、1024 行 1024 列の double 値入力 M を GPU メモリに転送します。myFFT_kernel1 カーネルは、cuFFT ライブラリの呼び出し前に、入力データの前処理を実行します。2 次元フーリエ変換の呼び出し fft2fft(fft(M).').' を計算することに相当します。バッチ変換は一般的に単一の変換よりもパフォーマンスが高くなるため、GPU Coder では 2 つの 1 次元 cuFFT 呼び出し cufftExecD2Z および cufftExecZ2Z が使用されます。cufftExecD2Z で入力 M について倍精度の実数から複素数へのフォワード変換を計算した後、cufftExecZ2Z でその結果について倍精度の複素数から複素数への変換を実行します。cufftEnsureDestruction() 呼び出しは、cuFFT ライブラリの呼び出しに関連付けられた GPU リソースを破棄して解放します。