Skip to content

PCR 重构主蓝图(Master Blueprint)

> 本文件取代 _archive/ 下所有旧 Refactoring 文档。 > 本版本(v1.0)相对于初稿的关键修订: > - 引入 environment/ 模块,将"普适物理场"从 plant/ 中剥离 > - 引入 simulation/ 跨域绑定层,作为 RocketBodyWorldStateProbe双层 RWS 实例化 的归宿 > - 重命名 dynamics/dynamics_core/,严格限定为 universal kernel(不依赖任何业务子域) > - runtime/ 退化为纯生命周期管理者,不再持有业务定义 > > 所有内容以四轮深度讨论后的最终裁定为准。推理溯源参见 PCR_Discussion_Log.md


0. 阅读指引

章节读者核心问题
§1 四视角架构全员系统里每一层各自"看到什么",闭环如何成立
§2 目标结构写新代码者库划分、依赖图、环境/对象分离、跨域绑定层
§3 Controller ProtocolFCC 开发者FCC 三层架构、GNC Mealy state、FccStage 代数
§4 推力跨域数据流动力学/航电开发者推力计算五阶段在新架构中的归位
§5 当前状态全员哪些可以直接用、哪些是脚手架、哪些必须从 main 迁回
§6 迁移计划(四波)执行者Wave 0-3 各自的 scope / 步骤 / 试验守门
§7 设计裁定架构师历史文档冲突的最终答案
§8 工程约定全员Scaffold 标记、commit 规范、TDD 四级体系

1. 四视角架构

理解这套系统最好的方式,是同时站在四个视角里看:FCC、Bus、Device、World。 每个视角只看自己能看到的东西。这种"被设计的无知"不是缺陷,是解耦的证明。

1.1 四个视角

FCC 视角:只看 FccInFrame(输入数据包)和 FccOutFrame(输出数据包)。 Bus 协议、设备型号、物理环境——一概不知。FccInFrame 本身已经封装了 Bus 的语义,它是一帧数据,不是原始总线帧。

Bus 视角:只看 (src_addr, dst_addr, payload) 三元组。 计算、状态、物理环境——一概不关心。Bus 是邮局:只投递信件,不阅读内容,不关心信件如何被使用。

Device 视角(IMU / GPS / Engine / Servo / ICU / Fin / FCC 等): 持有自身状态,接收来自 Bus 的输入或采样自身所在物理实体的状态,按 Mealy 状态机 演化,产出输出(写回物理实体或发到 Bus)。 Device 是物理实体的电子界面:它把"物理事实"翻译成"数字消息",把"数字命令"翻译成"物理驱动"。

