Wiki-style architecture note

用你熟悉的物理直觉,读懂 AFSIM 的代码架构

这不是概念清单,也不是图谱。左侧是一段段用物理学、实验系统和模型推演语言写成的解释;右侧是对应的 AFSIM 代码架构说明。点击左侧任意段落,右侧对应段落会高亮并滚动到相同主题。

左侧:用物理 / 实验系统语言理解
右侧:对应到 AFSIM 代码架构

1. 代码入口上,AFSIM 首先是一套任务级仿真运行框架

右侧源码里最能体现这个定位的是 swdev/src/missionswdev/src/core/wsfdemosmission 更像运行器:它负责读取场景、装载模型、推进仿真、写出事件和日志。core/wsf 则提供平台、航迹、事件、消息、组件、时间推进等基础机制。

这和你给的入门文章一致:AFSIM 的核心不是三维动画,而是仿真运算、事件推演和量化数据输出。可视化工具存在,但不是第一层代码骨架。

读代码时可以先建立一个总链路:mission 读取输入脚本,脚本实例化平台和组件,core/wsf 提供统一的数据结构和仿真循环,插件补充专门领域能力,最后事件系统把运行过程写成可分析的输出。这个链路比单个类名更重要。

  • swdev/src/mission/source/mission.cpp
  • swdev/src/core/wsf
  • demos/air_to_air

2. 场景层在 demos:它把一次仿真实验组织起来

本地源码里,最适合入门阅读的是 demos/air_to_air/1v1.txt。它会 include 公共配置和具体 scenario,设置日志输出、随机种子、结束时间、event pipe、event output 等。这些内容对应一次实验的“问题定义”。

再往下看,scenarios 目录描述具体场景,platforms 描述实体,sensorsweaponsprocessorsrules 描述平台能力和行为。它们一起构成可运行模型。

你可以把 1v1.txt 看成顶层实验文件,把 scenarios/1v1.txt 看成“摆放实验对象”的文件,把 platforms 等目录看成可复用的模型库。不同场景复用同一套平台、传感器和规则,就像不同实验复用同一套仪器和材料模型。

  • demos/air_to_air/1v1.txt
  • demos/air_to_air/scenarios
  • demos/air_to_air/_common.txt

3. 平台层由 demo 配置和 WsfPlatform 共同支撑

demos/air_to_air/platforms 里能看到具体平台配置,例如战斗机、高价值空中资产、护航平台等。源码底层则由 core/wsf/source/WsfPlatform* 这一类平台抽象承接。你可以把 demo 里的 platform 看成“实验中具体放进去的实体”,把 WsfPlatform 看成“实体这种东西在代码中的通用定义”。

读平台时要同时看它挂载了什么:运动模型、传感器、武器、Processor、通信链。AFSIM 的平台不是孤立类,而是组件容器。

