ソフトウェア/Igor の履歴(No.9)
更新Igor とは†
測定したデータの解析に Wave Metrics 社の Igor Pro を頻繁に使っています。
なかなか癖のあるソフトですが、 Igor 上でプログラムを組むことでかなり複雑なデータ解析も自動化できていろいろ捗ります。
ここには使い回しの効きそうなコード例を上げていこうと思います。
公式のオンラインヘルプはこちらです。
http://www.hulinks.co.jp/support/igor/programming/index.html
分野別記事へのリンク†
Igor のマルチスレッド対応†
Igor Pro 6.1 から、マルチスレッド対応が強化されたそうです。
LANG:Igor wave0 = any_expression(x)
のような代入文で時間がかかっている場合、
LANG:Igor MultiThread wave0 = any_expression(x)
とするだけで、個々の座標値に対する計算を異なるスレッドで行ってくれます。
当然、wave の個々の座標の値の間に依存関係がある場合にはうまくいきませんが、 独立に計算できる場合にはこれだけでかなり速度が上がります。
より高度なマルチスレッド†
もっと複雑なことをしたい場合には、 ThreadGroupCreate / ThreadStart / ThreadGroupPutDF / ThreadGroupGetDF / ThreadGroupWait / ThreadGroupRelease といった関数を使うことで、きめ細やかなマルチスレッド制御を行えます。
実際やってみると、メモリ確保などに時間がかかっていることも多いようで、 単純にスレッド数倍もの速度向上は望めませんが、シングルスレッド比で 2倍くらいの速度は簡単に出せるようでした。
例えば、Intel Core i7-3520M @ 2.9GHz + Windows 7 (64bit) で 1024 本のスペクトルに対して解析を行った結果、
- シングルスレッド = 11.0 秒
- マルチスレッド = 4.3秒
という結果が得られました。
注意点†
このようにマルチスレッドで使う関数、例えば SomeMutiThreadableFunction(x) には ThreadSafe というキーワードを付けて定義する必要があります。
LANG:Igor ThreadSafe function SomeMutiThreadableFunction(x) // マルチスレッド対応コード end
このような ThreadSafe な関数からは、同じく ThreadSafe とマークされた関数以外を呼び出せません。
やってみるとすぐ分かるのですが、現在のところ ThreadSafe とマークした関数には デバッガ機能が働かず、ブレークやステップ実行ができません。
シングルスレッドで十分にテストしてからマルチスレッドに移行しないと、 うまく動かないときに面倒なことになります。
デバッグ環境設定のようなところで「Multithread 機能をオフにして、 すべてをシングルスレッド(ノンプリエンプティブマルチスレッド)で動作させる」 なんていうのを選べると、デバッグが楽になって良いんですけどね・・・
幸い、print や printf は ThreadSafe 関数からも呼べるので、 デバッグにはこれらを使って頑張るしか今のところ手はないようです?
SetScale 関連†
SetScale でウェーブの縦横軸スケールを決められます。
CopyScales というのもあって、あるウェーブの縦横軸スケール情報を別のウェーブにコピーできます。
逆に、ウェーブから縦横軸スケールを読み取るには、
- DimOffset(wave0, 0) : wave0 の x 軸の左端 = LeftX(wave0)
- DimDelta(wave0, 0) : wave0 の x 軸の刻み幅 = DeltaX(wave0)
- DimSize(wave0, 0) : wave0 の x 軸方向の点数 = 一次元ウェーブなら NumPnts(wave0) と等しい
- WaveUnits(wave0, 0) : wave0 の x 軸の単位
- WaveUnits(wave0, 1) : 1次元ウェーブでは wave0 の値の単位
- DimOffset(wave0, 1) : 2次元以上のウェーブでは wave0 の y 軸の左端
- DimDelta(wave0, 1) : 2次元以上のウェーブでは wave0 の y 軸の刻み幅
- DimSize(wave0, 1) : 2次元以上のウェーブでは wave0 の y 軸方向の点数
- WaveUnits(wave0, 1) : 2次元以上のウェーブでは wave0 の y 軸の単位
- WaveUnits(wave0, 2) : 2次元ウェーブでは wave0 の値の単位
- ...
- StringByKey("DUNITS", WaveInfo(wave0, 0)) : 次元数に関係なく wave0 の値の単位が得られる
といった関数を使います。
これらと合わせて、以下の関数もよく使いますね。
- Pnt2X(wave0, p) : p 番目の点の x 座標を求める( p は丸められて、必ず DeltaX の整数倍が返る)
- X2Pnt(wave0, x) : x 座標を点のインデックスに直す(必ず整数が返る)
- NumPnts(wave0) : wave0 の総点数を返す(多次元でも使える)
- Note wave0, <str> : wave0 にノート文字列を付加する
- note(wave0) : wave0 に付加したノート文字列を取得する
SetScale/I の罠†
SetScale には /P と /I の2種類の指定の仕方がありますが、 /I についてはかなり注意が必要です。
LANG:Igor * Make/N=100 wave0 * SetScale/I x, 0, 100, wave0 * Print LeftX(wave0), DeltaX(wave0), Pnt2X(wave0, 99), RightX(wave0) 0 1.0101 100 101.01
この場合、DeltaX(wave0) は 1 ではなく 1.0101 になります。
これは、wave0 の右端の点、すなわち wave0[99] の x 座標が 100 になるようにするためです。
RightX も危険†
また、この場合の RightX(wave0) は 100 ではなく 101.01 になります。
すなわち、RightX(wave0) は一番右の点ではなくて、一番右の、さらに次の点の x 座標を返します。
かなり覚えにくいので、SetScale は /P で使うことをお勧めします。
LANG:Igor * Make/N=100 wave0 * SetScale/P x, 0, 1, wave0 * Print LeftX(wave0), DeltaX(wave0), Pnt2X(wave0, 99), RightX(wave0) 0 1 99 100
これなら驚きが少ないですよね。
ヒストグラムの罠†
Igor の Histogram は癖があるので、正しく使わないとおかしな結果を導いてしまいます。
詳しくは、棒グラフの罠 - Histogram との組み合わせ をご覧下さい。
もっともお手軽な定型処理の仕方 - コマンドラインへの貼り付け†
複数のグラフの見た目を揃えたい場合など、 ある動作を繰り返し行いたい場合に使える最もお手軽な方法は、 コマンドウィンドウに(複数の)コマンドをクリップボードから貼り付けて実行するやりかたです。
コマンドウィンドウとは†
コマンドウィンドウというのは、
[ウィンドウ]-[コマンドウィンドウ]
をせんたくするか、もっと普通には
Ctrl+J
を押すと現れる、
このウィンドウです。
このウィンドウは通常「操作のログが残るウィンドウ」として認識されているかもしれませんが、 ここに Igor のコマンドを手で打ち込むことで、任意のコマンドを実行することができます。
Hello world!†
例えばここに、
LANG:Igor DoAlert 0, "Hello world!"
と打ち込んで、最後に ENTER を押すと、
のようにアラートを表示できます。
複数行のコマンドを貼り付け†
このコマンドウィンドウには複数行のコマンドを一度に貼り付けられます。
次のテキストを選択して貼り付けると、
LANG:Igor Make/N=100 wave0 = sin(2*pi*x/99*2) Make/N=100 wave1 = cos(2*pi*x/99*3) Display wave1 vs wave0 ModifyGraph width={Plan,1,bottom,left} ModifyGraph mode=3,marker=60
こうなります。
いくつもあるグラフの見た目を揃える†
雑多なグラフが並んでいる状態から、
LANG:Igor make wave0=gnoise(1), wave1=gnoise(1), wave2=gnoise(1), wave3=gnoise(1) display wave0 display wave1 display wave2 display wave3
次の手順で1つのグラフ (Graph3:wave3) の見た目を整えました。
- 青線でマーカーを付ける
- グラフの大きさを 3cm x 6cm にする
- フォントを Times New Roman 14pt にする
- 縦横軸にラベルを付ける
コマンドウィンドウには一連の操作のログが残っていることを確認できます (黒く選択されている領域)。
このように操作ログをマウスカーソルで選択して Ctrl+C でコピーすると、 操作ログをクリップボードに入れられます。今の場合、その内容は
LANG:Igor *ModifyGraph mode=4,marker=19,msize=1,rgb=(0,0,65280) *ModifyGraph msize=3 *ModifyGraph width=170.079,height=85.0394,gFont="Times New Roman",gfSize=12 *Label left "Value [a.u.]";DelayUpdate *Label bottom "Time [s]"
のようになります。
(始め、マーカーサイズを1にしましたが、小さすぎたので3に直した様子も残っていますね)
この内容はコマンドのログのようでもありますが、 実際には同じ動作を行うためのコマンドのリストになっていて、 先頭の * さえ取り除けばそのまま Igor のコマンドとして解釈可能です。
ここで、Graph0:wave0 のグラフを選択し、前面に持ってきてから
Ctrl+J でコマンドウィンドウを出し、
Ctrl+V で先ほどコピーしたコマンドリストを貼り付けます。
(各行の先頭に * が付いていますが気にしなくて大丈夫です)
このように貼り付け後は最終行しか見えませんが、 実際にはちゃんとすべての行が貼り付けられています。
ここで ENTER を押すと、先ほどのコマンドがすべて実行され、 Graph0:wave0 の見た目が Graph3:wave3 と一致します。
この操作を Graph1:wave1, Graph2:wave2 についても行うことで、 すべてのグラフの見た目を統一することができました。
Igor で一連の動作を繰り返すにはこのように、
- まずは一回メニューなどから必要な操作をやってみて、
- コマンドウィンドウのログから必要部分を取りだして、
- 必要に応じてテキストエディタなどで編集して、
- コマンドウィンドウに貼り付けて実行する
または - Ctrl+M で出るプロシージャウィンドウに貼り付けて関数とする
- コマンドウィンドウに貼り付けて実行する
というのが一般的な手順になります。
始めからコマンドをすべて覚えていなくても メニューから選んだコマンドの名前をコマンドウィンドウのログから 知ることができるのが良いところですね。