架构的野心:它在对赌什么?
撇开实现细节,当前代码的骨架做了一件在 C++ 物理仿真领域极其罕见的事:它把 Haskell 的 RWS Monad、Monoid、Reader 依赖注入原封不动搬进了一个高性能数值内核。这不是风格选择,而是一个战略赌注。
这个赌注的赌桌
> 仿真的全部行为应该是一个纯数学函数 simulate : Env × State → (Log, State'),并且这个纯粹性既不牺牲性能,也不阻碍工程化。
这在简化主义者眼里是离经平衡。绝大多数商业/军用仿真器会 pick one:
- 研究级(Simulink、SPICE、MuJoCo):美但慢,不能上飞控。
- 生产级(工业六自由度代码):快但耦合,换火箭得重写。
- 认证级(DO-178C 工具链):可审计但僵化,一个 if 改 3 周。
- 可组合(ROS/AUTOSAR):灵活但状态泄漏,测试噩梦。
FCC-Dynamics 的赌注是同时拿下这四项。这就是它的野心边界。
架构里埋着的潜能(尚未被激活的能力)
当一个架构是由纯函数 + 代数结构 + 依赖注入构成时,它自动继承了很多"未写的能力"。这些能力不是新功能,而是已有结构的必然结论——只是还没有被 API 暴露出来。
潜能 1:时间可逆与分支宇宙 (Time Travel)
纯函数 + 显式 State = 时间可逆。当前 ODE 积分是前向的,但因为每步的 WorldState 是值语义,理论上可以:
- 倒带:保存历史 state 栈,任意时刻回到过去。
- 分支:从某时刻派生多条时间线(Monte Carlo 扫描参数,共享 0→t 的前缀计算)。
- 差分回归:把
state_A(t) - state_B(t)作为回归测试的信号。 这对 GNC 算法调参是降维打击——你可以在失效瞬间回放 100 次,每次调一个参数。Simulink 做不到这点(State 是全局引用)。
2. 可微物理 (Differentiable Simulation)
这是最大的一块肥肉。纯函数 = AD 的前提条件。如果 double 全换成 Dual<double>(正向 AD)或表达式模板(反向 AD),你会立刻得到:
- ∂(落点) / ∂(发动机推力) — 闭式梯度,不再用有限差分。
- 轨道优化:写一个代价函数,得到对 所有 控制参数的梯度。交给 IPOPT/SNOPT 或 Adam,自动优化弹道。
- 端到端训练神经控制器:把神经网络当作 FCC,梯度穿过整个动力学。Google Brax / NVIDIA Warp / JAX MuJoCo 就是吃这口饭的。 当前架构离这一步只差一个泛型化——把
Vec3_T / Matrix的标量类型参数化为T。Thrust.cpp里的全部代数运算天然支持此替换。
3. 物理 DAG 编译器
PhysicalRegistry 现在是静态硬编码链: Forces::zero() >> thrust >> aero >> gravity 但因为每个 kernel 仅声明 Reader = BodyEnv 和 Writer = DynLog,它们的依赖关系是可被静态分析的。真正的潜能是:
- 把物理模型表示为 DAG:节点声明
needs(AeroCtx) / produces(Forces)。 - 注册器自动拓扑排序、自动并行化独立分支、自动缓存共享的 Probe 结果(比如
TrajectoryCtx被 aero 和 thrust 都要读)。 - 用户注册一个自定义力(磁力矩、太阳辐射压)时,零代码修改即插即用。 这相当于把
dynamics/升级为一个嵌入式物理编译器。架构的骨架已经具备,缺的是元层的调度器。
4. 资产多态 (Vehicle-Agnostic Core)
当前 EngineUnitConfig 只描述发动机。但 BodyEnv.asset 的抽象允许: using ActuatorAsset = std::variant<Engine, RCS, GridFin, ControlSurface, Parachute>; 用 std::visit 派发,同一套 BodyRWS 管线就能仿真导弹、高超声速滑翔体、月面着陆器、载人飞船。火箭只是 ActuatorAsset 的一种实例。 这就是 ROS2 没做到的事——它的"组件"是带状态的类,不能简单求和。这里的资产是不可变代数数据,天然复合。
5. 多速率协同仿真 (Multi-Rate Co-Simulation)
真实系统是多时间尺度的:
- IMU: 10 kHz
- FCC 控制律: 1 kHz
- 气动查表: 100 Hz
- 大气模型: 10 Hz 当前单一 ODE 步长是一种妥协。但因为 kernel 是纯函数,可以把不同速率的 kernel 放进不同的 sub-monad,外层
WorldRWS做operator splitting(Strang / Lie 分裂法)。每一层以自己的节奏推进,在刻度对齐处重同步。 这是 OpenMBEE / SysML 试图用模型驱动做的事,这里可以用纯类型做。
6. 分布式仿真与蒙特卡洛
DynLog 是 Monoid 意味着日志可以异地合并。加上 WorldState 是值类型,就有了:
- Body-sharded 仿真:大规模星座(50 颗卫星)分布到 50 个节点,monoid-merge 结果。
- Monte Carlo 集群:10000 次弹道扫描 = 10000 个独立纯函数调用,零同步。
- CI 回归:提交代码时在 AWS 跑 1000 条弹道,统计分布漂移。
7. 形式化可验证 (Formal Verification)
纯函数 + 强类型 = 形式方法的入场券。
- 属性测试 (QuickCheck 风格):
∀ s, rotate_ecf_to_lic(rotate_lic_to_ecf(s)) ≈ s - 关键变换可导出到 Coq/Lean:证明坐标变换的幂等性、角动量守恒、能量有界。
- DO-178C Level A 可行路径(传统 C++ 仿真不可能达到)。
8. 时空双向 REPL
纯函数最爽的副产品:任何 kernel 可以在 REPL 里单独调用。想知道"t=47.3s 时,如果推力增加 5%,力矩会怎么变?"——载入 state,捏造 env,直接调用 compute_thrust_pipeline 看结果。 Simulink 的"stop and inspect"是仿真器视角,这里是数学对象视角。GNC 调试的速度会快一个数量级。
如何把潜能转化为能力
这些潜能都不需要重写架构,只需要补齐抽象层。按"杠杆率"排序:
- 杠杆 1:标量参数化(开启可微物理的钥匙)
- 所有
Vec3 / Matrix/ 物理量改为template<typename T>,默认T = double。 - 关键 kernel 保持纯函数不变。
- 一旦
T = Dual<double>,整个仿真器立刻变成可微。 - 投入产出比:1 周的模板化工作 → 解锁轨道优化、RL 训练、灵敏度分析三个研究方向。
- 所有
- 杠杆 2:Asset 的 Variant 化
- 引入
ActuatorAsset = variant<Engine, RCS, Fin, ...>。 BodyRWSkernel 用std::visit派发。- 立刻支持多型号载具,不再是"火箭专用"。
- 投入产出比:2 周重构 → 把工具从火箭扩展到全品类航天器。
- 引入
- 杠杆 3:DAG 调度器取代静态 >> 链
- 每个 kernel 声明依赖(类型级或运行时注册)。
PhysicalRegistry改为 topo-sort + 并行执行。- 同时解决之前提到的
std::async低效问题(统一调度 = 统一线程池)。 - 投入产出比:3 周 → 扩展性从"加 if 到 RegistryCpp"变为"插件式"。
- 杠杆 4:持久化时间线 (Time Line Store)
WorldState加入 ring buffer 或 persistent data structure。- 暴露
rewind(t)、branch_from(t)API。 - 投入产出比:1 周 → GNC 调试效率质变。
- 杠杆 5:Probe 缓存与 DAG 融合
- 当前
probe_trajectory_ctx、probe_aero_ctx在每个 body 单独调用。在多体场景下可以共享。 - DAG 化后自动解决,是杠杆 3 的副产品。
- 当前
- 杠杆 6:Monoid-merge 的分布式 Runner
- 封装一个
run_ensemble(N, param_sampler) -> std::vector<DynLog>。 - 后端可插:本地线程池 / MPI / Ray / Dask。
- 投入产出比:1 周 → 直接接入学术级 Monte Carlo 能力。
- 封装一个
- 杠杆 7:属性测试基础设施
- 引入
rapidcheck / Catch2的 property test。 - 为每个 kernel 写 3-5 条物理律不变量。
- 长期看是认证路径的起点。
- 引入
- 杠杆 8:类型级单位 (Units of Measurement)
Meter, Second, Newton作为 phantom type。- 编译期阻止单位错配(deg vs rad 的经典 bug 彻底消失)。
- C++20 concepts 可以做得相当优雅。
哲学层面的评价
这个架构在赌一件事: > 范畴论的纯粹性不是性能税,而是性能的基础设施。
这和 Jane Street 在 OCaml 里做高频交易、ITA Software 在 Lisp 里做机票定价、Bloomberg 在 C++ 里做金融分析是同一种哲学:选一个数学上干净的原语,然后把它打磨到金属性能。
C++ 社区里真正理解这个赌注的人不多。Eric Niebler(ranges)、Barry Revzin、Sean Parent("no raw loops")是代表。这个项目在思想传承上属于这一脉,而不是传统"面向对象 + 状态机 + callback 地狱"的工业 C++。
如果 P0/P1 的契约修复 + 杠杆 1 (标量参数化) + 杠杆 3 (DAG 调度) 这三件事做完,这个项目会从"又一个火箭仿真器"升格为"通用可微航天动力学平台"。在 open-source 领域,能对标的只有 Brax(JAX/Python)、Warp(NVIDIA)、MuJoCo XLA。C++ 原生的同类项——目前是空白。这是机会窗口。
一句话总结
> 当前架构的野心是把物理仿真当作一种可被编译的数学对象;它的潜能是可微、可证明、可分布、可合成;瓶颈不是天花板,而是最后一公里的抽象没补齐。把这一公里铺完,这不是一个火箭动力学项目,这是一个航天领域的 JAX。