phpでFFTW3
PHP extensionをかじって,作ってみようと思ったのがFFTWのバインディング.
正直,PHPでFFTW使いたいと思っているわけではないし,そもそもFFTWって何?ってレベル.学校の演習でちょろっと触っただけ.
もっと言うとC言語もよくわかんね.
でもPHP extensionの練習としてはなかなか面白そうだなとは思っていた.とりあえず,流行のCodegen_PECLでさくっと書いてみた.実装は実データの 1 次元離散フーリエ変換のみ.
fftw.xml
こんな感じ.
<? xml version="1.0" ?> <extension name="fftw" version="0.0.1"> <maintainers> <maintainer> <user>making</user> <email>makingx [at] gmail.com</email> </maintainer> </maintainers> <release> <version>0.0.1</version> <date>2007-08-12</date> <state>alpha</state> <notes> First version. </notes> </release> <deps language="c" platform="all"> <with defaults="/usr/include"> <header name="math.h" /> <header name="fftw3.h" /> <lib name="fftw3" platform="all" /> </with> </deps> <functions> <function name="fft"> <proto>array fft(array arr)</proto> <code> < ![CDATA[ int size = zend_hash_num_elements(arr_hash); double in[size]; fftw_complex out[size/2+1]; fftw_plan p; int i=0; zval **entry; zval *re, *im; p = fftw_plan_dft_r2c_1d(size, in, out, FFTW_ESTIMATE); zend_hash_internal_pointer_reset(arr_hash); while( zend_hash_get_current_data(arr_hash, (void **) &entry ) == SUCCESS) { convert_to_double_ex(entry); in[i] = Z_DVAL_PP(entry); zend_hash_move_forward(arr_hash); i++; } fftw_execute(p); MAKE_STD_ZVAL(re); MAKE_STD_ZVAL(im); array_init(re); array_init(im); for (i = 0; i< size/2+1 ; i++) { add_next_index_double(re,out[i][0]); add_next_index_double(im,out[i][1]); } add_index_zval(return_value,0,re); add_index_zval(return_value,1,im); fftw_destroy_plan(p); ]]> </code> </function> </functions> </extension>
ぼくはさくらインターネットで強引に環境作っているから実際に試したときとは若干違うが(fftw.hをフルパスで書いたり,できたMakefileをいじったり).Codegen_PECL使ってる時点でわかると思うがPHP5をインストールしてます.prefixは$HOMEです.
参考にしたのはこのページ
の和訳...
codegen & インストール
ここはいつものように
pecl-gen -f fftw.xml cd fftw phpize ./configure make make install echo "extension=fftw.so" >> ~/www/php.ini
まあ実際はこんなスムーズにはいかなかったが,理論上はこれでいいはず.
example
PHPコード1
define('LENGTH',16); $in = array(); $in2 = array(); for ($i = 0;$i < LENGTH; $i++) { $in[$i] = ($i % 2 ==0) ? 1 : -1; $in2[$i] = cos($i * M_PI / LENGTH) + cos($i * 2 * M_PI / LENGTH) + cos($i * 4 * M_PI / LENGTH); } var_dump($in); var_dump(fft($in)); var_dump($in2); var_dump(fft($in2));
出力結果
array(16) { [0]=> int(1) [1]=> int(-1) [2]=> int(1) [3]=> int(-1) [4]=> int(1) [5]=> int(-1) [6]=> int(1) [7]=> int(-1) [8]=> int(1) [9]=> int(-1) [10]=> int(1) [11]=> int(-1) [12]=> int(1) [13]=> int(-1) [14]=> int(1) [15]=> int(-1) } array(2) { [0]=> array(9) { [0]=> float(0) [1]=> float(0) [2]=> float(0) [3]=> float(0) [4]=> float(0) [5]=> float(0) [6]=> float(0) [7]=> float(0) [8]=> float(16) } [1]=> array(9) { [0]=> float(0) [1]=> float(0) [2]=> float(0) [3]=> float(0) [4]=> float(0) [5]=> float(0) [6]=> float(0) [7]=> float(0) [8]=> float(0) } } array(16) { [0]=> float(3) [1]=> float(2.6117715941011) [2]=> float(1.6309863136978) [3]=> float(0.50704626348109) [4]=> float(-0.29289321881345) [5]=> float(-0.53421998053204) [6]=> float(-0.32442334882146) [7]=> float(-0.021682429308611) [8]=> float(1.1102230246252E-16) [9]=> float(-0.41186307334087) [10]=> float(-1.0897902135516) [11]=> float(-1.6453604465712) [12]=> float(-1.7071067811865) [13]=> float(-1.155892961124) [14]=> float(-0.21677275132474) [15]=> float(0.6502010332946) } array(2) { [0]=> array(9) { [0]=> float(1) [1]=> float(9) [2]=> float(9) [3]=> float(1) [4]=> float(1) [5]=> float(1) [6]=> float(1) [7]=> float(1) [8]=> float(1) } [1]=> array(9) { [0]=> float(0) [1]=> float(-6.7248642982736) [2]=> float(-2.5837133103639) [3]=> float(-1.5446859686887) [4]=> float(-1.0195911582083) [5]=> float(-0.67759496338973) [6]=> float(-0.41892890977907) [7]=> float(-0.20091904348225) [8]=> float(0) } }
これってあってんの?FFTWの出力ってどう見たらいいの?
C言語はよく分かんないのでおかしなことしてたらつっこんでください.あとはもうちょっとFFTWを学んでから続きを実装するかも.
まあExtensionは楽しいってことはわかった.









