CUDA FFT ライブラリを使用した回折パターンのシミュレーション
この例では、GPU Coder™ を使って CUDA® Fast Fourier Transform library (cuFFT) を利用し、NVIDIA® GPU で 2 次元 FFT を計算する方法を示します。2 次元フーリエ変換は、遠視野回折パターンを計算するために光学において使用されます。Young の二重スリット実験のように、単色光源の光が小さな開口部を通過するときに、こうした回折パターンを観測できます。この例では、CUDA MEX、ソース コード、スタティック ライブラリ、ダイナミック ライブラリ、および実行可能ファイルを生成する際に GPU 入力をエントリポイント関数に渡す方法も示します。この機能を使用すると、生成コード内での cudaMemcpy 呼び出しの数が最小化され、その生成コードのパフォーマンスが向上します。
サードパーティの前提条件
必要
この例では、CUDA MEX を生成します。以下のサードパーティ要件が適用されます。
CUDA 対応 NVIDIA GPU および互換性のあるドライバー。
オプション
スタティック ライブラリ、ダイナミック ライブラリ、または実行可能ファイルなどの MEX 以外のビルドについて、この例では以下の要件も適用されます。
NVIDIA CUDA Toolkit。
コンパイラおよびライブラリの環境変数。詳細については、サードパーティ ハードウェアと前提条件となる製品の設定を参照してください。
GPU 環境の検証
この例を実行するのに必要なコンパイラおよびライブラリが正しく設定されていることを検証するために、関数coder.checkGpuInstallを使用します。
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);
座標系の定義
開口部を通過した光のシミュレーションを行う前に、座標系を定義しなければなりません。fft2を呼び出すときに正しい数値動作を得るには、ゼロ値が適切な位置になるように
と
を慎重に配置しなければなりません。N2 は各次元で半分のサイズになります。
N2 = 1024; [gx, gy] = meshgrid(-1:1/N2:(N2-1)/N2);
矩形開口部に対する回折パターンのシミュレーション
単色光の平行光線が小さな矩形開口部を通過するときの効果をシミュレートします。2 次元フーリエ変換によって開口部から遠く離れた光照射野を表現します。座標系に基づいて aperture を論理マスクとして形成します。光源は開口部の倍精度バージョンにします。関数 fft2 を使用して、遠視野の光信号を求めます。
aperture = (abs(gx) < 4/N2) .* (abs(gy) < 2/N2); lightsource = double(aperture); farfieldsignal = fft2(lightsource);
矩形開口部に対する光強度の表示
関数 visualize.m は、矩形開口部に対する光強度を表示します。遠視野の光強度を、光照射野の振幅二乗から計算します。可視化を支援するために、関数 fftshift を使用します。
type visualize
function visualize(farfieldsignal, titleStr) farfieldintensity = real( farfieldsignal .* conj( farfieldsignal ) ); imagesc( fftshift( farfieldintensity ) ); axis( 'equal' ); axis( 'off' ); title(titleStr); end
str = sprintf('Rectangular Aperture Far-Field Diffraction Pattern in MATLAB');
visualize(farfieldsignal,str);

関数の CUDA MEX の生成
エントリポイント関数を作成する必要はありません。MATLAB® 関数 fft2 のコードを直接生成できます。MATLAB 関数 fft2 の CUDA MEX を生成するには、構成オブジェクトで EnablecuFFT プロパティを設定し、関数 codegen を使用します。GPU Coder は、MATLAB コード内の関数 fft、ifft、fft2、ifft2、fftn および ifftn の呼び出しを適切な cuFFT ライブラリの呼び出しに置き換えます。2 次元以上の変換では、GPU Coder は複数の 1 次元バッチ変換を作成します。これらのバッチ変換は単一の変換よりもパフォーマンスが高くなります。MEX 関数を生成した後に、その関数に元の MATLAB エントリポイント関数と同じ機能があることを検証できます。生成された fft2_mex を実行し、結果をプロットします。
cfg = coder.gpuConfig('mex'); cfg.GpuConfig.EnableCUFFT = 1; codegen -config cfg -args {lightsource} fft2 farfieldsignalGPU = fft2_mex(lightsource); str = sprintf('Rectangular Aperture Far-Field Diffraction Pattern on GPU'); visualize(farfieldsignalGPU,str);
Code generation successful.

