Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

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 以外のビルドについて、この例では以下の要件も適用されます。

GPU 環境の検証

この例を実行するのに必要なコンパイラおよびライブラリが正しく設定されていることを検証するために、関数 coder.checkGpuInstall を使用します。

envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

座標系の定義

開口部を通過した光のシミュレーションを行う前に、座標系を定義しなければなりません。fft2 を呼び出すときに正しい数値動作を得るには、ゼロ値が適切な位置になるように $x$$y$ を慎重に配置しなければなりません。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 コード内の関数 fftifftfft2ifft2fftn および 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);

Young の二重スリット実験のシミュレーション

Young の二重スリット実験では、開口部が 2 つの平行なスリットで構成されているときの光の干渉を示します。建設的干渉が発生している場所に、一連の明るい点が見えます。この例では、2 つのスリットを表す開口部を形成します。結果のパターンがすべて横軸沿いに集まることがないように $y$ 方向の開口部を制限します。

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 を使用して、GPU ポインターを MATLAB® から CUDA MEX に渡すことができます。その他のターゲットの場合、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

GPU ポインターとしてエントリポイント関数に渡すことができるのは、数値および logical の入力行列タイプのみです。サポートされていない他のデータ型は CPU 入力として渡すことができます。コード生成時、エントリポイント関数に与えられた入力のうち少なくとも 1 つが GPU ポインターであれば、関数から返される出力も 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);