引言
本文档描述了将新功能扩展和集成到 AFSIM 中的有限方法。允许并描述多种方法,以及在 AFSIM 社区标准和指南中引入集成作为可共享资源的要求。
概述
核心可执行文件 基于 AFSIM 的可执行文件通常由单个 AFSIM “应用程序” 组成。该应用程序维护脚本类型、扩展和插件管理器以及应用程序配置数据。该应用程序由一个或多个场景组成,这些场景拥有类型工厂和列表、用户输入和脚本。根据应用程序的不同,场景由一个或多个仿真组成。仿真包含类型实例、接口(例如 DIS、XIO、观察者、地形)和运行时数据,包括事件管理和线程处理。
核心架构
AFSIM 的面向对象 C++ 架构提供了一种可扩展和模块化的架构,使许多附加功能能够轻松集成。AFSIM 允许新组件模型(例如传感器、通信、移动器等)以及完全新的组件类型被插入并在框架中使用。扩展和插件是框架扩展的主要机制,旨在集成新的平台组件模型、新的和扩展的平台能力,以及新的和扩展的仿真服务。插件能力是一种扩展形式,允许在不重新编译核心 AFSIM 代码的情况下添加功能。使用插件可以更轻松地分发扩展功能,并提供选择特定分析所需的扩展功能的能力。下图显示了 AFSIM 主要框架组件和提供的服务,这些服务可以被扩展。
注意:Doxygen 软件文档与 AFSIM 发布一起提供,开发人员可以通过 Doxygen 指令构建该文档。
基于组件的架构
AFSIM 的核心架构是基于组件的架构(CBA),允许通过组件包含许多功能,并通过组件列表进行管理。该 CBA 是通过 C++ 的面向对象原则(封装、继承、模板和多态)以及组件列表提供的,如下文进一步描述。
AFSIM 的 CBA 允许在框架的多个层级中使用组件和组件列表,包括应用程序、场景、仿真和平台,同时也包括其他领域如子系统。 在仿真和平台级别,组件类型通过名称或角色进行访问。这种访问使得可以通过组件列表以通用方式从仿真和平台中添加或移除组件类型。
组件(即 WsfComponent)是从层次结构中派生的基本元素,用于创建新类型或类型模板以实现特化。基础的 WsfComponent 不包含任何成员变量,因此任何函数都需要在派生类中通过 Wsf<type-name>Component 实现。
WsfComponent 定义了以下“主要”框架方法,其中许多是纯虚拟的,需要由派生类实现:CloneComponent、ProcessInput、PreInput、PreInitialize、Initialize、Initialize2、<Get/Set>ComponentName、<Get/Set>ComponentRole、InitializationOrder、QueryInterface 和 GetComponentInitializationOrder。
QueryInterfaceMethod 是一个必需的虚拟函数,允许查询角色,并要求也定义 GetComponentRoles。角色通常定义仿真组件列表中的服务或其他类型。角色通常定义平台组件列表中的类型,例如传感器、通信、移动器、处理器等。此外,为每个组件和部分类型在全局和有时在本地级别定义组件角色枚举,以支持组件列表中的 FindComponentByRole 功能。每个需要额外角色的项目会在其自己的项目中添加到全局组件角色枚举中。在全局上下文中添加角色确实需要在多个项目之间进行冲突解决,以避免角色的重复定义。
组件列表以及类型枚举提供了维护和管理组件的方法。WsfComponentList 定义了以下框架方法,其中许多是纯虚拟的,需要由派生类实现。
主要方法可用于添加/删除组件、迭代列表中的组件、按名称或角色查找组件以及与添加/删除相关的回调。
CBA 实现
平台 CBA 实现
WsfPlatform(即平台)本身就是一个组件,并且附带有组件列表,以便通过附加到平台的方式包含传感器、通信、处理器、移动器等组件。
WsfPlatform 从 WsfComponent(模板类)、WsfComponentList(模板类)和 WsfObject/WsfUniqueId 类派生。此派生允许直接访问 WsfComponentList 函数,并使平台能够成为另一个平台的组件,从而实现组合设计模式。
示例组件实现
WsfSensor 通过 WsfPlatformPart 继承 WsfComponent,WsfPlatformPart 提供成员变量并在 WsfSensor 中实现与组件相关的虚拟函数。WsfProcessor、WsfComm、WsfMover 等的实现类似。
Declarations:
WSF_DECLARE_COMPONENT_ROLE_TYPE(WsfSensor, cWSF_COMPONENT_SENSOR)
Functions:
WsfComponent* CloneComponent() WsfStringId GetComponentName() virtual void* QueryInterface(int aRole); virtual const int* GetComponentRoles(); PreInitialize(...), Initialize(...), Initialize2(...) and ProcessInput(...)
Example Sensor Role Implementation:
// ================================================================================================ const int* WsfSensor::GetComponentRoles() const { static const int roles[] = { cWSF_COMPONENT_SENSOR, cWSF_COMPONENT_ARTICULATED_PART, cWSF_COMPONENT_PLATFORM_PART, cWSF_COMPONENT_NULL }; return roles; } // ================================================================================================ void* WsfSensor::QueryInterface(int aRole) { if (aRole == cWSF_COMPONENT_SENSOR) { return this; } if (aRole == cWSF_COMPONENT_ARTICULATED_PART) { return (WsfArticulatedPart*)this; } if (aRole == cWSF_COMPONENT_PLATFORM_PART) { return (WsfPlatformPart*)this; } return nullptr; }
插件管理
AFSIM 的插件系统允许通过动态加载插件来实现定制化,提供与源代码修改相似的灵活性。使用插件消除了分发框架源代码以及更新核心可执行文件或库的必要性。此外,插件易于由最终用户共享、加载和卸载。
AFSIM 插件管理提供了通过主要和次要描述符进行版本管理的能力,它搜索由 WSF_PLUGIN_PATH 环境变量定义的路径,或者使用 ../<application>_plugin 或 ../wsf_plugins 目录。插件管理在注册插件之前还会进行操作系统、编译器和构建类型的检查,以确保兼容性。
扩展与扩展类型
应用程序、场景和仿真的扩展为在这些层级中扩展功能提供了灵活性。
应用程序扩展
应用程序的扩展是对应用程序单例或实例的扩展,归应用程序所有。
- 修改或表示应用程序的可选能力。
- 维护脚本类型和插件管理。
- 可用于向场景或仿真添加功能。
场景扩展
场景扩展是对场景的扩展,归场景所有。
- 拥有类型工厂和列表、用户输入和脚本。
- 允许读取输入,例如实现 ProcessInput(…)。
仿真扩展
仿真扩展是对仿真的扩展,归仿真所有。
- 提供特定的能力,例如接口、输出、观察者和其他服务。
AFSIM 构建系统
有关 AFSIM 构建系统的更多信息,请参见《构建 WSF 应用程序》,该系统使用 CMake。
可选项目
《构建 WSF 应用程序》概述了创建可选 AFSIM 项目的设置和必要文件,并让顶层 CMakeLists.txt 文件包含该项目。此外,《集成方法》一节概述了在这些文件中需要的不同文件和设置,以便将该项目纳入开发者选择的适当集成方法中的 AFSIM 构建系统。
集成方法
AFSIM 为任何扩展或模型提供了三种集成方法:直接集成、项目集成和插件集成。每种方法允许:
- 一个或多个扩展类型的集成。
- 不同的集成方法和包含方式。
- 扩展的不同交付方式。
这些方法的具体内容在下面进一步定义,包括其方法、实施、交付和其他独特方面。
直接集成
直接集成使用现有项目或插件通过新的类型定义或额外的扩展类型添加来扩展功能。通常,这些扩展已经存在于项目中,此方法用于添加额外的模型类型定义或进一步扩展现有扩展。
一个主要的例子是将新类型或额外的基本类型添加到现有框架项目中。在这种情况下,新类型将通过项目的接口添加到新的或现有的类型列表中,类似于:
项目集成
项目集成是扩展 AFSIM 功能的最常见方法之一。此方法也可以用来通过下一个部分描述的插件方法集成。这种方法涉及创建一个额外的项目,可以集成到任何扩展类型中,以扩展 AFSIM 的能力。
目录结构
AFSIM 中的项目目录结构由多个目录和文件组成,以支持将该项目作为可选项目添加到 AFSIM 构建系统中。此外,还有必要的 CMake 配置文件用于将项目包含在 AFSIM 构建系统中,这些文件必须被包含。
my_project
|- doc
|- grammar
|- source
|- CMakeLists.txt
|- <header-files>
|- <source-files>
|- test
|- test_<application>
|- CMakeLists.txt
|- wsf_cmake_extension.cmake
|- wsf_module
CMake 配置设置
根据目录结构,有四个必需文件,用于通过 CMake 将新项目包含到 AFSIM 构建系统中:
- wsf_module
- wsf_cmake_extension.cmake
- CMakeLists.txt
- source/CMakeLists.txt
wsf_module
该文件由 AFSIM 的主 CMakeLists.txt 使用。
wsf_cmake_extension.cmake
该文件用于告知 AFSIM 的主 CMakeLists.txt 本项目是一个可选项目,并设置扩展名称、源路径、构建类型和默认包含标志。
例子:
# configuration for automatic inclusion as a WSF extension
set(WSF_EXT_NAME my_project) # Required; Project name, match project name in main CMakeLists.txt
set(WSF_EXT_SOURCE_PATH .) # Required; Path to the project main CMakeLists.txt
set(WSF_EXT_TYPE lib) # Optional; default value: lib; available options: lib, plugin, exe
set(WSF_EXT_BUILD TRUE) # Optional; default value: TRUE; available options: TRUE, FALSE
CMakeLists.txt
该文件是项目的主 CMakeLists.txt 文件,通过 wsf_cmake_extension.cmake
文件包含和设置。它用于设置项目名称、在项目中添加子目录、包含其他必要目录、添加必要的文档和 doxygen 目录,并安装项目中未包含在其他 CMake 配置文件中的必要项目文件。
例子:
# Project Configuration
project(wsf_my_project)
cmake_minimum_required (VERSION 3.2.3)
include(swdev_project)
include_directories(include ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include)
add_subdirectory(source)
add_subdirectory(test)
# Add source directories to doxygen input
add_wsf_doxygen_input(${CMAKE_CURRENT_SOURCE_DIR}/source)
# Add project to Sphinx for documentation
add_wsf_doc_input(${CMAKE_CURRENT_SOURCE_DIR})
install_sources(source wsf_plugins/${PROJECT_NAME})
install_sources_all_files(grammar wsf_plugins/${PROJECT_NAME})
install_sources_all_files(doc wsf_plugins/${PROJECT_NAME})
install_sources_all_files(data wsf_plugins/${PROJECT_NAME})
install_sources_all_files(conversion wsf_plugins/${PROJECT_NAME})
install_tests(test_mission DESTINATION wsf_plugins/${PROJECT_NAME})
install_source_files(CMakeLists.txt
wsf_module
wsf_cmake_extension.cmake
wsf_plugins/${PROJECT_NAME})
install_source_files(FILES wsf_module DESTINATION ${INSTALL_SOURCE_ROOT}/wsf_plugins)
if(WSF_INSTALL_DEMOS)
# Demo directories included with this projects build
set(EXAMPLE_DEMO_DIRS
example_demo
)
install_wsf_demo("${EXAMPLE_DEMO_DIRS}" ${WSF_DEMOS_ROOT} demos)
endif()
source/CMakeLists.txt
这是一个通过项目的主 CMakeLists.txt 使用 add_subdirectory
命令调用的二级 CMake 配置文件。它的目的是为所有源文件定义通配符,指定语法文件,设置项目包含、库和链接,并最终安装源文件、演示和场景。
例子:
cmake_minimum_required (VERSION 3.2.3)
include (GenerateExportHeader)
include(swdev_project)
FILE(GLOB SRCS *.cpp *.hpp)
wsf_grammar_file(SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../grammar/wsf_my_project.ag")
add_library(${PROJECT_NAME} ${SRCS})
generate_export_header(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}"
"${PROJECT_BINARY_DIR}/source")
target_link_libraries(${PROJECT_NAME} wsf util)
swdev_warning_level(${PROJECT_NAME})
swdev_lib_install(${PROJECT_NAME})
源配置设置
WsfExampleExtension 应用程序扩展的注册函数定义:
WsfExampleExtension.hpp
#ifndef WSFEXAMPLEEXTENSION_HPP #define WSFEXAMPLEEXTENSION_HPP #include "wsf_example_export.hpp" #include "WsfScenarioExtension.hpp" //! An implementation of WSf Scenario Extension that //! adds replicated project capability to an application. //! @see WsfScenarioExtension class WSF_EXAMPLE_EXPORT WsfExampleExtension : public WsfScenarioExtension { public: //! Called when the extension has been added to the scenario //! to add script types and wsf_my_project specific types virtual void AddedToScenario(); }; #endifWsfExampleExtension.cpp
#include "WsfExampleExtension.hpp" #include "UtMemory.hpp" #include "WsfApplication.hpp" #include "WsfApplicationExtension.hpp" #include "WsfExampleProcessor.hpp" #include "WsfProcessorTypes.hpp" #include "WsfScenario.hpp" #include "WsfScriptExampleProcessorClass.hpp" #include "script/WsfScriptManager.hpp" using namespace std; namespace { class ApplicationExtension : public WsfApplicationExtension { public: void AddedToApplication(WsfApplication& aApplication) override { // Register script classes associated with this extension UtScriptTypes* scriptTypesPtr = aApplication.GetScriptTypes(); scriptTypesPtr->Register(new WsfScriptExampleProcessorClass("WsfExampleProcessor", scriptTypesPtr)); } void ScenarioCreated(WsfScenario& aScenario) override { aScenario.RegisterExtension(GetExtensionName(), ut::make_unique<WsfExampleExtension>()); } }; } void WsfExampleExtension::AddedToScenario() { WsfScenario& scenario = GetScenario(); WsfProcessorTypes::Get(scenario).AddCoreType("WSF_EXAMPLE_PROCESSOR", ut::make_unique<WsfExampleProcessor>(scenario)); } //! Registers the wsf_example extension with the application //! so it is available for use. void WSF_EXAMPLE_EXPORT Register_wsf_example(WsfApplication& aApplication) { if (!aApplication.ExtensionIsRegistered("wsf_example")) { aApplication.RegisterFeature("example", "wsf_example"); // Indicate the feature is present aApplication.RegisterExtension("wsf_example", ut::make_unique<ApplicationExtension>()); } }
Registration function definition for WsfExampleExtension Scenario extension:
WsfExampleExtension.hpp
#ifndef WSFEXAMPLEEXTENSION_HPP #define WSFEXAMPLEEXTENSION_HPP #endifWsfExampleExtension.cpp
#include "WsfExampleExtension.hpp" #include "UtMemory.hpp" #include "WsfApplication.hpp" #include "WsfApplicationExtension.hpp" #include "WsfExampleProcessor.hpp" #include "WsfProcessorTypes.hpp" #include "WsfScenario.hpp" #include "WsfScenarioExtension.hpp" using namespace std; namespace { class ScenarioExtension : public WsfScenarioExtension { public: void AddedToScenario() override { WsfScenario& scenario = GetScenario(); WsfProcessorTypes::Get(scenario).AddCoreType("WSF_EXAMPLE_PROCESSOR", ut::make_unique<WsfExampleProcessor>(scenario)); } }; } //! Registers the wsf_example extension with the application //! so it is available for use. void WSF_EXAMPLE_EXPORT Register_wsf_example(WsfApplication& aApplication) { if (!aApplication.ExtensionIsRegistered("wsf_example")) { aApplication.RegisterFeature("example", "wsf_example"); // Indicate the feature is present aApplication.RegisterExtension("wsf_example", ut::make_unique<WsfDefaultApplicationExtension<ScenarioExtension>()); } }
插件
作为一个插件,与项目相似,并且可以双重使用。本节概述了项目集成方法的修改。
注意:可以通过项目接口设置将项目同时集成为项目和插件。
CMake 配置设置
创建或将项目转换为插件项目需要对以下文件进行修改:
wsf_cmake_extension.cmake
source/CMakeLists.txt
wsf_cmake_extension.cmake
添加逻辑检查,如果在 CMake 构建配置中选择了 WSF_PLUGIN_BUILD
,则将扩展类型设置为插件。
注意:如果将 WSF_PLUGIN_BUILD
设置为 FALSE,则将使用该配置构建项目集成方法,因为默认的 WSF_EXT_TYPE
为 lib。
示例:
# configuration for automatic inclusion as a WSF extension
set(WSF_EXT_NAME my_project) # 必需;项目名称,匹配主 CMakeLists.txt 中的项目名称
set(WSF_EXT_SOURCE_PATH .) # 必需;项目主 CMakeLists.txt 的路径
if(WSF_PLUGIN_BUILD)
set(WSF_EXT_TYPE plugin) # 可选;默认值:lib;可用选项:lib, plugin, exe
endif()
set(WSF_EXT_BUILD TRUE) # 可选;默认值:TRUE;可用选项:TRUE, FALSE
source/CMakeLists.txt
这是一个通过项目的主 CMakeLists.txt
使用 add_subdirectory
命令调用的二级 CMake 配置文件。它的目的是收集所有源文件,指定语法文件,设置项目包含、库和链接,最后安装源文件和演示。
示例:
cmake_minimum_required(VERSION 3.2.3)
include(GenerateExportHeader)
include(swdev_project)
FILE(GLOB SRCS *.cpp *.hpp)
wsf_grammar_file(SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../grammar/wsf_my_project.ag")
add_library(${PROJECT_NAME} ${SRCS})
generate_export_header(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}"
"${PROJECT_BINARY_DIR}/source")
target_link_libraries(${PROJECT_NAME} wsf util)
swdev_warning_level(${PROJECT_NAME})
if(WSF_PLUGIN_BUILD)
swdev_plugin_install(${PROJECT_NAME} wsf_plugins)
else()
swdev_lib_install(${PROJECT_NAME})
endif()
源配置设置
类似于项目源配置设置部分,以下是包含 extern "C"
的附加部分,位于全局 Register_wsf_example
定义下方。插件项目的注册函数示例定义:
//! 注册 wsf_example 扩展到应用程序
//! 使其可供使用。
void WSF_EXAMPLE_EXPORT Register_wsf_example(WsfApplication& aApplication)
{
if (!aApplication.ExtensionIsRegistered("wsf_example"))
{
aApplication.RegisterFeature("example", "wsf_example"); // 指示功能存在
aApplication.RegisterExtension("wsf_example", ut::make_unique<ApplicationExtension>());
}
}
extern "C"
{
//! 此方法在插件加载时调用,以确保插件和加载它的可执行文件使用的是
//! 相同版本的插件 API。
UT_PLUGIN_EXPORT void WsfPluginVersion(UtPluginVersion& aVersion)
{
aVersion = UtPluginVersion(WSF_PLUGIN_API_MAJOR_VERSION,
WSF_PLUGIN_API_MINOR_VERSION,
WSF_PLUGIN_API_COMPILER_STRING);
}
//! 此方法在插件加载时调用。它必须具有完全相同的签名(名称和参数)才能成功。
//! 由于我们在加载时只有应用程序引用,因此通常在其中注册一个应用程序扩展,
//! 通过覆盖 ScenarioCreated 方法来获得对场景的访问。如果还需要
//! 访问模拟,则应通过覆盖
//! 场景扩展中的 SimulationCreated 方法来实例化和注册模拟扩展。
UT_PLUGIN_EXPORT void WsfPluginSetup(WsfApplication& aApplication)
{
Register_wsf_example(aApplication);
}
}
其他集成项目和要求
代码标准
所有集成都应遵循《编码标准》中概述的编码标准。与 AFSIM 社区没有直接关联的第三方库和源代码可能无法始终遵循标准,但这并不妨碍 AFSIM 接口与第三方源/库遵循标准。
CMake
所有 CMake 文件应遵循本文件或《构建 WSF 应用程序》中概述的目录结构。存在许多示例,格式应尽量与已发布项目保持一致。
有关 AFSIM 使用 CMake 的构建系统的更多信息,请参见《构建 WSF 应用程序》。
语法
任何集成所需的用户输入应包含在语法文件夹及相应文件中,该项目添加此功能,并应在测试时无错误和警告地执行。语法详细说明在《WSF 语法指南》和《WSF 语法格式》中。
文档
AFSIM 文档通过 Sphinx 和 Doxygen 工具分别提供给用户和开发者。两者在构建时应无错误和警告。
Sphinx
任何用户输入或集成所需的参考材料文档应包含在添加功能的项目的 doc 文件夹中。此包含确保该功能对最终用户可用。Sphinx 用于生成 reStructuredText 格式的 HTML 输出。CMake 提供了一个 DOCUMENTATION 目标,用于构建和安装文档。
要在构建目标中正确包含 doc 文件夹,请在项目的 CMakeLists.txt 文件中添加以下内容:
# 将项目添加到 Sphinx 文档
add_wsf_doc_input(${CMAKE_CURRENT_SOURCE_DIR}/..)
有关文档的更多信息,请参考《AFSIM 文档指南》。
Doxygen
Doxygen 代码文档支持由开发者提供。要将项目的源代码添加到 Doxygen 目标进行解析,请在项目的 CMakeLists.txt 文件中添加以下 CMake 宏:
# 将源目录添加到 Doxygen 输入
add_wsf_doxygen_input(${CMAKE_CURRENT_SOURCE_DIR}/source)
构建
在 AFSIM 生产中使用的每个构建配置和平台应消除所有警告和错误。由 AFSIM 社区或集成者未维护的第三方源和库可能无法满足此准则。
有关文档的更多信息,请参见《构建 WSF 应用程序》。
测试
单元测试
AFSIM 内的单元测试按《构建 AFSIM 应用程序》中概述的方式提供。
要将单元测试添加到您的项目中,您需要提供以下内容:
test/CMakeLists.txt
test/test_example.cpp
test/CMakeLists.txt
这是一个测试 CMake 配置文件,通过项目的主 CMakeLists.txt 使用 add_subdirectory
命令调用。其目的是收集所有测试源文件,链接测试可执行文件,并将测试注册为 CMake 目标的一部分。
示例:
cmake_minimum_required(VERSION 3.2.3)
file(GLOB SRCS *.cpp *.hpp)
if(GTest_FOUND)
add_executable(example_test ${SRCS})
target_include_directories(example_test PUBLIC ${EXAMPLE_PROJECT_INCLUDES})
target_link_libraries(example_test
${WSF_LIBS}
${PROJECT_NAME}
${SWDEV_THREAD_LIB}
${SWDEV_DL_LIB}
${GTEST_BOTH_LIBRARIES}
)
add_test(NAME "example" COMMAND example_test)
set_property(TARGET example_test PROPERTY FOLDER UnitTests)
endif()
test/test_example.cpp
这是一个源文件,包含针对特定函数或类的测试。在测试目录中可以创建多个源文件,并将自动包含以进行编译。最佳实践是为每个被测试的类创建一个新的源文件。
示例:
#include <gtest/gtest.h>
// 假设 Example.hpp 声明了一个阶乘函数
#include "Example.hpp"
TEST(Factorial, HandlesZeroInput)
{
ASSERT_EQ(1, factorial(0));
}
TEST(Factorial, HandlesPositiveInput)
{
ASSERT_EQ(1, factorial(1));
ASSERT_EQ(2, factorial(2));
ASSERT_EQ(6, factorial(3));
ASSERT_EQ(362880, factorial(9));
}
TEST(Factorial, ThrowsOnNegativeInput)
{
ASSERT_THROW(factorial(-12), InvalidValueException);
}
系统、集成测试
AFSIM 内的系统或集成测试按《构建 AFSIM 应用程序》中概述的方式提供。
要将系统或集成测试添加到您的项目中,您需要提供以下文件:
test_<application>/test_<capability>.txt
该文件包含 AFSIM 测试命令和脚本,用于针对定义的 <application> 测试 AFSIM 和 WSF。该文件应至少包含一个通过/失败标准,并输出一个 -FAIL,如下所示,并提供可选的 -PASS- 输出,以便 run 脚本进行正确解析,并在解析到 -FAIL- 时输出失败。
示例:
# 示例文件:test_mission/test_maketrack.txt
platform test_platform WSF_PLATFORM
execute at_time 1 s absolute
WsfTrack track = PLATFORM.MakeTrack();
if (track.LocationValid())
{
writeln("-PASS-");
}
else
{
writeln("-FAIL-");
}
end_execute
end_platform
术语
- AFSIM - 高级模拟、集成和建模框架
- WSF - 世界仿真框架