コンテンツにスキップ

アーキテクチャ

アーキテクチャ

English: ARCHITECTURE.md

1. 全体像

orts は Rust ワークスペース (シミュレーションコア + CLI + プラグイン SDK) と TypeScript 側 (リアルタイム 3D ビューア + ストリーミングチャート) に分かれる。 両者は live では WebSocket で、replay ではファイル (RRD / CSV) で繋がる。

flowchart TB
  subgraph rust["Rust ワークスペース"]
    utsuroi["utsuroi<br/>ODE ソルバ"]
    arika["arika<br/>座標系 / 時刻系 / 天体暦"]
    tobari["tobari<br/>地球環境モデル"]
    orts["orts<br/>軌道 + 姿勢 + 宇宙機"]
    cli["orts-cli<br/>run / serve / replay / convert"]
    sdk["orts-plugin-sdk<br/>WASM guest SDK"]
    rrdwasm["rrd-wasm<br/>RRD decoder (wasm)"]
  end
  subgraph ts["TypeScript パッケージ"]
    uneri["uneri<br/>DuckDB-wasm + uPlot"]
    viewer["orts-viewer<br/>React + @react-three/fiber"]
  end
  wasm[(WASM plugin<br/>Component Model)]

  arika --> tobari
  arika --> orts
  utsuroi --> orts
  tobari --> orts
  orts --> cli
  sdk -. WIT world を実装 .-> orts
  wasm -. ロードされる .-> orts
  cli -- WebSocket :9001 --> viewer
  rrdwasm --> viewer
  uneri --> viewer

2. Rust ワークスペースの層構造

LayerCrate責務
Foundationutsuroi汎用 ODE ソルバ (RK4, DOP853, Dormand-Prince, Störmer-Verlet, Yoshida)。OdeState, DynamicalSystem trait を提供。
Foundationarika型安全な座標系 (ECI / ECEF / IAU)、時刻系 (UTC / TT / TDB / TAI)、Meeus 解析天体暦、JPL Horizons 取得、WGS-84、EOP。
Environmenttobari大気モデル (Exponential, Harris-Priester, NRLMSISE-00)、地磁気場 (IGRF-14, 傾斜双極子)、宇宙天気プロバイダ (CSSI, GFZ)。
SimulationortsOrbitalState / AttitudeState / SpacecraftState、統一 Model<S> trait、OrbitalSystem / AttitudeSystem / SpacecraftDynamics、センサモデル、プラグインホスト、Rerun .rrd 出力。
Applicationorts-cliorts run / orts serve / orts replay / orts convert。viewer を埋め込み、port 9001 で WebSocket ストリームを公開。
Extensionorts-plugin-sdkWASM plugin guest 制御則を書くための Rust SDK (callback 形式 / main-loop 形式)。
Bridgerrd-wasmRerun RRD デコーダを WebAssembly にコンパイルしたもの。ブラウザ内 replay 用。

3. 中核の trait 階層

シミュレーションコアは 2 つの軸で組み立てられている。utsuroi の汎用数値積分 抽象と、orts の capability-based モデル機構 — これにより、同一の摂動モデルを orbit-only / attitude-only / 結合 spacecraft のどのシステムからでも再利用できる。

classDiagram
  class OdeState {
    <<trait>>
    +zero_like()
    +axpy()
    +scale()
    +error_norm()
  }
  class DynamicalSystem {
    <<trait>>
    +type State : OdeState
    +derivatives(t, y, dy)
  }

  class HasFrame {
    <<capability>>
    +type Frame : Eci
  }
  class HasOrbit {
    <<capability>>
    +orbit() OrbitalState~Frame~
  }
  class HasAttitude {
    <<capability>>
    +attitude() AttitudeState
    +attitude_to_inertial() Rotation~Body, Frame~
  }
  class HasMass {
    <<capability>>
    +mass() f64
  }

  class Model~S~ {
    <<trait>>
    +name() str
    +eval(t, state, epoch) ExternalLoads~S::Frame~
  }

  OdeState <|.. OrbitalState
  OdeState <|.. AttitudeState
  OdeState <|.. SpacecraftState

  HasFrame <|-- HasOrbit
  HasFrame <|-- HasAttitude

  HasFrame <|.. OrbitalState
  HasFrame <|.. AttitudeState
  HasFrame <|.. SpacecraftState
  HasOrbit <|.. OrbitalState
  HasOrbit <|.. SpacecraftState
  HasAttitude <|.. AttitudeState
  HasAttitude <|.. SpacecraftState
  HasMass <|.. SpacecraftState