例如 platforms/hvaa.txt 会 include 传感器 cue、任务分配和 uplink 相关 processor;platforms/escort.txt 也会挂载 sensor cue、weapon datalink 和 assessment 相关逻辑。也就是说,平台文件本身就是“这个实体有哪些器官和控制器”的清单。

  • demos/air_to_air/platforms/*.txt
  • swdev/src/core/wsf/source/WsfPlatform*
  • swdev/src/core/wsf/source/WsfPlatformPart*

4. 状态层分布在 mover、track、processor、rules 和 event 中

连续运动状态主要看 core/wsf/source/mover,例如各种 WsfMover*、路线、燃料、导航、路径相关类。目标被探测和融合后的状态主要看 WsfTrack*WsfTrackManager*。任务和行为状态则更多体现在 processorsrules 文件里。

如果你只看 mover,会误以为 AFSIM 是运动仿真;如果只看 rules,又会漏掉连续状态。正确理解是:AFSIM 把连续运动、感知表象、任务状态和事件记录合在一起做任务级推演。

一个典型信息流是:mover 更新平台位置,sensor 根据几何和探测条件产生 track,processor 读取 track 并判断是否分配任务,rules 根据任务改变航向/速度/武器行为,event output 记录这次状态转移。这个流动比任何一个目录本身都更能解释架构。

  • swdev/src/core/wsf/source/mover
  • swdev/src/core/wsf/source/WsfTrack*
  • demos/air_to_air/processors
  • demos/air_to_air/rules

5. 传感器层连接 demo 配置、探测过程和 track 表象

传感器相关的入门阅读可以从 demos/air_to_air/sensors 开始,里面有雷达、ESM/RWR 等样例配置。再看 sensor_cue_processor.txtsensor_observer.txt,你会看到传感器信息如何进入处理器、如何被记录。

在代码概念上,传感器不是孤立地产生“真值”,而是产生 detection、track、更新事件等中间表象。这些表象再进入任务和交战逻辑。也就是说,传感器层是“真实对象”和“决策对象”之间的转换层。

sensor_observer.txt 很适合辅助理解,因为它把传感器更新、local track 更新、drop、仿真初始化和结束这些回调事件写出来。你会看到“看见目标”在 AFSIM 里不是一句话,而是一串状态更新和事件记录。

  • demos/air_to_air/sensors/radar
  • demos/air_to_air/sensors/esm_rwr
  • demos/air_to_air/processors/sensor_cue_processor.txt
  • demos/air_to_air/sensor_observer.txt

6. 武器和交战层主要落在 weapons、engage、weapon_tools 与插件

demo 里可以先看 demos/air_to_air/weapons/aam,理解空空导弹、发射计算、结果表等配置。源码层再看 swdev/src/engageswdev/src/weapon_tools。这些模块把“是否交战、如何结算、结果如何输出”组织起来。

对入门者来说,先不要陷入每个武器模型的细节。先抓结构:武器配置定义能力,交战模块执行作用过程,事件输出记录结果,后处理再拿这些结果做效能分析。

例如 medium_range_radar_missile.txtmrm_launch_computer*shoot_it.txt 可以连起来读:前者描述武器能力,launch computer 描述发射包线/计算表,规则脚本描述何时决定开火。这样读会比单独看某个武器文件更容易理解交战链路。

  • demos/air_to_air/weapons/aam
  • swdev/src/engage/source
  • swdev/src/weapon_tools/source
  • swdev/src/wsf_plugins

7. Processor、rules、command chain、插件和外部算法共同组成任务逻辑层

demos/air_to_air/processors 里放的是任务处理、评估、传感器 cue、uplink 等逻辑配置。它们决定平台如何使用自己已有的能力。你可以把它们看成“平台的大脑接口”:它们读状态、读任务、读感知结果,然后推动下一步行为。它不是底层运动学,也不是单纯 AI 黑箱,而是任务级仿真里承上启下的控制层。

这一层和入门文章里的“平台自主智能行为”对应。AFSIM 的智能行为不是凭空出现的,它通常由 Processor、rules、command chain、插件和外部算法共同构成。下面这五类要分开理解:

  • Processor:持续评估状态并管理任务。例如 hvaa_tasker.txt 会在发现有效 track、距离进入阈值后,把 INTERCEPT 任务分配给编队 lead;sensor_cue_processor.txt 会根据已有 track cue 某个传感器进入跟踪模式。
  • rules:定义“条件满足后如何行动”。例如 intercept_rules.txt 判断平台是否处于 intercept 规则类型,再根据任务 track 设置航向、速度、高度和编队飞行命令。
  • command chain:定义组织关系。空战 demo 的 README 明确说 aircraft 会属于 IFLITEELEMENT 这类 command_chain;源码里的 WsfCommandChain 支持 commander、peers、subordinates,所以任务可以从 lead 传给下属。
  • 插件:提供领域能力。例如 wsf_air_combatwsf_brawlerwsf_six_dofwsf_multiresolution 不是简单工具,而是把空战、机动、多分辨率等专用模型接进框架。
  • 外部算法:通常通过自定义脚本、插件或接口把你的 AI/优化器/强化学习策略接进来。入门阶段可以先把它理解为“替换或增强 Processor/rules 的决策来源”。

更具体地看,hvaa_tasker.txt 像“任务分配器”:它检查 track 是否有效、是否足够新、是否有位置和速度、距离是否小于阈值,然后寻找 IFLITE command chain 的 lead,给它分配 INTERCEPTsensor_cue_processor.txt 像“传感器调度器”:它从其他传感器来源的 track 判断是否 cue 雷达进入指定 tracking mode。

uplink.txt 则体现另一类 Processor:它关心武器/平台之间的信息链路是否可用,以及导弹是否还能接收目标更新。把这几个文件合起来看,你会发现 Processor 并不等于“AI 大脑”,而是一组围绕任务、传感器、通信和武器的局部控制器。

  • demos/air_to_air/processors/hvaa_tasker.txt:发现目标后分配 INTERCEPT 任务。
  • demos/air_to_air/processors/sensor_cue_processor.txt:根据已有 track cue 传感器跟踪。
  • demos/air_to_air/processors/assessment_scripts.txt:评估/判断类脚本入口。
  • demos/air_to_air/processors/uplink.txt:上行链路/信息传递相关逻辑。
  • swdev/src/core/wsf/source/WsfCommandChain*:commander、peers、subordinates 的源码抽象。

8. rules 目录是理解“条件触发行为”的最佳入口

demos/air_to_air/rules/intercept_rules.txt 很适合用来建立直觉。它不是 C++ 主体代码,而是行为规则脚本。你可以重点看它有哪些变量、初始化做什么、precondition 判断什么、execute 里如何改变速度、高度、航向、任务或输出。

ftr_rules.txtselect_wpn.txtshoot_it.txtegress.txt 等文件可以按行为阶段继续读。这样你会看到 AFSIM 如何把“战术行为”拆成一组可组合的条件规则。

这些 rules 和 Processor 的关系可以这样理解:Processor 更像“什么时候该评估、任务是否存在、目标是否有效”;rules 更像“进入某个任务或阶段之后,具体怎么飞、怎么选武器、什么时候开火、什么时候脱离”。例如 Processor 分配了 INTERCEPT,而 intercept_rules.txt 才具体把平台带入拦截行为。

继续展开可以按行为阶段读:ingress.txt 处理进入任务区域,intercept_rules.txt 处理拦截,crank.txtpump.txt 处理战术机动,select_wpn.txtshoot_it.txt 处理武器选择和开火,egress.txt 处理脱离。它们共同构成一条战术状态机。

  • demos/air_to_air/rules/intercept_rules.txt
  • demos/air_to_air/rules/ftr_rules.txt
  • demos/air_to_air/rules/select_wpn.txt
  • demos/air_to_air/rules/shoot_it.txt
  • demos/air_to_air/rules/egress.txt

9. wsf_plugins 是领域能力扩展层

swdev/src/wsf_plugins 下有很多专用能力:wsf_air_combatwsf_brawlerwsf_six_dofwsf_p6dofwsf_multiresolutionwsf_iads_c2_libwsf_fireswsf_simdis 等。它们不是外围杂项,而是 AFSIM “开放、模块化、高可扩展”的核心体现。

你可以把核心框架看成通用实验台,把插件看成专用仪器。某个场景需要更复杂的空战、六自由度、多分辨率或 IADS 能力时,就通过插件把领域模型装进来。

外部算法通常也会走类似“扩展层”的思路:如果只是调整规则,可以先从脚本和 Processor 入手;如果要接更复杂的 AI、优化器或第三方模型,就需要通过插件、工具链或运行接口把外部计算结果转成 AFSIM 能理解的任务、参数、行为或事件。换句话说,外部算法不是凭空替代仿真框架,而是嵌入到平台、Processor、rules 或插件这些既有接口中。

判断某个能力是否属于插件,可以看它是否有自己的 wsf_moduleCMakeLists.txt、grammar、source 和示例配置。插件不是“脚本片段”,而是可以被构建系统发现、编译、注册并在场景里使用的领域模块。

  • swdev/src/wsf_plugins/wsf_air_combat
  • swdev/src/wsf_plugins/wsf_brawler
  • swdev/src/wsf_plugins/wsf_six_dof
  • swdev/src/wsf_plugins/wsf_multiresolution
  • swdev/src/wsf_plugins/wsf_iads_c2_lib

10. 输出层把一次推演变成可分析证据

demo 场景里会配置 event_pipeevent_output、日志文件和 observer。输出目录里的 .aer.evt.log、CSV 等文件,才是这次仿真真正留下来的实验记录。入门文章里说的交战日志、统计报表、效能量化分析,最终都依赖这一层。

源码中可以继续看 WsfEventOutput*evt_readerpost_processortools。它们负责把事件读出来、转换、统计和展示。

mission.cpp 文件开头也强调 event log 可以被 SIMDIS、Mystic 或脚本程序处理。这个细节说明 AFSIM 的设计不是“跑完就结束”,而是默认要把仿真轨迹和事件交给后续分析链。

  • demos/air_to_air/output
  • swdev/src/core/wsf/source/WsfEventOutput*
  • swdev/src/evt_reader
  • swdev/src/post_processor
  • swdev/src/tools

11. CMake 和 wsf_module 负责把大型工程装配起来

swdev/src/CMakeLists.txt 是顶层构建入口。它设置版本、构建选项、插件开关、安装选项,并扫描模块。cmake/Presets/base.cmakerestricted.cmake 则像不同实验装置的预设配置。

很多插件目录里有 wsf_modulewsf_cmake_extension.cmake,这说明 AFSIM 的模块发现和装配不是手工散乱组织的,而是有一套工程机制。读源码时,CMake 能告诉你“哪些目录会变成真正参与运行的模块”。

如果你想判断一个目录是不是“真正可运行的一部分”,可以沿着 CMake 查:它是否被顶层包含,是否声明 module,是否生成库或可执行文件,是否安装资源。这样能避免把文档、测试、样例、工具和核心运行模块混在一起。

  • swdev/src/CMakeLists.txt
  • swdev/src/CMakePresets.json
  • swdev/src/cmake/Presets/base.cmake
  • swdev/src/wsf_plugins/*/wsf_module

