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 代码典型反模式:把"喷管转动需要时间"和"喷管转角产生推力力矩"混进一个庞大的物理函数。两大恶果:
- 破坏函数式纯粹性:物理力公式里掺了"上一时刻喷管角"这种状态变量(二阶系统的状态空间),无法做纯函数测试
- 阻塞组件复用:换伺服型号(改阻尼比、限幅)需要去改推力计算公式,甚至重编整个动力学核心
v1.0 不可动摇的原则:"物理只管算受力,硬件只管算响应"。
2. 三层边界
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 控制律产出期望指令:
// 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/)
有状态。模拟"物体不能瞬移"的物理常识。
// 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 包装下)。
// 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/:
// 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. 数据流全景
[ 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_angle | FCC 越权感知硬件细节;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 上输出有效信号 |
绝不:
// 反模式:在 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