アニメーションのエクスポート
--animate は、実行の時系列を動くものに変えます。出力は、アニメーション SVG(Scalable Vector Graphics)ファイル、単体で動作する一つの HTML(HyperText Markup Language)プレーヤー、またはビデオエンコーダー向けの連番 SVG フレームです。キャンペーンは、そのフェーズ(ジャミング、スプーフィング、ホールドオーバー、インテグリティ警報)として、警報のマークを付けて再生されます。スペクトルの実行は、ウォーターフォールを一行ずつ再生します。低軌道(LEO)のパスは、バンドごとのリンクを再生し、スプーファーがある場合は、モニターの統計量をエポックごとに再生します。
kshana scenarios/campaign-jam-spoof-holdover-integrity.toml --animate all
kshana scenarios/l-band-waterfall-jamming.toml --animate html
kshana scenarios/clock-holdover.toml --animate frames --animate-fps 24 --animate-duration 10
コード:src/animation.rs。テスト:tests/animation.rs。
何であり、何でないか#
エクスポーターが読むのは、実行がすでに書き出した結果ドキュメントです。物理計算を再実行せず、サンプル間のリサンプリング、平滑化、補間も行わず(トレースをカーソルで終える一本の直線区間を除く)、独自の数値を一切加えません。したがって、アニメーションの品質は、その元になった実行の品質そのものです。そのティアは MODELLED、内部整合性です。これは描画であって、エビデンスではなく、それ自体の検証マトリクスの行もありません。
出力#
各フォーマットは、通常の result.json、chart.svg、report.html と並べて、シナリオの隣に書き出されます。
| フォーマット | 書き出される形 | 内容 |
|---|---|---|
svg |
<scenario>.animation.svg |
CSS(Cascading Style Sheets)のキーフレームでアニメーション化した、スクリプトなしの一つの SVG です。トレースは動くタイムカーソルの後ろに描かれ、イベントはその時刻に現れ、ウォーターフォールの行は時間順に現れます。ループ再生し、完成した画像を 1.5 s 保持します。 |
html |
<scenario>.animation.html |
インラインのスクリプトとスタイルを含み、外部アセットのない一つのファイルです。再生と一時停止、スクラバー、速度(0.25x から 4x)、同期した一つのカーソルを共有するすべてのパネル、トレースごとのライブ値、フェーズの帯、クリックで該当位置に移動するイベント一覧を備えます。Space で再生または一時停止、矢印キーでステップ、Home と End でジャンプします。 |
frames |
<scenario>.frames/ |
frame_0000.svg、frame_0001.svg、…、および manifest.json。 |
--animate は繰り返し指定でき、カンマ区切りのリスト(--animate svg,html)または all を取ります。--animate-fps(1 から 60、既定は 12)と --animate-duration(0.5 s から 600 s、既定は 8 s)で再生を設定します。フレームの連番は 7,200 フレームが上限です。
同じコマンドで --export を実行すると、HTML プレーヤーは、その隣に書き出されたエクスポートファイル(CZML、KML、GeoJSON、STK、SigMF)を、同じ階層のファイルへの相対リンクとして一覧にします。リンクが書き出されるのはファイル名だけの場合に限られるため、フォルダーの外に出ることも、ネットワークに到達することもありません。詳細レポート(report.html)は、結果に時系列があれば、--animate が実行されたかどうかにかかわらず、アニメーション描画を埋め込みます。
--animate を実行すると、result.json に animation ブロックが加わります。内容は、フォーマット、毎秒フレーム数(fps)、長さ、フレーム数、時間範囲、パネルのタイトル、各トレースを読み取った JSON パス(sources)、および見つかったが描画されなかった系列(omitted)です。--animate がなければ、結果は通常の実行とバイト単位で同一です。
フレームの連番#
連番は、ちょうど round(duration × fps) フレームです。フレーム i は t_start + (t_end − t_start) × i / (n − 1) までのタイムラインを示すので、最初のフレームは開始時点、最後のフレームは完成した画像です。manifest.json には、fps、duration_s、frame_count、frame_pattern(frame_%04d.svg)、ピクセルサイズ、t_start、t_end、各フレームのミッション時刻(frame_times)、フェーズ、イベント、ソースが記録されます。同じディレクトリへ再エクスポートする際は、まずそこにある frame_NNNN.svg をすべて削除し(それ以外は削除しません)、より短い連番が、より長い連番のフレームを残してエンコーダーに読み込ませることがないようにします。
フレームは、PNG(Portable Network Graphics)ではなく SVG です。librsvg ライブラリでビルドした ffmpeg は、連番を書き出したときのレート(上の例では 24、マニフェストの fps)で、それらを直接読み込めます。
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.svg -pix_fmt yuv420p clock-holdover.mp4
librsvg を含まない ffmpeg は、「no decoder found for: svg」と表示して停止します。まず rsvg-convert などでフレームをラスタライズし、PNG をエンコードしてください。
for f in clock-holdover.frames/frame_*.svg; do rsvg-convert "$f" -o "${f%.svg}.png"; done
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.png -pix_fmt yuv420p clock-holdover.mp4
アクセシビリティとテーマ#
- 配色。プレーヤーは
prefers-color-schemeに従い、変化すると再描画します。アニメーション SVG は、同じメディアクエリの下に、パレットの明るい配色を持ちます。フレームは、静的なグラフのダークパレットを使います。動画には配色の切り替えがないためです。 - 視覚的な動きの軽減。
prefers-reduced-motion: reduceの下では、アニメーション SVG はすべてのアニメーションを停止して完成した画像を表示し(基本スタイルが最終状態なので、何も隠れません)、プレーヤーは再生せずに、完成した画像で一時停止した状態で開きます。ユーザーはスクラブも再生ボタンの操作もできます。 - SVG には
<title>と<desc>があります。プレーヤーのコントロールは、ラベル付きのボタン、読み上げ可能な時刻の値を持つレンジ入力、セレクトです。
時系列と見なされるもの#
結果ドキュメントは種類ごとに異なるため、エクスポーターは、種類の一覧ではなく、エンジンが出力する形を認識します。
- 時間フィールドを持つレコードの配列(
t、t_s、t_hours、t_min、t_days、またはepochs配列のk)で、配列に沿って厳密に増加するもの。それ以外の数値フィールドはすべてトレースになります。二つのルートの下にある同じフィールド(quantum.series[].error_nsとclassical.series[].error_ns)は、一つのパネルを共有します。 - 厳密に増加する時間配列を持つオブジェクト(
t_s、t、times_s、…)で、同じ長さの配列を伴うもの。同じ階層の数値配列、{unit, values}レコードのchannelsマップ(campaignのタイムライン)、そうした配列を持つレコードの配列(spectrumのバンド、コンステレーションの衛星トラック)、および行が時間軸に一致し、同じ階層に*_hzの周波数軸を持つ二次元配列(spectrumのウォーターフォール)です。 - その時間配列と並んで、
phases(name、t0_s、t1_s)はフェーズの帯になり、events(t_s、label、alarm)はマーカーになります。バンドの*_t_sスカラー(最初のロックロス、最も低い搬送波対雑音密度比)にもマークが付きます。
単位を持つトレースは、大きさが 100 倍以内であれば一つのパネルを共有するため、50 ns のガードが 2 ns の誤差を平坦にしてしまうことはありません。描画されるのは、最大 6 個のパネル、各 6 トレースまでで、残りは omitted の下に一覧されます。2,400 サンプルを超えるトレースは、最後のサンプルを残す等間隔のストライドで間引かれ、96 × 120 セルを超えるウォーターフォールは、平均化して縮小されます(デシベルのセルではパワーで平均化するため、狭いジャマーが薄まることはありません)。
これらの形のいずれも結果に含まない kind(リンクバジェット、単一エポックの幾何、統計のみのモンテカルロ要約、あるいは、結果が記録のハッシュは公開するが記録そのものは公開しない通信タイミングのホールドオーバー)は、no time series to animateで拒否され、何も書き出されません。kshana 0.40.0 では、実行可能な 193 件のシナリオファイル(スタディスイートを除くすべてのファイル)のうち 94 件がアニメーション化でき、99 件が拒否されます。cargo test --test animation -- --nocaptureは集計を出力します。
LEO の種類では、同梱のすべての leo-pass、leo-pnt-chain、leo-ppp シナリオがアニメーション化できます。leo-pvt は、ドップラー、統合測位、タイミングのモードでアニメーション化できます(タイミングの実行には trace = true が必要で、これによりすべての行がエポックごとに時刻誤差と予測シグマを報告します)が、極域カバレッジのモードでは拒否されます。leo-navmsg は、パス途中の更新をアニメーション化でき、エンコーディング、フィット区間、モデル比較の解析では拒否されます。leo-signal と ntn-positioning の結果には時間軸がないため、拒否されます。
決定性#
出力は、結果ドキュメントとオプションの純粋な関数です。ライブラリには、時計も、乱数も、ハッシュマップの反復も、ファイルやネットワークへのアクセスもなく、どこにもタイムスタンプがないため、同じシナリオ、シード、オプションからは、バイト単位で同一のファイルが得られます。モジュールは、そのまま WebAssembly 向けにビルドできます。ファイルを書き出すのは、コマンドラインインターフェースだけです。
ライブラリでの利用#
use kshana::animation::{AnimationFormat, AnimationOptions};
let anim = kshana::api::animate_toml(src, AnimationFormat::Html, &AnimationOptions::default())?;
std::fs::write("run.html", &anim.files[0].content)?;
kshana::animation::animate_result は、すでに手元にある結果ドキュメントをアニメーション化し、extract_timeline は、描画せずに、描画される内容を返します。
制限#
- Python のホイールと WebAssembly モジュールは、まだエクスポーターを公開していません。コマンドライン、Rust ライブラリ、Model Context Protocol(MCP)サーバーの
animate_scenarioツール(一回の返信で最大 120 フレームを返します)から利用できます。 - 軸は線形です。多くの桁にわたる系列(時計の誤差の増大が 0.1 ns からマイクロ秒に及ぶ場合など)は、実行の終盤近くまで平坦に見えます。
- アニメーション SVG は、クリップ矩形の CSS アニメーションに依存します。現在の Chromium、Firefox、Safari のエンジンは再生できますが、CSS アニメーションのないビューアーでは、完成した画像が表示されます。
- 掃引、モンテカルロ、合成のキャンペーンには時間軸がないため、拒否されます。掃引やアンサンブルの要約統計量は時系列ではありません。連鎖したキャンペーンはアニメーション化できます。