海事向けの連携:ブリッジでの信頼スコア
Kshana の海事向け信頼スコア(MARITIME-TRUST.md)は、船乗りがすでに使っているソフトウェアから利用できます:Signal K サーバープラグインと、TCP 上のゲートモード NMEA を介した OpenCPN です。リファレンスビルドでは、受信機の隣にある小型コンピューターにこれを載せます。
助言用ソフトウェア。Kshana は、型式承認を受けた航法装置(IEC 61108、IEC 61162)ではなく、いかなる性能規格に対しても評価を受けていません。このページにあるものはすべて、航海士の判断を助けるものです。船舶の安全な航行、および測位解に依拠する、または依拠をやめるという判断の責任は、引き続き運用者にあります。ここでは何も送信せず、測位解をより正確にするものもありません。
| 構成要素 | 場所 | 0.35 での状況 |
|---|---|---|
| Signal K プラグイン | integrations/signalk/ |
提供済み。記録した合成出力でユニットテスト済み。npm には公開していません |
| TCP 上のゲートモード NMEA を介した OpenCPN | integrations/opencpn/ |
提供済みでテスト済み(利用側のリプレイ)。OpenCPN のユーザーインターフェース自体は、どのテストでも操作していません |
| OpenCPN ネイティブのスコアパネルプラグイン | integrations/opencpn/plugin/ |
ビルド済み、ロジックはユニットテスト済みで、仮想ディスプレイ上の OpenCPN 5.8.4 の内部で実行済み(証拠は integrations/opencpn/evidence/)。プラグインマネージャー用にはパッケージ化されていません。レビュー後にのみ提供されます |
| リファレンスビルド | deploy/reference-build/ |
部品、OS の手順、systemd ユニット(ドライランで検査)、コンテナの選択肢。船舶ではテストしていません |
すべては一つのものを読み取ります:kshana receiver-trust live の出力(JSON Lines、$PKSHT センテンス、ゲート)です。ワイヤ形式は MARITIME-TRUST.md にあります。Signal K プラグインは、これらについての知識を一つのファイル integrations/signalk/lib/adapter.js にまとめており、形式の変更は一つのファイルの編集で済みます。
Signal K プラグイン#
npm の依存パッケージはありません。プラグイン自体は Node 18 以降で動作しますが、現行の signalk-server のリリースは Node 22 以降を必要とするため、実際には 22 を使ってください。integrations/signalk/ をサーバーの node_modules(例:~/.signalk/node_modules/signalk-kshana-trust)にコピーまたはリンクし、サーバーを再起動して、Server、Plugin Config で Kshana GNSS trust を有効にします。
エポックの取得元(source)#
source |
プラグインの動作 |
|---|---|
spawn-signalk-nmea(既定) |
kshana receiver-trust live <sessionFile> を実行し、サーバーが受信した生の NMEA 0183 センテンスをすべて(サーバーの nmea0183 イベント)その標準入力に書き込みます。終了した場合は、バックオフを置いて再起動します | NMEA ソースが一つだけのサーバーでのみ使用してください:すべてのプロバイダーのすべてのセンテンスを混在させて渡すため、二台目の GNSS 受信機や AIS があると、位置が飛ぶ一台の受信機のように見え、スプーフィングとして採点されることがあります。ソースが複数ある場合は、spawn-args でその受信機自身の --tcp ストリームを使うか、ゲートからの tcp-pksht を使ってください。 |
spawn-args |
kshana receiver-trust live <sessionFile> <inputArgs...> を実行します。例:["--tcp","192.0.2.10:10110"] または ["--udp","10110"] |
tcp-json |
kshana が書き出す JSON Lines のフィードに接続します(例:integrations/opencpn/ のリレーから) |
tcp-pksht |
NMEA ストリーム(リファレンスビルドのサービスまたはコンテナのゲート出力、ポート 10110 など)に接続し、その $PKSHT センテンスだけを読み取ります |
モニターが最初に接続した時点ですでにスプーフィングを受けているストリームには、クリーンなベースラインがありません(最初の calibration_s 秒は採点されません)。航海の前に起動してください。
公開されるパス#
エポックごとに更新されます(ソース kshana-trust):
| パス | 値 |
|---|---|
navigation.gnss.kshana.band |
calibrating、nominal、degraded、または untrusted |
navigation.gnss.kshana.score |
0 から 100、キャリブレーション中は null |
navigation.gnss.kshana.reasons |
[{monitor, points}]、大きい順:どのチェックがスコアを下げたか |
navigation.gnss.kshana.alarms |
現在しきい値を超えているモニター |
navigation.gnss.kshana.gate |
off、passed、または withheld(ゲートが別の場所で動作している場合。ない場合は $PKSHT からの null) |
navigation.gnss.kshana.reportedPosition |
{latitude, longitude, altitude}:テスト対象の受信機がそのエポックに報告した位置(JSON スキーマ 1.1 以降。ストリームに位置が含まれない場合、たとえば $PKSHT や古い kshana からのものでは公開されません)。信頼性の文脈としてのみ:プラグインは navigation.position を決して書き込まないため、船自身の位置パスには影響しません |
notifications.navigation.gnss.kshana.trust |
状態が変わったときに発行:{state, method, message} |
プラグインは、開始時にこれらのパスの Signal K メタデータも一度だけ送ります。score は Kshana の 0 から 100 の信頼スコアで、比率でも確率でもなくスコアであるため、SI 単位はありません。そのメタデータには、範囲、説明、および下記のしきい値に従うゾーンが含まれます。reasons[].points は、その 0 から 100 のスコアから差し引かれたスコアポイントです。
通知は normal、alert、warn、または alarm です。解除は状態 normal を発行することで行い、null ではありません:null だけを解除とみなす利用側は、normal も解除とみなすべきです。既定では、degraded の帯域は warn、untrusted の帯域は alarm を与え、method: ["visual","sound"] を伴います。より良い状態が clearAfterEpochs エポック続くと、通知は下げられます。staleAfterS 秒間エポックが届かない場合は、スコアが更新されていないという警告を出します。キャリブレーション中は通知を上げません。$PKSHT ソースには alarms のリストがありません(センテンスには帯域、スコア、上位二つの理由だけが含まれます)。
設定(すべてのしきい値)#
| キー | 既定値 | 意味 |
|---|---|---|
source |
spawn-signalk-nmea |
上記を参照 |
command |
kshana |
実行ファイル(スポーンモード)。サーバーのユーザーとして任意の実行ファイルを実行します:プラグインの設定を変更できるのは、Signal K サーバーの管理者だけにしてください |
sessionFile |
/etc/kshana/session.toml |
船の限界値、しきい値、スコアの重み(スポーンモード) |
inputArgs |
[] |
両方のスポーンモードで kshana receiver-trust live <sessionFile> に追加される引数:spawn-args の入力、spawn-signalk-nmea の --replay(実時間より速く入力される保存済みログ)などの追加フラグ。プラグインは --gate、--listen、--json、--pksht を拒否し(kshana の標準出力の JSON を読み取るため)、spawn-signalk-nmea では入力フラグ(--stdin、--file、--tcp、--udp、--follow、--from-end)も拒否します |
host, port |
127.0.0.1, 10111 |
TCP モード(ゲートは 10110 で待ち受けます:tcp-pksht ではポートを設定してください) |
thresholdMode |
band |
band:Kshana が報告する帯域で、境界値はセッションファイルにあります。score:下の二つのスコア |
warnBelowScore |
90 |
score モード:これを下回ると、状態は degradedState になります(nominal に対する Kshana の既定の境界値) |
alarmBelowScore |
55 |
score モード:これを下回ると、状態は alarm になります(degraded に対する Kshana の既定の境界値) |
degradedState |
warn |
degraded の帯域に対する状態:normal、alert、または warn |
raiseAfterEpochs |
1 |
通知が上げられるまでに、より悪い状態が連続するエポック数 |
clearAfterEpochs |
10 |
通知が下げられるまでに、より良い状態が連続するエポック数 |
staleAfterS |
10 |
この時間エポックが届かないと警告します。0 で無効になります |
method |
["visual","sound"] |
通知方法 |
プラグインはゲートを行いません:測位解を変更することは決してありません。チャートシステムに対して測位解を無効とマークするのは、下記のゲートです。
テスト#
cd integrations/signalk && npm test
node:test、依存パッケージなし、127.0.0.1 以外のネットワークなし。テストは、kshana receiver-trust live が合成のバルト海デモ(作成したデータで、テキストのみ)向けに書き出した JSON Lines と $PKSHT センテンスの 66 エポックの抜粋を解析して再生し、二つの形式の一致、保持と解除の動作、スコアモード、陳腐化、そしてローカルのフィードと代役の子プロセスに対する三つの入力経路を検査します。これらのテストは実際の Signal K サーバーを起動しません。別のスクリプト実行がそれを行います(下記を参照)。
実際の Signal K サーバーでの実行#
integrations/signalk/evidence/ には、固定した signalk-server 2.33.0 パッケージにプラグインを読み込ませ(ループバック専用の専用ネットワーク名前空間内で)、サーバー自身の REST と WebSocket の API が示す内容を記録するスクリプトがあります。信頼性のパスが現れ、通知は warn、alarm、normal(保持の後)となり、データが止まると再び warn になります。また、サーバー自身の NMEA 入力から供給される実際の kshana では、reportedPosition を公開し、navigation.position は一度も公開しませんでした。サーバーのバージョンは一つ、実行は一回で、実際の船はありません。制約と再現手順は、evidence の README にあります。
OpenCPN#
OpenCPN はネットワークから NMEA を読み取り、kshana receiver-trust live --gate はゲートされたストリームを自分で TCP ポートに提供できます。
推奨:直接接続。
some-nmea-source | kshana receiver-trust live session.toml --gate --listen tcp:10110
(some-nmea-source は、stty と cat で読み取る受信機のシリアルポート、マルチプレクサー、または kshana 自身の --tcp/--udp 入力です。リファレンスビルドの kshana-gate.service は、systemd のもとでこれを行います。)--listen tcp:<port> はループバックアドレスにバインドします。読み取り専用のクライアントはいくつでも接続でき、追従できないクライアントは、他のクライアントを遅らせることなく切断されます。
代替:リレー。 integrations/opencpn/nmea-tcp-relay.mjs は、依存パッケージのない Node のファンアウトで、--listen のない kshana に対して同じことを行うか、他の任意の行ストリームを提供します(コンテナの選択肢では JSON のエポックに使います):
some-nmea-source | kshana receiver-trust live session.toml --gate --json trust.jsonl \
| node integrations/opencpn/nmea-tcp-relay.mjs --listen 10110
バイト列を変更せずに、完全な行だけを転送し、読み取らないクライアントは切断します。直接接続のほうが望ましいです:チェーン内のプロセスが一つ少なくなります。
OpenCPN で:Options、Connections、Add Connection、Network、プロトコル TCP、アドレス 127.0.0.1、ポート 10110、方向 Input。信頼性が崩れていない間、ストリームは受信機自身のもので、サイクルごとに $PKSHT センテンスが加わります。崩れている間は、転送される GGA の品質は 0、RMC のステータスは V となり、モードインジケーターは測位解なしを示し、チェックサムは再計算されます:機器は、受信機自身が測位解を無効と宣言するのを見て、自身の警報を上げます。$PKSHT センテンスは、OpenCPN の NMEA デバッグウィンドウ(Options、Connections、"NMEA debug window")で確認できます。位置フィールドは受信したままです。
これに依拠する前に、MARITIME-TRUST.md の「Gate mode」を読んでください:これはオプトインであり、遅延を加え(サイクルは、そのエポックが採点されるまで保留されます)、チェーンの中の単一の点であり、偽造された測位解を通してしまうだけでなく、正しい測位解を保留してしまうこともあります。
テスト#
cd integrations/opencpn && npm test
test/relay.test.mjs は、合成のゲート済みストリームの記録された抜粋(信頼性が崩れる瞬間の前後の 186 センテンス、kshana receiver-trust live --gate が書き出したもの)を、実際の TCP ソケット経由でリレーに通して再生し、利用側が受け取るものを検査します:任意のチャンク分割でもバイト単位で同一のストリーム、書き換えたものを含むすべてのセンテンスで有効なチェックサム、GGA と RMC が一致して、有効から無効へちらつきなく変わること、サイクルごとに一つの $PKSHT があり、そのゲートフィールド W が測位解の無効な箇所とぴったり一致すること、二つの利用側が同一であること、不完全な行が決して転送されないこと。これは OpenCPN に渡されるストリームの検査であり、OpenCPN 自身の画面の検査ではありません。
実際のバイナリを使ったエンドツーエンドの検査です。既定のテストには含まれません(ビルド済みの kshana が必要です):
KSHANA_BIN=target/release/kshana npm run e2e # kshana --gate --listen | TCP consumer; the consumer's bytes must equal the gate's stdout
KSHANA_BIN=target/release/kshana npm run e2e -- relay # kshana --gate | relay | TCP consumer
どちらも、一時間の合成デモを実行し、測位解が有効になってから無効になること、エポックごとに $PKSHT があることを検査します。
ネイティブプラグイン#
integrations/opencpn/plugin/ は OpenCPN 用のスコアパネルです(スコア、帯域、ゲート、上位の理由、信頼性が untrusted になったときのアラート)。OpenCPN 自身の NMEA ストリームから $PKSHT を読み取るため、上記の接続以外の接続は不要です。CMake で、OpenCPN のプラグイン API ヘッダー(コミットとともに同梱)と wxWidgets に対してビルドされます。ctest は、wx を使わないロジックのテストを実行し、ライブラリが OpenCPN の探すエントリポイントをエクスポートしていることを検査します。合成のゲート済みストリームを使い、仮想ディスプレイ上の OpenCPN 5.8.4 の内部で実行しました(OpenCPN が $PKSHT をプラグインに渡し、パネルが赤くなり、ゲートが作動すると OpenCPN 自身の位置が凍結しました。スクリーンショット、ログ、スクリプトは integrations/opencpn/evidence/ にあります)。しかし、実際のデスクトップ、他のバージョンやプラットフォームでは実行しておらず、OpenCPN のプラグインマネージャー用にはパッケージ化されていません。プラグインの README.md を参照してください。リポジトリの他の部分とは異なり、GPL-3.0-or-later でライセンスされています(LICENSING.md)。
その実行のスクリーンショットは integrations/opencpn/evidence/ にあります(実行は一回、仮想ディスプレイ上の OpenCPN 5.8.4、合成データ。制約は README.md を参照):
これらが示すのは配線と、ゲートされた測位解が OpenCPN に届くことであり、実際の船で警報がタイミングよく正しいことではありません。助言用ソフトウェアであり、型式承認を受けた機器ではありません。
リファレンスビルド#
deploy/reference-build/:汎用の部品リスト、OS のセットアップ、二つの systemd ユニット(助言用モニターとオプトインのゲート)、コンテナの選択肢、Signal K の結線。deploy/reference-build/check-units.sh は、何も起動せずに、ユニットに対して systemd-analyze verify を実行します。
制限#
- スコアは、その背後にあるチェックの質以上のものにはなりません。チェックは船の物理と他のセンサーを見ているため、時計も一致した自己無矛盾な偽造は、NMEA のみのモニターでは検出されません(
MARITIME-TRUST.md)。警報がないことは、測位解が良好であることの証拠ではありません。 - このページの数値は、実測した検出率や誤警報率ではありません。上記のテストは、合成テキストで配線を検査するものであり、実際の干渉に対してどのモニターがどう動作するかについては何も述べません。
- 型式承認を受けていません。運用者が引き続き責任を負います。