Young の二重スリット実験のシミュレーション
Young の二重スリット実験では、開口部が 2 つの平行なスリットで構成されているときの光の干渉を示します。建設的干渉が発生している場所に、一連の明るい点が見えます。この例では、2 つのスリットを表す開口部を形成します。結果のパターンがすべて横軸沿いに集まることがないように
方向の開口部を制限します。
slits = (abs(gx) <= 10/N2) .* (abs(gx) >= 8/N2); aperture = slits .* (abs(gy) < 20/N2); lightsource = double(aperture);
Young の二重スリットに対する光強度の表示
入力のサイズ、型、および実数/複素数は変わらないため、生成された MEX 関数 fft2_mex を再利用して、前と同じように強度を表示します。
farfieldsignalGPU = fft2_mex(lightsource);
str = sprintf('Double Slit Far-Field Diffraction Pattern on GPU');
visualize(farfieldsignalGPU,str);

GPU 入力を受け入れる CUDA MEX の生成
上で生成した CUDA MEX では、MEX への入力が CPU から GPU メモリにコピーされ、GPU 上で計算が実行された後、結果が CPU にコピーで戻されます。代わりに、GPU から直接入力を受け入れるように CUDA コードを生成することができます。MEX ターゲットの場合、gpuArray を使用することで、MATLAB® から CUDA MEX に GPU 入力を渡すことができます。その他のターゲットの場合、GPU メモリを割り当てなければなりません。また、入力はエントリポイント関数に渡される前に手書きの main 関数内で CPU から GPU にコピーされなければなりません。
lightsource_gpu = gpuArray(lightsource); cfg = coder.gpuConfig('mex'); cfg.GpuConfig.EnableCUFFT = 1; codegen -config cfg -args {lightsource_gpu} fft2 -o fft2_gpu_mex
Code generation successful.
エントリポイント関数には、数値型または logical 行列型の GPU 入力を渡すことができます。サポートされていない他のデータ型は CPU 入力として渡すことができます。コード生成時、エントリポイント関数に渡される入力のうち少なくとも 1 つが GPU 入力である場合、GPU Coder は GPU から直接出力を返すように試みます。ただし、出力のデータ型が GPU 出力としてサポートされていない場合 (struct や cell 配列など)、生成コードは CPU 上で出力を返します。GPU 入力からエントリポイント関数への受け渡しの詳細については、GPU 配列のサポートを参照してください。
GPU 入力 lightsource_gpu を使用した場合の生成された CUDA コードの違いに注目してください。CPU から GPU メモリに入力をコピーすることや、GPU から CPU メモリに結果をコピーで戻すことが回避されます。この結果、cudaMemcpys が少なくなり、生成された CUDA MEX のパフォーマンスが向上します。
GPU 入力を受け入れる CUDA MEX の結果検証
gpuArray を使用して生成された CUDA MEX の機能が同じであることを検証するために、生成された fft2_gpu_mex を実行し、ホストで結果を収集し、その結果をプロットします。
farfieldsignal_gpu = fft2_gpu_mex(lightsource_gpu);
farfieldsignal_cpu = gather(farfieldsignal_gpu);
str = sprintf('Double Slit Far-Field Diffraction Pattern on GPU using gpuArray');
visualize(farfieldsignal_cpu,str);

参考
関数
codegen|coder.gpu.kernel|coder.gpu.kernelfun|gpucoder.matrixMatrixKernel|coder.gpu.constantMemory|stencilfun|coder.checkGpuInstall