Skip to content

Hardware vs Physics Boundary

> Aligned with PCR Master Blueprint v1.0 — see Blueprint §2.4、§1.1(World/Device 视角)、§7.15、§7.16。 > 职责:阐明执行机构(Engine/Servo/Fin)的"硬件机械演化"与"动力学物理计算"的职责边界。这是 v1.0 中 plant/hardware/plant/physics/ 拆分的设计动因。 > C-Distillation note:边界本身就是接口契约;蒸馏后两边变成不同的 C 文件,调用关系保持不变。


1. 核心困境与原则

遗留 C 代码典型反模式:把"喷管转动需要时间"和"喷管转角产生推力力矩"混进一个庞大的物理函数。两大恶果:

  1. 破坏函数式纯粹性:物理力公式里掺了"上一时刻喷管角"这种状态变量(二阶系统的状态空间),无法做纯函数测试
  2. 阻塞组件复用:换伺服型号(改阻尼比、限幅)需要去改推力计算公式,甚至重编整个动力学核心

v1.0 不可动摇的原则:"物理只管算受力,硬件只管算响应"


2. 三层边界

text
                  FCC 控制律
                  (纯函数,无状态)

                       │  FccOutFrame.tvc_gimbal_cmd = 5° (期望指令)

              ┌────────────────────────┐
              │  Software / Hardware   │   <-- 边界 1
              │       Boundary         │
              └────────────────────────┘


          avionics::device::scu::step
          plant::hardware::step_servo_mech
          (Mealy 状态机 + 一阶/二阶演化 + 限幅)

                       │  servo.mech.actual_angle = 2° (真实达到值)

              ┌────────────────────────┐
              │  Hardware / Physics    │   <-- 边界 2
              │       Boundary         │
              └────────────────────────┘


          plant::physics::compute_thrust
          (纯几何 + 推力公式,无状态)

                       │  Forces { total_force_b, total_moment_b, ... }

              ┌────────────────────────┐
              │  Forces Monoid +       │
              │  dynamics_core ODE     │
              └────────────────────────┘

3. 边界 1:软件 ↔ 硬件(FCC → Device)

FCC 控制律产出期望指令

cpp
// fcc 内部
FccOutFrame { tvc_gimbal_cmd = Angle::from_deg(5.0), ... };

FCC 不知道喷管是否瞬时到位,也不关心伺服阻尼。它的契约只是"我希望喷管摆到 5°"。

指令通过 BusManager::encode_from_fcc_out 装包为 ScuPayload 经 Bus 投递(详见 Semantic_Bus_Pattern.md §9)。


4. 边界 2:硬件 ↔ 物理(Device → Dynamics)

4.1 硬件机械面(plant/hardware/

有状态。模拟"物体不能瞬移"的物理常识。

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

struct EngineMech {
    double chamber_pressure = 0.0;
    double true_thrust      = 0.0;
    double mass_flow        = 0.0;
};

struct ServoMech {
    Angle  actual_angle;     // 真实达到的角度
    Angle  target_angle;     // 当前 step 的目标
    double oil_pressure = 0.0;
};

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);

}

