
Github Repository:7m4mon/ais-traffic-scenario-toolkit
1. はじめに
ハードウェア編では、PCで作ったAISデータを実際の受信機やプロッターへ渡すため、BluepillとADF7021を使った小型RFインターフェースを製作しました。AIVDMをUSBシリアルで受け取り、無線区間のフレームへ変換して、閉じた試験系でAIS-catcherが位置を表示するところまでがハードウェア編でした。
しかし、欲しかったのは送信機そのものではありません。複数の船を決めた位置、速力、針路で動かし、CPA/TCPA表示や衝突警報を何度でも同じ条件で確かめる環境です。そこで、PC側のAIS Traffic Scenario Toolkitを作り、シナリオの定義、計算、電文生成、再生までを一つの流れにまとめました。
2. ハードウェア編の続きをPC側で作る
ハードウェア編の装置は、PCから受け取ったAIVDMをRFへ出す「出口」でした。出口が決まったので、PC側は船の動きと評価条件に集中できます。自船とターゲットの初期位置、SOG、COG、時間途中の変針や変速を与え、時刻ごとの緯度・経度を計算する構成にしました。
最初は、計算した位置をそのままシリアルへ流すだけでもよいと考えました。ところが、それでは計算、電文生成、通信のどこで問題が起きたのか分かりにくく、同じ試験を後から再現することも難しくなります。そこで「シナリオを定義する」「タイムラインへ展開する」「出力先へ再生する」の三段階に分けました。
この分離により、一度作ったタイムラインをコンソール、OpenCPN、シリアル機器などへ繰り返し再生できます。CSVで数値だけを確認することも、JSONLを別のプログラムへ渡すこともでき、ハードウェアを接続する前にソフトウェア側を切り分けられるようになりました。
3. 本記事での公開範囲について
本ツールはRFを送信しません。行うのは、AIS遭遇シナリオの計算と、NMEA 0183、AIVDM、AIS payload bit stringの生成・再生です。ただし、生成したデータを外部のRF機器へ渡せば、扱い方によっては公共のAIS運用へ影響を与える可能性があります。
公開するのは、シナリオJSON、CPA/TCPA計算、タイムライン生成、AIS電文のエンコード/デコード、TCP・UDP・シリアル・WebSocketへの出力、AIS-catcherログの取り込みです。記事中のシナリオでは合成したMMSIを使い、実在船舶になりすます用途は想定していません。表示評価だけなら、まずTCP、UDP、シリアルNMEA、シミュレータ用WebSocketを利用します。
4. システム構成
全体は、シナリオJSON、コンパイラ、時系列タイムライン、プレーヤー、出力先の五つに分かれます。JSONで船と遭遇条件を定義し、コンパイラが1秒ごとの自船・ターゲット状態とCPA/TCPAをJSONLまたはCSVへ展開します。プレーヤーは自船をRMC/GGA/HDT、ターゲットをAIVDMまたはAIS payload bit stringへ変換し、OpenCPNや第一部のインターフェースへ渡します。AIS-catcherの受信ログも同じタイムライン形式へ取り込めます。
5. まず「シナリオ」と「再生」を分ける
シナリオJSONは、人が編集する試験仕様書です。原点、試験時間、時間刻み、警報しきい値、自船、複数ターゲットをまとめ、各船には初期位置、針路、速力と、途中で状態を変えるイベントを持たせます。期待する判定もexpected_levelとして記録できます。
一方、JSONLタイムラインは機械が順番に読む再生用データです。1行が1隻・1時刻の記録で、ローカル座標、緯度・経度、SOG、COG、CPA、TCPA、期待値と計算値を保持します。CSVにも同じ主要項目を書き出せるため、表計算ソフトで値を追うときにも便利です。
6. シナリオJSONの構成
| 項目 | JSONキー | 用途 |
|---|---|---|
| 形式 | schema_version | シナリオ形式の版 |
| 名前 | name / description | 試験の識別と説明 |
| 原点 | origin.lat / lon | ローカル座標の基準 |
| 試験時間 | duration_sec | 再生する総秒数 |
| 時間刻み | time_step_sec | 計算・記録の間隔 |
| 警報条件 | thresholds | CPA/TCPAしきい値 |
| 自船 | own_ship | 自船の初期状態とイベント |
| ターゲット | targets | 複数の他船定義 |
| 初期状態 | initial | x/y、針路、速力 |
| イベント | events | 時刻指定の変針・変速 |
| 期待判定 | expected_level | safe / caution / danger |
7. ローカル座標で船を動かす
遭遇条件は、緯度・経度を直接少しずつ変えるより、原点を中心とした海里単位のx/y座標で考える方が分かりやすくなります。本ツールではxを東西、yを南北とし、針路と速力から1秒あたりの移動量を求めます。緯度は1度を60海里、経度は原点緯度のcosを使って緯度・経度へ戻します。
これは地球全体を航海するための測地計算ではなく、プロッター評価用の近距離シナリオを簡潔に扱うための局所近似です。原点を試験海域に置けば、右舷横切り、正面行き会い、追い越しなどの相対配置を海里で素直に記述できます。
8. イベントで針路と速力を変える
船は初期状態のまま直進するだけでなく、指定時刻にheading_degまたはspeed_knを変更できます。計算時にはイベントを時刻順にたどり、前の状態でその時刻まで進めてから、新しい針路や速力を適用します。これにより、途中変針や減速を含む試験を一つのシナリオに書けます。
付属のmixed_demoでは、自船が360秒で針路0度から20度へ変針します。同時に、危険な右舷横切り船と十分離れて通過する船を置き、一つの再生の中で複数ターゲットと自船の運動変化を扱えることを確認しました。
9. CPA/TCPAを同じ条件で計算する
CPA/TCPAは、自船とターゲットの相対位置と相対速度から計算します。相対速度がほぼゼロなら現在距離をCPAとし、それ以外は最接近となる時刻を内積から求めます。TCPAが負ならすでに最接近を過ぎたものとして、安全側の判定に戻します。
標準しきい値は、CPAが0.2海里未満かつTCPAが300秒未満ならdanger、CPAが0.5海里未満かつTCPAが600秒未満ならcaution、それ以外をsafeとしました。dangerを先に評価することで判定の優先順位も固定しています。追い越しシナリオのように、目的に合わせてしきい値をJSON側で変更することもできます。
10. safe/caution/dangerを用意する
付属シナリオは、右舷横切り危険、正面行き会い危険、追い越し注意、安全通過、複合デモの五つです。右舷横切りは初期CPA 0.000海里・TCPA 210秒、正面行き会いは0.050海里・216秒、追い越しは0.200海里・720秒、安全通過は2.000海里・450秒でした。
各ターゲットには期待するsafe、caution、dangerを持たせ、コンパイラが算出したcomputed_levelと並べて記録します。今回の初期条件では、五つの例に含まれる各ターゲットが意図した判定から始まることを確認できました。警報の出方そのものはプロッターごとに異なるため、この値は試験条件の基準として使います。
11. 1秒刻みのタイムラインへ展開する
コンパイラは0秒からduration_secまでをtime_step_sec刻みで進み、各時刻に自船と全ターゲットの記録を作ります。600秒・1秒刻みで自船1隻とターゲット1隻なら、時刻は0秒を含む601点、合計1,202レコードです。各行には位置と運動状態だけでなく、ターゲット側のCPA/TCPA、期待判定、計算判定も入ります。
12. 自船とターゲットの電文を分ける
プロッターへは、自船と他船を別の種類のデータとして与える必要があります。自船はGPSやコンパスから来る想定で、RMCに位置・SOG・COG、GGAに測位情報、HDTに真方位を出します。ターゲットはAIS受信データとしてAIVDMを出します。
同じタイムラインから両者を作るため、位置関係と時刻がずれません。OpenCPNには自船NMEAとターゲットAIVDMを混在させた一本のTCPストリームを渡せます。一方、実機配線では自船NMEAとターゲットAIVDMを別々のシリアルポートへ分けられます。
13. ターゲットをAIVDMへ変換する
合成ターゲットの位置通報はAIS Message 1または18へエンコードできます。付属シナリオではClass B相当のMessage 18を使い、MMSI、緯度・経度、SOG、COG、Heading、UTC秒を168bitのpayloadへ詰め、6bit文字列とNMEAチェックサムを付けてAIVDMにします。
エンコードして終わりではなく、作ったAIVDMを再びbit列へ戻し、Message 18としてMMSI、位置、速力が復元できることも確認しました。分割AIVDM/AIVDOを組み立てる処理も用意しており、単一文だけに依存しない構成にしています。
14. 静的情報も定期的に出す
位置通報だけでは、プロッター上の船名や船種がいつまでも空欄になる場合があります。そこでプレーヤーは既定で60秒ごとにMessage 24Aと24Bを生成し、船名と船種を送ります。crossingシナリオでは0秒から600秒まで11回の静的情報送信が加わります。
15. 出力先を差し替える
プレーヤーの計算部は出力方法を知らず、Exporterへ文字列を渡すだけです。用意した出力先は、コンソール、TCPサーバー、UDP、シリアル、外部依存のないws:// WebSocketです。通信方法を変えても、シナリオ計算やAISエンコードを作り直す必要はありません。
出力経路も分けました。mixed NMEAには自船NMEAとターゲットAIVDM、own NMEA serialには自船だけ、target AIVDM serialにはターゲットだけ、bitstring WebSocketにはAIS payload bit stringだけを送ります。どの文を送ったかを時刻・役割・MMSI付きで表示するecho-outputも追加しました。
16. OpenCPNへつなぐ
OpenCPNで確認する場合は、プレーヤーを127.0.0.1:10110などでTCPサーバーとして起動し、OpenCPN側から接続します。自船のRMC/GGA/HDTとターゲットのAIVDMが同じ接続へ流れるため、シリアル機器なしで自船位置、他船、相対運動の表示を試せます。
まずdry-runで出力を目視し、replay-speedを上げて短時間で一巡させ、その後に実時間再生へ移すと切り分けが容易です。echo-outputを使えば、画面に現れた船と、その時刻に送ったAIVDMを突き合わせられます。
17. RFインターフェースへつなぐ
ハードウェア編のBluepillはUSBシリアルからAIVDMを受け取るため、プレーヤーのtarget-aivdm-serialをそのポートへ向ければ、ソフトウェア側とRF側の境界がつながります。また、Mictronics系シミュレータを想定したbit string WebSocketも選べます。
18. AIS-catcherログを取り込む
合成シナリオだけでなく、AIS-catcherが出力したAIVDMログもタイムラインへ変換できます。Message 1、2、3、18の位置通報をデコードし、受信時刻を先頭からの経過秒へ直します。原点を与えれば緯度・経度からローカルx/yも計算し、signalpower、ppm、timestampなどのメタデータを保存します。
付属の1行サンプルでは、MMSI 999002005、受信電力-3.4104、ppm -0.289352、UTC 2026-06-01 12:53:33を保持した1レコードを作れました。合成自船を置けばCPA/TCPAも計算できますが、実際の自船NMEAログを読むown-source nmea-logは将来用として予約されており、現時点では未実装です。
19. 10項目の確認を通す
AIVDMログ解析、payload変換、Message 18の往復、CPA/TCPAと判定優先順位、NMEAチェックサム、シナリオコンパイル、echo-outputの10項目はすべて通過しました。
CLIでも右舷横切りシナリオから1,202レコードのJSONL/CSVを生成し、プレーヤーを高速dry-runして3,049行を出力しました。内訳には各秒の自船3文、ターゲットAIVDMと168bit列、60秒ごとのMessage 24A/24Bが含まれます。これはソフトウェア経路の確認であり、RF波形や実プロッターの警報動作を保証する試験ではありません。
20. 現在のソフトウェア
| 項目 | 内容 |
|---|---|
| Project | AIS Traffic Scenario Toolkit |
| Version | 0.1.0 |
| Scenario input | JSON / 複数船 / 時刻イベント |
| Timeline output | JSONL / CSV |
| Position message | AIS Message 1 / 18 |
| Static message | AIS Message 24A / 24B |
| Own ship | RMC / GGA / HDT |
| Target | AIVDM / payload bit string |
| Risk | CPA / TCPA / safe / caution / danger |
| Replay | fixed-step / original-timing / speed変更 |
| Network | TCP server / UDP |
| Serial | own NMEA / target AIVDM |
| WebSocket | ws:// text / AIS bit string |
| Log import | AIS-catcher AIVDM + 受信メタデータ |
| Verification | 同等ハーネス10/10、1,202レコード生成 |
21. シナリオジェネレータが完成した
第一部の終わりに書いた「本当に作りたかったもの」は、シナリオを再現可能なデータへ落とし、同じ条件を複数の出力先へ流せるところまで形になりました。船の運動、CPA/TCPA、期待判定、NMEA/AIVDM生成が一つのタイムラインで結ばれ、RFを使わない段階でもOpenCPNやコンソールで動作を確かめられます。
付属シナリオには、右舷横切り、正面行き会い、追い越し、安全通過、複合デモを用意しました。JSONで条件を変え、JSONLまたはCSVへ展開し、TCP、UDP、シリアル、WebSocketへ再生できます。10項目の確認と、1,202レコードの生成、高速dry-runによる3,049行の出力までを通し、第二部の目標だったAISターゲット/衝突シナリオジェネレータは完成です。
本稿は、シナリオジェネレータができたところで完成とします。ハードウェア編のRFインターフェースから実際のDUTまでを閉じた試験系で通し、期待判定とプロッターの表示や警報を比較する作業は、次の段階として別に扱います。
安全上の注意
本ソフトウェアはRF送信機能を持ちません。 生成したAISデータを外部のRF機器へ接続する場合は、法令および周囲のAIS運用に十分配慮し、ダミーロード、十分なアッテネータ、シールド環境などを用いた閉じた試験系で扱ってください。公共のAISシステムへ不要な信号を送信する用途を想定していません。