World 视角

  • 驱动环境采样(probe_trajectory / probe_aero / probe_mass_props
  • 演化每个 body 内的物理实体(伺服机构、发动机、栅格舵)
  • 演化每个 body 内的电子设备(SCU/ECU/ICU/IMU/GPS/FCC)
  • 执行物理力学计算(thrust / aero / gravity)
  • 积分;处理拓扑事件(StageOp)
  • 真值反过来作为下一拍 Device 的物理输入

> 最关键的解耦:换发动机推力曲线 = 换发动机(plant/model 的 YAML 变了), > 但推力计算的 pipeline(plant/physics)一字不变。配方换了,流水线不变。 > > 更深一层的解耦:换地球 → 月球 = 换 environment/(无大气、不同重力场), > 但 plant/(火箭本身)和 dynamics_core/(积分引擎)都一字不变。舞台换了,演员和导演不变。

1.2 系统运行与闭环

重要澄清:AvionicsSystem 不是自闭环子系统。它必须与物理实体(伺服机构、发动机、栅格舵、IMU 物理元件、GPS 天线)共同构成完整闭环。

> 电气链路闭环:FCC → Bus → SCU → 电信号 → 回采到 SCU → Bus → FCC(仅数字层面) > > 完整闭环:上述 + ServoMech 真实摆角 + EngineMech 真实推力 + 大气环境 + 重力 + IMU 物理感知

所谓 "FCC 模飞测试" 也不是 Avionics 单跑——它是 Avionics + 静态 Plant: 物理实体被冻结在初始状态(伺服摆角=0,发动机推力=0,IMU 物理元件不动), 但物理实体仍然存在并被 Avionics 采样。

┌──────────────────────────────────────────────────────────────────────────┐
│ Composition Root (runtime::Runner)                                        │
│ 读 run_xxx.yaml → assemble(rocket × mission × world × deployment)         │
│ → simulation::Instance { WorldEnv(只读), WorldState(per-body 全状态) }│
└───────────────────────────┬──────────────────────────────────────────────┘
                            │ 启动期一次性装配

┌──────────────────────────────────────────────────────────────────────────┐
│ simulation::world_tick (per-body 并行,多速率)                          │
│                                                                          │
│ For each RocketBody:                                                     │
│                                                                          │
│  ① simulation::probe (Trajectory / Aero / MassProps) → BodyEnv          │
│                                                                          │
│  ② simulation::body_tick (BodyEnv, RocketBody) ─────────────────         │
│     ▸ Avionics:                                                          │
│        Engines:  ECU 处理 Bus 命令 → 推进 EngineMech FSM → EngineEffect │
│        Servos:   SCU 接 Bus 命令 → 推进 ServoMech 摆角                  │
│        Fins:     FinCtrl 接 Bus 命令 → 推进 FinMech                     │
│        IMUs:     从 body.aux 读真值 → 加噪/量化 → 发 Bus                │
│        GPSs:     从 body.spatial 读真值 → 加噪 → 发 Bus                 │
│        ICUs:     接 Bus 命令 → 计时 → 到期发 DiscreteEvent             │
│                                                                          │
│     ▸ FCC tick (仅当 fcc_dt 边界到达,e.g. 50Hz)                      │
│        decode Bus → FccInFrame → execute(strategy) → FccOutFrame → Bus  │
│                                                                          │
│     ▸ plant::physics: thrust ⊕ aero ⊕ gravity (EngineEffect 已就绪)   │
│                                                                          │
│     ▸ dynamics_core::ode (RK4) → 新 spatial / inertial / aux            │
│                                                                          │
│ World 末尾:                                                             │
│  ③ 收集所有 body 的 DiscreteEvent → 解释为 StageOp →                   │
│     dynamics_core::algebra::evolve_topology(bodies, op) → 处理分离      │
└──────────────────────────────────────────────────────────────────────────┘

1.3 三种部署/测试模式

模式描述信道实现
avionics_dry(FCC 模飞测试)物理冻结,电气链路完整跑。验证 FCC 时序、调度、状态机、设备 FSM。InMemory + Plant 静态
sil_monolithicAvionicsSystem + PlantPhysics 同进程,全闭环InMemory(DynChannel + Bus 都内存)
hil_dyn物理在本机,FCC + Bus + Devices 在远端DynChannel = UDP;远端 Bus 内存或物理
hil_fccFCC 在 RTOS,Devices + Bus + 物理在 SIL 仿真器DynChannel = 内存;Bus = 物理(1553B / TTE)

HIL 的本质:不是"重新设计架构",而是在两个数据包边界上换信道

DynChannel 跨 AvionicsSystem ↔ PlantPhysics(数据是 DynInFrame / DynOutFrame); Bus 跨 FCC ↔ Devices(数据是 BusMessage)。


2. 目标结构

2.1 库划分与依赖图

本项目的目录结构反映了一条核心架构哲学:universal kernel ↔ specific instantiation 的彻底分离

                                runtime


                              simulation         ◄── 跨域绑定层
                  ┌─────────┬─────┴────┬──────┬─────┬──────────┐
                  │         │          │      │     │          │
                  ▼         ▼          ▼      ▼     ▼          ▼
            dynamics_core  fcc    avionics/  plant  bus    environment
                  │         │     devices    │ │     │         │
                  │         │        │       │ │     │         │
                  └─────────┴────────┴───────┴─┴─────┴─────────┘


                                contracts          ← header-only 中立层
                                  /  |  \
                                 /   |   \
                              types frames monad   ← 基础数学层

核心约束(编译期强制):

  • contracts/ 是 header-only 的中立层,定义所有跨子系统数据包,无运行逻辑
  • bus/fcc/ 互不依赖(FCC 不知道 Bus 协议,Bus 不知道 FCC 算法)
  • fcc/ 不依赖 plant_* / dynamics_core/ / environment/(HIL 部署的前置条件)
  • plant/physics/ 不依赖 bus/ / fcc/ / avionics/(力学是纯函数)
  • dynamics_core/ 不依赖任何业务子域(不依赖 plant / avionics / fcc / environment / bus)
  • simulation/ 是唯一允许聚合所有子域的层(这是它存在的意义)
  • runtime/ 只依赖 simulation/(不持有业务定义,只做装配 + main loop)
目录职责命名空间依赖
typessrc/types/Vec3 / Matrix / Quat / Angle / Time / InterpTable1D::
framessrc/types/frames/坐标系定义、ECF/LIC/BODY 变换、WGS84frame::types
monadsrc/types/monad/RWS / Free / Writer 模板monad::types
contractssrc/contracts/DynInFrame / DynOutFrame / FccInFrame / FccOutFrame / BusMessage / EngineEffect / DiscreteEvent + 强类型 IDcontracts::types + frames
environmentsrc/environment/普适物理场:Atmosphere / GravityField / WindField,关于位置/时间的纯函数env::types + frames
plant/modelsrc/plant/model/对象专属本构关系(静态规格):EngineSpec / ServoSpec / FinSpec / ImuSpec / GpsSpec / IcuSpec / BodyAsset / AeroSpecplant::model::types + frames
plant/physicssrc/plant/physics/力组装纯函数:compute_thrust / compute_aero / compute_gravity,只依赖 BodyEnvplant::physics::types + frames + plant_model + contracts
plant/hardwaresrc/plant/hardware/物理机械面:EngineMech / ServoMech / FinMech + 演化函数plant::hardware::types + plant_model
bussrc/bus/IBus / BusMessage / BusBuffer / SemanticInterpreter / 1553BInterpreterbus::types + contracts
avionics/devicessrc/avionics/devices/电子器件 step 函数:ecu / scu / icu / imu / gps / fin_ctrlavionics::device::types + plant_model + plant_hardware + bus
fccsrc/fcc/Free Monad DSL / Interpreter / GNC 算法纯函数 / FccStage 代数fcc::types + frames + monad + contracts
dynamics_coresrc/dynamics_core/Universal kernel:ODE + 积分器 + 拓扑代数 + RWS 模板。不知道火箭长什么样dynamics::types + frames + monad + contracts
simulationsrc/simulation/跨域绑定层RocketBody / WorldState / WorldEnv / BodyEnv 复合类型 + probe_* 函数 + 双层 RWS 实例化 + 多速率调度sim::全部业务子域(合法聚合)
runtimesrc/runtime/Loader / Assembler / Runner / IDynChannel / PlantScope,生命周期管理runtime::simulation

> 一票否决线(编译期强制): > - fcc/ 不得 #include 任何 plant/* / dynamics_core/* / environment/* 头文件 > - plant/physics/ 不得 #include 任何 bus/fcc/avionics/* 头文件 > - dynamics_core/ 不得 #include 任何 plant/* / avionics/* / fcc/ / bus/ / environment/ / simulation/ 头文件 > - simulation/ 是唯一允许 include 全部业务子域的层 > - contracts/.cpp 文件,纯 struct 定义

2.2 contracts 中立层

定义所有跨子系统对话用的数据包结构。Per-body 粒度,body_id 即 vector 下标。

cpp
// contracts/PerBodyFrames.h

// Avionics → Plant Physics
struct DynInFrame {
    BodyId                      body_id;
    std::vector<EngineEffect>   engine_effects;
    std::vector<FinDeflection>  fin_deflections;
    std::vector<DiscreteEvent>  events;
};

// Plant Physics → Avionics(每个 body 一份,作为 Sensor 真值输入)
struct DynOutFrame {
    BodyId                      body_id;
    Vec3_T<frame::ECF>          pos_ecf;
    Vec3_T<frame::ECF>          vel_ecf;
    Quat_T<frame::LIC, frame::BODY> att_q;
    Vec3_T<frame::BODY>         omega_b;
    Vec3_T<frame::BODY>         spec_force_b;
    double                      total_mass;
    Vec3_T<frame::BODY>         centroid_b;
};

// 边界对象:Engine FSM 的输出,喂给 thrust pipeline
struct EngineEffect {
    EngineId  engine_id;
    double    vacuum_thrust;
    double    mass_flow_fuel;
    double    mass_flow_ox;
    double    current_throttle;
    Angle     nozzle_pitch;
    Angle     nozzle_yaw;
};

struct DiscreteEvent {
    enum class Kind { EngineShutdown, BoltFired, StageSeparation, FinDeploy };
    Kind         kind;
    BodyId       source_body;
    uint32_t     payload_id;
    Time         emitted_at;
};

struct BusMessage {
    BusAddr  src;
    BusAddr  dst;
    Time     emitted_at;
    std::variant<ImuPayload, GpsPayload, ScuPayload, EcuPayload,
                 IcuPayload, FinCtrlPayload, TelemetryPayload> payload;
};

struct FccInFrame {
    ImuPayload    imu;
    GpsPayload    gps;
    Time          timestamp;
};

struct FccOutFrame {
    ScuPayload      scu;
    IcuPayload      icu;
    EcuPayload      ecu;
    TelemetryPayload tlm;
};

// 强类型 ID(避免 uint32 互换)
enum class BodyId   : uint32_t {};
enum class EngineId : uint32_t {};
enum class ServoId  : uint32_t {};
enum class FinId    : uint32_t {};
enum class ImuId    : uint32_t {};
enum class GpsId    : uint32_t {};
enum class IcuId    : uint32_t {};
enum class BusAddr  : uint32_t {};

2.3 Environment:普适物理场

environment/ 装的是关于位置/时间的函数 f(x, t)。它不属于任何具体物体,但被所有物体感受到。

cpp
// environment/Atmosphere.h
namespace env {

struct Atmosphere {
    // USSA1976 表 + 插值器
    double pressure_at(double h_msl) const;
    double density_at (double h_msl) const;
    double sound_speed_at(double h_msl) const;
};

struct GravityField {
    // WGS84 椭球重力场
    Vec3_T<frame::ECF> gravity_at(Vec3_T<frame::ECF> pos_ecf) const;
};

struct WindField {
    Vec3_T<frame::ECF> wind_at(Vec3_T<frame::ECF> pos_ecf, Time t) const;
};

} // namespace env

> 设计原则environment/ 的所有类对外只暴露纯函数pressure_at, gravity_at …)。它内部可以持有插值表/CSV 数据,但不持有任何随时间演化的状态。 > > 替换地球→月球只改 env::Atmosphere::pressure_at 的数据源;不影响 plant/dynamics_core/

