4. パルス計測プログラムのビルドと測定実行 – GROWTH FPGA/高速ADCボード

Pocket

雷雲ガンマ線プロジェクト(GROWTH / Thundercloud Project)で開発したGROWTH FPGA/高速ADCボードに関する記事の第四回です。

GRWOTH FPGA/ADCボード関連の記事一覧

  1. GROWTH FPGA/高速ADCボードの概要
  2. GROWTH FPGA/高速ADCボードの拡張コネクタ
  3. GROWTH FPGA/高速ADCボードのFPGA書き込み
  4. パルス計測プログラムgrowth_daqのビルドと測定実行

GROWTH実験チームでは、GROWTH FPGA/ADCボード用のFPGAイメージに対応したパルス計測・波形取得用のDAQプログラム(growth_daq)をC++で開発して、オープンソースで公開しています。第三回の手順でFPGAを書き込んだボードをMacやRaspberry Piに接続して、growth_daqを実行すると、パルス信号をセルフトリガ方式でトリガしてFITSファイルやROOTファイルにデータを保存できます。なお、growth_daqはC++で記述されたスタンドアロンのプログラムですが、FPGAボードを制御したり取得したデータを伝送したりする機能はライブラリとして分離されています。このライブラリのクラスをユーザが自作したプログラムから利用すれば、実験ごとの要求に応じたデータ取得プログラムを開発することも可能です。

今回はこのgrowth_daqの入手方法、ビルド手順と実行方法を説明します。

この手順にそって作業していても、依存関係のエラーが出る場合があります。その場合はお手数ですが、このブログのコメント欄かgithubのIssueページで連絡してください。

GROWTH-DAQの入手とビルド

gitレポジトリのクローン

growth_daqは、githubで公開されているGROWTH-DAQというgitレポジトリに入っています。Mac/Raspberry Pi上のコマンドラインから以下のようにしてcloneしてください。gitが入っていない場合は、Homebrewやapt-getでインストールしてください。git submoduleコマンドは、GROWTH-DAQが依存しているライブラリのうち、githubからcloneできるものを自動的にcloneしてくるためのコマンドです。具体的には、GROWTH-DAQ/.gitmodulesに列挙されたライブラリがcloneされます。

cd $HOME
mkdir git
cd git

# Clone the repository
git clone https://github.com/growth-team/GROWTH-DAQ.git

cd GROWTH-DAQ

# Pull git submodules
git submodule init
git submodule update

なおGROWTH-DAQは、GROWTH実験で開発した検出器システムを雷雲ガンマ線の観測実験で屋外で自律運用するためのソフトウエア群をまとめたgitレポジトリなので、トップディレクトリのREADME.mdではGROWTH-FY2016(とそれ以降)の検出器を駆動する際の手順が説明されています。growth_daqはdaq/内に格納されており、対応するREADMEファイルはdaq/README.mdです。

依存関係のインストール

Macでは、Homebrewをインストールしてから、以下の手順でgrowth_daqが依存しているライブラリをインストールしてください。

cd $HOME/git/GROWTH-DAQ/setup
bash install_brew.sh

Raspberry Piでは以下の手順でgrowth_daqが依存しているライブラリをインストールしてください。

cd $HOME/git/GROWTH-DAQ/setup
sudo ./install_apt-get.sh &> log_apt.text
sudo ./install_python.sh &> log_python.text
./install_adafruit_ssd1306.sh &> log_adafruit.text
sudo ./install_ruby_gem.sh &> log_ruby_gem.text
sudo ./install_wiringPi.sh &> log_wiringPi.text

 

ビルド(FITSファイルに保存する場合 == デフォルト)

以下の手順でビルドしてください。

cd $HOME/git/GROWTH-DAQ/daq
# Build
mkdir build
cd build
cmake ..
make -j2
ls growth_daq

ビルドが終了するとgrowth_daqという実行形式ができているはずです。

ビルド(ROOTファイルに保存する場合)

デフォルトのデータフォーマットは高エネルギー宇宙物理学でよく使われているFITS形式です。RubyFitsやpyfitsでデータ解析できます。

ROOTファイルで保存したい場合は、cmakeに-DUSE_ROOT=1を指定してください。

cd $HOME/git/GROWTH-DAQ/daq
# Build
mkdir build
cd build
cmake .. -DUSE_ROOT=1
make -j2
sudo make install

