C/C++によるイベント計測
Cosmo-Zには、トリガが発生したaaaaaaa場合のみ記録するというイベント計測機能があります。
このページではイベント計測を行うプログラムの作成方法を説明します。
最初に、イベントキャプチャのプログラムの例を示し、個々の部分を解説していきます。
#include "cosmoz.h" #include <unistd.h> int main () { csz_open(INTERFACE_ZYNQ,NULL); // csz_adc_freq(80); // usleep(100000); // ADC周波数を変えた場合は30ms以上のWaitが必要 const int DATASIZE=2048; CAPTURE_INFO info; csz_capture_abort(); // 既に何かのキャプチャが実行されていたら強制終了 for(int ch = 0 ; ch < 8 ; ch++) { // 不要なチャネルはトリガオフ csz_trig_set_voltage(ch + 1,TRIGTYPE_OFF, 0); } csz_trig_set_voltage(1,TRIGTYPE_FALL, -0.05); // CH1を-0.1Vを閾値としてFALL条件 // トリガ前20ポイント、トータル140ポイントをキャプチャする csz_pretrig_set(20); csz_posttrig_set(140); csz_posttrig_fixed(true); // 固定長トリガ // イベントキャプチャの実行 // CH1をキャプチャし、10イベント発生したら終了する info = csz_evcap_execute(0x01, 10, CAPTRIG_EVENT, NULL, NULL); if(info.result != CAPRESULT_SUCCESS) { printf("Capture error %d\n",info.result); csz_close(); return 0; } // 何個のイベントが発生したかを調べて、格納する配列を確保する printf("Total Event count = %d\n",info.iteration); uint16_t **data = new uint16_t*[info.iteration]; int *evlen = new int[info.iteration]; for(int i=0;i<info.iteration;i++) { data[i] = new uint16_t[DATASIZE]; } uint64_t starttime48 = info.start_time48;// 開始時刻 int maxlen = 0; // 一連の計測の中で一番長いもの EVHEADER_STR hdr; // 個々のイベント情報を取り出す for(int i=0;i<info.iteration;i++) { csz_evcap_get_next(&info, &hdr, data[i]); // イベントのヘッダと波形を取得 evlen[i] = hdr.length; if(hdr.length > maxlen) maxlen = hdr.length; printf("event %d on CH%d ",hdr.evcount, hdr.ch); // ヘッダ情報の表示 printf("%.3f[ms] ",(hdr.time48 - starttime48) * 10 / 1000000.); printf("Len:%d Height:%d ",hdr.length, hdr.plsh); printf("\n"); } // イベントキャプチャ波形の表示 // タイトル行 printf("Time[ns]\t"); for(int i=0;i<info.iteration;i++) { printf("Event%d\t",i); } printf("\n"); // 縦横を並べ替えて表示 for(int j=0;j<maxlen;j++) { printf("%.1f\t",1000.0 / info.sampling_rate * j); for(int i=0;i<info.iteration;i++) { if(evlen[i] >= j) printf("%d\t",data[i][j]); else printf("\t"); } printf("\n"); } // 配列の解放 delete[] evlen; for(int i=0;i<info.iteration;i++) { delete[] data[i]; } delete[] data; csz_close(); }
以前のキャプチャの強制終了
csz_capture_abort関数は、現在実行中の波形キャプチャを強制終了します。
csz_capture_abort(); // 既に何かのキャプチャが実行されていたら強制終了
計測長の設定
下記の例では、csz_posttrig_set関数により長さ140の計測を行う設定を行います。固定長トリガに設定しているのでトリガがかかった時点を基準に後ろに140の長さの計測を行います。長さ140というのは、140×1/サンプリング周波数 秒になります。
csz_pretrig_set(20); csz_posttrig_set(140); csz_posttrig_fixed(true); // 固定長トリガ
イベントキャプチャの実行
イベントキャプチャはcsz_evcap_execute関数で行います。
この関数のプロトタイプは
CAPTURE_INFO csz_evcap_execute( uint32_t chmask, int count, CAPTURE_TRIGGER type, CALLBACK_EVENTCAP func, void *param);
です。
第一引数はチャネルの指定でビットフィールドになっています。例えば、CH1~CH8を記録する場合は0xffを指定します。CH1とCH3とCH5を記録する場合は0x15を指定します。
第二引数は時間またはイベントの個数です。
第三引数にCAPTRIG_MESUNITが指定された場合は秒数で、CAPTRIT_EVENTが指定された場合はイベント数が終了条件となります。
次の例は、100個のイベントを、CH1に関してキャプチャします。
info = csz_evcap_execute(0x01, 100, CAPTRIG_EVENT, NULL, NULL);
次の例は、100秒間のイベントを、CH1に関してキャプチャします。
info = csz_evcap_execute(0x01, 100, CAPTRIG_MESUNIT, NULL, NULL);
第四、第五引数はイベントが入るとコールバックされる関数の登録とその引数です。例えば、イベントが発生した場合にTCP/IPで通信を行ったり、時々刻々と記録していくような場合に使用します。
イベントキャプチャの戻り値
csz_evcap_execute関数はイベントキャプチャが完了するかエラーで終了するまで制御を返しません。戻り値はCAPTURE_INFO型の構造体で、様々な情報がセットされて戻ります。
この中で重要なのはresultとiterationです。resultは、キャプチャが成功したかエラーで終了したかを示します。iterationは、キャプチャしたイベントの個数を示します。
型 | 変数名 | 機能 |
---|---|---|
CAPTURE_RESULT | result | キャプチャ実行結果 CAPRESULT_SUCCESS キャプチャは成功した CAPRESULT_ABORTED ユーザからの指示で中断された CAPRESULT_ERROR データの転送が間に合わない CAPRESULT_ANOTHERRUN 他のキャプチャが動作中 CAPRESULT_TRIGGER_TIMEOUT トリガ待ち状態 CAPRESULT_CORRUPTED 取得したデータが壊れている |
uint32_t | chmask | キャプチャしたチャネル |
int | chcount | キャプチャしたチャネル数 |
int | length | キャプチャ長 |
int | iteration | 繰り返し回数 |
int | maxseq | 最大シーケンス長 |
CAPTURE_TRIGGER | trig | キャプチャトリガの種類 CAPTRIG_AUTO オシロのAUTOと同じ CAPTRIG_NORMAL オシロのNORMALと同じ CAPTRIG_MESUNIT イベントモードで秒数で指定 CAPTRIG_EVENT イベントモードでイベント数で指定 CAPTRIG_LAST 最後に表示した波形を再取得 |
time_t | start_time | 開始時刻 |
time_t | end_time | 終了時刻 |
double | sampling_rate | サンプリングレート |
int | adc_freq | 実行開始時のADC周波数 |
int | adc_div | 実行開始時のデシメーション比 |
int | resolution | 分解能(bit単位) |
uint32_t | gps_time | 実行開始時のGPS時刻 |
uint32_t | gps_10ns | 実行開始時のGPS時刻 10ns単位 |
uint32_t | gps_maxcount | 実行開始時のGPS最大カウント |
uint64_t | start_time48 | 実行開始時の48bitタイムスタンプ |
uint32_t | top_addr | 格納される物理アドレスの先頭 |
uint32_t | bot_addr | 格納される物理アドレスの最後尾 |
uint32_t | last_addr | 格納された物理アドレスのlast |
int | mesp | 現在読み出し中のデータのポインタ |
int | evcount | 現在読み出し中のデータの数 |
uint32_t | prev_capaddr | イベントキャプチャのデータをここまで読んだポインタ |
uint32_t | start_addr | イベントキャプチャのデータが入っている先頭アドレス |
RESULTは実行結果で、CAPRESULT_SUCCESSを返した場合はキャプチャは成功です。
この構造体を参照することで、キャプチャ時のADC分解能やサンプリングレート、開始時刻、データ長などを知ることができます。
ヘッダの値の詳しい解説はファイルフォーマットのページご覧ください。
イベントデータの取り出し
csz_evcap_execureが終了した時点では波形メモリの中(基板上のDDR3 SDRAM内のOS管理外領域)に波形が入っていて、ユーザのバッファにはコピーされていません。
波形メモリからデータを取り出してユーザバッファにコピーする関数が、
BOOL csz_evcap_get_next(CAPTURE_INFO *info,EVHEADER_STR *hdr,uint16_t *data);
です。
この関数を呼び出す前に、EVHEADER_STR型のインスタンスと、データを受け取るためのバッファを作っておく必要があります。csz_evcap_get_nextを実行すると、hdrに波形の情報が、dataに個々のイベントキャプチャされた波形が入ります。
info.iterationに示された回数だけcsz_evcap_get_nextを実行を繰り返し実行すると、すべての波形を取得することができます。
第一引数のinfoには、csz_evcap_executeの戻り値を入れます。
第二引数のhdrは、EVHEADER_STR型のインスタンスへのポインタを入れます。EVHEADER_STRは波形のヘッダ情報が入る構造体ですが、
EVHEADER_STR hdr;
でインスタンスを作り、初期化しないまま&を付けてアドレスを与えれば十分です。構造体の各要素はcsz_evcap_get_next関数内でセットされます。
hdrの各要素には次のような情報が格納されます。
型 | 変数名 | 機能 |
---|---|---|
int | evcount | このイベントが何番目のイベントか |
uint16_t | hdr | ヘッダ情報 |
uint16_t | ch | 発生したイベントのチャネル番号 |
uint16_t | length | 波形の長さ |
uint64_t | time48 | 発生した時刻。FPGAの起動時から10ns単位で表される |
uint16_t | plsh | パルスハイト(イベント波形の最大値) |
uint32_t | sum | パルス面積(トリガ期間中の値の総和) |
uint16_t | ped | ペデスタルレベル(無信号時の値) |
uint16_t | meslen | トリガ長 |
int | mesp | システム内部で使用 |
ヘッダの値の詳しい解説はファイルフォーマットのページご覧ください。
第三引数のdataは、dataは波形が入るバッファのアドレスを入れます。イベントキャプチャされた波形の長さはプレトリガとポストトリガの長さの和なので、最大でも2048あれば足ります。new uint16_t[2048]とすれば十分なバッファが作れます。
この部分のサンプルプログラムを以下に示します。
// 何個のイベントが発生したかを調べて、格納する配列を確保する printf("Total Event count = %d\n",info.iteration); uint16_t **data = new uint16_t*[info.iteration]; int *evlen = new int[info.iteration]; for(int i=0;i<info.iteration;i++) { data[i] = new uint16_t[DATASIZE]; } uint64_t starttime48 = info.start_time48;// 開始時刻 int maxlen = 0; // 一連の計測の中で一番長いもの EVHEADER_STR hdr; // 個々のイベント情報を取り出す for(int i=0;i<info.iteration;i++) { csz_evcap_get_next(&info, &hdr, data[i]); // イベントのヘッダと波形を取得 evlen[i] = hdr.length; if(hdr.length > maxlen) maxlen = hdr.length; printf("event %d on CH%d ",hdr.evcount, hdr.ch); // ヘッダ情報の表示 printf("%.3f[ms] ",(hdr.time48 - starttime48) * 10 / 1000000.); printf("Len:%d Height:%d ",hdr.length, hdr.plsh); printf("\n"); }
上記プログラムの実行結果
本ページの最初に掲載されたプログラムを動作させた結果を示します。このプログラムはCH1に発生した10個のイベントをキャプチャして、それを縦横を並べ替えて表示します。
これをテキストファイルに保存すれば、Excelなどで波形を重ねて表示できます。
イベントプログラムでは具体的に何をすればよいか?
取り出したイベントの波形データの処理方法は計測の目的によって異なります。
時間ごとのカウントの変化だけを見ればよい場合は、取得された波形や時刻情報は捨ててしまってもよいでしょう。例えば、PET-CT後に人体から放出される放射線の数を測りたい場合などが該当します。
時刻と波高値を記録したい場合には、time48とplshを記録していけばよいでしょう。
天文現象などで正確な時刻が必要な場合はGPS関係の値も保存する必要があるかもしれません。
逆に、レーザーを使ったポンプ光プローブ光の測定の場合はdataも保存する必要があるかもしれません。