12. 推荐代码阅读路径:从 demo 到核心,再到插件和工具

具体阅读顺序建议是:先看 demos/air_to_air/1v1.txt,再看它 include 的 scenario;然后看 platformssensorsweaponsprocessorsrules;接着看 mission.cpp 如何运行;再看 core/wsf 里的平台、航迹、事件、mover;最后按需要进入 wsf_pluginstools/post_processor

这样读,你每进入一个代码目录时都知道它在整条链上的位置:它是在定义实验、定义实体、定义能力、定义行为、推进仿真、记录输出,还是在做构建和扩展。

一个实用的源码阅读动作是“从配置反查 C++”:先在 demo 里看到一个关键字,例如 WSF_UPLINK_PROCESSORWSF_COMMAND_CHAINevent_output,再用搜索工具在 swdev/src 里找对应实现。这样你读到的 C++ 永远和一个具体场景相连,不会陷入抽象类海洋。

  • demos/air_to_air/1v1.txt → 场景入口
  • demos/air_to_air/{platforms,sensors,weapons,processors,rules} → 模型配置
  • swdev/src/mission/source/mission.cpp → 运行入口
  • swdev/src/core/wsf → 核心框架
  • swdev/src/wsf_plugins → 领域扩展

最短阅读路线

第一步:读实验定义

demos/air_to_air/1v1.txt 开始,理解一次仿真如何被声明。

第二步:读实体和能力

platformssensorsweaponsprocessors

第三步:读行为规则

rules/intercept_rules.txt 这类脚本如何做条件判断和行为选择。

第四步:读运行和输出

再看 mission.cpp、event output、post processor,理解仿真如何留下证据。

第五步:从关键词反查

用 demo 中的 processorcommand_chainevent_outputswdev/src 搜实现。

第六步:区分代码层次

coremissionwsf_pluginstools 分成底座、运行器、扩展和分析链。