gitレポジトリに入っているCMakeLists.txtは、ROOTのヘッダファイル/ライブラリの検索パスとして以下を使用します。本当はFindROOT.cmakeを読み込むのが正しい方法なのですが、現時点では環境・インストール方法によっていろんなパスの組み合わせがあるため、代表的なパスをハードコードしています。お使いの環境でROOTのヘッダファイル・ライブラリファイルが入っているパスに書き換えて使用してください。

 set(ROOT_INCLUDE_DIR $ENV{ROOTSYS}/include/root)
 set(ROOT_LIB_DIR $ENV{ROOTSYS}/lib/root)

デフォルトでは/usr/local/bin/growth_daqとしてインストールされるはずです。インストール先を変更したい場合は、cmakeコマンドに-DCMAKE_INSTALL_PREFIX=…を追加してください。

Example:
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/bin/

CMakeLists.txtはHomebrewでROOTがインストールされていることを仮定しています。もしROOTのインストールパスが/usr/local/でない場合は、GROWTH-DAQ/daq/CMakeLists.txtの

if(USE_ROOT)
 set(CMAKE_MODULE_PATH /usr/local/etc/root/cmake/)
 find_package(ROOT REQUIRED)
 include_directories(${ROOT_INCLUDE_DIRS})
 add_definitions(-DUSE_ROOT)
 set(ROOT_LIBS ${ROOT_LIBRARIES})
endif(USE_ROOT)

という部分で、CMAKE_MODULE_PATHがroot/cmakeを指すように変更・保存してから、上記のビルドを実行してください。

growth_daqによる測定

コンフィグレーションファイル

growth_daqは、測定のパラメタYAML形式のコンフィグレーションファイルから読み込みます。測定を実行するまえに、その測定で適切なパラメタを設定したYAMLファイルを用意する必要があります。

YAMLファイルのサンプルを以下に示します。

DetectorID: growth-fy2016z
PreTriggerSamples: 20
PostTriggerSamples: 1000
SamplesInEventPacket: 1000
ChannelEnable: [yes,yes,yes,yes]
TriggerThresholds: [2100, 2100, 2100, 2100]
TriggerCloseThresholds: [2090, 2090, 2090, 2090]

この中で設定している項目は以下の通りです。

  • DetectorID: FITSファイルのヘッダに記録される検出器名(任意に設定)
  • PreTriggerSamples: thresholdを超える波高値をもつパルスをFPGAで処理する際に、トリガ前の情報をどれだけ使用するか(単位 = ADCサンプル; max 31)
  • PostTriggerSamples: thresholdを超える波高値をもつパルスをFPGAで処理する際に、トリガ後の波高値をどれだけ使用するか(単位 = ADCサンプル; max 1023 – PreTriggerSamples)
  • SamplesInEventPacket: FPGAでの波高値計算処理のあと、イベントパケットを作成する際にどれだけ波高値情報を残すか。各パルスの波高値だけ残したい場合は、YAMLコンフィグレーションファイルでSamplesInEventPacketを1にする(単位 = ADCサンプル; max PostTriggerSamples + PreTriggerSamples)
  • ChannelEnable: Ch.0 〜 Ch.4 のどのChannelをenableするか(例: [yes,yes,yes,yes]だと4chすべてenable、[yes, yes, no, no]だとCh.0とCh.1のみenable、Ch.2/3は測定しない)
  • TriggerThresholds: トリガを開始するthreshold(単位 = ADC ch; 例: [2100, 2100, 2100, 2100])
  • TriggerCloseThresholds: トリガを終了するthreshold。トリガが開始して、PreTriggerSamples + PostTriggerSamplesサンプルにわたって波高値を記録したあと、波高値がこのthresholdを下回るとトリガ終了となり、取得された波高値情報が後段の処理回路に渡ります。(単位 = ADC ch; 例: [2090, 2090, 2090, 2090])

GROWTH FPGA/ADCは入力レンジが+/-5Vで、-5〜+5Vが0〜4095chに対応します。0Vはだいたい2048chです。入力するパルスに合わせてthresholdを計算して設定してください。

よくあるミス: 入力しているアナログ信号のベースライン(パルスイベントがないときの電圧値)が、アンプのオフセットのために0V (2048ch)よりも少し高くて2095chになっているとします。このときに、TriggerCloseThresholdsを2090chに設定していると、「TriggerThresholdsを上回る波高値のパルスイベントが到来したあと、波高値が2090chを下回らないために、最初のトリガがいつまでも終了しない」ということが起こります。これは見かけ上、全くイベントが出力されないようにみえるので、デバッグがややこしいです。TriggerCloseThresholdsをどこに設定すればよいかわからない場合は、このような問題を避けるため、TriggerThresholdsと同じ値を設定しておいてもよいと思います。

GROWTH FPGA/ADCボードの接続

