SpaceAST-一个C++航天仿真基础组件库
做航天任务仿真和分析的人,手边多半摆着这么几个工具:STK 功能全但贵且闭源,英文文档、COM技术学习难度大;GMAT 开源,但接口和用法绑定 NASA 的习惯,底层基础算法要自己抠出来才能复用;Orekit 是纯 Java 的,想嵌进 C++ 工程得走 JNI,比较别扭;Poliastro、astropy、pykep等 适合教学和快速原型;NASA 的 SPICE 只管星历和几何,不提供动力学。真要自己用C++做仿真软件、使用一些基础算法,往往没有一个特别顺手的。
SpaceAST 是一个面向航天任务分析、设计与仿真的 C++11 基础组件库,从最底层的数学工具一路提供到高层的仿真对象模型和智能体接口。跨平台、模块化,按需取用。编译产物是一组模块粒度的共享库:Windows 下是 DLL,Linux 下是 SO。本文按四层架构梳理它的功能全貌。
一句话定位
像 Qt 给图形界面提供控件那样,SpaceAST 给航天任务分析提供基础组件:轨道预报、坐标变换、力模型、访问窗口分析、碰撞检测、仿真对象、智能Agent……等,可以按需取用,拼成自己的软件。想只做轨道基础计算,取 Math + Core 就够;想做完整的任务分析工具,再把 Sim、Report、AI 等一层层叠起来。
架构:四层组织
模块按层次分为四层:基础层 → 引擎层 → 业务层 → 接口层
| 层次 | 模块 |
|---|---|
| 接口层 | Cmd、COM、Script、AI |
| 业务层 | Sim、Report、Loader |
| 引擎层 | Core、Weather、SPICE |
| 基础层 | Math、Util |
基础层
Math — 数学工具库
提供航天动力学所需的底层数学支持,是整个库的数值计算基石。
主要功能:
- 线性代数 — 动态矩阵、固定大小矩阵、向量、下三角矩阵、稀疏矩阵与四元数
- 姿态/旋转 — 轴角表示
AngleAxis(与旋转矩阵互转)、欧拉角Euler(支持 XYZ/ZYZ 等 14 种旋转序列,可与矩阵/四元数互转)、旋转矩阵Rotation、运动学旋转KinematicRotation与运动学变换KinematicTransform - 常微分方程求解 (ODE) — 固定步长积分器(RK4、RK8、RKV8)与自适应步长积分器(RKF45、RKF56、RKF78、RKCK),含事件检测器
ODEEventDetector与状态观测器 - 非线性方程求解 (NLE) — 割线法、Ridder、Brent、二分法等多种求根算法
- 函数极值求解 — Brent、黄金分割等求极值算法
- 插值 — 抽象插值接口
Interpolator,含拉格朗日插值器LagrangeInterpolator - 姿态转换 —
AttitudeConvert系列,提供四元数/欧拉角/轴角/旋转矩阵之间的完整转换
Util — 通用工具库
最大的基础模块,提供序列化、解析、压缩、颜色、反射等通用基础设施。
主要功能:
- 压缩解压 — 支持 tar/tgz/zip/7z 多种格式,可探测后端(ShellCOM/System/Tar/Raw)
- 解析器 — STK 配置文件与 CelesTrak 数据解析、SPICE 数据文件解析、Markdown、Json、Xml解析等
- 颜色 — 基础颜色类型,含
rgb/rgba辅助函数与命名颜色表 - 网络 — 支持发送 HTTP 网络请求
- 单位量纲 — 提供单位量纲转换,支持基本单位、派生单位、自定义单位等
- 其他 — 字符串处理、文件系统管理、动态反射、C++拓展容器等
引擎层
Core — 航天动力学核心引擎
库中最大的核心模块,提供坐标系统、力模型、轨道预报、大气模型、可见性分析等完整的航天动力学计算能力。
主要功能:
- 时间系统 — 儒略日、闰秒、EOP、不同时间系统转换
- 坐标与参考系 — 提供完整的坐标系层次结构:地心惯性系(ICRF)、地固系(BodyFixed)、真赤道系(TOD)、平赤道系(MOD)、冻结系(Frozen)、体轴系(BodyInertial/BodyRelated)等
- 力模型块系统 — 基于信号-块的架构,通过命名信号(Pos/Vel/Acc/AccTwoBody/AccGravity/AccDrag/AccSRP 等)自动连接各功能块,提供二体引力、第三体引力、重力场、大气阻力、太阳光压(SRP)、相对论效应、运动方程、质量模块、状态转移矩阵(STM)
- 轨道预报 — SGP4、HPOP、J2/J4 解析解、二体运动,以及 DE/SPK/Lagrange/二进制星历源
- 轨道根数 — 经典轨道根数、春分点根数、德洛奈根数等定义与相互转换
- 轨道设计器 — 圆轨道、冻结轨道、太阳同步轨道、闪电轨道、回归轨道、静止轨道等设计器
- 大气模型 — 抽象
Atmosphere基类,具体实现包括:MSISE90、NRLMSISE00、MSIS86、HarrisPriester、JacchiaRoberts、DTM2012、USSA1976 - 访问窗口分析 —
AccessEvaluator采样可见性约束条件,通过 Brent 求根法精确定位时间区间边界,返回满足约束的时间段列表 - 碰撞检测 — 检测航天器之间的碰撞,返回最接近时刻、最小距离、相对速度等数据
- 数据库 — TLE数据库加载、CelesTrak卫星数据库
Weather — 大气与空间环境模型
提供大气密度、地磁场与辐射带模型。
主要功能:
- 大气密度模型 — USSA1976、JacchiaRoberts、Harris-Priester、NRLMSISE-00、DTM-12
- 地磁场模型 — IGRF13 国际地磁参考场
- 辐射带模型 — AE8/AP8 辐射带电子/质子模型
SPICE — 兼容 SPICE 的接口
参考 NASA SPICE工具包的接口定义,对核心算法进行轻量封装,提供 SPICE 兼容的接口。函数签名对齐 SPICE,底层却落在核心库对象上。熟悉 SPICE 的人可以直接上手,又不必绑定整套 SPICE 工具链。
SPICE 兼容函数:
- 帧变换 —
pxform(坐标系间变换矩阵)、tipbod(体固系相对惯性系变换) - 旋转与姿态表示 —
axisar(轴角→矩阵)、eul2m/m2eul(欧拉角↔矩阵)、q2m/m2q(四元数↔矩阵)、mxm/mxvg(矩阵乘/矩阵-向量) - 坐标转换 —
latrec(经纬高→直角)、radrec(半径/方位/仰角→直角)、azlrec(方位/仰角/距离→直角) - 星历查询 —
spkpos、spkgeo、spkgps、spkapo、spkssb等,读取 SPK 星历 - 时间系统 —
utc2et(UTC→星历时间 ET),以及j2000/b1950/clight/dpr等常量 - 光行差修正 —
stelab、stlabx,处理观测者与天体的相对运动 - 状态变换 —
rav2xf(角速度/旋转→状态变换矩阵)
业务层
Sim — 仿真对象模型
定义场景中的各类对象(卫星、飞行器、地面站、天线、传感器等)及其运动与姿态模型(完善中…)。
主要功能:
- 对象体系 — 完整的对象继承链:
SpaceObject→Spacecraft→Satellite,以及Aircraft、Missile、LaunchVehicle、GroundStation、GroundVehicle、Facility、Ship、Submarine、Star、Planet、Asteroid、Antenna、Radar、Sensor、CommSystem、Constellation、AreaTarget、LineTarget等 - Mover 机制 — 所有运动对象的核心抽象,组合
MotionProfile(运动模型)与AttitudeProfile(姿态模型),生成星历并提供位置/速度查询 - 运动模型 (Motion) — 二体运动、SGP4、HPOP(可配置力模型+航天器参数+积分器)、J2/J4 解析解、弹道导弹、SPICE 星历、SP3、GPS、大圆弧、外部星历、任务指令、实时/本地轨道预报等
- 姿态模型 (Attitude) — 约 30 种预定义指向模式:太阳指向、天底指向、固定/自旋指向、轨道速度坐标系(VVLH)、目标指向、GPS 姿态、导弹姿态、多段姿态、进动自旋、太阳法线指向(黄道面法线)等(完善中…)
- 场景管理 —
Scenario顶层容器,以及覆盖定义CoverageDefinition、品质因数FigureOfMerit、链路Chain等分析概念(完善中…)
Report — 报表与数据导出
面向表格与图形化报表的数据组织与导出模块。
主要功能:
- 数据序列 —
DataSeries类型擦除的 1D 数据列(底层VariantVector),含统计方法(均值/最值/求和/标准差) - 数据组 —
DataGroup命名数据组基类,含按名称提取extract()方法;提供约 20 种具体数据组类型:直角坐标位置/速度、赤道轨道根数、欧拉角、四元数、球坐标、经纬高(LLA/LLR)、姿态、轨迹、Beta 角、改进轨道根数、点/向量等 - 报表元素 —
ReportElement数据元素模型(数据源、格式化、聚合掩码、单位设置、线/点/填充样式) - 报表结构 —
ReportSection(节)、ReportLine(行)、ReportWriter(写入器)、ReportStyle(样式)
Loader — 场景加载器
解析 STK/GMAT 风格的场景与定义文件,构建任务分析对象。
主要功能:
- 约 60 个类型专用加载器,每个对应一个对象类型:
ScenarioLoader、ConstellationLoader、ForceModelLoader、ObjectLoader、SensorLoader、RadarLoader、PlanetLoader、StarLoader、FacilityLoader、PropagatorLoader、ManeuverLoader等 - 运动模型 SAX 加载器 —
MotionHPOPSax、MotionJ2AnalyticalSax、MotionJ4AnalyticalSax、MotionOrbitDynamicsSax、MotionOrbitDynamicsKeplerianSax等 LoaderContext— 加载过程上下文(父对象指针、场景目录、文件路径)GMATScriptParser— GMAT 脚本解析器(规划中)- 加载 API 模式 — 每个类型对应一个 C-API 导出函数
aLoadX(filepath, object)返回errc_t
接口层
Cmd — 命令分发引擎
将文本命令字符串路由到已注册的处理函数。
主要功能:
CommandDispatcher— 持有CommandTrie前缀树,execute()路由命令字符串,addRuleHandler()注册命令模板CommandRouting—CommandTrie基于命令 token 的树结构,节点携带参数数量与可选处理函数- 编译时参数解码 —
REGISTER_COMMAND/COMMAND_RULE宏在编译时根据命令模板字符串推导参数类型 - 公共 API —
aExecuteCommand(cmd)/aExecuteCommand(cmd, result),CommandResult为std::vector<std::string>
COM — COM 自动化接口
通过 Microsoft COM 将核心引擎能力暴露给脚本语言(VBScript、Python 等)。
主要功能:
COMAPI—aComObjectRoot()返回根IDispatch*,aComGetObject()将原生对象包装为 COM 接口- ATL COM 共类 —
CObject、CScenario、CSatellite(基于CComObjectRootEx/CComCoClass,暴露IObject/IDispatch/IUnknown) IObjectImpl— 使用IDispatchImpl从 DLL 加载类型库,桥接原生子对象ComObjectManager— 单例对象池,维护原生对象到 COM 包装器的映射
Script — 脚本引擎
完整的脚本语言实现,从词法分析、语法解析到 AST 解释执行,并提供外部语言执行器。
主要功能:
- 表达式系统 —
Expr为所有 AST 节点基类,支持多态求值eval()、访问者模式accept(ExprVisitor&)与宏展开expand() - 解析器 — 递归下降解析器,覆盖赋值、条件、逻辑/位/关系/移位/加法/乘法/指数/区间表达式及 if/while/for 块语句
- 解释器 —
Interpreter解析脚本并基于符号作用域ISymbolScope执行,含调用栈跟踪 - 调试器 —
Debugger/Breakpoint提供断点、单步调试与变量检查能力(规划中) - 函数系统 —
Function为可调用脚本函数(参数+函数体) - 外部脚本执行器 —
ActiveScriptExecutor通过 COMIActiveScript接口运行 JScript/VBScript;ScriptExecutor抽象层支持 Python、MATLAB、JScript、VBScript、Julia、Lua 等多种语言
AI — AI 对话集成
将大语言模型(LLM)对话能力集成到应用中。
主要功能:
- LLM 客户端 — 统一的
LLMClient接口(chat/chatStream),具体实现:OpenAI(OpenAI 兼容 API)、DeepSeek(继承 OpenAI,指向 DeepSeek 端点)、Anthropic(规划中) - 对话管理 —
Chat阻塞式对话 API(aChat系列函数),ChatMessages消息历史管理 - 智能体框架 —
ChatAgent抽象基类(含流式runStream+ChatEventHandler),AssistantAgent助手实现,UserProxyAgent用户代理 - 群聊 —
BaseGroupChat/RoundRobinGroupChat多智能体轮询对话 - 工具调用 —
ChatTool/ChatTools支持 LLM 函数调用 - SSE 流解析 —
SSEParser支持 Server-Sent Events 流式响应解析 - 终止条件 —
TerminationCondition/TextMentionTermination基于文本内容的对话终止判断 - 配置管理 —
LLMConfig(模型名、温度、额外请求体),ChatConsole控制台交互
一个能跑的真实例子
下面用几段代码展示几个典型用法,均从仓库示例里节选,按"坐标变换 → 快速预报 → 高精度预报 → 可见性分析"的顺序由浅入深。
坐标变换:J2000 到 ECF
#include"ast/FrameTransform.hpp"#include"ast/TimePoint.hpp"#include"ast/Vector.hpp"#include"ast/Literals.hpp"AST_USING_NAMESPACEusingnamespace_AST literals;intmain(){// 创建时间点TimePoint tp=TimePoint::FromUTC(2026,1,1,0,0,0);// J2000 坐标(_km 字面量自动换算成米)Vector3d vecJ2000{1000_km,2000_km,3000_km};// 转换到 ECF 坐标Vector3d vecECF;aJ2000ToECF(tp,vecJ2000,vecECF);printf("J2000坐标: %.3f m, %.3f m, %.3f m\n",vecJ2000[0],vecJ2000[1],vecJ2000[2]);printf("ECF坐标: %.3f m, %.3f m, %.3f m\n",vecECF[0],vecECF[1],vecECF[2]);return0;}几百行就能看到这个库的用感:_km这种字面量替代裸数字,函数直接做变换,不搞一堆临时对象。
快速预报:从 TLE 算国际空间站
两行根数(TLE)是 NORAD 发布的卫星轨道标准格式,SGP4 是对近地卫星做快速预报的标配。
#include"ast/TLE.hpp"#include"ast/SGP4.hpp"#include"ast/TimePoint.hpp"#include"ast/Vector.hpp"#include"ast/RunTime.hpp"#include<cstdio>AST_USING_NAMESPACEintmain(){// 国际空间站 (ISS) 的两行根数constchar*line1="1 25544U 98067A 24185.54861111 .00012345 00000+0 22222-3 0 9991";constchar*line2="2 25544 51.6400 210.1234 0005000 100.0000 260.0000 15.50000000123456";// 解析 TLE,构造 SGP4 预报器(封装类)TLE tle=TLE::FromLines(line1,line2);SGP4sgp4(tle);// 预报 TLE 历元后约 90 分钟的位置速度(默认输出在 TEME 坐标系)TimePoint tp=TimePoint::FromUTC(2024,7,3,14,40,0);Vector3d r,v;sgp4.getPosVel(tp,r,v);printf("ISS 位置 (km): %s\n",r.toString().c_str());printf("ISS 速度 (km/s): %s\n",v.toString().c_str());return0;}TLE::FromLines()解析两行根数,SGP4类把底层细节收起来,getPosVel()按时间点取位置速度。想换坐标系,改调getPosVelIn(frame, tp, r, v)就行。
高精度预报:HPOP 与可配置力模型
想要精度,就得把力模型配全。HPOP是数值积分的高精度预报器,力模型通过"块"来配。
#include"ast/HPOP.hpp"#include"ast/HPOPForceModel.hpp"#include"ast/TimePoint.hpp"#include"ast/Vector.hpp"#include"ast/Literals.hpp"#include"ast/RunTime.hpp"#include<iostream>AST_USING_NAMESPACEusingnamespaceast::literals;intmain(){// 力模型:JGM3 重力场(8x8)HPOPForceModel force_model;force_model.gravity().model_="JGM3";force_model.gravity().maxDegree_=8;force_model.gravity().maxOrder_=8;HPOP hpop;hpop.setForceModel(force_model);hpop.initialize();// 近地初始状态TimePoint start=TimePoint::FromUTC(2026,1,1,0,0,0);Vector3d pos{7000_km,0.0,0.0};Vector3d vel{0.0,7.5_km_s,1.0_km_s};// 预报 1 天autostop=start+24*3600.0;hpop.propagate(start,stop,pos,vel);std::cout<<"1 天后位置 (km): "<<pos.norm()/1000.0<<" 速度 (km/s): "<<vel.norm()/1000.0<<std::endl;return0;}setForceModel()里可以配 JGM3 重力场的阶数,要不要第三体、要不要大气阻力。
任务分析:地面站可见性窗口
构造一颗卫星、一座地面站,然后问:卫星过站时,哪些时段连线不被地球挡住?
#include"ast/Facility.hpp"#include"ast/Satellite.hpp"#include"ast/Mover.hpp"#include"ast/MotionTwoBody.hpp"#include"ast/StateKeplerian.hpp"#include"ast/EventIntervalExplicit.hpp"#include"ast/CelestialBody.hpp"#include"ast/OrbitElement.hpp"#include"ast/BodyObstructionConstraint.hpp"#include"ast/AccessEvaluator.hpp"#include"ast/FixedStepStepper.hpp"#include"ast/TimePoint.hpp"#include"ast/TimeIntervalList.hpp"#include"ast/Literals.hpp"#include"ast/RunTime.hpp"#include<cstdio>AST_USING_NAMESPACEusingnamespaceast::literals;intmain(){// 1) 构造一颗二体运动卫星(近地圆轨道,28.5° 倾角)CelestialBody*earth=aGetEarth();autoframe=earth->makeFrameICRF();automotion=MotionTwoBody::New();autostate=StateKeplerian::New();ModOrbElem elem{};elem.rp_=6678137.0;// 近地点半径 (m)elem.e_=0.0;// 圆轨道elem.i_=deg2rad(28.5);elem.raan_=deg2rad(0.0);elem.argper_=deg2rad(0.0);elem.trueA_=deg2rad(0.0);TimePoint epoch=TimePoint::FromUTC(2026,7,22,4,0,0.0);state->setFrame(frame.get());state->setState(elem);state->setStateEpoch(epoch);motion->setInitialState(state);motion->setPropagationFrame(frame.get());motion->setInterval(EventIntervalExplicit::New(epoch,epoch+86400.0));motion->setStepSize(60.0);autosat=newSatellite();sat->setName("Satellite1");sat->setMotionProfile(motion);sat->generateEphemeris();// 2) 建一座地面站Facility*fac=newFacility();fac->setLatitude(deg2rad(40.0));fac->setLongitude(deg2rad(-75.0));fac->setAltitude(0.0);// 3) 可见性约束:连线不被地球遮挡BodyObstructionConstraintconstraint(sat,fac,earth);// 4) 60s 粗采样 + Brent 求根精化边界FixedStepStepperstepper(60.0);AccessEvaluator evaluator;evaluator.setConstraint(&constraint);evaluator.setStepper(&stepper);TimeIntervalList intervals;evaluator.evaluate({epoch,epoch+86400.0},intervals);// 5) 打印每个可见窗口for(size_t i=0;i<intervals.size();++i){TimeInterval ti=intervals[i];printf("[%zu] %s duration=%.1f s\n",i,ti.toString().c_str(),ti.duration());}return0;}AccessEvaluator先按 60 秒粗采样,再用 Brent 求根把"可见/不可见"的切换时刻精化到秒级,输出一天里几段过站窗口。想加传感器视场,再叠一个FieldOfViewConstraint,或者用AndConstraint把视线和视场一起满足(aEvaluateAccess还能一次处理多个约束)。
如果你的工作是航天仿真,或者手头也缺这么一块地基,可以把它拿来当工具箱。
二进制库下载:https://github.com/space-ast/ast/releases
本文梳理自文档站与源码示例。文中模块名、API 与架构以仓库最新版本为准。
- GitHub:SpaceAST
- Gitee:SpaceAST
- GitCode:SpaceAST
- 文档:SpaceAST