要点:

  • Model<S> は必要とする state の capability を S の trait bound として 宣言する (例: 大気抵抗は impl<S: HasFrame + HasOrbit> Model<S>、重力傾斜 トルクは impl<S: HasFrame + HasAttitude + HasOrbit> Model<S>)。同じ実装を、 bound を満たすあらゆる System にそのまま差し込める。
  • HasFrame::Frame は state を伝播する慣性系で、HasOrbitHasAttitude はこれを supertrait として共有する。model の返り値は ExternalLoads<S::Frame> — loads を返す frame は state を読んだ frame そのものなので、両者が食い違うことがない。自身の frame を持つ model は それを state のそれに equality bound で束縛する。この bound が意味を持つのは 2 通り — frame の capability を要する場合 (impl<F: EarthFixedTransform, S: HasFrame<Frame = F> + HasOrbit> Model<S> for AtmosphericDrag<F>) と、frame-typed data を保持する場合 (ConstantThrust<F> は Δv を Vec3<F> で持つ)。frame のの性質を要求 する場合は frame ごとに実装する: ConstantThrust は燃焼中ずっと方向を固定 するが、of-date な Cirs / Teme はこれを満たせないので、F: Eci 全体では なく SimpleEciGcrs に対して Model を実装する。
  • System は 3 種類 — OrbitalSystem / AttitudeSystem / SpacecraftDynamics — いずれも state と Vec<Box<dyn Model<S>>> を 束ねる DynamicalSystem

4. プラグインシステム

姿勢制御則やモード管理といった guest 制御則は WebAssembly サンドボックスで 動く。これにより WASI + Component Model をターゲットにできる任意の言語で 制御則を書ける。

  • インターフェース: WIT world orts/wit/v0/orts.wit
  • World exports (guest → host): metadata(config), run(config), current-mode()
  • World imports (host → guest): host-env (地磁気場取得、log)、 tick-io (wait_tick, send_command)
  • Tick ごとの契約: host が TickInput (真値 state + デバイスごとの sensor 読み値 + actuator テレメトリ) を渡し、guest が Command (MTQ 毎の 磁気モーメント、RW 毎の回転速度 or トルク、スラスタ毎のスロットル) を返す。
  • ランタイム: wasmtime の Pulley interpreter でホスト非依存な決定論的 実行を保証。
  • 配布: .wasm (可搬)。

WASM guest は PluginController trait で駆動される。native 制御則は別の DiscreteController trait を実装しており、両者の統一は計画段階 (ROADMAP.md 参照)。

5. データフロー (シミュレーション → viewer)

sequenceDiagram
  participant sim as orts-cli serve
  participant ws as WebSocket :9001
  participant src as Source layer
  participant trail as TrailBuffer (GPU)
  participant chart as ChartBuffer (ring)
  participant duck as DuckDB (uneri)
  participant ui as React UI

  sim->>ws: WsMessage { State, metrics }
  ws->>src: SourceEvent
  src->>trail: orbit points
  src->>chart: columnar samples
  src->>duck: ingest (履歴キャッシュ)
  chart->>ui: uPlot live frame
  duck->>ui: zoom / downsampled query
  • Live path (hot): ChartBuffer から uPlot に直結。DuckDB は live レンダ経路に乗っていない。
  • History path (cold): IngestBuffer → DuckDB が zoom / downsample / 事後クエリ用のキャッシュ。ring buffer と eventually consistent。
  • Source 抽象: 全入力が同じ SourceEvent ストリームに正規化されるため、 live と replay は単一パイプラインを通る。live WebSocket 経路は useWebSocket hook のブリッジ (useWebSocketSource)、ファイル再生 (CSVFileAdapter / RrdFileAdapter) は Web Worker でメインスレッド外 パースを行う。
  • 2 系統の表示と共有する描画部品: ./lib は軌道表示 (OrbitViewerOrbitSceneOrbitSceneContents) と姿勢表示 (AttitudeViewerAttitudeSceneAttitudeSceneContents) を公開する。 どちらも「Canvas 込みの wrapper → 利用側の Canvas に配置する scene graph → 内部レンダラ」の 3 層。共有するのは表示フレーム変換 (displayFrame.ts) と SpacecraftVisual で、scene graph は共有しない。理由は DESIGN.md を参照。DirectionArrows も同じ契約で書いてあるが、現在描いているのは姿勢表示 だけで、軌道表示は後続 PR で使う。

6. 設計原則

  1. Capability-based composition. State は提供するもの (HasOrbit, HasAttitude, HasMass) を宣言し、Model は必要とするものを宣言する。 これが、同一の drag 実装を OrbitalSystemSpacecraftDynamics で 重複なく再利用できる仕組み。
  2. 型安全な座標系。 Vec3<F: Frame> により ECI / ECEF / Body を別型に することで、frame の取り違えを silent bug ではなくコンパイルエラーにする。
  3. ホットパスはモノモーフィゼーション重視。 ODE state は固定次元 (6D / 7D / 14D。補助状態は AugmentedState で拡張) なので integrator は タイトにインライン化される。可変 N (コンステレーション、柔軟構造) は GroupState<S: OdeState> で扱う。
  4. 決定論的 plugin 実行。 Pulley interpreter により、ホストや CI 環境に 依らず guest の挙動が再現可能。
  5. Viewer 端での Source 抽象化。 Transport (WS / CSV / RRD) は単一の SourceEvent 型に正規化されるため、新しい source を追加するには adapter を 1 つ書くだけで済む。

7. 関連ドキュメント