Skip to content

FCC 架构演进:函数式核心与数据驱动的混合调度系统

日期: 2026-04-11 主题: FCC (Flight Control Computer) 核心架构重构总结 核心思想: Functional Core, Imperative Shell (函数式核心,命令式外壳) + Time-Triggered Architecture (时间触发架构) + Hybrid Systems (混杂系统建模)


1. 架构演进背景与痛点诊断

在早期的设计中,我们将 Free Monad (DSL) 视为飞控引擎的绝对主导,导致了一个严重的架构反模式:把“纯计算”和“副作用(I/O)”在指令集(FccOp)中混为一谈

  • 臃肿的解释器:当时的 FccInterpreter 不仅要负责硬件 I/O,还要负责执行具体的导航、制导算法。这意味着如果更换底层硬件(从 Windows 仿真器迁移到 RTOS 箭载计算机),整个算法体系需要在新的硬件解释器中被重新实现或强耦合绑定。
  • 多态与多频的硬编码:为了处理不同飞行阶段(一子级、级间分离、滑行段)和不同执行频率(1Hz迭代制导,50Hz姿态控制),代码中出现了大量的 if-else (stage == ... && time % N == 0),违背了开闭原则,难以维护。

2. 关键架构洞察 (Key Insights)

通过深入的工程探讨,我们确立了以下几项源自高级航天系统工程的核心洞察:

Insight 1: 物理隔离与离散事件 (Hybrid Systems)

动力学 (Dynamics)飞控 (FCC) 在物理概念上是完全隔离的。FCC 只负责基于定周期计算发出连续的控制指令和离散的事件指令 (Discrete Events, 如关机、分离)。动力学端作为“监听者”,在收到事件后自主决定如何响应(如变步长积分、切换气动模型)。FCC 绝不直接干预动力学的运行逻辑。这种强解耦通过 FccOutFrame 中的事件总线完美实现。

Insight 2: 时间触发架构与静态调度表 (Data-Driven Scheduling)

不要用代码(if-else)去管理计算流程(菜谱),要用**数据字典(配置)**去驱动计算引擎。 引入静态调度表(YAML配置),将控制流元数据提取为 ScheduleConfig。调度表规定了特定飞行阶段下,需要执行哪些算法,以及它们的执行周期。调度器只需成为一个无情的“查表派发机器”。

Insight 3: 时钟建模的绝对解耦 (Clock & Time Abstraction)

硬件定时器中断、操作系统的 Tick、以及仿真器里的虚假时钟,这些复杂性全都被包裹在 FccInterpreter (外壳) 中。核心算法只看到单调递增的、表示物理意义的 Time 值(基于纳秒/Ticks的定点数封装)。这让算法天然支持蒙特卡洛加速仿真和真实的 RTOS 部署,且 100% 复用。

Insight 4: I/O 与计算的彻底剥离 (Pure Core vs. Imperative Shell)

解释器 (Interpreter) 应该退化为极其轻量级的硬件抽象层(HAL),只负责三件事:读传感器 (ReadIMU)、管理内存状态的借入借出 (GetState/UpdateState)、写执行器/总线 (OutputControls/WriteTelemetry)。 所有复杂的矩阵运算、卡尔曼滤波、PID,都被剥离出解释器,成为接收输入并返回输出的纯函数(Pure C++ Functions)


3. 重构后的分层架构实现

基于以上洞察,目前的 FCC 架构被划分为极其清晰的两层:

第 1 层:命令式外壳 (Imperative Shell - Free Monad)

负责管理所有与外部世界的交互副作用。 DSL 主循环 (flight_control_loop) 变得异常干净,它本质上是一个 数据流管道

cpp
// 获取 IO 数据和内存状态
read_imu() >> get_time() >> get_env() >> get_state() >> 
// 喂入纯函数核心进行无副作用的数学计算
compute_flight_logic(imu, current_time, dt)
// 侧写遥测日志,更新内存,并通过 IO 输出指令
write_telemetry(log) >> update_state(new_state) >> output_controls(cmd)

第 2 层:函数式核心 (Functional Core - RWS Monad & Dispatcher)

负责所有的业务多态、多速率调度和算法执行。它是一个 RWS (Reader-Writer-State) Monad:

  • Reader (FccEnv): 提供只读的 YAML 环境配置,包括气动表、增益和静态调度表
  • State (FccState): 维护所有的数学中间变量(协方差矩阵、PID积分项),以及用于调度的 task_timers 和倒计时 pending_events 队列。
  • Writer (FccLog): 在深层算法中收集遥测数据,向外层穿透并打包。

Dispatcher (多频分发器) 的工作原理 (compute_flight_logic)

  1. FccEnvschedule 中查出当前 Stage 的任务列表。
  2. 遍历任务,计算 current_time - task_timers[task_name]
  3. 如果时间差 $\ge$ 配置的周期,则执行该任务映射的纯函数(如 run_navigation_algo),并更新 task_timers
  4. 检查 pending_events 队列,若有事件(如“发动机关机”)计时到期,将其塞入 FccOutFrame.sequencing 事件槽中。

4. 架构优势总结

  1. 极致的算法复用性:算法工程师无需关心任何 Free Monad、内存指针、总线协议。他们编写的只是 State next = run_nav(current_state, imu) 这样的纯函数。无论是在 x86 下用 GTest 测,还是烧录到 ARM Cortex-R 裸机,代码一字不改。
  2. 无限扩展的调度能力:想要新增一个 10Hz 的导航诊断算法?只需在 schedule.yaml 里加两行配置,再注册一个纯函数,系统会自动按需将其纳入时间切片进行调度。
  3. 完美的测试隔离:系统状态被收敛到了显式的 FccState 结构体中。我们可以轻易地在单元测试中注入“故障状态”或“跳变时钟”,去验证 Dispatcher 的健壮性。

这是一个将严谨的航天级系统工程前卫的函数式编程范式无缝融合的教科书级实现。