第4章 パルスシーケンス記述言語(pulse sequence description language : PSDK)

パルスシーケンスを開発するためには,パルスシーケンスを記述するツール(言語)が不可欠である.ここでは,Pythonで記述することにより,さまざまな機能を柔軟に表現できる,Python pulse sequence description language (P2SDK or PSDK)の機能を説明する.

まず,Fig.4-1に,最も基本的なパルスシーケンス(グラジエントエコー法)を示し,これにしたがって,以下の説明を行う.

Fig.4-1. 基本的なパルスシーケンス(グラジエントエコー法:ubSSFP法)

パルスシーケンスの記述には,RFパルスグラジエント(磁場勾配)データ収集3種類の要素が不可欠である.実際のMRI装置では,心拍や呼吸などの同期信号の入力が必要になることもあるが,撮像対象の状態にも依存するので,ここでは取り扱わない.

以下,RFパルスグラジエントデータ収集を実現するAPI(Application Program Interface)関数もしくはクラスを説明する(詳しくは,https://mrisimulations.com/psdk/index.htmlを参照).

まず,RFパルスは,
RF(time, waveform, pitch, factor=1.0, gain=0.0, phase=0.0, frequency=0.0, channels=None) という形式で表現する.
ここで,timeは,RFパルスのBlock(後述)内での開始時刻(micro second),waveformは,パルスの波形(micro Tesla),pitchは,波形サンプリングの時間刻み(micro second),factorは波形の倍率(無名数,省略可),gainは送信ゲイン(dB,省略可),phaseはRFパルスの位相(radian,省略可),frequencyは周波数(kHz,省略可),channelsは送信チャンネル(現在のところ1チャンネルのみ使用)となっている.ここで,省略可と書いた引数を省略した場合には,上記の既定の値が代入される.

シーケンスチャート上では,RFパルスの実数部(回転座標系でx'軸に加えられる)と,虚数部(回転座標系のy'軸に加えられる),そして,その絶対値を示している.RFパルスの他の表示法として,RFパルスの強度と位相で表す方法もある(MRIメーカーのシーケンス表示では,こちらが主流?).

次に,一定のグラジエント強度は,
GX(time, value, risetime),GY(time, value, risetime),GZ(time, value, risetime)という形式で表現する.
ここで,timeは,グラジエント変化のBlock内での開始時刻(micro second),valueは,変化の目標とするグラジエント強度(mT/m),risetimeは,現在のグラジエント強度から目標とするグラジエント強度への変化時間(micro second)である.ただし,グラジエントの変化は,時間的にリニアであることを仮定している.実際,このAPIで,ほとんどのパルスシーケンスを記述することができる

Spiral scanなどで使用する任意波形のグラジエント波形は,
GX.waveform(time, waveform, pitch, risetime)などで表現する(GY.waveform(),GZ.waveform()などもある).ここで,timeは,グラジエント変化のBlock内での開始時刻(micro second),waveformはグラジエント波形(mT/m),pitchは,波形変化の時間間隔(micro second),risetimeは,波形の各点の間の変化時間(micro second)である.このため,pitchとrisetimeを同一にすると,波形の各点がリニアに接続される波形が出力される

データ収集は,
AD(time, points, pitch, factor=1.0, gain=0.0, phase=0.0, frequency=0.0, channels=None)という形式で表現する.
ここで,timeは,データ収集のBlock内での開始時刻(micro second),pitchは,データ収集の時間刻み(micro second),factorは,収集した信号の倍率(無名数,省略可),gainは,収集した信号のゲイン(dB,省略可),phaseは位相(radian,省略可),frequencyは周波数(kHz,省略可)(この周波数で回転する回転座標系から見た信号強度),channelsは,データ収集チャンネル名(省略可)である.省略可のパラメタを省略した場合には,既定の値が代入される.

次に,これらのAPIを用いて,パルスシーケンスプログラムを記述する方法を以下に説明する.典型的なパルスシーケンスとして,後にも紹介する,二次元グラジエントエコー法のシーケンスを取り上げる(Fig.4-2).

PSDKによるパルスシーケンスは,Pythonを使用して記述するので,まず,プログラムの前段で,使用するライブラリの宣言や,使用する変数(定数)の初期化を行う.また,シーケンスで使用する関数などの定義などもしておく.

Fig.4-2. 二次元グラジエントエコーのパルスシーケンス

1行目は,psdkのライブラリのインポート,2行目は,numpyライブラリのインポートである.4行目は,プロトンの磁気回転比の設定,それ以降の部分(5~21行)で,パルスシーケンスを特徴づけるパラメタの初期設定が行われている.この部分は,パルスシーケンスに依存する部分であるので,各シーケンスの章で具体的に説明する.

23~27行目は,RFパルスに使用するhamming windowed sinc functionの関数定義である.このRFパルスは,現在,ほとんどのMRIメーカーで使用されているRFパルス形状である.

29行目には,パルスシーケンスの各機能を有するBlock()クラスの定義と,それらを実行制御するためのMain()を記述するためのSequence()クラスを,with構文を使用して記述するSequenceクラスの引数は,’シーケンス名’などである.

31行目以降には,各機能を有するBlock()クラスを記述する.Block()の引数は,’ブロック名’と,その持続時間(micro second)である.ここでは,スライス励起を行うためのBlock(‘Excitation’)位相エンコードを行うためのBlock(‘PhaseEncoding’)信号読出しのためのBlock(‘Readout’)位相エンコードの巻き戻しのためのBlock(‘Rewinding’)から構成されている.

それぞれのBlock()クラスの中に,実際のパルスシーケンスの機能を表現するRF()GX()AD()などのAPI関数を記述する.

これらのBlock()の時間的な制御を記述するのが,Main()である.

Main()の中に,実行の順番にBlock()をBlockRef('block name')という形式で並べ,それらを繰り返す必要がある場合には,Loop()構文を使用する.そして,Loop()に,ループ変数ループの回数などを指定する.なお,Block()の実行間に,時間を挿入する必要がある場合には,WaitFor()WaitUntil()というAPIを使用する.WaitFor(period)は,periodで指定される時間間隔(microsecond)だけ待つAPIであり,WaitUntil()は,Loop内で流れる時間の特定時刻まで待つAPIである.

以上のように,PSDKを用いたパルスシーケンスは,「Block()の定義」と,それらの「時間的な実行制御」の二つの部分から構成されている.これが,パルスシーケンスの基本である.

以下に,PSDKで定義されているAPIをまとめたものを示す(Fig.4-3).このように,わずか15個のAPIで,パルスシーケンスを柔軟に記述することができる.

Fig.4-3. APIの一覧