GROWTH FPGA/ADCボードをUSBケーブルでMac/Raspberry Piに接続して、ボードの電源を投入します。自動的にドライバが読み込まれ、/dev/以下にこのボードに対応したttyデバイスが2つ追加されるはずです。デバイスの名前は毎回かわる可能性があるので、以下のようにして確認してください。

# Mac:
ls /dev/tty.usbserial*
# Raspberry Pi:
ls /dev/ttyUSB*

デバイスが追加されない場合は、FPGAが正しく書き込めていない可能性があります。また、他の用途でVMWareの仮想マシンをバックグラウンドで起動している場合は、USBデバイスがVMWare側に接続されてしまっているかもしれません。デバイス一覧からFTDIデバイスを接続解除するとホストマシンに接続され、上記のlsコマンドでデバイス名が確認できるはずです。

growth_daqの実行

FPGAボードと通信するためのデバイス名(AとBが追加されるうちのA側を指定。1/2の場合は1)と、コンフィグレーションファイル、測定の積分時間(秒)を指定して以下のように実行してください。カレントディレクトリにイベントファイルがYYYYMMDD_HHMMSS.fitsという名称で作成されます。

Usage:
$ growth_daq (serial device) (configuration file) (exposure in sec)

Example (Mac):

$ growth_daq /dev/tty.usbserial--FT0K8WCSA configuration.yaml 100

Example (Raspberry Pi):
$ growth_daq /dev/ttyUSB1 configuration.yaml 100

なお、Macでgrowth_daqを動作させるときは、Terminal.appの設定画面から、ログの保存を10000行などの有限の値に制限してください。デフォルトだと、永久にスクロールして戻れるようにメモリに画面データを保存しつづけるため、長時間の観測を行うとログがどんどんメモリを圧迫してメモリ不足になる可能性があるので注意してください。

イベントファイルの構造

保存されるFITSファイルは以下のような構造になっています。

growth_daq_sample_fits_hdus

EVENTS extension

EVENTS extensionのヘッダは以下のようになっています。

XTENSION= 'BINTABLE' / binary table extension
BITPIX = 8 / 8-bit bytes
NAXIS = 2 / 2-dimensional binary table
NAXIS1 = 27 / width of table in bytes
NAXIS2 = 32000 / number of rows in table
PCOUNT = 0 / size of special data area
GCOUNT = 1 / one data group (required keyword)
TFIELDS = 11 / number of fields in each row
TTYPE1 = 'boardIndexAndChannel' / label for field 1
TFORM1 = 'B ' / data format of field: BYTE
TTYPE2 = 'timeTag ' / label for field 2
TFORM2 = 'K ' / data format of field: 8-byte INTEGER
TTYPE3 = 'triggerCount' / label for field 3
TFORM3 = 'I ' / data format of field: 2-byte INTEGER
TZERO3 = 32768 / offset for unsigned integers
TSCAL3 = 1 / data are not scaled
TTYPE4 = 'phaMax ' / label for field 4
TFORM4 = 'I ' / data format of field: 2-byte INTEGER
TZERO4 = 32768 / offset for unsigned integers
TSCAL4 = 1 / data are not scaled
TTYPE5 = 'phaMaxTime' / label for field 5
TFORM5 = 'I ' / data format of field: 2-byte INTEGER
TZERO5 = 32768 / offset for unsigned integers
TSCAL5 = 1 / data are not scaled
TTYPE6 = 'phaMin ' / label for field 6
TFORM6 = 'I ' / data format of field: 2-byte INTEGER
TZERO6 = 32768 / offset for unsigned integers
TSCAL6 = 1 / data are not scaled
TTYPE7 = 'phaFirst' / label for field 7
TFORM7 = 'I ' / data format of field: 2-byte INTEGER
TZERO7 = 32768 / offset for unsigned integers
TSCAL7 = 1 / data are not scaled
TTYPE8 = 'phaLast ' / label for field 8
TFORM8 = 'I ' / data format of field: 2-byte INTEGER
TZERO8 = 32768 / offset for unsigned integers
TSCAL8 = 1 / data are not scaled
TTYPE9 = 'maxDerivative' / label for field 9
TFORM9 = 'I ' / data format of field: 2-byte INTEGER
TZERO9 = 32768 / offset for unsigned integers
TSCAL9 = 1 / data are not scaled
TTYPE10 = 'baseline' / label for field 10
TFORM10 = 'I ' / data format of field: 2-byte INTEGER
TZERO10 = 32768 / offset for unsigned integers
TSCAL10 = 1 / data are not scaled
TTYPE11 = 'waveform' / label for field 11
TFORM11 = '1I ' / data format of field: 2-byte INTEGER
TZERO11 = 32768 / offset for unsigned integers
TSCAL11 = 1 / data are not scaled
EXTNAME = 'EVENTS ' / name of this binary table extension
FILEDATE= '20151023_000859' / fileCreationDate
DET_ID = 'fy2015_version_a' / detectorID
NSAMPLES= 1 / nSamples
EXPOSURE= 1.80E+03 / exposure specified via command line
HISTORY YAML-- DetectorID: fy2015_version_a
HISTORY YAML-- PreTriggerSamples: 31
HISTORY YAML-- PostTriggerSamples: 800
HISTORY YAML-- SamplesInEventPacket: 1
HISTORY YAML-- DownSamplingFactorForSavedWaveform: 1
HISTORY YAML-- ChannelEnable: [no,yes,no,no]
HISTORY YAML-- TriggerThresholds: [810, 500, 810, 800]
HISTORY YAML-- TriggerCloseThresholds: [800, 495, 800, 800]
HISTORY YAML--
END

