WinSpec32/WinView32のマクロプログラミング
概略
VBScript,VisualBasicでのプログラム例
Data Acquisition を行うマクロ データファイル名を要求するダイアログを出し、その名前に変更するマクロ
演算の例 TTL(1番)ポートにパルスを送信しながらスペクトルを取得する ポンプ-プローブの例
WinSpec32/WinView32のマクロ(Automation)は、以下の点で16bit版より優位です。
1. 言語を選ばない
2. 機能(ファンクション)が豊富
1 の特徴は使い慣れた言語(Visual Basic, Visual C++)が使用でき、かつ、その言語のもつ豊富な関数をすべて利用できる事を示しています。例えば、自由にダイアログを設計したり、(既に作成済みの)科学計算用のサブルーチンを使用できます。
2の特徴は、WinSpec32/WinView32のかなりの機能を呼び出す事が出来るようになっており、今後のバージョンアップでも、その範囲は拡大される予定です。
ただし16bitにあったマクロ・レコーディング機能は、現在(Ver. 2.4)サポートされていませんが、Ver. 2.5以降ではマクロレコーディング機能が付加されます。下はα版の図ですが、操作した内容をVBScript言語で記録する事ができるようになります。
VBScriptはWindowsの標準的なスクリプト言語です。これはWindows Scripting Host (WSH)により動作するスクリプト言語です。WSHはWindows98に標準で含まれ、NT4.0やWindows95でもInternet Explorer (4.0 or later) をインストールすれば導入されます。
VBScript言語で書かれたプログラムは、Visual Basicに移行するのが容易なため、はじめVBScriptでテストして、最終的に(実行速度等で有利なため)Visual Basicで動作させると言ったことも可能です。
さらに高度なマクロ(AddIn, SnapIn)を記述するためにVisual C++を使用する事も可能です。例えば、下図は、Visual C++で記述したポンプ&プローブ(SnapIn)プログラムです。WinSpec32で取得したデータを演算し、その結果を独自にグラフ描画しています。
WinSpec32/WinView32にはVisual Basicでのマクロ(SnapIn, AddIn)の作成方法が記述された文書(Winx32 VB Automation 2.4.doc)が付属しています(邦訳は日本ローパーまでお問い合わせください)。本稿では、ダイアログボックス等を必要としない、より簡単なVBScript, Visual Basicでのマクロの例を幾つか示しますが、より詳しい内容に関しては、そちらをご覧下さい。
Set dx = CreateObject("WinX32.DocFile") Set Exp1 = CreateObject("WinX32.ExpSetup") Set Ox = Exp.Start(dx) ' Start Acquisition Exp1.WaitForExperiment ' Wait for collection to complete上の3行をエディタ等で作成し、例えばSample.vbsというファイル名で保存します。WinSpec32を起動して、MacroのExecute macro...から実行してみてください。またはVisual Basicをお持ちであれば、Sample.basというファイル名で保存し、Visual Basicでコンパイルの上、実行させて下さい。
WinSpec32は、測定を開始するはずです。
では、マクロの中身を見てみましょう。
WinSpec32/WinView32を総称して"WinX32"と呼びますが、その機能を使用するためにObjectを作成します。1行目では、WinX32の中のExpSetupというObjectを作成しています。そして、ExpSetupの中の一つのファンクションである測定を開始するファンクション-start-と、測定終了を待つファンクション-WaitForExperiment-を使用しています。
このように、WinSpec32/WinView32のマクロとは、Objectを作成して、その中のファンクションを呼ぶという作業を行う事です。では、WinX32には、どのようなObjectがあり、そのObjectは、どんなファンクションを有しているのでしょう? それは、付属のマニュアルをご覧になるか、もしVisual Basicをお使いであればObject Browserを使用する、(Microsoftが配布しているツールである)OLEVIEWを使用するなどの方法があります。
例2:データファイル名を要求するダイアログを出し、その名前に変更するマクロ
Set Exp1 = CreateObject("WinX32.ExpSetup") strName=inputbox("ファイル名を入力してください:") if strName <> "" then Exp1.SetParam 780, strName 'EXP_DATFILENAME strMsg=Exp1.GetParam(780) else strMsg="名前が入力されていません" end if wscript.echo strMsgExpSetup Objectを介してSetParam, GetParamを使用する事で、データファイル名や、露光時間等を取得したり変更したりすることが出来ます。上の780という数字はOLEVIEWで取得しました。
以下の例は、データファイルを開き、その最初のフレームを2倍した値を持つ画像を表示します。なお、VBScriptでは動作しません(後述)。
Dim theFrame As Variant ' Array that holds the image
Dim dx As New WINX32Lib.DocFile
Dim theFrame2 As Variant ' Array that holds the image
Dim dx2 As New WINX32Lib.DocFile
Dim bRes As Integer
' 最初に計算用のデータを開く
dx.Open "D:\temp\sample.spe"
Xdim = dx.GetParam(DM_XDIM) ' get the document x dimension
Ydim = dx.GetParam(DM_YDIM) ' get the document y dimension
' 1 フレーム目を取得
dx.GetFrame 1, theFrame ' retrieve 1 image
' 計算用のイメージを開く
dx2.Open "", Xdim, Ydim, 1, 4, "temp" ' double floating type
' 1 フレーム目を取得
dx2.GetFrame 1, theFrame2 ' retrieve 1 image
'****************************************
' 実際の計算部分
'****************************************
For i = 0 To (Ydim - 1) 'Loop through y dim
For j = 0 To (Xdim - 1) ' Loop through x dim
theFrame2(j, i) = theFrame(j, i) * 2
Next j
Next i
dx2.PutFrame 1, theFrame2
dx2.Update
拡張子をbasとしてセーブし実行します。同様な事はVBScriptでも可能で、以下に例を示します。Option Explicit 'Strict
Dim dx1
Set dx1 = CreateObject("WinX32.DocFile")
Acquisition(dx1)
CalcSub(dx1)
Sub Acquisition(ByRef dx1)
Dim dx2, Exp1, xdim, ydim, zdim, strMsg
Set Exp1 = CreateObject("WinX32.ExpSetup")
Exp1.Start(dx1)
Exp1.WaitForExperiment ' Wait for collection to complete
End Sub
Sub CalcSub(ByRef dx1)
Dim temp
Dim dx2, Exp1, xdim, ydim, zdim, strMsg, i, j
Dim datatype
xdim=dx1.GetParam(6) 'DM_XDIM
ydim=dx1.GetParam(7) 'DM_YDIM
zdim=dx1.GetParam(24) 'DM_NUMFRAMES
datatype=dx1.GetParam(9) 'DM_DATATYPE
strMsg = CStr(xdim) & "x" & CStr(ydim) & "x" & CStr(zdim) & "のデータを2倍します"
Wscript.Echo strMsg
' 新しいデータファイルを開く
' ディメンジョンはdx1と同じ
' ファイル名は"temp"
Set dx2 = CreateObject("WinX32.DocFile")
dx2.Open "", xdim, ydim, zdim, datatype, "temp"
'****************************************
' 実際の計算部分
'****************************************
For i = 0 To xdim 'Loop through x dim
For j = 0 To ydim ' Loop through y dim
temp=2*dx1.GetPixel(1, j, i)
dx2.PutPixel 1, j, i, temp
Next
Next
dx2.Update
End Sub
ただし、実際に動作させて見ると、非常に遅い事がわかると思います。これは、ピクセルの値を毎回WinSpecに問い合わしているためで、先のVisual Basic版では、フレームごとデータを取得しているため高速に動作するのです。つまり、マクロを高速で動作させるには、WinSpecとの通信オーバーヘッドを減らす事が重要になります。(著者はVisual Basicに精通していないのですが、Visual Basicの例では1フレームのデータを配列で一度に取得している。VBScriptでは、こうした事は出来ない様に思われます。)
例4:TTL(1番)ポートにパルスを送信しながらスペクトルを取得する
PI社のCCDカメラコントローラーには、外部出力用のTTLポートがあります。このポートを使用してステッピングモータを動作させたりする場合のサンプルです。
Dim Exp1 Dim dx Dim count Dim framecount Dim ttl count=0 Set dx1 = CreateObject("WinX32.DocFile") Set Exp1 = CreateObject("WinX32.ExpSetup") Exp1.Start( dx1 ) While Exp1.GetParam(797) ' 797=EXP_RUNNING framecount=dx.GetParam(91) If count < framecount Then ttl=&H00FF Exp1.SetParam 91, ttl ttl=&H00FE Exp1.SetParam 91, ttl count=count+1 End If Wend
白色光吸収スペクトルを測定するプログラム(ポンプ-プローブ)を示します。TTLポートの1番に外部シャッターを接続し、そのシャッターでポンプ光を遮断した時のスペクトルと開いた時のスペクトルの除算(透過率)を表示するプログラムです。演算速度の問題からVisual Basicでの記述としております。
Dim theFrame1 As Variant Dim theFrame2 As Variant Dim ex As New ExpSetup Dim dx1 As DocFile Dim dx2 As DocFile Dim bRes As Integer Dim filename1 As Variant Dim filename2 As Variant Dim ttl As Variant filename1 = "Io" filename2 = "I" ttl = &H0 ex.SetParam EXP_TTL_LINES, ttl ex.SetParam EXP_DATFILENAME, filename1 If ex.Start(dx1) Then ex.WaitForExperiment dx1.GetFrame 1, theFrame1 ex.SetParam EXP_DATFILENAME, filename2 ttl = &H1 ex.SetParam EXP_TTL_LINES, ttl If ex.Start(dx2) Then ex.WaitForExperiment dx2.GetFrame 1, theFrame2 '以上でデータの取得は終了 For i = LBound(theFrame1, 2) To UBound(theFrame1, 2) For j = LBound(theFrame1, 1) To UBound(theFrame1, 1) If theFrame1(j, i) > 0 Then theFrame2(j, i) = theFrame2(j, i) / theFrame1(j, i) Else theFrame2(j, i) = 0 End If Next Next dx2.PutFrame 1, theFrame2 dx2.Update End If End If
また、更にTTLポートの3番を使用してパルスを送ってステージを動作させる事を想定したサンプルプログラムも用意しています。こちらは、下のVC++での例と同様、TTLポートの1番と2番に外部シャッターを接続し、1番のシャッターでプローブ光(白色光)を、2番のシャッターでポンプ光をコントロールし、ダークも自動的に測定します。さらに、CCD素子のビニング(グルーピング)がしてあるとして(もしくはDual PDAを使用して)、上の領域に試料を通過するスペクトルを、下の領域でサンプルを通過しない参照スペクトルを取得して、白色光の揺らぎを抑える事が出来るように作成してあります。
その他、WinSpec32/WinView32に付属の文書(Winx32 VB Automation 2.4.doc)には、幾つかのプログラミング例が掲載されています。ぜひ、そちらをご覧になることをお勧めします。
日本ローパー及び、ローパーサイエンティフィック社では、C++言語でのマクロ(Automation)の公式なサポートは行っていません。C++で制御したい方は市販のCOMプログラミングに関する書籍をご覧下さい。ここでは、簡単な例だけを示しておきます。(C++でのプログラミングに関するご質問には回答できません)
下のプログラム例をコンパイルするために、VC++6.0のプロジェクトウィザードからWin32 Console Applicationを作成してください。C++言語では、COMインターフェースの情報をタイプライブラリと呼ばれるファイルから取得します。このために、
#import "C:\Program Files\Princeton Instruments\WinSpec32\WinSpec.exe"
のようにインポートディレクティブを使用します。例として白色光吸収スペクトルを測定するプログラム(ポンプ-プローブ)を示します。Visual Basicでの例より少し凝っています。TTLポートの1番と2番に外部シャッターを接続し、1番のシャッターでプローブ光(白色光)を、2番のシャッターでポンプ光をコントロールし、ダークも自動的に測定します。さらに、CCD素子のビニング(グルーピング)がしてあるとして(もしくはDual PDAを使用して)、上の領域に試料を通過するスペクトルを、下の領域でサンプルを通過しない参照スペクトルを取得して、白色光の揺らぎを抑える事が出来るように作成してあります。2番のシャッターでポンプ光を遮断した時のスペクトルと開いた時のスペクトルの除算(透過率)を表示するプログラムです(ちと長いです)。
#include "stdafx.h" #include "stdio.h" #import "C:\Program Files\Princeton Instruments\WinSpec32\WinSpec.exe" WINX32Lib::IDocFilePtr pMeasureSub(_variant_t Filename, int nCount) { WINX32Lib::IExpSetupPtr pExp( __uuidof(WINX32Lib::ExpSetup) ); static WINX32Lib::IDocFilePtr pDoc( __uuidof( WINX32Lib::DocFile )); long framecount=0; long count; short running; _variant_t var; short response; // Backgroundを使わない var=(long)FALSE; pExp->SetParam( WINX32Lib::EXP_BBACKSUBTRACT, &var ); // data-typeをLongに固定 var=(long)WINX32Lib::X_LONG; pExp->SetParam( WINX32Lib::EXP_DATATYPE, &var ); // Overwriteでいく var=(long)WINX32Lib::EXPFA_OVERWRITE; pExp->SetParam( WINX32Lib::EXP_FILEACCESS, &var ); /* overwrite confirmを消す */ var=(long)FALSE; pExp->SetParam( WINX32Lib::EXP_OVERWRITECONFIRM, &var ); // Auto-saveを設定 var=(long)WINX32Lib::EXPAS_AUTO; pExp->SetParam( WINX32Lib::EXP_AUTOSAVE, &var ); // ファイル名を設定する var=Filename; pExp->SetParam( WINX32Lib::EXP_DATFILENAME, &var ); // Frame数を設定 var=(long)nCount; pExp->SetParam( WINX32Lib::EXP_SEQUENTS, &var ); // 測定スタート pExp->Start(&pDoc); running = TRUE; count=1; framecount=0; /* loop until all frames acquired */ do { while (( framecount < count ) && (running)) { /* While Experiment is running */ var = pDoc->GetParam( WINX32Lib::DM_LASTFRAMERDY, &response ); framecount = (long) var; running = pExp->GetParam(WINX32Lib::EXP_RUNNING, &response); } if ( running ) count++; } while (( count <= nCount ) && (running)); var = pDoc->GetParam( WINX32Lib::DM_LASTFRAMERDY, &response ); framecount = (long) var; /* ABORT */ if ( framecount < nCount ) { return NULL; } /* END ABORT */ return pDoc; } int main(int argc, char* argv[]) { CoInitialize( NULL ); // 必須 WINX32Lib::IExpSetupPtr pExp( __uuidof(WINX32Lib::ExpSetup) ); WINX32Lib::IDocFilePtr pDoc( __uuidof( WINX32Lib::DocFile )); WINX32Lib::IDocFilePtr pDocNew( __uuidof( WINX32Lib::DocFile )); _variant_t vData, vData2; // make an empty variant for the data SAFEARRAY *pSA, *pSA2; LONG *pDataLong; // 2 double *pDataDouble; // 4 long frames; short response; _variant_t var; int j, k; int status = 1; _variant_t ttl((long)0x00); double *dBkg1, *dBkg2, *dRef, *dTrans; double dTmp1, dTmp2; int *nAvr; variant_t Filename, FilenameOrg; long xdim, ydim, zdim; xdim = (long) pExp->GetParam( WINX32Lib::EXP_XDIM, &response ); ydim = (long) pExp->GetParam( WINX32Lib::EXP_YDIM, &response ); if (ydim!=2){ // ROIが2つ設定されていないと動作しない CoUninitialize(); // 必須 return -1; } dBkg1=new double[xdim]; dBkg2=new double[xdim]; dRef=new double[xdim]; dTrans=new double[xdim]; nAvr=new int[xdim]; /* Get the number of frames that we are getting */ frames=(long)pExp->GetParam( WINX32Lib::EXP_SEQUENTS, &response ); // new doc xdim X ydim X zdim as float type var=pExp->GetParam( WINX32Lib::EXP_DATFILENAME, &response ); FilenameOrg = var.bstrVal; // まずバックグラウンドを取得 // シャッターをクローズ ttl = (long)0x0c; pExp->SetParam( WINX32Lib::EXP_TTL_LINES, &ttl ); Filename="PumpPrb_Bkg"; pDoc=pMeasureSub(Filename, 1); if (pDoc==NULL){ return 0; } zdim = (long) pDoc->GetParam( WINX32Lib::DM_FRAMECOUNT, &response ); for (k = 0; k < (long)xdim; k++){ dBkg1[k]=0.0; dBkg2[k]=0.0; } for ( j=0; j < zdim;j++){ pDoc->GetFrame(j+1, &vData); // get the data pSA = V_ARRAY(&vData); if (S_OK ==(long)SafeArrayAccessData(pSA, (void **)&pDataLong)){ for (k = 0; k < (long)xdim; k++){ dBkg1[k]+=(double)pDataLong[k]; dBkg2[k]+=(double)pDataLong[k+xdim]; } SafeArrayUnaccessData(pSA); // unlock the array } } for (k = 0; k < (long)xdim; k++){ dBkg1[k]/=(double)zdim; dBkg2[k]/=(double)zdim; } pDoc->Close(); /* 透過率用のデータを開く */ pDocNew->Open("", xdim, 1L, 1L, (long)WINX32Lib::X_DOUBLE, "Trans"); WINX32Lib::IDocWindowPtr pWin=pDocNew->GetWindow(); var=(long)FALSE; pWin->SetParam(WINX32Lib::DI_BINITAUTOSCALE, &var); var=(double)0.0; pWin->SetParam(WINX32Lib::DI_DATAINTENLO, &var); var=(double)1.2; pWin->SetParam(WINX32Lib::DI_DATAINTENHI, &var); // 次にIoを取得 // LSBをHighにしてシャッターをオープン ttl = (long)0x0d; pExp->SetParam( WINX32Lib::EXP_TTL_LINES, &ttl ); for (int nCount=0;nCount<2; nCount++){ Filename="PumpPrb_Io"; pDoc=pMeasureSub(Filename, 1); if (pDoc==NULL){ break; } zdim = (long) pDoc->GetParam( WINX32Lib::DM_FRAMECOUNT, &response ); for (k = 0; k < (long)xdim; k++){ dTrans[k]=0.0; nAvr[k]=0; } for ( j=0; j < zdim;j++){ pDoc->GetFrame(j+1, &vData); // get the data pSA = V_ARRAY(&vData); if (S_OK ==(long)SafeArrayAccessData(pSA, (void **)&pDataLong)){ for (k = 0; k < (long)xdim; k++){ dTmp1=(double)pDataLong[k]-dBkg1[k]; dTmp2=(double)pDataLong[k+xdim]-dBkg2[k]; if (dTmp2>0.0){ dTrans[k]+=dTmp1/dTmp2; nAvr[k]++; } } SafeArrayUnaccessData(pSA); // unlock the array } } for (k = 0; k < (long)xdim; k++){ if (nAvr[k]>0) dTrans[k]/=(double)nAvr[k]; else dTrans[k]=0.0; } pDoc->Close(); if (nCount==1){ for (k = 0; k < (long)xdim; k++){ if (dRef[k]>0.0) dTrans[k]/=dRef[k]; else dTrans[k]=0.0; } for (k = 0; k < (long)xdim; k++) dRef[k]=dTrans[k]; pDocNew->GetFrame(1, &vData2); // get the data pSA2 = V_ARRAY(&vData2); if (S_OK == (long)SafeArrayAccessData(pSA2, (void **)&pDataDouble)){ for (k = 0; k < (long)xdim; k++){ pDataDouble[k]=dTrans[k]; } SafeArrayUnaccessData(pSA2); // unlock the array pDocNew->PutFrame(1, &vData2); // stuff the data back into the doc pDocNew->Update(); } } } delete[] dBkg1; delete[] dBkg2; delete[] dRef; delete[] dTrans; delete[] nAvr; // シャッターをクローズ ttl = (long)0x0c; pExp->SetParam( WINX32Lib::EXP_TTL_LINES, &ttl ); // ファイル名を戻す var=FilenameOrg; pExp->SetParam( WINX32Lib::EXP_DATFILENAME, &var ); // データタイプを戻す var=(long)WINX32Lib::X_UNKNOWN; pExp->SetParam( WINX32Lib::EXP_DATATYPE, &var ); CoUninitialize(); // 必須 return 0; }
最終更新日 2000/07/14