Skip to content

Device Dual-Face Pattern

> Aligned with PCR Master Blueprint v1.0 — see Blueprint §1.1, §2.4, §2.5, §7.4, §7.10. > 职责:定义"设备"在本架构中的二元结构——一个 device 是物理机械面(Mech)+ 电子控制面(Electronic) 的复合体,两面归属于不同的子域,由不同的步进函数演化,但同属一个 Engine / Servo / Fin 实体。


1. 一个 Device,两张面

text
                         ┌───── 电子控制面 ─────┐
                         │  avionics/devices/   │
                         │  (EcuState / ScuState│
                         │   / FinCtrl / Imu /  │
                         │   Gps / Icu)         │
                         │                      │
                         │  step(): Bus 命令 →  │
                         │    驱动 Mech →       │
                         │    发 Bus 消息       │
                         └──────────┬───────────┘
                                    │  drives

                         ┌───── 物理机械面 ─────┐
                         │  plant/hardware/     │
                         │  (EngineMech /       │
                         │   ServoMech /        │
                         │   FinMech)           │
                         │                      │
                         │  step_*_mech():      │
                         │    一阶/二阶演化 +   │
                         │    限幅 + 残差       │
                         └──────────────────────┘

两面合体在 simulation/state/RocketBody.h

cpp
// simulation/state/RocketBody.h
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 {
    contracts::ServoId              id;
    plant::hardware::ServoMech      mech;     // 物理机械面
    avionics::device::scu::ScuState scu;      // 电子控制面(部分情况下 SCU 一对多)
};

struct Fin {
    contracts::FinId                id;
    plant::hardware::FinMech        mech;
    avionics::device::fin_ctrl::FinCtrlState fin_ctrl;
};

2. 三类 Device 的拓扑

不是所有 device 都"双面"。根据是否含机械面,分三类:

类别实例物理机械面电子控制面物理输入来源
双面Engine / Servo / Fin✅ 有 EngineMech / ServoMech / FinMech✅ 有 EcuState / ScuState / FinCtrlState自身 Mech
只有电子面(含传感)IMU / GPS❌ 没有独立 Mech✅ 有 ImuState / GpsStatebody.aux(IMU)/ body.spatial(GPS)
纯电子ICU❌ 没有 Mech✅ 有 IcuState无(只听 Bus 命令计时器)

> 传感器没有独立 Mech,是因为它们的"物理输入"就是 body 本身的状态(如 IMU 感测的就是 aux.spec_force_b)。把"传感器 Mech"剥离出来反而冗余。


3. step 函数签名(与代码对齐)

3.1 双面 Device:两个 step

电子面(位于 src/avionics/devices/):

cpp
// avionics/devices/Ecu.h
namespace avionics::device::ecu {
void step(EcuState& ecu,
          plant::hardware::EngineMech& target_mech,   // 直接驱动 Mech(输出端)
          bus::IBus& bus,
          const EcuConfig& cfg,
          Time dt);
}

注意:

  • ECU step 直接持有 EngineMech 引用 → 它有权"驱动机械面"。
  • 同时接 bus::IBus& → 读 Bus 命令、发 Bus 状态。
  • cfg.fidelity 决定 Transparent / Realistic / Fault 三档行为。

机械面(位于 src/plant/hardware/):

cpp
// plant/hardware/Mech.h
namespace plant::hardware {
void step_engine_mech(EngineMech& mech,
                      EcuDriveCommand cmd,    // 由 ECU step 计算出的"驱动量"
                      Time dt);
void step_servo_mech (ServoMech& mech,  Angle target, Time dt);
void step_fin_mech   (FinMech& mech,    Angle target, Time dt);
}

注意:

  • 机械面 step 无 Bus 依赖plant/hardware/ 不知道 Bus 存在。
  • 接收"驱动指令"(EcuDriveCommand / Angle target)作为输入,演化机械状态。
  • 这一层是"一阶惯性环节 / 二阶阻尼 / 限幅"的物理拟合。