特性:

  • 接收:从电子面(ECU/SCU)来的驱动指令
  • 演化:一阶惯性环节 / 二阶阻尼 / 限幅 + 残差累积
  • 输出:当前 step 末尾的"真实状态"(actual_angle / true_thrust
  • 依赖types/ + plant/model/(spec 表)。不依赖 bus/ / avionics/ / fcc/ / dynamics_core/

4.2 物理力计算(plant/physics/

无状态。绝对纯函数(在 Reader/Writer monad 包装下)。

cpp
// plant/physics/Thrust.h
namespace plant {
dynamics::BodyRWS<dynamics::Forces>
compute_thrust_contribution(const std::vector<EngineEffect>&);
}

特性:

  • 接收:硬件面已演化好的"真实推力 / 真实角度"(通过 EngineEffect / BodyEnv 间接),加上从 AeroCtx 来的大气真值
  • 计算:3D 矢量变换 + 推力公式 + 力矩 = lever × F_body
  • 输出Forces(Monoid,可累加)
  • 依赖types/ + plant/model/ + dynamics_core/state/不依赖 plant/hardware/ 的演化函数——它只看演化结果

详见 Plant_Physics_Constitutive.md

4.3 边界对象:EngineEffect

Stage 3(硬件) → Stage 4(物理)的数据契约对象,定义在 contracts/

cpp
// contracts/EngineEffect.h
struct EngineEffect {
    contracts::EngineId engine_id;
    double              vacuum_thrust;   // 真空标称推力(已查 spec.tables)
    double              mass_flow_fuel;
    double              mass_flow_ox;
    Angle               nozzle_yaw;      // 喷管真实摆角
    Angle               nozzle_pitch;
};

两侧通过 DynInFrame.engine_effects 传递,不直接 #include 对方。可独立 bench 测试:

  • 给 EcuState + EngineMech 喂点火指令,验证 EngineEffect.vacuum_thrust 曲线吻合 CSV
  • 给 plant::physics 喂固定 EngineEffect,验证力 / 力矩数值

5. 数据流全景

text
[ FCC 控制算法(纯函数) ]
   │  FccOutFrame { tvc_gimbal_cmd = 10° }

[ Bus 投递(语义信道) ]
   │  ScuPayload { commands = [...] }

[ 电子面 step(avionics/devices/, Mealy 状态机) ]
   │  目标角写入 ServoMech.target_angle = 10°

[ 机械面 step(plant/hardware/, 一阶惯性 + 限幅) ]
   │  ServoMech.actual_angle = 2°(一拍只能转 2°)

[ ECU step 查 spec 表 + actual_angle 装配 EngineEffect ]
   │  EngineEffect { vacuum_thrust = 4MN, nozzle_yaw = 2°, ... }

[ plant::physics::compute_thrust_contribution(纯函数 monad) ]
   │  Forces { total_force_b, total_moment_b, d_mass_dt }

[ dynamics_core::ode::rk4_step(数值积分) ]
   │  新的 SpatialState / InertialState / AuxState

[ 下一拍传感器 step 读 body.aux / body.spatial 作为物理输入 ]

完整闭环:软件 → 硬件 → 物理 → 积分 → 真值 → 硬件感知 → 软件


6. 三层为何不可融合

反模式后果
ServoMech 演化写进 compute_thrust物理函数变成有状态;纯函数测试不可行
把推力计算放进 plant/hardware/物理算法被锁死在硬件型号;换发动机型号要改硬件代码
把 FCC 控制律直接写 ServoMech.actual_angleFCC 越权感知硬件细节;HIL 时 FCC 飞远端,无法访问 ServoMech
plant::physics #include <plant/hardware/Mech.h>编译期把硬件型号绑死到物理函数

> Blueprint §2.4 强制:plant/physics/plant/hardware/平级子目录,互不依赖;它们共同被 simulation/ 编排。


7. 进阶:GNC 状态切换与硬件触发

复杂场景如"组合导航只在窗口运行"、"迭代制导锁定":

决策放在哪内容
FCC 调度层通过可配置状态机(YAML Schedule)动态开启 / 关闭算法算子
物理层永远持续产生真实物理状态(TruthState),不主动停摆
硬件层(传感器)根据自身物理特性(GPS 丢星率、盲区)动态决定是否在 Bus 上输出有效信号

绝不

cpp
// 反模式:在 FCC 内部硬编码时间窗口
if (time > 10s) { use_gps(); }

应当:触发条件定义在 ScheduleConfig 中,FccCore 根据条件调度对应算子。详见 04_FCC/FCC_Algebraic_Interpretation.md §schedule。


8. 与 Blueprint §2.4 的对齐核查

约束(Blueprint)本文档体现
plant/hardware/ 不依赖 bus/ / fcc/ / avionics/§4.1 第三项
plant/physics/ 不依赖 plant/hardware/§4.2 第三项
EngineEffect 作为跨域契约对象§4.3
dynamics_core/ 不知道 plant 任何细节§5(dynamics_core 只接 Forces / Body)
FCC 不直接修改物理状态§3、§7

9. Cross References

  • 双面(Mech + Electronic)拆分原理 → Device_Dual_Face.md
  • 物理算子 monadic 形态 → 02_Physical_World/Plant_Physics_Constitutive.md
  • 资产 spec(推力曲线 / 气动表)→ 02_Physical_World/Plant_Model_Assets.md
  • 硬件机械演化方程细节 → 02_Physical_World/Plant_Hardware_Mech.md
  • Bus 投递机制 → Semantic_Bus_Pattern.md
  • 推力跨域数据流的完整 5 阶段 → Blueprint §4.1