2.4 Plant:对象本构关系

plant/ 装的是对象专属的查表关系。它代表了"这台火箭具体是什么"。

cpp
// plant/model/EngineSpec.h
namespace plant::model {

struct EngineSpec {
    InterpTable1D thrust_curve;        // 真空推力曲线
    InterpTable1D mass_flow_curve;
    double        nozzle_exit_area;     // Sa
    std::array<double, 12> perturb_coeffs;
    std::array<double, 4>  stage_deviations;
    // ...
};

struct AeroSpec {
    InterpTable3D drag_table;          // Cd(Mach, alpha, beta)
    InterpTable3D lift_table;
    InterpTable3D moment_table;
    double        reference_area;
    double        reference_length;
};

} // namespace plant::model

plant/physics/纯力学函数,它接受 BodyEnv(局部上下文)和 RocketBody 状态,返回 Forces

cpp
// plant/physics/Thrust.h
namespace plant::physics {

Forces compute_thrust(const sim::BodyEnv& env, const sim::RocketBody& body);
Forces compute_drag  (const sim::BodyEnv& env, const sim::RocketBody& body);
Forces compute_gravity(const sim::BodyEnv& env, const sim::RocketBody& body);

} // namespace plant::physics

plant/hardware/ 装的是物理机械面(Mech)的定义与演化:

cpp
// plant/hardware/Mech.h
namespace plant::hardware {

struct EngineMech { double chamber_pressure; double true_thrust; double mass_flow; };
struct ServoMech  { Angle  actual_angle;     Angle  target_angle; double oil_pressure; };
struct FinMech    { Angle  actual_angle; };

void step_engine_mech(EngineMech&, EcuDriveCommand cmd, Time dt);
void step_servo_mech (ServoMech&,  Angle target, Time dt);
void step_fin_mech   (FinMech&,    Angle target, Time dt);

} // namespace plant::hardware

2.5 dynamics_core:Universal Kernel

dynamics_core/通用推演引擎,它不知道火箭长什么样。它只知道:

  • 给定一个 RHS function,怎么用 RK4 积分
  • 给定一个 Body 集合 + StageOp,怎么演化拓扑
  • 给定一个 Env / State / Log 三元组,怎么组装 RWS pipeline
cpp
// dynamics_core/ode/EquationsOfMotion.h
namespace dynamics::ode {

// 通用:对任何有 spatial+inertial+aux 三状态的 body 做导数计算
template<typename Body>
auto compute_derivatives(const Body& body, const Forces& f) -> BodyDerivatives;

} // namespace dynamics::ode

// dynamics_core/ode/Integrator.h
namespace dynamics::ode {

template<typename Body, typename RhsFn>
Body rk4_step(const Body& state, RhsFn rhs, Time t, Time dt);

template<typename Body, typename RhsFn>
Body euler_step(const Body& state, RhsFn rhs, Time t, Time dt);

} // namespace dynamics::ode

// dynamics_core/algebra/StageOp.h
namespace dynamics::algebra {

enum class WorldStage : uint16_t {};

struct NoOp {};
template<typename BodyIdT> struct TransitionOp { BodyIdT body; WorldStage next; };
template<typename BodyIdT, typename EngineIdT>
struct SeparationOp {
    BodyIdT                source;
    BodyIdT                new_body;
    std::vector<EngineIdT> detached_engines;
    AvionicsAction         avionics_for_new;
};
template<typename BodyIdT, typename EngineIdT>
struct IgnitionOp { BodyIdT body; EngineIdT engine; };

template<typename BodyIdT, typename EngineIdT>
using StageOp = std::variant<NoOp,
                              TransitionOp<BodyIdT>,
                              SeparationOp<BodyIdT, EngineIdT>,
                              IgnitionOp<BodyIdT, EngineIdT>>;

// 模板化的自由函数:算法在底层,类型在上层
template<typename Body>
std::vector<Body> evolve_topology(
    const std::vector<Body>& bodies,
    const StageOp<contracts::BodyId, contracts::EngineId>& op);

} // namespace dynamics::algebra

// dynamics_core/pipeline/Forces.h
namespace dynamics {

// Monoid: 多力相加自然组合
struct Forces {
    Vec3_T<frame::BODY> force_b;
    Vec3_T<frame::BODY> moment_b;

    static Forces zero();
    Forces  operator+(const Forces& other) const;
    Forces& operator+=(const Forces& other);
};

} // namespace dynamics

// dynamics_core/pipeline/RWSAlias.h
namespace dynamics {

template<typename Env, typename State, typename Log>
using RWS = monad::RWS<Env, Log, State>;

}

> 关键测试dynamics_core/ 的所有文件,grep -r "plant/\|avionics/\|fcc/\|bus/\|environment/\|simulation/" 必须 零命中

2.6 Simulation:跨域绑定层

simulation/ 是这套架构的核心创新。它是唯一一层允许聚合所有业务子域的模块。它的存在解决了一个真实存在的架构压力:RocketBody 是跨域复合体,没有任何单一子域可以独占它

simulation/ 的职责有四块:

2.6.1 复合状态容器 (simulation/state/)

cpp
// simulation/state/RocketBody.h
namespace sim {

// 物理状态原语(在 dynamics_core 中定义)
using dynamics::SpatialState;
using dynamics::InertialState;
using dynamics::AuxState;

struct Engine {
    contracts::EngineId             id;
    plant::model::InstallParams     install;
    const plant::model::EngineSpec* spec;

    plant::hardware::EngineMech     mech;     // 物理机械面
    avionics::device::ecu::EcuState ecu;      // 电子控制面
};

struct Servo { /* ... 同样的双面结构 ... */ };
struct Fin   { /* ... */ };
struct ImuUnit { /* 只有电子面,物理输入是 body.aux */ };
struct GpsUnit { /* 只有电子面,物理输入是 body.spatial */ };
struct Icu     { /* 纯电子,无物理输入 */ };

struct RocketBody {
    contracts::BodyId             body_id;
    dynamics::algebra::WorldStage world_stage;

    // ── 物理状态(dynamics_core 关心) ──
    SpatialState   spatial;
    InertialState  inertial;
    AuxState       aux;

    // ── 设备(avionics + plant 关心) ──
    std::vector<Engine>     engines;
    std::vector<Servo>      servos;
    std::vector<Fin>        fins;
    std::vector<ImuUnit>    imus;
    std::vector<GpsUnit>    gpss;
    std::vector<Icu>        icus;

    // ── 航电基础设施 ──
    bus::BusBuffer            bus;
    std::optional<fcc::FccCore> fcc;
};

struct WorldState {
    std::vector<RocketBody> bodies;
    Time                    current_time;
};

} // namespace sim

2.6.2 环境装配 (simulation/env/)

