約 2,448,743 件
https://w.atwiki.jp/amaeda/pages/58.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース - 実データ離散フーリエ変換 実データ離散フーリエ変換 Real-Data DFTs fftw_plan fftw_plan_dft_r2c_1d( int n, double *in, fftw_complex *out, unsigned flags ); fftw_plan fftw_plan_dft_r2c_2d( int nx, int ny, double *in, fftw_complex *out, unsigned flags ); fftw_plan fftw_plan_dft_r2c_3d( int nx, int ny, int nz, double *in, fftw_complex *out, unsigned flags ); fftw_plan fftw_plan_dft_r2c( int rank, const int *n, double *in, fftw_complex *out, unsigned flags ); 実数入力/複素数出力の0次以上の離散フーリエ変換(DFT)のプランをたてて、fftw_planを返します(4.2節のプランの利用参照)。 いったんある変換タイプおよびパラメータのプランを生成すれば、異なる配列に対して、同じタイプおよびパラメータのプランを生成する際に、高速にプランが生成され、定数は共有されます(もし存在すれば)。 プランナーはプランが生成できなかったとき、返り値としてNULLを返します。そして、ベーシックインターフェースでは、FFTWをある制限された変換群をサポートする設定にカスタマイズするか、入出力が異なるout-of-placeのc2r多次元変換でFFTW_PRESERVE_INPUTフラグを使わない限り、返り値としてNULLでない値を返します。 引数 Arguments rank ランク(rank)は、変換の次元で(これは配列*nのサイズであるはずです)任意の非負整数を取りえます。 _1d 、 _2d 、 _3d のプランナーはそれぞれランク(rank)が1,2,3に対応します。ランク(rank)0は、サイズ1の変換、つまり入力から出力への数のコピーに相当します(ただし、0の虚部を伴います)。 nまたは、nx/ny/nzまたは、n[rank] nまたは、nx,ny,nzもしくは、n[rank]はそれぞれ変換の次元の論理的サイズを与え、任意の非負整数をとりえます。これは一般的に、物理的配列次元とはことなります。これについては4.3.4章の実データ離散フーリエ変換配列形式に記されています。 FFTWは配列サイズがの時に、一番性能が発揮され ます。ただし、e+fは、0か1で他の係数(a,b,c,d)は任意です。他のサイズの時は、一般的なアルゴリズムを用いた遅いアルゴリズムで計算されます(それでも遅くてもO(nlogn)の次元です)。FFTWを違うサイズ用にカスタマイズすることもできるので、必要なら8章のInstallation and Customizationを参照してください。2の階乗のサイズの変換はとりわけ高速に計算でき、それは一般的にr2c/c2r変換の最後の次元が偶数であるときに効果があるということになります。 in,out inとoutは変換の入力および出力の配列を表し、同じものを取りえます(in-place変換)。これらの配列は、FFTW_ESTIMATEフラグが使われない限り、プラン生成の際に値が上書きされます。(配列は初期化する必要はないが、確保する必要があります)。入出力が同じであるin-place変換の時は、実配列はパディングが必要です。これについては4.3.4章の実データ離散フーリエ変換配列様式に記されています。 flags flagはビットごとのORで構成されるゼロ以上のフラグです。24ページの4.3.2章のプランナーフラグで定義されます。 逆変換については、複素数の入力(エルミート配列の論理的に半分のサイズに非冗長に格納されているもの)をとり、実数を出力とする以下のようなものです。 fftw_plan fftw_plan_dft_c2r_1d( int n, fftw_complex *in, double *out, unsigned flags ); fftw_plan fftw_plan_dft_c2r_2d( int nx, int ny, fftw_complex *in, double *out, unsigned flags ); fftw_plan fftw_plan_dft_c2r_3d( int nx, int ny, int nz, fftw_complex *in, double *out, unsigned flags ); fftw_plan fftw_plan_dft_c2r( int rank, const int *n fftw_complex *in, double *out, unsigned flags ); 引数は、入出力のデータ形式が逆になっているところ以外はr2c変換と、まったく同じです。 FFTWの演算では規格化がされません。すなわち、c2r変換を行った後、r2c変換(またははその逆)を行うと、計算結果は元のデータを変換のサイズ倍(配列の論理的次元の積)されます。r2c変換は、同じ入力を用いて、複素離散フーリエ変換のでFFTW_FORWARDとした時と、同じ結果になり、c2r変換はFFTW_BACKWARDに対応します。より詳しい情報は、4.7章のWhat FFTW Really Computesを参照してください。
https://w.atwiki.jp/amaeda/pages/55.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース ベーシックインターフェース Basic Interface ベーシックインターフェースは、おそらく大多数のユーザーの要望を満たすもので、FFTWのサポートする全てのタイプの、単一の連続した配列の変換に関するプランナールーチンを提供します。 複素離散フーリエ変換 プランナーフラグ 実データ離散フーリエ変換 実データ離散フーリエ変換の配列の形式 実数から実数への変換 実数から実数への変換種
https://w.atwiki.jp/amaeda/pages/60.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース - 実数から実数への変換 実数から実数への変換 Real-to-Real Transforms
https://w.atwiki.jp/amaeda/pages/57.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース - プランナーフラグ プランナーフラグ Planner Flags FFTWのすべてのプラン生成ルーチンは、整数のflags引数をとり、これは以下で定義される0個以上のビット毎定数フラグの、のOR( | )となります。これらのフラグは、プラン生成の計算の厳密性(および時間)に関係し、同時にまた、使われる変換アルゴリズムに制限を加えることも可能です。 重要 プラン生成時に、入力配列は上書きされます。したがって、プラン生成の後に入力配列の初期化を行う必要があります。これは、FFTW_ESTIMATEフラグを宣言することによってのみ、回避可能です。 プラン生成のの厳密さにかかわるフラグ Planning-rigor flags FFTW_ESTMATE FFTW_ESTIMATEは、異なるアルゴリズムを用いたときの計算時間を実測する代わりに、ヒューリスティックかつ高速にプランを決めます(このプラン選択は、おそらく準最適でしょう)。 このフラグを使えば、入出力配列はプラン生成時には上書きされません。 FFTW_MEASURE FFTW_MEASUREは、実際にいくつかのFFTを計算し実行時間を計測することによって、最適なプランを探索します。ご使用の計算機によって、この操作にはしばし時間がかかるかもしれません(ほとんどの場合2,3秒)。FFTW_MEASUREは、標準のプラン生成オプションです。 FFTW_PATIENT FFTW_PATIENTは、FFTW_MEASUREと似ていますが、より広範囲のアルゴリズムを考慮にいれるため、"より最適な"プランを生成します(特に大きいサイズの変換の場合)。しかし、プラン生成にかかる時間はいくらか長くなります(特に大きいサイズの変換の場合)。 FFTW_EXHAUSTIVE FFTW_EXHAUSTIVEはFFTW_PATIENTと似ていますが、さらに広範囲のアルゴリズムを考慮に入れます。一番最適なプランを生成するために、さらにプラン生成に時間をかけて、我々が、速くなりそうにないと考えるようなアルゴリズムも含めてアルゴリズム選択を行います。 アルゴリズム制限フラグ Algorithm-restriction flags FFTW_DESTROY_INPUT FFTW_DESTROY_INPUTは、入出力が異なるout-of-place変換の際に、入力配列を上書きすることを許すことを指定します。これによって、時により効率のよいアルゴリズムが採用されます。 FFTW_PRESERVE_INPUT FFTW_PRESERVE_INPUTは、入出力が異なるout-of-place変換の際に、入力配列の変更を許可しないことを指定します。これは通常デフォルトになっていて、c2rとhc2r(すなわち複素数から実数への変換)変換の時だけ、FFTW_DESTROY_INPUTがデフォルトとなっています。後者の場合、FFTW_PRESERVEを用いることで、入力配列を変更しないアルゴリズムを使うようになりますが、これはパフォーマンスを犠牲にします。しかしながら、多次元のc2r変換では、入力配列を保存するアルゴリズムは実装されていないので、FFTW_PRESERVEが使われてもプランナーはNULLを返すでしょう。 FFTW_UNALIGNED FFTW_UNALIGNEDは、入出力配列に特別なメモリ配列を求めない(つまりSIMDなどが使われない)アルゴリズムを指定します。このフラグは、通常プランナーが自動的にメモリ配置が正しくない配列を検知するため不要です。このフラグが唯一使われるのは、グルインターフェースを使って、あるプランを、元の配列とは違うメモリ配置の異なる配列に対して実行したい場合です(fftw_mallocを使っていればこのフラグは不要です)。 プラン生成時間の制限 extern void fftw_set_timelimit( double seconds ); この関数は、FFTWがプラン生成に使う時間の上限を(おおよそ)seconds秒に制限するものです。seconds == FFTW_NO_TIMELIMIT(デフォルトでこの値で、これは負)とすれば、プラン生成所要時間は一切制限されません。その他の場合は、FFTWは指定された時間および探索すべきアルゴリズムの範囲が探索し終わるまで、漸次広範囲のアルゴリズムを探し、最良のプランを返します。 例えば、FFTW_PATIENTが指定されたとすれば、まずFFTW_ESTIMATEモードで探索が行われ、FFTW_MEASUREモード、最後に(時間が許せば)FFTW_PATIEMNTモードと探索が行われます。 ここで、引数secondsは、おおよその制限値であるにすぎないことに注意してください。実際は、中断できない作業の途中で制限時間に達した場合など、指定値より多く時間がかかる可能性があります。最短の場合でも、プランナーはFFTW_ESTIMATEモードを完了するまで実行します(時間制限を0にした場合)。
https://w.atwiki.jp/amaeda/pages/16.html
複素1次元離散フーリエ変換 Complex One-Dimensional DFTs プランとは、偶然の結果を達成するための最善の方法をいろいろ思い悩むことである。 (Ambrose Bierce, The Enlarged Devil’s Dictionary.) FFTWで、サイズNのデータの一次元DFTを計算する方法はいたって簡単で、おおよそ以下のようなコードになります。 #include fftw3.h ... { fftw_complex *in, *out; fftw_plan p; ... in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); ... fftw_execute(p); /* 必要なだけ繰り返す */ ... fftw_destroy_plan(p); fftw_free(in); fftw_free(out); } コンパイル時には、fftw3ライブラリをリンクしなければなりません。つまり例えばUnix系では -lfftw3 -lmをリンカオプションとしてつけます。 まず初めに、入出力の配列のメモリを確保します。 メモリは好きなように確保して構いませんが、fftw_mallocを使うことを推奨します。 fftw_mallocはmallocのように動作しますが、違いとしてはSSEやAltivecなどのSIMD命令が利用出きるように配列が確保されます。(3.1.1節 SIMD alignment and fftw mallocを参照) データはfftw_complex型の変数の配列になっており、fftw_complexはデフォルトでdouble二つ分の配列(double[2])です。それぞれ実部(in[i][0])、虚部(in[i][1])に対応します。 次のステップは、プランの生成です。プランはFFTWがFFTを計算する際に必要な全ての情報を含んだものです。以下の関数がプランを作ります。 fftw_plan fftw_plan_dft_1d(int n, fftw_complex *in, fftw_complex *out, int sign, unsigned flags); 最初の引数nは計算しようとしている変換のサイズです。nは任意の正の整数をとりえますが、サイズが小さい素数のみを因数に持つ場合、最も効率よく計算できます。(しかしどんな素数であれ,O(nlogn)アルゴリズムを採用しています) 計算時間の次元が、データ数nに対して、nlogn 次の二つの引数は、入出力の配列へのポインタです。これらのポインタは同じものを入れることも可能で、この場合は入力配列が書き換わります。 四番目の引数signは、正変換か逆変換かを表す、FFTW_FORWARD(-1)かFFTW_BACKWARD(+1)のどちらかを入れます。技術的にはこれは、変換の指数部になります。 最後の引数flagは、通常FFTW_MEASUREかFFTW_ESTIMATEをとります。FFTW_MEASUREは実際にいくつかのFFTWを実行して実行時間を計り、サイズnの変換を計算するのに一番良い方法を選択します。このプロセスは少し時間がかかり、(通常、2、3秒)これは変換のサイズnや計算機環境に依存します。FFTW_ESTIMATEは、実際に実行することなく、おそらく準最適だと思われる方法を選択します。 つまり、同じサイズの変換を複数回行い、かつ初期化の時間が重要でない場合はFFTW_MEASUREを使い、そうでなければFFTW_ESTIMATEを利用すれば良いことになります。 inやoutといった入出力データの配列は、FFTW_MEASUREのプランニングを行う際に上書きされるので、FFTW_MEWSUREでのプランニングを行う場合は、入力がユーザーに初期化される前にプランニングを行う必要があります。 一旦プランが生成されれば、特定のint/out配列に対して実際の変換をfftw_execute(plan)で計算する際に、プランは何度でも再利用できます。 ちなみにfftw_executeは, void fftw_execute(const fftw_plan plan); です。 もし、同じサイズの違う配列を変換したい場合は、fftw_plan_dft_1dを使って新しいプランを作れます。するとFFTWは、可能であれば、自動的に前回のプランの情報を再利用します。(一方で、グルインターフェースでは、既に生成済みのプランを他の配列に用いることができますが、十分気をつける必要があります。4章のFFTW Referenceを参照のこと) プランを用いて計算が終了したら、fftw_destroy_plan(plan)を呼び出すことによって、メモリを解放します。 void fftw_destroy_plan(fftw_plan plan); fftw_mallocで確保された配列は、通常のfreeでなく、fftw_freeで開放してください。(ましてや、deleteなどしてはいけません) 離散フーリエ変換DFTの結果は、配列outに順番に格納され、周波数がゼロの直流成分(DC)がout[0]に入ります。もし、入出力配列が異なる配列なら(in!=out)、入力配列は変更されません。 そうでなければ、入力の配列は変換によって上書きされます。 ユーザーはFFTWがノーマライズしていないDFTを計算することに注意する必要があります。このようにして、逆変換のあと正変換(または、正変換のあと逆変換)した場合、元の配列がn倍された結果が得られます。 DFTの定義については、4.7のWhat FFTW Really Computesを参照してください。 もし、gccなどの最近のC99スタンダードをサポートするCコンパイラが利用可能な場合、以下のように、complex.hをfftw3.hの前にインクルードすれば、fftw_complexは倍精度の複素数型になり、通常の演算で扱うことができます。 #include complex.h #include fftw3.h その他の場合では、FFTWはC99と互換性のある独自の型fftw_complexを定義します。4.1.1 Complex numbersも参照のこと(C++のテンプレートクラスも、型をキャストすることによって使えます) single(float)と、long-doubleの精度のバージョンもインストールされていて、それらを使うためには、fftw_というプレフィクスをfftw_fやfftwl_に置き換え、リンク時に -lfftw3fや -lfftw3lを用いてください。ヘッダーファイルは同じもの(fftw3.h)で構いません。 FFTW_MEASUREとFFTW_ESTIMATE以外にも多数のフラグがあります。例えば、FFTW_PATIENTは、プラン生成に相当程度長い時間がかかる代わりに、実に速くプランが実行できます(4章のFFTW Referenceを参照) プランを今後の為に保存することもできて、それについては3.3のWords of Wisdom-Saving Plansを参照してください。
https://w.atwiki.jp/amaeda/pages/56.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース - 複素離散フーリエ変換 複素離散フーリエ変換 fftw_plan fftw_plan_dft_1d( int n, fftw_complex *in, fftw_complex *out, int sign, unsigned flags ); fftw_plan fftw_plan_dft_2d( int nx, int ny, fftw_complex *in, fftw_complex *out, int sign, unsigned flags ); fftw_plan fftw_plan_dft_3d( int nx, int ny, int nz, fftw_complex *in, fftw_complex *out, int sign, unsigned flags ); fftw_plan fftw_plan_dft( int rank, const int *n, fftw_complex *in, fftw_complex *out, int sign, unsigned flags ); 複素数を入出力とする、0次元または多次元の離散フーリエ変換(DFT)をおこない、fftw_planを返り値として返します(4.2章プランの利用参照)。 一たび、特定の型及びパラメータに対しプランを作り、その後同じ型、パラメータに対する異なるプラン(ただし対象とする配列が異なるもの)を生成すれば、プラン生成は高速におこなわれ、最初のプランと同じデータは共有されます(仮に最初のプランがまだ存在すれば)。 プランナーは、プランの生成に失敗すればNULLを返します。 FFTWの設定をカスタマイズして、特定の変換を行うようにしない限りベーシックインターフェースは常にNULLでない値を返します。 引数 rank ランク(rank)は変換の次元(配列*nのサイズであるはずです)であり、任意の非負整数をとりえます。"_1d","_2d","_3d"のプランナーはそれぞれrankが1,2,3に対応します。rankが0は、サイズ1の変換に対応し、これはすなわち1つの数を入力から出力へコピーとなります。 n, nx, ny, nz, n[rank] nまたは、nx,ny,nzもしくは、n[rank]はそれぞれ変換の次元のサイズを与え、任意の非負整数をとりえます。 多次元の配列は列メジャー順で次元が格納されます。すなわちnx x ny、あるいはnx x ny x nz、あるいはn[0] x n[1] x ... n[rank-1]という順です。詳細は3.2章の多次元配列のフォーマット参照。 FFTWは配列サイズがの時に、一番性能が発揮され ます。ただし、e+fは、0か1で他の係数(a,b,c,d)は任意です。他のサイズの時は、一般的なアルゴリズムを用いた遅いアルゴリズムで計算されます(それでも遅くてもO(nlogn)の次元です)。FFTWを違うサイズ用にカスタマイズすることもできるので、必要なら8章のInstallation and Customizationを参照してください。2の階乗のサイズの変換はとりわけ高速に計算できます。 in, out inとoutは変換の入力および出力の配列を表し、同じものを取りえます(in-place変換)。これらの配列は、FFTW_ESTIMATEフラグが使われない限り、プラン生成の際に値が上書きされます。(配列は初期化する必要はないが、確保する必要があります)。 in == outの時には、変換はin-placeとなり、入力配列は上書きされます。in != outであれば、2つの配列はメモリ領域が重なってはいけません(FFTWはこの条件はチェックしません)。 sign signはフーリエ変換を定義するエクスポーネントです。-1(=FFTW_FOWRARD)もしくは+1(FFTW_BACKWARD)の値をとります。 ※変換の方向と考えてよい flags flagはビットごとのORで構成されるゼロ以上のフラグです。24ページの4.3.2章のプランナーフラグで定義されます。 FFTWの演算では規格化がされません。すなわち、逆変換を行った後、正変換(またはその逆)を行うと、計算結果は元のデータを変換のサイズ倍(配列の次元の積)されます。より詳しい情報は、4.7章のWhat FFTW Really Computesを参照してください。
https://w.atwiki.jp/amaeda/pages/33.html
/** * @brief test of fftw r2c transform * @author maeda * @date 2008/09/24 */ #include cv.h #include cxcore.h #include highgui.h #include "fftw3.h" #include "powerspectol.h" #pragma comment( lib, "cv.lib" ) #pragma comment( lib, "cxcore.lib" ) #pragma comment( lib, "highgui.lib" ) #pragma comment( lib, "fftw3.lib" ) int main( void ) { IplImage *img = NULL; IplImage *imgman = NULL; IplImage *show = NULL; IplImage *spectol = NULL; CvSize size; fftw_complex *out = NULL; fftw_plan plan = NULL; int width,height; int i,j; // (1) load image (unsigned char) img = cvLoadImage( "lena.bmp", CV_LOAD_IMAGE_GRAYSCALE ); if( !img ){ printf("no image.\n"); return false; } width = img- width; height = img- height; size = cvSize( width/2+1, height ); out = (fftw_complex*)fftw_malloc( sizeof(fftw_complex) * (width/2 + 1) * height ); spectol = cvCreateImage( size, IPL_DEPTH_64F, 1 ); show = cvCreateImage( size, IPL_DEPTH_8U, 1 ); imgman = cvCreateImage( cvSize( width, height ), IPL_DEPTH_64F, 1 ); if( !imgman || !out || !spectol || !show ){ printf("failed to allocate memory.\n"); return false; } // (2) convert image (unsigned char- double) cvScale( img, imgman ); plan = fftw_plan_dft_r2c_2d( height, width, (double*)imgman- imageData, out, FFTW_ESTIMATE ); if( !plan ){ printf("failed to create plan\n"); return false; } // (3) fft (double- fftw_complex) fftw_execute(plan); // (4) get powerspectol (fftw_complex- double) maGetPowerSpectol2D( out, (double*)spectol- imageData, width/2+1, height ); // (5) convert image (double- unsigned char) cvScale( spectol, show, 255 ); // (6) show result cvNamedWindow( "window" ); cvShowImage( "window", show ); cvWaitKey(0); cvDestroyWindow( "window" ); if( out ) fftw_free( out ); if( img ) cvReleaseImage( img ); if( imgman ) cvReleaseImage( imgman ); if( show ) cvReleaseImage( show ); if( spectol ) cvReleaseImage( spectol ); if( plan ) fftw_destroy_plan( plan ); return true; }
https://w.atwiki.jp/amaeda/pages/59.html
FFTWマニュアル - FFTWリファレンス - ベーシックインターフェース - 実データ離散フーリエ変換配列様式 実データ離散フーリエ変換配列様式 実データの離散フーリエ変換出力(r2c変換)は、対称性を持つ。つまり、原則的には、2倍の冗長性を持つ(4.7節What FFTW Really Computes参照)。(逆c2r変換の入力も、同様)。実際のところ、これらの冗長性の排除を、効果的かつ理解しやすい形式(多次元変換の一般化するもの)で行うことを、完全に実現することは不可能である。その代わりに、r2c変換の出力は、対応する複素変換の出力の半分をわづかに超える。データはいかなる方法でも”圧縮”せず、通常のfftw_complex値の配列として、格納している。実際のところ、このデータは対応する複素変換の配列の一部分である。 具体的にいえば、d(=ランク)次元の n1 x n2 x n3 x ... x nd の実変換では、複素データは、fftw_complex値で、n1 x n2 x n3 x ... x (nd/2 + 1)の行メジャー形式の配列である(割り算の余りは切り捨て)。つまり、我々は通常の複素変換で得られるデータの最後の次元の、小さいほうの半分(非負周波数)、に加えて1要素しか保存していません。(他の次元を半分にすることも可能でしたが、実装が最も簡単だったため、最後の次元を半分にしました)。 入出力が異なる、アウトオブレイス変換では、実データは単なる配列で、物理次元 n1 x n2 x n3 x ... x nd(列メジャー形式)となっています。 入出力が同じである、インプレイス変換では、いくつか複雑な問題が生じます。というのも、複素データは、実データより僅かに大きいためです。このケースでは、実データの最後の次元は、必ず余白がとられている必要があり、そこには追加の余分な値が格納されます。--最後の次元が偶数であれば、2つの追加、奇数であれば1つの追加データです。 つまり、実データの最後の次元は、物理的に 2(nd + 1)個のdouble値である必要があります(複素データを格納するのに過不足ないサイズ)。しかしながら、この物理的配列サイズは、論理的な配列サイズは変更しません。ndの値だけが、実際に最後の次元に格納され、ndがプランナーに渡される最後の次元となります。
https://w.atwiki.jp/amaeda/pages/28.html
複素多次元離散フーリエ変換 Complex Multi-Dimensional DFTs 多次元変換も、一次元の変換とほとんど同じように動きます。すなわち、まずfftw_complexの配列のメモリを確保し、(fftw_mallocの使用を推奨)、次にfftw_planを作成し、3番目に、fftw_execute(plan)を必要な回数実行し、最後にfftw_destroy_plan(plan)とfftw_freeでメモリの解放を行います。唯一の違いは、プランを作るときに使うルーチンだけです。 すなわち、 fftw_plan fftw_plan_dft_2d(int nx, int ny, fftw_complex *in, fftw_complex *out, int sign, unsigned flags); fftw_plan fftw_plan_dft_3d(int nx, int ny, int nz, fftw_complex *in, fftw_complex *out, int sign, unsigned flags); fftw_plan fftw_plan_dft(int rank, const int *n, fftw_complex *in, fftw_complex *out, int sign, unsigned flags); となっています。 これらのルーチンはnx×nyの2次元(2d)変換、nx×ny×nzの3次元(3d)変換、そして任意のサイズの変換をそれぞれ表します。 3番目のfftw_plan_dftのケースでは、nは配列n[rank]へのポインタです。配列n[rank]は、n[0]×n[1]×...×n[rank-1]変換を示します。 これらの変換は、C標準の行メジャー順(※1)で規定される連続な配列で扱われます。したがって、最後の次元のインデクスが最も速く変わります。このメモリ配置については、3.2節Multi-dimensional Array Formatを参照してください。 ここまでで、全てのプラン生成のルーチンが、機能的に重複していることにお気づきかもしれません。例えば、1次元や2次元変換のプランを立てるのには、fftw_plan_dftのランク1か2をつかっても良いでしょうし、あるいは、fftw_plan_dft3dでnxとny(かnxまたはny)を1にしたってよいでしょう(こうしても、パフォーマンスの低下は一切起きません)この傾向は、他に対しても同じで、FFTWのプラン作成ルーチンは、概して”半順序”で、さまざまなインターフェースで、一般性が増せば、それに応じて複雑さも増します。 fftw_plan_dftは、このチュートリアルで述べた中で、もっとも一般的な複素離散フーリエ変換のルーチンです。しかし、これに加え、アドバンストインターフェース、グルインターフェースというものもあって、それらを使えば、複数の変換、あるいはstrided transformを、効率的に1つのFFTWプランでまとめることや、多次元の大きい配列の一部の変換や、さらに、より一般的な形式を扱うことができます。 詳細な情報は、4章のFFTW Referenceを参照してください。 (※1) 行メジャー
https://w.atwiki.jp/amaeda/pages/45.html
FFTWマニュアル - その他重要なこと - 多次元配列のフォーマット - C言語における動的配列 C言語における動的配列 Dynamic Arrays in C ほとんどの場合に、動的にfftw_mallocを使って、配列を確保することを推奨します。1次元の場合よりも、多次元の方が複雑ではありますが、これは難しいことではありません。 配列の生成は簡単です。fftw_mallocのような動的メモリ確保ルーチンを使って、N個のfftw_complex値(複素数DFTに関しては)の大きさの配列を確保します。ここで、Nは配列の次元の積(すなわち、配列の複素数知の総数)です。以下に、ランク3の5x12x27の配列を確保するコード例を示します。 fftw_complex *an_array; an_array = (fftw_complex*)fftw_malloc( 5*12*27 * sizeof(fftw_complex) ); 配列の要素にアクセスするには、少しテクニックがいります。つまり、固定サイズの配列と同じように"[]"を複数回使えばよいといものではありません。代わりに、明示的に列メジャー配列へ変換するための公式をつかって、オフセットを計算する必要があります。たとえば、上記の方法で確保された、(i,j,k)番目の要素を参照するためには、 an_array[k + 27 * (j + 12*i)] という表現を使えばよいでしょう。 この手間は、適切なマクロを定義するか、もしくはC++言語では、"()"演算子をオーバーロードするクラスを作れば、軽減できます。最近のC99標準は、動的配列を、[]表現が使える”可変長”多次元配列として、解釈する機能がありますが、これはまだコンパイラで広くサポートされるものではありません。