detectorIDはDET_IDに記録されます。

DET_ID = 'fy2015_version_a' / detectorID

イベントパケットに記録されたwaveformのサンプル数はNSAMPLESに記録されています。 この数が、waveformカラムの要素数に対応します。各パルスの波高値だけ残したい場合は、YAMLコンフィグレーションファイルでSamplesInEventPacketを1にしてください。

NSAMPLES= 1 / nSamples

コマンドラインで指定した測定時間は秒単位でEXPOSUREに記録されます。

EXPOSURE= 1.80E+03 / exposure specified via command line
HISTORY YAML--の行は、configuration fileのコピーを保存しています。

カラム定義は以下のようになっています。

TTYPE TFORM TZERO データ型 コメント
boardIndexAndChannel B uint8_t チャネル番号
timeTag K int64_t FPGAローカルクロックのtime tag
triggerCount I 32768 uint16_t トリガカウンタ
phaMax I 32768 uint16_t 最大波高値
phaMaxTime I 32768 uint16_t 最大波高値を迎えたサンプル番号
phaMin I 32768 uint16_t 最小波高値
phaFirst I 32768 uint16_t トリガ内の最初のサンプルの波高値
phaLast I 32768 uint16_t トリガ内の最後のサンプルの波高値
maxDerivative I 32768 uint16_t トリガした波形内の微分の絶対値の最大値
baseline I 32768 uint16_t トリガした波形の最初の4サンプルの平均値
waveform I×N 32768 uint16_t 波形データ(N=nSamples)

fvでサンプルデータのデータ部分を表示した例を以下に示します。波高値情報を2個以上残している場合は、waveformカラムに「Plot」ボタンが表示され、クリックすることで波形データをプロットして確認できるようになります。

growth_daq_sample_fits_hdu1_data

GPS Extension

GROWTH FPGA/ADCボードにドーターカードを接続して、GPSの1PPSとNMEA信号をFPGAに供給している場合、GPSの1PPSにあわせて記録されたFPGAのローカルクロックのtime tagと、GPSの絶対時刻の文字データが記録されます。データ解析の際に時刻付ソフトウエアで較正データとして使用できます。

GPS信号が入力されていない、もしくはGPSは接続されているが信号が補足できていない場合はこのExtensionのデータは無効です。

TTYPE TFORM TZERO データ型 コメント
timeTag K int64_t FPGAローカルクロックのtime tag(40bit)
gpsTime 20A char[20] GPSのYYMMDD HH:MM:SS
unixTime J 2147483648 uint32_t UNIX Time

正常に日時・時刻が 記録できている場合は以下のようになります。

growth_daq_sample_fits_hdu2_data

イベントファイルのサンプル

BGO結晶で環境放射線を30分間測定して得られたイベントファイルをサンプルとして以下にアップロードしてあります。ダウンロードして解析してみてください。

20161013_092127.fits.zip

growth_daqの改良

実験ごとにデータ取得の要求は大きく異なるので、growth_daqそのままでは機能が不足している場合があるかもしれません。GROWTH-DAQ内のソフトウエアはオープンソースで公開しているので、改変・機能追加は自由に行ってください。他の人にも有用と思われる機能追加をした場合は、githubでPull Requestを出してもらえれば、本体のgitレポジトリにマージします。車輪の再発明による時間の無駄をを防ぐために、ソフトウエアの改良と改良結果の共有に協力おねがいします。

次回以降は、、、

次回以降の記事では、以下の解説を予定しています。この他にも、ボードの動作やプログラムの使い方で質問があったらコメント欄に書き込んでください。

  • FPGAの内部構造の解説
  • データ解析ソフトウエア