cpp
// simulation/env/WorldEnv.h
namespace sim {

// 严格只读 Reader,由 Assembler 装配后冻结
struct WorldEnv {
    // ── 全局常量与坐标系 ──
    frame::FrameConfig         frame;
    Constants                  constants;

    // ── 普适物理场(来自 environment/) ──
    env::Atmosphere            atmosphere;
    env::GravityField          gravity_field;
    env::WindField             wind_field;

    // ── 对象本构资产(来自 plant/model/,按 type_id 索引) ──
    std::vector<plant::model::BodyAsset>     body_assets;
    std::vector<plant::model::EngineSpec>    engine_specs;
    std::vector<plant::model::ServoSpec>     servo_specs;
    std::vector<plant::model::FinSpec>       fin_specs;
    std::vector<plant::model::ImuSpec>       imu_specs;
    std::vector<plant::model::GpsSpec>       gps_specs;
    std::vector<plant::model::IcuSpec>       icu_specs;
    std::vector<plant::model::AeroSpec>      aero_specs;

    const plant::model::BodyAsset& get_asset(contracts::BodyId id) const;
};

// 局部 Body Reader:probe 函数的产物
struct BodyEnv {
    // ── 当前 Body 的局部上下文切片 ──
    TrajCtx                   traj;       // 经纬高、速度方位角
    AeroCtx                   aero;       // 动压、马赫数、密度
    MassPropsCtx              mass_props; // 当前质量、质心、惯量

    // ── 该 Body 引用的资产 ──
    const plant::model::BodyAsset*  asset;
    const plant::model::AeroSpec*   aero_spec;
    // (engine_specs / servo_specs 通过 RocketBody.engines[i].spec 指针访问)

    // ── 全局只读引用 ──
    const env::Atmosphere*    atmosphere;
    const env::GravityField*  gravity_field;
    const env::WindField*     wind_field;
};

} // namespace sim

> WorldEnv 不持有任何运行时实例。设备实例属于 RocketBodypath_index(string→uint)只在 Assembler 内部局部使用,装配结束 RAII 析构。

2.6.3 探测器 (simulation/probe/)

Prober 函数是双层 RWS 之间的降维算子。它把全局只读 WorldEnv 与局部状态 RocketBody 结合,产出局部只读 BodyEnv

cpp
// simulation/probe/Probe.h
namespace sim::probe {

TrajCtx       probe_traj      (const WorldEnv&, const RocketBody&, Time t);
AeroCtx       probe_aero      (const WorldEnv&, const RocketBody&, Time t);
MassPropsCtx  probe_mass_props(const WorldEnv&, const RocketBody&, Time t);

// 一次性装配整个 BodyEnv
BodyEnv assemble_body_env(const WorldEnv&, const RocketBody&, Time t);

} // namespace sim::probe

> 设计原则plant/physics/compute_thrust 等纯函数只读 BodyEnv,不直接读 WorldEnv 大表。换大气模型只改 probe_aero,pipeline 不动。这就是"配方与流水线分离"在算子内部的实现。

2.6.4 双层 RWS 实例化与多速率调度 (simulation/pipeline/)

cpp
// simulation/pipeline/RWSTypes.h
namespace sim {

using BodyRWS  = dynamics::RWS<BodyEnv,  RocketBody, BodyLog>;
using WorldRWS = dynamics::RWS<WorldEnv, WorldState, WorldLog>;

} // namespace sim

// simulation/pipeline/BodyTick.h
namespace sim {

// 单体 tick:avionics → physics → integrate
BodyRWS body_tick(BodyEnv env, RocketBody body, Time dt);

}

// simulation/pipeline/WorldTick.h
namespace sim {

// 全局 tick:probe → body_tick × N → topology
WorldRWS world_tick(Time dt);

}

// simulation/pipeline/Scheduler.h
namespace sim {

// 多速率:FCC 50Hz vs Physics 1kHz vs Bus 同 tick
struct MultiRateScheduler {
    Time fcc_period   { Time::from_hz(50)  };
    Time phys_period  { Time::from_hz(1000) };
    Time last_fcc_tick;

    bool should_fcc_tick(Time now) const;
};

} // namespace sim

> 核心洞察:BodyRWS pipeline 本身是跨域的——它会调用 avionics、plant、dynamics_core 多个子域。因此它必须在 simulation/ 中实例化,而不是放在 dynamics_core(违反 universal 承诺)或某个具体子域(不能持有跨域调用)。

2.7 Runtime:生命周期管理

runtime/ 退化为非常薄的一层:它只负责程序的启动、装配、运行循环、退出。它不持有任何业务定义。

cpp
// runtime/Assembler.h
namespace runtime {

struct SimulationInstance {
    sim::WorldEnv   env;        // 装配产物,冻结
    sim::WorldState state;      // 初始状态
    PlantScope      scope;      // 部署切片配置
};

class Assembler {
public:
    // 从一组 YAML 配置文件装配出完整的 SimulationInstance
    SimulationInstance assemble(const std::string& run_config_path);

private:
    // 装配期局部状态:path_index 在此 RAII,装配结束析构
    std::unordered_map<std::string, uint32_t> path_index_;

    // 阶段
    void load_environment_(...);      // → env::Atmosphere, GravityField, WindField
    void load_plant_assets_(...);     // → plant::model::*Spec
    void instantiate_world_state_(...); // → sim::RocketBody × N
};

} // namespace runtime

// runtime/Runner.h
namespace runtime {

class Runner {
public:
    int run(SimulationInstance instance);

private:
    sim::MultiRateScheduler scheduler_;
    std::unique_ptr<bus::IBus>             bus_;
    std::unique_ptr<IDynChannel>           dyn_channel_;
};

} // namespace runtime

// runtime/IDynChannel.h
namespace runtime {

class IDynChannel {
public:
    virtual void send(const std::vector<contracts::DynInFrame>&) = 0;
    virtual std::vector<contracts::DynOutFrame> recv() = 0;
    virtual ~IDynChannel() = default;
};

class InMemoryDynChannel : public IDynChannel { /* SIL */ };
class UdpDynChannel       : public IDynChannel { /* HIL */ };

} // namespace runtime