3.2 传感器:只有电子 step

cpp
// avionics/devices/Imu.h
namespace avionics::device::imu {
void step(ImuState& imu,
          const dynamics::AuxState& aux_truth,  // 物理输入:body.aux
          bus::IBus& bus,
          const ImuConfig& cfg,
          Time dt);
}

// avionics/devices/Gps.h
namespace avionics::device::gps {
void step(GpsState& gps,
          const dynamics::SpatialState& spatial_truth,    // 物理输入:body.spatial
          const plant::model::FrameConfig& frame_cfg,
          bus::IBus& bus,
          const GpsConfig& cfg,
          Time dt);
}

注意:

  • 物理输入是 const& → 传感器只读物理真值,不修改。
  • 写出口在 Bus(不修改 RocketBody)。

3.3 ICU:纯电子

cpp
// avionics/devices/Icu.h
namespace avionics::device::icu {
void step(IcuState& icu, bus::IBus& bus, const IcuConfig& cfg, Time dt);
}

无物理输入。只在 Bus 上听命令、计时,到点产生 DiscreteEvent


4. 演化顺序(在 sim::body_tick 中)

一拍内的 device 演化遵循固定序:

text
拍 k+1 开始

  ├─ ① 传感器 step(IMU / GPS)
  │     输入:body.spatial / body.aux (上拍的真值)
  │     输出:Bus 消息

  ├─ ② FCC tick (仅当 fcc_dt 边界到达)
  │     接 Bus → 计算 → 发 Bus

  ├─ ③ 执行机构电子面 step(ECU / SCU / FinCtrl / ICU)
  │     接 Bus 命令 → 计算 EcuDriveCommand / 目标角
  │     ECU 还会顺便查 spec 表生成 EngineEffect

  ├─ ④ 物理机械面 step(step_engine_mech / step_servo_mech / step_fin_mech)
  │     接 EcuDriveCommand / 目标角 → 演化 Mech

  ├─ ⑤ plant::physics 力计算
  │     用 EngineEffect(含真实推力曲线) + ServoMech.actual_angle 算 Forces

  └─ ⑥ dynamics_core::ode::rk4_step
        积分得新的 spatial / inertial / aux

关键时序:传感器在拍头读上一拍真值(先采样),执行机构在拍尾驱动机械面(后驱动)。这样在一个 body_dt 内,FCC 看到的传感器值是"上一拍末态",FCC 决策再驱动当前拍的执行机构,匹配真实硬件的时序。


5. 跨域归属的所有权

数据成员归属子域谁负责定义谁负责演化
Engine.mech: EngineMechplant/hardware/plant::hardware::EngineMechplant::hardware::step_engine_mech
Engine.ecu: EcuStateavionics/devices/avionics::device::ecu::EcuStateavionics::device::ecu::step
Engine.spec: const EngineSpec*plant/model/plant::model::EngineSpec装配期注入,运行期只读
Engine.install: InstallParamsplant/model/plant::model::InstallParams装配期注入,运行期只读
Engine 本身simulation/state/sim::Engine(跨域复合)不被"整体演化",只各面分别演化

重要的"无知性"链条

  • plant::hardware::EngineMech 不知道 EcuState 长什么样
  • avionics::device::ecu::EcuState 不知道 EngineMech 的内部场量,但持引用驱动
  • plant::model::EngineSpec 既不知道 Mech 也不知道 ECU,它是静态资产
  • sim::Engine 是唯一一个知道所有三者的类型,它就是为聚合而存在

6. 配置 fidelity:局部决策 vs interpreter

Blueprint §7.4:Device 不用 algebra+interpreter 模式。原因:

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

Device fidelity 通过 config enum 切换,不是 interpreter swap:

