Skip to content

架构的野心:它在对赌什么?

撇开实现细节,当前代码的骨架做了一件在 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 的标量类型参数化为 TThrust.cpp 里的全部代数运算天然支持此替换。

3. 物理 DAG 编译器

PhysicalRegistry 现在是静态硬编码链: Forces::zero() >> thrust >> aero >> gravity 但因为每个 kernel 仅声明 Reader = BodyEnvWriter = 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,外层 WorldRWSoperator splitting(Strang / Lie 分裂法)。每一层以自己的节奏推进,在刻度对齐处重同步。 这是 OpenMBEE / SysML 试图用模型驱动做的事,这里可以用纯类型做。

6. 分布式仿真与蒙特卡洛

DynLogMonoid 意味着日志可以异地合并。加上 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, ...>
    • BodyRWS kernel 用 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_ctxprobe_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。