> 职责切割: > - simulation::Assembler 不存在(这是 runtime 的事) > - runtime 不定义 RocketBodyWorldEnv(这是 simulation 的事) > - Runner 不直接调用 dynamics_core::rk4(必须通过 sim::world_tick

2.8 PlantScope:部署切片

Plant 物理资产唯一,PlantScope 决定本进程实例化什么:

cpp
// runtime/PlantScope.h
namespace runtime {

struct PlantScope {
    bool physics_bodies;
    bool sensor_truth;
    bool actuator_effect;
    bool fcc;

    enum class TransportKind { InMemory, UdpServer, UdpClient };
    TransportKind            dyn_transport;

    enum class BusKind { InMemory, Bridge1553B, RealtimeBus };
    BusKind                  bus_kind;

    std::vector<contracts::BusAddr> local_bus_addrs;
    std::vector<contracts::BusAddr> remote_bus_addrs;
};

} // namespace runtime

YAML 示例:

yaml
# data/input/sim/deployments/sil_monolithic.yaml
plant_scope:
  physics_bodies: true
  sensor_truth:   true
  actuator_effect: true
  fcc:            true
  dyn_transport:  InMemory
  bus_kind:       InMemory

2.9 World Stage 与拓扑代数

WorldStage 是火箭整体的飞行阶段(YAML 驱动),与 FccStage(FCC 自己内部状态)独立(详见 §3.7)。

cpp
// dynamics_core/algebra/StageOp.h
namespace dynamics::algebra {

enum class WorldStage : uint16_t {};

struct NoOp {};
struct TransitionOp { contracts::BodyId body; WorldStage next; };
struct SeparationOp {
    contracts::BodyId                source;
    contracts::BodyId                new_body;
    std::vector<contracts::EngineId> detached_engines;
    AvionicsAction                   avionics_for_new;
};
struct IgnitionOp { contracts::BodyId body; contracts::EngineId engine; };

using StageOp = std::variant<NoOp, TransitionOp, SeparationOp, IgnitionOp>;

// 自由函数(algorithm 在 dynamics_core,类型 contracts::* 来自 contracts)
template<typename Body>
std::vector<Body> evolve_topology(
    const std::vector<Body>& bodies,
    const StageOp& op);

} // namespace dynamics::algebra

数据流:

ICU FSM → DiscreteEvent → DynInFrame.events
                           ↓ sim::world_tick 末尾
                       sim::interpret_event(event) → StageOp

                       dynamics::algebra::evolve_topology(bodies, op)

ICU 不直接修改 World 状态,事件解释器在 simulation/(simulation 决定一个 BoltFired 事件是变成 SeparationOp 还是 NoOp)。

2.10 信道抽象与 Bus

IBus 与 BusBuffer

IBus 是 FCC ↔ Devices 的语义信道,使用 algebra+interpreter 模式(因为有多种物理协议):

cpp
// bus/IBus.h
struct BusLog {
    std::vector<RoutingTrace> traces;
    std::vector<DropEvent>    drops;
    BusLog& operator+=(const BusLog& other);   // Monoid
};

template<typename A>
using BusM = monad::Writer<BusLog, A>;

class IBus {
public:
    virtual BusM<void>                          publish(contracts::BusMessage msg) = 0;
    virtual BusM<std::vector<contracts::BusMessage>> poll(contracts::BusAddr local) = 0;
    virtual void                                step_cycle(Time t) = 0;
    virtual ~IBus() = default;
};

class InMemoryBus    : public IBus {};
class Bridge1553BBus : public IBus {};
class RealtimeBus    : public IBus {};

BusMonitor 不再独立,融入 BusM<...>BusLog。这通过 Writer Monad 自然汇聚到 World tick 的总日志。

bus::BusBuffer 是 RocketBody 内部的"局部线束"——一个延时队列副本,供该 body 内的 device 互相通信;不与外部 Bus 直接通信,由 sim::world_tick 末尾的总线路由阶段统一处理。


3. Controller Protocol(FCC)

FCC 是一个独立的 RWS 引擎,以自己频率运行(默认 50Hz),通过 FccInFrame / FccOutFrame 与外部对话。

3.1 三层架构

┌────────────────────────────────────────────────────────────────┐
│  Layer 1:Declarative Strategy (声明式策略)                   │
│  Free<FccOp, A>  DSL                                           │
│  描述"做什么",不描述"怎么做"。无副作用。                       │
│  read_imu() >>= run_nav >>= run_guide >>= run_ctrl >>= output  │
│  策略由 FccStage 决定:select_strategy(stage) → Free<FccOp, A> │
└────────────────────────────┬───────────────────────────────────┘
                             │ FccInterpreter::foldMap()

┌────────────────────────────────────────────────────────────────┐
│  Layer 2:Imperative Interpreter (命令式解释器)                │
│  解释 FccOp 为 RWS 副作用                                       │
└────────────────────────────┬───────────────────────────────────┘
                             │ algorithms::nav_step / ...

┌────────────────────────────────────────────────────────────────┐
│  Layer 3:Pure Functional Core (函数式核心)                  │
│  纯 C++ 函数,接收输入返回输出,零副作用                        │
└────────────────────────────────────────────────────────────────┘

3.2 与 simulation 的契约

FCC 不直接依赖 bus::IBus 也不依赖 simulation/。FCC 只看 FccInFrame / FccOutFrame组装 / 拆解逻辑在 simulation/pipeline/

sim::body_tick 内:
  Bus.poll(fcc.addr) → [BusMessage]
                    → BusManager::decode_to_fcc_in
                    → FccInFrame
                    → fcc::tick()
                    → FccOutFrame
                    → BusManager::encode_from_fcc_out
                    → [BusMessage]
                    → Bus.publish(...)

3.3 隔离保证

约束原因
fcc/#include plant/*FCC 不知道气动模型 / 发动机型号
fcc/#include dynamics_core/*FCC 不知道积分器 / 拓扑代数
fcc/#include simulation/*FCC 不知道仿真 orchestration(HIL 必备)
fcc/#include bus/IBus.hFCC IO 由 Interpreter 隔离
FccEnv 只含控制器配置Plant 有真实气动表,FCC 有 nominal 估计;两份独立

3.4 FccState(GNC 三模块 Mealy 机)

参见原 v0 文档 §3.6(内容不变,仅章节号下移)。

3.5 FccStage 状态机与 FccStageOp 代数

参见原 v0 文档 §3.7(内容不变,仅章节号下移)。


4. 推力跨域数据流

推力计算横穿多个域,每个阶段的归属与边界对象都已明确。

4.1 五阶段概览

Stage 1  配置加载
  YAML(devices.yaml) + 6×CSV/engine
  → runtime::Assembler::load_plant_assets_()
  → sim::WorldEnv.engine_specs[type_id].tables

Stage 2  插值工具
  InterpTable1D(线性插值 + 边界钳位)
  → types 层

Stage 3  发动机状态机(ECU + EngineMech)            ← Avionics + Plant 边界
  avionics::device::ecu::step(EcuState, EngineMech, bus, cfg, dt)
    - 处理 Bus 命令(点火 / 关机)
    - 推进 EngineMech FSM(OFF→STARTING(3s)→RUNNING→SHUTTING_DOWN(1s)→OFF)
    - 查 spec.tables 计算 vacuum_thrust + mass_flow → EngineEffect
  plant::hardware::step_engine_mech(EngineMech, ecu_drive, dt)
    - 燃烧室压力、阀门开度的物理演化
  → contracts::EngineEffect 写入 DynInFrame

Stage 4  动力学推力管线                               ← Plant Physics 边界
  plant::physics::compute_thrust(BodyEnv, RocketBody) → Forces
  三步链:
    apply_perturbation()    ← 12 系数摄动修正
    compensate_pressure()   ← 背压 F += Sa*(P0 - P_amb),其中 P_amb 来自 BodyEnv.aero
    resolve_thrust_vectors() ← 喷管→体轴系,力矩 = lever × F_body

Stage 5  Forces Monoid 累加                          ← dynamics_core
  Forces::zero() + thrust + aero + gravity → dynamics::ode::rk4_step

4.2 EngineEffect 边界

EngineEffect 是 Stage 3 → Stage 4 的边界对象,定义在 contracts/。 两侧通过 DynInFrame.engine_effects 传递,互不直接依赖。

可独立测试:

  • bench:给 EcuState 喂点火指令,验证 EngineEffect.vacuum_thrust 时序与 CSV 表吻合
  • bench:给 thrust pipeline 喂固定 EngineEffect,验证力/力矩数值
  • subsystem:两者串联跑 3s 起动 + 稳态 + 关机,验证力的时间积分

4.3 probe_aero:局部 Context 解耦推力与大气

plant::physics::compute_thrust 不直接读 env::Atmosphere。它读 BodyEnv.aero.static_pressure,由 sim::probe::probe_aero 在 BodyRWS pipeline 开头一次性算好:

cpp
// simulation/probe/Probe.cpp
AeroCtx probe_aero(const WorldEnv& env, const RocketBody& body, Time t) {
    return AeroCtx {
        .static_pressure = env.atmosphere.pressure_at(body.spatial.h_msl()),
        .density         = env.atmosphere.density_at (body.spatial.h_msl()),
        .mach            = mach_from(body.aux.spec_force_b, body.spatial.vel_lic),
        .dyn_pressure    = 0.5 * density * v_squared,
    };
}

// plant/physics/Thrust.cpp
Forces plant::physics::compute_thrust(const sim::BodyEnv& env, const sim::RocketBody& body) {
    double P_amb = env.aero.static_pressure;  // 不直接知道 env::Atmosphere 的存在
    // ...
}

这个模式让 compute_thrust 不知道 env::Atmosphere 是什么,只看一个数值 static_pressure。 换大气模型只改 probe_aero,pipeline 不动。

同样的局部 Context 模式应用到:

  • TrajCtx:经纬高、速度方位角
  • MassPropsCtx:当前质量、质心、惯量

每个 BodyRWS 算子只读对应的 Ctx,不直接读 WorldEnv 大表。


5. 当前状态(迁移基线)

5.1 ✅ 正确落实,不要动

位置内容
src/types/Vec3_T<Frame> / Matrix / Quat / Time / Frames.h
src/types/monad/RWS.hRWS 单子 / Free / Writer 模板
src/dynamics/ode/EquationsOfMotion.cppRK4 导数 / pack/unpack / 欧拉方程 / 四元数导数(待 rename 至 dynamics_core/
src/dynamics/ode/Integrator.cpp纯数值 RK4 / Euler(待 rename)
src/dynamics/state/Forces.hMonoid(待 rename 至 dynamics_core/pipeline/
src/contracts/PerBodyFrames.hWave 0 已建
src/avionics/devices/*.hWave 0 已建骨架
src/plant/hardware/Mech.hWave 0 已建

5.2 🟡 结构落地,逻辑空壳

位置现状需要做
src/bus/{IBus,BusPayloads,TransparentBus}.hinclude 路径错误,编不过修 include 路径
src/plant/model/仅有 BodyAsset.h 与若干迁移的 config 头EngineSpec / ServoSpec / FinSpec / ImuSpec / GpsSpec / IcuSpec
src/plant/hardware/Mech.h 已建,旧的 OOP 模型类待删Wave 1 迁入 step_engine_mech / step_servo_mech / step_fin_mech
src/avionics/devices/骨架已建,所有 step 函数为空Wave 2 实现 step 函数
src/dynamics_core/不存在Wave 0 创建并迁入原 dynamics/ 内容
src/simulation/不存在Wave 0 创建,引入 RocketBody/WorldState/WorldEnv/BodyEnv/Probe/Pipeline
src/environment/不存在Wave 0 创建,迁入大气/重力/风场模型
src/runtime/含 WorldEnv.h 等业务定义Wave 0 清空业务定义,只留 Assembler/Runner/IDynChannel
src/main/closed_loop_10s.cpp弹道骨架,无 FCCWave 3 改名 + 新建 closed_loop_full.cpp

5.3 ❌ 关键逻辑降级,必须从 main 迁回

模块main 中pcr-arch 占位
FlightStateProberpipeline/FlightStateProber.cpp(104 行)plant/physics/FlightStateProber.cpp(61 行)
Dragpipeline/Drag.cpp(137 行,上升/下降双模)plant/physics/Drag.cpp(44 行)
Thrustpipeline/Thrust.cpp(158 行,三阶段)plant/physics/Thrust.cpp(46 行)
Engine/Servo/ICU FSMrocket/device/DeviceOperators.cpp(102 行)plant/hardware/DeviceOperators.cpp(19 行)
FCC 全家桶src/fcc/{free_monad,navigation,guidance,control,stage}/src/fcc/FccCore.cpp(7 行 stub)

5.4 关键迁移归位表(v1.0 修订)

当前位置迁移目标Wave
src/dynamics/ode/src/dynamics_core/ode/Wave 0
src/dynamics/algebra/src/dynamics_core/algebra/(class → 模板化自由函数)Wave 0
src/dynamics/state/Forces.hsrc/dynamics_core/pipeline/Forces.hWave 0
src/dynamics/state/SpatialState.h<br>src/dynamics/state/InertialState.h<br>src/dynamics/state/AuxState.hsrc/dynamics_core/state/*(物理状态原语)Wave 0
src/dynamics/state/RocketBody.h(device-as-unified-entity)src/simulation/state/RocketBody.hWave 0
src/dynamics/state/WorldState.hsrc/simulation/state/WorldState.hWave 0
src/dynamics/state/BodyEnv.hsrc/simulation/env/BodyEnv.hWave 0
src/runtime/WorldEnv.hsrc/simulation/env/WorldEnv.hWave 0
src/plant/model/AeroConfig.h<br>src/plant/model/InertialConfig.h保留原位(plant/model/)不动
src/dynamics/PhysicalRegistry.*src/simulation/pipeline/BodyTick.* + WorldTick.*Wave 1
src/dynamics/pipeline/*src/plant/physics/Wave 1
src/plant/model/(包含的大气/重力配置)拆出至 src/environment/Wave 0
src/runtime/loader/*保留原位不动
src/dynamics_core/ (旧目录,含 StageMachine.h)删除(合并入新 dynamics_core/algebra/Wave 0
src/plant_model/删除(合并入 src/plant/model/Wave 0

6. 迁移计划(四波)

Wave 0 · 目录正骨 + 结构定型(无逻辑变化)

v1.0 重大调整:本 Wave 的核心是目录拓扑的全面对齐。在没有正确的目录骨架之前,任何 CMake 编译都是有害的。

6.0.1 目录正骨

  1. 删除遗留平行目录

    • src/plant_model/ → 合并入 src/plant/model/
    • src/dynamics_core/(旧)→ 删除
    • src/plant/interface/ → 删除(职责移交 contracts/
    • src/dynamics/pipeline/ → 内容迁至 src/plant/physics/
  2. 创建新顶层目录

    • src/environment/:装 Atmosphere.hGravityField.hWindField.h
    • src/dynamics_core/:装 universal kernel(ode + algebra + pipeline + state 原语)
    • src/simulation/:装跨域绑定层(state + env + probe + pipeline)
  3. 迁移现有内容:参见 §5.4 表。

  4. 创建 types/frames/ 子目录:把 phantom types 从 types/Frames.h 析出。

6.0.2 CMake 库划分

每个顶层模块对应一个 CMake target:

cmake
# src/contracts/CMakeLists.txt
add_library(contracts INTERFACE)   # header-only
target_include_directories(contracts INTERFACE ...)

# src/environment/CMakeLists.txt
add_library(environment STATIC ...)
target_link_libraries(environment PUBLIC types frames)

# src/dynamics_core/CMakeLists.txt
add_library(dynamics_core STATIC ...)
target_link_libraries(dynamics_core PUBLIC types frames monad contracts)
# 禁止 link plant/avionics/fcc/bus/environment/simulation

# src/simulation/CMakeLists.txt
add_library(simulation STATIC ...)
target_link_libraries(simulation PUBLIC
    types frames monad contracts
    environment plant_model plant_physics plant_hardware
    avionics_devices bus fcc
    dynamics_core)

# src/runtime/CMakeLists.txt
add_library(runtime STATIC ...)
target_link_libraries(runtime PUBLIC simulation)

6.0.3 自底向上的"逐层编译"循环

正确目录建好后,按依赖图自底向上编译:

顺序:
  1. types + frames + monad     → 单独编译验证
  2. + contracts                → 加入
  3. + environment + plant/model + plant/hardware
  4. + plant/physics
  5. + bus
  6. + avionics/devices
  7. + fcc
  8. + dynamics_core
  9. + simulation
  10. + runtime

每一步保持上面 N 个库链接通过,下面所有目录在 CMake 中暂时 add_subdirectory 注释掉。这避免遗留代码的报错污染当前层的排错。

6.0.4 状态结构最终定型(无逻辑实现)

  1. dynamics_core/algebra/:删 class,改模板化自由函数 evolve_topology&lt;Body&gt;
  2. dynamics_core/algebra/StageOp.henum class WorldStage : uint16_t {}
  3. simulation/state/RocketBody.h:device-as-unified-entity 形态(已在 Wave 0 前完成原型)
  4. simulation/env/WorldEnv.h:严格只读,含 environment + plant assets
  5. simulation/probe/Probe.h:声明 probe_aero / probe_traj / probe_mass_props
  6. bus/{IBus,BusPayloads,TransparentBus}.h:修 include 路径
  7. bus/BusChannel.h + SignalTag:加 [[deprecated]],Wave 2 删除

Wave 0 守门

  • 全量编译通过(10 个 CMake target 全绿)
  • 现有所有测试至少通过编译(功能可能 stub,但必须能 link)
  • grep -r "plant/\|avionics/\|fcc/\|bus/\|environment/\|simulation/" src/dynamics_core/ → 零命中

Wave 1 · Plant Physics 内核恢复

目标simulation::body_tick 在相同 BodyEnv 输入下,与 main 力/力矩输出相对误差 ≤ 1e-6。

准备:生成 main golden trajectory 作为回归基线。

迁移顺序

  1. plant::physics::FlightStateProber 从 main 迁入
  2. plant::physics::compute_drag 从 main 迁入(上升/下降双模 + 完整 6 分量)
  3. plant::physics::compute_thrust 从 main 迁入(三阶段 + EngineForceState)
  4. plant::physics::compute_gravity 加 ECF→LIC 旋转
  5. sim::probe::probe_aero / probe_traj / probe_mass_props 实现(替代旧 BodyEnv 直读 WorldEnv 大表的模式)
  6. sim::body_tick 雏形:probe → forces → integrate

守门(bench + trajectory 级)

试验类别期望
bench_prober_static_sea_levelbench4 气动角全 0,q=0
bench_prober_above_karmanbenchdyn_pressure=0,mach=0
bench_drag_ascending_subsonicbenchF_x ≈ -Cd·S·q
bench_drag_descending_gridfinbench含力矩
bench_thrust_perturbationbench公式验证
bench_thrust_pressure_compensationbenchΔF = Sa·101325
bench_thrust_off_axis_enginebench旋转方向
trajectory_physics_vs_maintrajectory力/力矩对 main 相对差 ≤ 1e-6

Wave 2 · 设备层 + Avionics 闭环

目标:每个 device 独立工作(fidelity=Transparent),FCC 模飞测试跑通。

  1. Plant Hardware 演化step_engine_mech / step_servo_mech / step_fin_mech)从 main 迁入
  2. Device step 函数 完整实现:
    • ecu::step(含 EngineFSM)
    • scu::step(采样真实摆角)
    • fin_ctrl::step
    • imu::step(从 body.aux 读真值)
    • gps::step(从 body.spatial 读真值)
    • icu::step(计时器,到期发 DiscreteEvent)
  3. Bus 单源化:删 BusChannel.h + SignalTag;BusBuffer 挂在 RocketBody
  4. sim::body_tick 完整化:avionics step → physics → integrate
  5. DiscreteEvent 解释器sim::world_tick 末尾把 events 翻译成 StageOp)

守门:见原 v0 §6 Wave 2 表(内容不变)。

Wave 3 · FCC + Mission + 全闭环

  1. FCC 复活git show main:src/fcc/... 整组迁回(不重写)
    • 仅适配 FccInFrame 从 BusMessage 组装(由 sim::body_tick 内的 BusManager 完成)
  2. FccStage 代数fcc/stage/FccStageOp.hevolve_fcc_stage 自由函数
  3. stages.yaml 加载runtime::Assembler 解析为 FccEnv.stage_table[]
  4. Mission YAMLdata/input/missions/nominal_ascent.yaml
  5. Deployment YAMLsil_monolithic.yaml + hil_dyn.yaml + hil_fcc.yaml
  6. closed_loop_10s.cpp 改名 ballistic_smoke_test.cpp;新建 closed_loop_full.cpp

守门:见原 v0 §6 Wave 3 表(内容不变)。


7. 设计裁定

7.1 Bus:bus::IBus 唯一,BusMonitor 用 Writer Monad 内化

vtable + 强类型 payload variant。删 BusChannel.h + SignalTagBusMonitor 不独立存在,融入 BusM&lt;...&gt;BusLog

7.2 Stage 代数:模板化自由函数 + 强类型 enum

  • dynamics::algebra::evolve_topology&lt;Body&gt;(bodies, op) 模板化自由函数
  • 算法在 dynamics_core/algebra/,类型 contracts::BodyId 来自 contracts/
  • enum class WorldStage : uint16_t {} 强类型

7.3 FccStage 与 WorldStage 独立 + 双代数化

  • WorldStagedynamics::algebra,由 StageOp 演化
  • FccStagefcc::stage,由 FccStageOp 演化
  • 两者通过 DiscreteEvent + ICU 间接关联

7.4 Device 不使用 algebra+interpreter 模式

algebra+interpreter?原因
Bus✅ 用多消息类型共信道 + 多物理协议
FCC✅ 用策略 YAML 驱动 + Sim/RTOS 部署需不同 interpreter
Device❌ 不用操作集合固定 + fidelity 是局部决策

7.5 RocketBody 形态:device-as-unified-entity + 跨域归属

每个 device 是 RocketBody 的一个完整实体,自身同时持有 mech(如有)+ 电子面。 RocketBody 整体归属于 simulation/state/,不归属于任何单一业务子域。

7.6 强类型 ID 与 enum class

  • BodyId / EngineId / ServoId / FinId / ImuId / GpsId / IcuId / BusAddrenum class : uint32_t 包装
  • 所有 stage / phase / fidelity / algo 用 enum class : uint16_t

7.7 WorldEnv 严格只读 + Path Index 装配期 RAII

sim::WorldEnv 只持有 environment 引用 + 静态资产规格 + 全局常量。 path_indexruntime::Assembler 内部局部存在,装配结束析构。

7.8 update_inertial_properties 删除

质量 / 质心 / 惯量每 tick 在 sim::probe::probe_mass_props 中从 BodyAsset.inertia_table 查表。

7.9 AssembledPlant / RuntimeTables 反射树废弃

前端自读 YAML 构建数据结构,C++ 端无需可序列化反射树。 "AssembledPlant" 退化为 runtime::SimulationInstance 的非正式代称。 WorldEnv 内部 vector&lt;T&gt; + uint32 索引即是"运行时表"实现,不引入 RuntimeTables 名词。

7.10 AvionicsState/Env 不存在

不作为独立结构。Avionics 组件状态全部进 RocketBody(即 simulation/state/)。 没有 avionics_step(AvionicsEnv, AvionicsState) 这个签名。

7.11 DynInFrame / DynOutFrame per-body

不是 world 级。sim::world_tick 接受 / 产出 vector&lt;DynInFrame&gt;vector&lt;DynOutFrame&gt;,body_id 即 vector 下标。

7.12 C-Distillation 软化

后续目标,不约束当前设计细节。 PoC 阶段优先"干净的语法抽象 + 清晰的隔离",性能优化后置。

7.13 FCC 模飞测试是一等公民

avionics_dry_flight 是独立测试场景,对应物理冻结、电气链路完整跑通。

7.14 AvionicsSystem 不自闭环

AvionicsSystem 必须与物理实体共同闭环。

7.15 【v1.0 新增】Environment 与 Plant 严格分离

environment/ 装的是关于位置/时间的纯函数(场),不属于任何具体物体。 plant/ 装的是对象专属的本构关系(查表)。 两者通过 sim::WorldEnv 一起被聚合,但它们的版本独立、变化频率独立、可替换性独立。

7.16 【v1.0 新增】dynamics_core 严格普适

dynamics_core/ 是 universal kernel,不知道火箭长什么样。 它只能 #include types / frames / monad / contracts禁止 #include 任何业务子域(plant / avionics / fcc / bus / environment / simulation)。

7.17 【v1.0 新增】simulation 是跨域绑定的唯一合法层

RocketBody 是跨域复合体(同时被 dynamics_core / plant / avionics / bus / fcc 操作)。 它不能归属于任何单一子域,否则违反对应子域的"无知性"承诺。 simulation/ 是唯一允许聚合所有业务子域的层,专门承担这种跨域复合体的归属。

7.18 【v1.0 新增】runtime 退化为纯生命周期管理

runtime/ 不持有业务定义(不定义 RocketBody / WorldEnv)。 它只做三件事:

  • YAML 解析(Loader)
  • 装配(Assembler):构造 sim::WorldEnv 与初始 sim::WorldState
  • 运行(Runner):调用 sim::world_tick 的 main loop

7.19 【v1.0 新增】BodyEnv 由 Probe 显式生成

双层 RWS 的咬合靠 sim::probe::* 函数。 plant::physics::* 只读 BodyEnv,不直接读 WorldEnv。 换 environment / 换 plant assets 都只影响 probe 实现,不影响 physics pipeline。


8. 工程约定

8.1 Scaffold 标记

cpp
// SCAFFOLD: &lt;required-test-name&gt; [Wave-N]
//   原因:xxx
//   预期替换:yyy
double engine_mass = 50.0;  // SCAFFOLD: bench_inertia_table_lookup [Wave1]

每完成一个 Wave,对应 scaffold 测试转绿,git grep 'SCAFFOLD:' src/ | wc -l 严格下降。

8.2 commit 规范

[wave-N][module] 简要说明

migrated from: src/dynamics/pipeline/Drag.cpp@main
ns: dynamics:: → plant::physics::
delta vs main: &lt;有意识的修改列表&gt;
test: bench_drag_ascending_subsonic ✓
scaffolds: 5 → 4

8.3 TDD 四级体系(火箭试验语义)

不以函数签名级 assert 为导向,以"试验任务书"为导向。

级别目录对应工程实践
benchtests/bench/单机台架试验
subsystemtests/subsystem/子系统联试
trajectorytests/trajectory/6DoF 仿真回归
missiontests/mission/任务场景 / 飞行包络
faulttests/fault/容错注入
goldentests/golden/参考数据集

目录结构

tests/
├── bench/
│   ├── device/         # IMU / GPS / SCU / ECU / ICU / Fin Ctrl
│   ├── physics/        # Drag / Thrust / Gravity / Prober
│   ├── hardware/       # EngineMech / ServoMech / FinMech
│   ├── fcc/            # FccStage 演化 / GNC 算法
│   ├── environment/    # Atmosphere / Gravity / Wind 查表
│   ├── simulation/     # Probe / BodyTick / WorldTick
│   └── bus/            # IBus 路由
├── subsystem/
│   ├── avionics_dry/   # 模飞测试(电气闭环 + 物理冻结)
│   └── physics_open/   # 弹道联调(物理闭环 + FCC 旁路)
├── trajectory/         # 全链路数值回归
├── mission/            # 场景级
├── fault/              # 故障注入
└── golden/
    └── main_baseline_t10s.csv

8.4 配置目录最终裁定

data/input/
├── world/                    # 环境真相(environment/ 的数据源)
│   ├── earth.yaml
│   └── atmosphere.csv
├── rocket_v1/                # 物理资产真相(plant/model/ 的数据源)
│   ├── rocket.yaml
│   ├── devices.yaml
│   ├── aero/
│   ├── mass/
│   └── engine/
├── fcc_v1/                   # 飞控软件配置
│   ├── fcc.yaml
│   ├── control.yaml
│   ├── guidance.yaml
│   ├── program_att/
│   └── stages.yaml
├── missions/                 # 任务剖面
│   └── nominal_ascent.yaml
└── sim/
    ├── deployments/
    │   ├── sil_monolithic.yaml
    │   ├── hil_dyn.yaml
    │   └── hil_fcc.yaml
    └── runs/
        └── run_001.yaml

附录:v0 → v1.0 章节迁移索引

v0 章节v1.0 章节变更
§2.1 库划分(11 库)§2.1(13 库)新增 environment / simulationdynamics 改名 dynamics_core
§2.2 contracts§2.2不变
§2.3 RocketBody§2.6.1迁至 simulation/state/
§2.4 WorldEnv§2.6.2迁至 simulation/env/;引用 environment/
§2.5 PlantScope§2.8章节号下移
§2.6 World Stage 代数§2.9algebra 迁至 dynamics_core/algebra/,模板化
§2.7 IBus§2.10章节号下移
§2.3 Environment【新增】
§2.4 Plant详细展开 model/physics/hardware
§2.5 dynamics_core【新增】
§2.6 Simulation【新增】跨域绑定层完整描述
§2.7 Runtime**【新增】**生命周期管理层
§4 Thrust dataflow§4路径调整
§5 当前状态§5增补 v1.0 迁移归位表
§6 Wave 0§6 Wave 0重写:目录正骨 + CMake 库划分 + 逐层编译
§7.1-7.15§7.1-7.14章节号微调
§7.15-7.19【新增】 environment/plant 分离、dynamics_core 普适、simulation 跨域绑定、runtime 退化、BodyEnv probe