cpp
// avionics/devices/Imu.h
struct ImuConfig {
    enum class Fidelity : uint16_t {
        Transparent,    // 直接转写真值
        Realistic,      // 加噪 + 量化 + 残差累积
        Fault           // 故障注入
    } fidelity = Fidelity::Transparent;
};

// step 内部直接 switch
void step(ImuState& imu, const AuxState& truth, ...) {
    switch (cfg.fidelity) {
        case Transparent: emit_transparent(truth, bus); break;
        case Realistic:   emit_realistic(imu, truth, bus, dt); break;
        case Fault:       emit_fault(imu, truth, bus); break;
    }
}

为什么 device 不上 interpreter:操作集合固定(不变化),fidelity 之间的差异是数值/噪声层面,不是协议层面。引入 interpreter 是冗余抽象。


7. 与传统遗留代码的对照

传统 OOP 设计本架构 v1.0
class EngineModel { ... } 单类持有所有状态 + 计算Engine = { Mech in plant/hardware/ , EcuState in avionics/devices/ , spec in plant/model/ } 拆分
engine.step(dt) 一个函数处理所有ecu::step(...) ; step_engine_mech(...) 两阶段
改伺服阻尼比 = 改 EngineModel = 改物理引擎ServoMech 的演化方程 = 只改 plant/hardware/
改控制延迟 / fidelity = 改 EngineModelavionics::device::ecu::step
测试需要拉起整个 EngineModel三面(mech / ecu / spec)可独立 bench 测试

反模式:把 ECU 状态和 Mech 状态混进一个 struct,用一个 step 函数操作。会立即破坏:

  • plant/hardware/ 应当 #include 不到 bus/(无知性原则)
  • 测试单独跑 mech 演化(不挂 Bus)的能力
  • fidelity 切换的局部性

8. C-Distillation 视角

C++ 阶段:

  • Engine 是聚合 struct,跨命名空间引用
  • step 函数族在不同 namespace 里独立编译

C 蒸馏阶段:

  • Engine 退化为 struct EngineFull { EngineMech mech; EcuState ecu; const EngineSpec* spec; ... }
  • step 函数族失去 namespace,变成 ecu_step(...) / engine_mech_step(...) 自由函数
  • 跨域调用关系(ecu_step 内调用 mech 引用)保持不变
  • 编译期可见性约束(plant/hardware 不见 bus/)退化为代码评审约束

双面拆分的好处在 C 阶段依然成立:调试时打印 engine.mechengine.ecu 分别可读,不会出现"整个 EngineModel 黑箱"。


9. 测试策略

测试目标适用层级示例
Mech 一阶演化数值正确bench给 ServoMech 喂 target=10°,验证 1s 后位置 + rate 限幅
ECU 状态机时序bench喂 IgniteEngines 命令,验证 mech.true_thrust 在 3s 启动期内的曲线
双面联合启动subsystem30s 仿真 ECU + EngineMech,记录 EngineEffect → 力 → 加速度
Bus 协议层时延bench喂 SemanticInterpreter,验证 base_delay + jitter
Fidelity 切换bench切换 IMU fidelity = Realistic,验证残差累积 0-bias

详见 08_Cross_Cutting/Testing_Framework.md


10. Cross References

  • 三类设备的具体 step 实现 → 各自源文件 src/avionics/devices/*.cpp
  • Mech 的演化方程 → plant/hardware/Mech.{h,cpp} + 02_Physical_World/Plant_Hardware_Mech.md
  • Bus 接口 → Semantic_Bus_Pattern.md(同目录)
  • 物理与硬件边界的原则讨论 → Hardware_Physics_Boundary.md(同目录)
  • 传感器细节 → Sensor_Modeling.md(同目录)
  • 推力跨域数据流(Stage 3 涉及 ECU+Mech 双面)→ Blueprint §4.1
  • RocketBody 的 device 聚合形态 → 06_Simulation/Body_World_Tick.md(待写)§3