Axes轴系模块
2026/4/9大约 4 分钟
Axes轴系模块
说明:本文档旨在帮助理解Axes轴系模块的功能和使用方法,具体API和行为请查阅源代码。
模块概述
Axes模块提供了统一的坐标系(轴系)抽象和管理功能。在航天动力学中,不同的计算需要在不同的参考系下进行,如惯性系、地球固连系、天体固连系等。Axes模块通过层次化的设计,提供了轴系之间的旋转变换计算能力。
核心概念
轴系类层次结构
Axes (基类)
├── AxesRoot # 根轴系,层级结构的起点
├── AxesICRF # 国际天球参考系(J2000的现代实现)
├── AxesECF # 地球固连系
├── AxesJ2000 # J2000惯性系
├── AxesMOD # 瞬时平赤道系
├── AxesTOD # 瞬时真赤道系
├── AxesGTOD # 格林尼治真赤道系
├── AxesFrozen # 冻结轴系(在特定时刻冻结的轴系)
├── AxesBodyRelated # 天体相关轴系的基类
│ ├── AxesBodyInertial # 天体惯性轴系
│ ├── AxesBodyFixed # 天体固连轴系
│ ├── AxesBodyMOD # 天体MOD轴系
│ └── AxesBodyTOD # 天体TOD轴系
└── ... (其他专用轴系)轴系变换原理
每个轴系维护其到父轴系的旋转变换。通过组合从子轴系到父轴系的变换,可以计算出任意两个轴系之间的变换。
旋转表示
- Rotation类:表示纯旋转变换,包含旋转矩阵
- KinematicRotation类:表示运动学旋转,包含旋转矩阵和角速度
主要功能
1. 获取轴系实例
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/Rotation.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
printf("Axes实例获取示例:\n\n");
// 1. 全局单例轴系
printf("--- 全局单例轴系 ---\n");
Axes* icrf = aAxesICRF();
Axes* j2000 = aAxesJ2000();
Axes* ecf = aAxesECF();
Axes* mod = aAxesMOD();
Axes* tod = aAxesTOD();
Axes* gtod = aAxesGTOD();
Axes* root = aAxesRoot();
printf("ICRF: %p\n", (void*)icrf);
printf("J2000: %p\n", (void*)j2000);
printf("ECF: %p\n", (void*)ecf);
printf("MOD: %p\n", (void*)mod);
printf("TOD: %p\n", (void*)tod);
printf("GTOD: %p\n", (void*)gtod);
printf("Root: %p\n", (void*)root);
// 2. 通过名称获取轴系
printf("\n--- 通过名称获取轴系 ---\n");
Axes* galactic = aGetAxes("GALACTIC");
if (galactic != nullptr) {
printf("GALACTIC轴系获取成功\n");
}
// 3. 检查轴系层级关系
printf("\n--- 轴系层级关系 ---\n");
printf("ICRF深度: %d\n", icrf->getDepth());
printf("ECF深度: %d\n", ecf->getDepth());
printf("TOD深度: %d\n", tod->getDepth());
// 4. 验证父子关系
printf("\n--- 验证父子关系 ---\n");
printf("ECF的父轴系是否为ICRF: %s\n",
(ecf->getParent() == icrf) ? "是" : "否");
printf("TOD的父轴系是否为MOD: %s\n",
(tod->getParent() == mod) ? "是" : "否");
printf("GTOD的父轴系是否为TOD: %s\n",
(gtod->getParent() == tod) ? "是" : "否");
return 0;
}1.1 全局单例轴系
// 获取ICRF惯性系
Axes* icrf = aAxesICRF();
// 获取J2000惯性系
Axes* j2000 = aAxesJ2000();
// 获取ECF地球固连系
Axes* ecf = aAxesECF();
// 获取MOD瞬时平赤道系
Axes* mod = aAxesMOD();
// 获取TOD瞬时真赤道系
Axes* tod = aAxesTOD();
// 获取GTOD格林尼治真赤道系
Axes* gtod = aAxesGTOD();
// 获取根轴系
Axes* root = aAxesRoot();1.2 通过名称获取轴系
// 通过名称获取内置轴系
Axes* galactic = aGetAxes("GALACTIC");1.3 创建天体相关轴系
// 创建天体惯性轴系
auto bodyInertial = AxesBodyInertial::NewShared(earth);
// 创建天体固连轴系
auto bodyFixed = AxesBodyFixed::NewShared(earth);
// 创建天体MOD轴系
auto bodyMOD = AxesBodyMOD::NewShared(earth);
// 创建天体TOD轴系
auto bodyTOD = AxesBodyTOD::NewShared(earth);2. 轴系变换计算
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/Rotation.hpp"
#include "AstMath/Matrix.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
// 创建时间点
TimePoint tp = TimePoint::FromUTC(2026, 1, 1, 12, 0, 0);
printf("获取旋转变换示例:\n\n");
// 获取两个轴系
Axes* j2000 = aAxesJ2000();
Axes* ecf = aAxesECF();
// 方式1: 使用全局函数
printf("--- 使用全局函数 aAxesTransform ---\n");
Rotation rotation1;
errc_t err = aAxesTransform(j2000, ecf, tp, rotation1);
if (err != eNoError) {
printf("错误: 转换失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat1 = rotation1.getMatrix();
printf("J2000到ECF转换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat1(i,0), mat1(i,1), mat1(i,2));
}
// 方式2: 使用成员函数 getTransformTo
printf("\n--- 使用成员函数 getTransformTo ---\n");
Rotation rotation2;
err = j2000->getTransformTo(ecf, tp, rotation2);
if (err != eNoError) {
printf("错误: getTransformTo失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat2 = rotation2.getMatrix();
printf("J2000到ECF转换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat2(i,0), mat2(i,1), mat2(i,2));
}
// 方式3: 使用成员函数 getTransformFrom
printf("\n--- 使用成员函数 getTransformFrom ---\n");
Rotation rotation3;
err = ecf->getTransformFrom(j2000, tp, rotation3);
if (err != eNoError) {
printf("错误: getTransformFrom失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat3 = rotation3.getMatrix();
printf("J2000到ECF转换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat3(i,0), mat3(i,1), mat3(i,2));
}
return 0;
}2.1 获取旋转变换
// 获取轴系到另一个轴系的旋转变换
Rotation rotation;
errc_t err = aAxesTransform(source, target, timePoint, rotation);
// 使用成员函数
source->getTransformTo(target, timePoint, rotation);2.2 获取转换矩阵
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/Matrix.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
// 创建时间点
TimePoint tp = TimePoint::FromUTC(2026, 1, 1, 12, 0, 0);
printf("获取转换矩阵示例:\n\n");
// 获取两个轴系
Axes* j2000 = aAxesJ2000();
Axes* tod = aAxesTOD();
// 直接获取转换矩阵(不需要先获取Rotation对象)
Matrix3d matrix;
errc_t err = aAxesTransform(j2000, tod, tp, matrix);
if (err == eNoError) {
printf("J2000到TOD转换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.10f %.10f %.10f]\n", matrix(i,0), matrix(i,1), matrix(i,2));
}
// 直接使用矩阵进行坐标变换
Vector3d vecJ2000{1000.0, 2000.0, 3000.0};
Vector3d vecTOD = matrix * vecJ2000;
printf("\n坐标变换:\n");
printf("J2000坐标: (%.3f, %.3f, %.3f)\n", vecJ2000[0], vecJ2000[1], vecJ2000[2]);
printf("TOD坐标: (%.3f, %.3f, %.3f)\n", vecTOD[0], vecTOD[1], vecTOD[2]);
}
return 0;
}// 直接获取转换矩阵
Matrix3d matrix;
errc_t err = aAxesTransform(source, target, timePoint, matrix);2.3 获取运动学旋转变换
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/KinematicRotation.hpp"
#include "AstMath/Matrix.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
// 创建时间点
TimePoint tp1 = TimePoint::FromUTC(2026, 1, 1, 12, 0, 0);
TimePoint tp2 = TimePoint::FromUTC(2026, 1, 1, 12, 1, 0); // 1分钟后
printf("获取运动学旋转变换示例:\n\n");
// 获取两个轴系
Axes* j2000 = aAxesJ2000();
Axes* ecf = aAxesECF();
// 获取第一个时刻的运动学旋转
KinematicRotation kinRot1;
errc_t err = aAxesTransform(j2000, ecf, tp1, kinRot1);
if (err == eNoError) {
// 获取旋转矩阵
Matrix3d rot = kinRot1.getRotation().getMatrix();
printf("时刻1 - J2000到ECF旋转矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", rot(i,0), rot(i,1), rot(i,2));
}
// 获取角速度向量
Vector3d angVel = kinRot1.getRotationRate();
printf("\n时刻1 - 角速度 (rad/s):\n");
printf(" (%.10e, %.10e, %.10e)\n", angVel[0], angVel[1], angVel[2]);
}
// 获取第二个时刻的运动学旋转,用于计算平均角速度
KinematicRotation kinRot2;
aAxesTransform(j2000, ecf, tp2, kinRot2);
printf("\n时刻2 - 角速度 (rad/s):\n");
Vector3d angVel2 = kinRot2.getRotationRate();
printf(" (%.10e, %.10e, %.10e)\n", angVel2[0], angVel2[1], angVel2[2]);
// 估算地球自转角速度(简化计算)
double dt = 60.0; // 1分钟
Vector3d avgAngVel = (angVel2 - kinRot1.getRotationRate()) / dt;
printf("\n角速度变化率:\n");
printf(" (%.10e, %.10e, %.10e) rad/s^2\n", avgAngVel[0], avgAngVel[1], avgAngVel[2]);
return 0;
}// 获取包含角速度的运动学旋转
KinematicRotation kinRot;
errc_t err = aAxesTransform(source, target, timePoint, kinRot);
// 获取旋转矩阵
Matrix3d rot = kinRot.getRotation().getMatrix();
// 获取角速度向量
Vector3d angVel = kinRot.getRotationRate();3. 冻结轴系
冻结轴系用于在特定时刻"冻结"某个轴系,之后任何时间获取该轴系的变换都返回冻结时刻的值。
3.1 创建冻结轴系
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/AxesFrozen.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/Rotation.hpp"
#include "AstMath/Matrix.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
// 创建冻结时间和求值时间
TimePoint freezeTime = TimePoint::FromUTC(2026, 1, 1, 0, 0, 0);
TimePoint evalTime1 = TimePoint::FromUTC(2026, 6, 15, 12, 0, 0); // 6个月后
TimePoint evalTime2 = TimePoint::FromUTC(2026, 12, 31, 23, 59, 59); // 1年后
printf("创建冻结轴系示例:\n\n");
// 获取ECF轴系
Axes* ecf = aAxesECF();
Axes* icrf = aAxesICRF();
// 创建冻结轴系:在freezeTime时刻冻结ECF轴系
// referenceAxes指定参考轴系,用于确定变换方向
AxesFrozen* frozenAxes = AxesFrozen::New(ecf, freezeTime, icrf);
printf("冻结时间: 2026-01-01 00:00:00 UTC\n");
printf("ECF轴系: %p\n", (void*)ecf);
printf("参考轴系(ICRF): %p\n", (void*)icrf);
printf("冻结轴系: %p\n", (void*)frozenAxes);
// 获取冻结轴系的属性
printf("\n冻结轴系属性:\n");
printf(" 冻结时间: %.3f JD\n", freezeTime.J2000TT());
printf(" 冻结轴系指针: %p\n", (void*)frozenAxes->getAxes());
printf(" 参考轴系指针: %p\n", (void*)frozenAxes->getReferenceAxes());
// 验证冻结轴系的父轴系是参考轴系
Axes* parent = frozenAxes->getParent();
printf("\n冻结轴系的父轴系: %p (应为ICRF: %p)\n",
(void*)parent, (void*)icrf);
return 0;
}// 创建冻结轴系(使用智能指针避免内存泄漏)
TimePoint freezeTime = TimePoint::FromUTC(2026, 1, 1, 0, 0, 0);
auto frozenAxes = AxesFrozen::MakeShared(ecf, freezeTime, aAxesICRF());3.2 使用冻结轴系
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/AxesFrozen.hpp"
#include "AstCore/TimePoint.hpp"
#include "AstMath/Rotation.hpp"
#include "AstMath/Matrix.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
// 创建冻结时间和求值时间
TimePoint freezeTime = TimePoint::FromUTC(2026, 1, 1, 0, 0, 0);
TimePoint evalTime1 = TimePoint::FromUTC(2026, 6, 15, 12, 0, 0); // 6个月后
TimePoint evalTime2 = TimePoint::FromUTC(2026, 12, 31, 23, 59, 59); // 1年后
printf("使用冻结轴系示例:\n\n");
// 获取轴系
HAxes ecf = aAxesICRF();
HAxes reference = aAxesJ2000();
// 创建冻结轴系(使用智能指针自动管理内存)
HAxesFrozen frozenAxes = AxesFrozen::MakeShared(ecf.get(), freezeTime, reference.get());
printf("冻结时间: 2026-01-01 00:00:00 UTC\n\n");
// 在冻结时刻获取变换
printf("--- 在冻结时刻获取 ---\n");
Rotation rot1;
errc_t err = frozenAxes->getTransformTo(reference.get(), freezeTime, rot1);
if (err != eNoError) {
printf("错误: 获取变换失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat1 = rot1.getMatrix();
printf("变换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat1(i,0), mat1(i,1), mat1(i,2));
}
// 在6个月后获取变换(应该返回冻结时刻的值)
printf("\n--- 在6个月后获取(应该与冻结时刻相同) ---\n");
Rotation rot2;
err = frozenAxes->getTransformTo(reference.get(), evalTime1, rot2);
if (err != eNoError) {
printf("错误: 获取变换失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat2 = rot2.getMatrix();
printf("变换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat2(i,0), mat2(i,1), mat2(i,2));
}
// 在1年后获取变换(也应该与冻结时刻相同)
printf("\n--- 在1年后获取(应该与冻结时刻相同) ---\n");
Rotation rot3;
err = frozenAxes->getTransformTo(reference.get(), evalTime2, rot3);
if (err != eNoError) {
printf("错误: 获取变换失败,错误码: %d\n", (int)err);
return 1;
}
Matrix3d mat3 = rot3.getMatrix();
printf("变换矩阵:\n");
for (int i = 0; i < 3; i++) {
printf(" [%.8f %.8f %.8f]\n", mat3(i,0), mat3(i,1), mat3(i,2));
}
return 0;
}// 任何时刻获取变换都返回冻结时刻的值
Rotation rotation1, rotation2;
frozenAxes->getTransformTo(aAxesICRF(), freezeTime, rotation1); // 冻结时刻
frozenAxes->getTransformTo(aAxesICRF(), otherTime, rotation2); // 其他时刻
// rotation1 和 rotation2 相同4. 轴系层级操作
#include "AstCore/BuiltinAxes.hpp"
#include "AstCore/TimePoint.hpp"
#include <stdio.h>
AST_USING_NAMESPACE
int main()
{
printf("轴系层级操作示例:\n\n");
// 获取各种轴系
Axes* root = aAxesRoot();
Axes* icrf = aAxesICRF();
Axes* ecf = aAxesECF();
Axes* j2000 = aAxesJ2000();
Axes* mod = aAxesMOD();
Axes* tod = aAxesTOD();
Axes* gtod = aAxesGTOD();
// 1. 获取父轴系
printf("--- 获取父轴系 ---\n");
printf("ICRF的父轴系: %p (应为Root: %p)\n",
(void*)icrf->getParent(), (void*)root);
printf("ECF的父轴系: %p (应为ICRF: %p)\n",
(void*)ecf->getParent(), (void*)icrf);
printf("J2000的父轴系: %p (应为ECF: %p)\n",
(void*)j2000->getParent(), (void*)ecf);
printf("MOD的父轴系: %p (应为J2000: %p)\n",
(void*)mod->getParent(), (void*)j2000);
printf("TOD的父轴系: %p (应为MOD: %p)\n",
(void*)tod->getParent(), (void*)mod);
printf("GTOD的父轴系: %p (应为TOD: %p)\n",
(void*)gtod->getParent(), (void*)tod);
// 2. 获取轴系深度
printf("\n--- 轴系深度 ---\n");
printf("Root深度: %d\n", root->getDepth());
printf("ICRF深度: %d\n", icrf->getDepth());
printf("ECF深度: %d\n", ecf->getDepth());
printf("J2000深度: %d\n", j2000->getDepth());
printf("MOD深度: %d\n", mod->getDepth());
printf("TOD深度: %d\n", tod->getDepth());
printf("GTOD深度: %d\n", gtod->getDepth());
// 3. 获取祖先轴系
printf("\n--- 获取祖先轴系 (以GTOD为例) ---\n");
printf("GTOD的第0层祖先(自身): %p (应为GTOD: %p)\n",
(void*)gtod->getAncestor(0), (void*)gtod);
printf("GTOD的第1层祖先: %p (应为TOD: %p)\n",
(void*)gtod->getAncestor(1), (void*)tod);
printf("GTOD的第2层祖先: %p (应为MOD: %p)\n",
(void*)gtod->getAncestor(2), (void*)mod);
printf("GTOD的第3层祖先: %p (应为J2000: %p)\n",
(void*)gtod->getAncestor(3), (void*)j2000);
printf("GTOD的第4层祖先: %p (应为ECF: %p)\n",
(void*)gtod->getAncestor(4), (void*)ecf);
printf("GTOD的第5层祖先: %p (应为ICRF: %p)\n",
(void*)gtod->getAncestor(5), (void*)icrf);
printf("GTOD的第6层祖先: %p (应为Root: %p)\n",
(void*)gtod->getAncestor(6), (void*)root);
// 4. 层级遍历
printf("\n--- 从GTOD向上遍历到Root ---\n");
Axes* current = gtod;
int level = 0;
while (current != nullptr) {
printf("Level %d: %p\n", level, (void*)current);
current = current->getParent();
level++;
}
return 0;
}4.1 获取父轴系
Axes* parent = axes->getParent();4.2 获取轴系深度
int depth = axes->getDepth();4.3 获取祖先轴系
Axes* ancestor = axes->getAncestor(depth);常用轴系说明
| 轴系名称 | 说明 | 父轴系 |
|---|---|---|
| ICRF/J2000 | 国际天球参考系,惯性系 | Root |
| ECF | 地球固连系,地球固定坐标系 | ICRF |
| J2000 | J2000惯性系 | ECF |
| MOD | 瞬时平赤道系,瞬时平赤道和平春分点 | J2000 |
| TOD | 瞬时真赤道系,瞬时真赤道和平春分点 | MOD |
| GTOD | 格林尼治真赤道系,格林尼治子午面和真赤道 | TOD |
文件结构
src/AstCore/Coordinate/Axes/
├── Axes.hpp # 轴系基类定义
├── AxesRoot.hpp/cpp # 根轴系
├── AxesICRF.hpp/cpp # ICRF轴系
├── AxesFrozen.hpp/cpp # 冻结轴系
├── AxesFrozenAtEventTime.hpp/cpp # 事件时间冻结轴系
├── AxesBodyRelated.hpp/cpp # 天体相关轴系基类
├── AxesBodyInertial.hpp/cpp # 天体惯性轴系
├── AxesBodyFixed.hpp/cpp # 天体固连轴系
├── AxesBodyMOD.hpp/cpp # 天体MOD轴系
├── AxesBodyTOD.hpp/cpp # 天体TOD轴系
├── AxesMacro.hpp # 轴系声明宏
├── BuiltinAxes.hpp # 内置轴系声明
├── BuiltinAxes.cpp # 内置轴系实现
└── BuiltinAxesRegistry.hpp/cpp # 内置轴系注册表依赖关系
- AstCore/Object.hpp:对象基类
- AstCore/TimePoint.hpp:时间点定义
- AstMath/Rotation.hpp:旋转变换
- AstMath/KinematicRotation.hpp:运动学旋转
- AstMath/Matrix.hpp:矩阵运算
注意事项
- 线程安全:单例轴系实例是线程安全的,但多个线程同时进行轴系变换计算时需要注意同步
- 时间系统:轴系变换依赖于准确的时间输入,确保使用正确的TimePoint
- 精度考虑:不同轴系之间的变换可能存在微小差异,高精度应用需注意
- 内存管理:建议使用SharedPtr版本(NewShared/MakeShared)简化内存管理,避免内存泄漏