Trace と replay のアーキテクチャ
semantic trace の目的は、run の最終結果を保存することではなく、divergence の最初の causal boundary を残すことです。 そのため ExternalInput、Device、actuator、physics state を一つの数値 vector に潰しません。
永続化形式
trace persistence には MCAP を使います。 frame と metadata は versioned schema を持ち、Plan provenance と Plan inspection document も trace sink に渡せます。
trace は simulation runtime の semantic record であり、ROS message recording の代替ではありません。
ROS message の raw record/replay が必要な場合は fibril_sim_ros の rosbag2 adapter を使います。
Capture policy の選択
trace を有効にしただけでは、毎 physics step の full numerical/contact dump は行いません。 通常実行の既定は causal capture で、ExternalInput、Device delivery envelope、actuator application、domain、semantic event を残し、Device payload、full numerical state、contact wrench は省略します。
詳細観測が必要な場合は用途に応じて capture policy を上げます。
causal: 通常の常時 trace。replay と causal divergence の追跡用。numerical: causal + Device payload + post-physics numerical state。numerical state は decimation 可能。contact: causal + contact topology / frame / wrench。full: numerical + contact を毎 step 記録する最大 detail の trace。
CLI の fibril_sim run では --trace-detail causal|numerical|contact|full を使います。
numerical は既定で10 stepごとに numerical state を取り、--trace-state-every N で変更できます。
trace frame 自身が capture policy と、その frame に numerical state が存在するかを保持するため、replay と query は間引きされた trace を区別できます。
Device boundary の記録
Device trace は三つの boundary を区別します。
- raw source
- Device semantics 適用後の acquired value
- runtime 外へ配信可能になった delivered value
Fibril Simulation runtime は stage、Device ID、sequence、nominal time、actual time などの envelope を所有します。 payload schema は Device が versioned namespaced format として所有します。
standard Device は三 boundary の payload trace を提供します。 plugin-defined Device が payload codec を提供しない場合でも timing metadata は残せます。
Controller output の記録
controller は SimulationInstance の外側にあり、その output は ExternalInput として runtime に入ります。
したがって production software output の causal record は、source ID、source sequence、acceptance sequence、commit tick、payload を持つ committed ExternalInput です。
SIL 専用の controller execution record や controller command record は持ちません。
Actuator boundary の記録
command latency、timeout、hardware-specific conversion は component-owned ActuatorDriver の内部状態です。 kernel trace は ActuatorApplication の execution boundary、timeout safe-state selection、MuJoCo に適用した value、resolved MuJoCo actuator identity、completed post-physics boundary の actuator force を記録します。
controller output と downstream virtual hardware の差は、committed ExternalInput と ActuatorApplication を比較して特定します。
applied command と mechanism response の差は actuator force、joint-space qfrc_actuator / qfrc_constraint、qvel を同じ boundary で比較して特定します。
ExternalInput の replay
ingress acceptance には run-unique acceptance_sequence を割り当てます。
commit phase は accepted set を cut し、effective time、source ID、source sequence、acceptance sequence による canonical ordering で処理します。
recorded replay は payload だけでなく acceptance ordering identity と commit tick を復元します。 producer arrival timing を適当に再現する方式では、deferred input と same-time input の visibility が変わるためです。
D1 と D2
diagnostic comparison は D1 semantic/causal comparison と D2 numerical comparison を分けます。
D1 は ID、ordering、payload structure、boolean や enum の semantic value などを比較します。 D2 は numerical leaf を configured tolerance で比較します。
たとえば mode button の false と true は D1 divergence です。
floating-point range の微小差は D2 tolerance で評価します。
Post-physics numerical state の記録
full numerical trace は qpos、qvel、sensordata、body world position / quaternion、qfrc_actuator、qfrc_constraint を completed post-physics boundary で保持します。
contact も geom/flex endpoint identity と element identity、dimension、exclude、efc_address、solver constraint participation を semantic topology として記録し、distance、position、full contact frame、adhesion、contact-frame 6D wrench は numerical evidence として比較します。
contact record の存在と solver-active contact は区別します。
constraint_active は completed boundary で efc_address >= 0 の contact を表し、その contact では mj_contactForce() から得た contact-frame wrench を保持します。
contact wrench は world-frame force ではないため、consumer が world axis へ解釈する場合は同じ record の full contact frame を使います。
永続 trace の query
fibril_sim_trace の source は decoded frame を一件ずつ visit できる streaming API を持ちます。
fibril_sim trace info/query はこの API 上に実装し、long trace を一度すべて std::vector<SimulationTraceFrame> へ展開しなくても時間窓を絞れます。
query の semantic name resolution は query 実行時の SimulationPlan に対して一度行い、recorded qpos / qvel / body arrays の raw index を user-facing contract にしません。
ROS host boundary の扱い
live ROS execution でも mutable SimulationInstance は SimulationHost worker thread が単独所有します。
trace enabled の場合、worker は step 完了後に drain_trace_frames() して immutable SimulationHostFrame へ移し、ROS frontend / node 側が persistent sink へ書きます。
trace persistence を理由に physics owner thread へ MCAP I/O や ROS callback access を持ち込みません。
診断結果
比較 report は equivalent、diverged、insufficient_evidence を区別します。
空 trace や必要 signal の欠落を「差が見つからなかったから equivalent」と扱うと、観測不足と同値性を混同するためです。