读取行星星历
2026/5/13大约 2 分钟
读取行星星历
概述
SpaceAST库提供了两种方式读取行星星历数据:
- JPL DE系列星历(如DE440、DE441等)
- SPICE SPK星历文件(.bsp格式)
读取JPL DE星历数据
使用JplDe类读取JPL DE系列星历数据文件。
功能特点
- 支持DE系列星历文件
- 支持位置和速度的读取
- 支持章动角和月球天平动相关角度的读取
- 线程安全的数据缓存机制,支持多线程并行读取
使用示例
#include "ast/JplDe.hpp"
#include "ast/TimePoint.hpp"
#include "ast/TimeInterval.hpp"
#include "ast/Vector.hpp"
#include "ast/JulianDate.hpp"
#include "ast/DateTime.hpp"
#include "ast/Euler.hpp"
#include <iostream>
#include <iomanip>
#include <clocale>
AST_USING_NAMESPACE
int main()
{
// 设置UTF-8编码,确保中文正确显示
setlocale(LC_ALL, ".UTF-8");
// 创建JplDe对象
JplDe de;
// 打开DE星历文件(请替换为实际文件路径)
errc_t err = de.open("./data/SolarSystem/plneph.430");
if (err != eNoError) {
std::cerr << "无法打开DE星历文件" << std::endl;
std::cerr << "错误码: " << err << std::endl;
return -1;
}
std::cout << "成功打开DE星历文件" << std::endl;
std::cout << "星历版本: DE" << de.getEphemVersion() << std::endl;
// 获取星历时间区间
TimeInterval interval;
de.getInterval(interval);
std::cout << "星历时间范围: " << std::endl;
std::cout << " 开始时间: " << interval.getStart().toString() << std::endl;
std::cout << " 结束时间: " << interval.getStop().toString() << std::endl;
// 创建一个时间点(J2000.0 UTC时刻)
TimePoint time = TimePoint::FromUTC(2000, 1, 1, 12, 0, 0.0);
// 获取地球相对于太阳系质心的位置和速度
Vector3d pos, vel;
err = de.getPosVelICRF(
time,
JplDe::eEarth,
JplDe::eSSBarycenter,
pos,
vel
);
if (err == eNoError) {
std::cout << "\n2000年1月1日 12:00:00 UTC 时刻:" << std::endl;
std::cout << "地球相对太阳系质心的位置 (m):" << std::endl;
std::cout << " X: " << std::setprecision(6) << pos.x() << std::endl;
std::cout << " Y: " << std::setprecision(6) << pos.y() << std::endl;
std::cout << " Z: " << std::setprecision(6) << pos.z() << std::endl;
std::cout << "地球相对太阳系质心的速度 (m/s):" << std::endl;
std::cout << " Vx: " << std::setprecision(6) << vel.x() << std::endl;
std::cout << " Vy: " << std::setprecision(6) << vel.y() << std::endl;
std::cout << " Vz: " << std::setprecision(6) << vel.z() << std::endl;
} else {
std::cerr << "获取位置速度失败,错误码: " << err << std::endl;
}
// 获取月球相对于地球的位置
err = de.getPosVelICRF(
time,
JplDe::eMoon,
JplDe::eEarth,
pos,
vel
);
if (err == eNoError) {
std::cout << "\n月球相对地球的位置 (m):" << std::endl;
std::cout << " X: " << std::setprecision(6) << pos.x() << std::endl;
std::cout << " Y: " << std::setprecision(6) << pos.y() << std::endl;
std::cout << " Z: " << std::setprecision(6) << pos.z() << std::endl;
// 计算地月距离
double distance = pos.norm();
std::cout << "地月距离: " << std::setprecision(6) << distance << " m" << std::endl;
} else {
std::cerr << "获取月球位置失败,错误码: " << err << std::endl;
}
// 获取章动角
double nutLong, nutObl;
err = de.getNutation(time, nutLong, nutObl);
if (err == eNoError) {
std::cout << "\n章动角 (rad):" << std::endl;
std::cout << " 黄经章动: " << std::setprecision(10) << nutLong << std::endl;
std::cout << " 倾角章动: " << std::setprecision(10) << nutObl << std::endl;
} else {
std::cerr << "获取章动角失败,错误码: " << err << std::endl;
}
// 获取月球天平动相关角度
Euler libration;
err = de.getLibration(time, libration);
if (err == eNoError) {
std::cout << "\n月球天平动相关角度 (rad):" << std::endl;
std::cout << " 进动角 (omega): " << std::setprecision(10) << libration.angle1() << std::endl;
std::cout << " 章动角 (i): " << std::setprecision(10) << libration.angle2() << std::endl;
std::cout << " 自转角 (u): " << std::setprecision(10) << libration.angle3() << std::endl;
} else {
std::cerr << "获取天平动数据失败,错误码: " << err << std::endl;
}
// 关闭星历文件
de.close();
std::cout << "\n示例程序执行完毕" << std::endl;
return 0;
}支持的天体
| 天体 | 枚举值 |
|---|---|
| 水星系质心 | JplDe::eMercury |
| 金星系质心 | JplDe::eVenus |
| 地球 | JplDe::eEarth |
| 火星系质心 | JplDe::eMars |
| 木星系质心 | JplDe::eJupiter |
| 土星系质心 | JplDe::eSaturn |
| 天王星系质心 | JplDe::eUranus |
| 海王星系质心 | JplDe::eNeptune |
| 冥王星系质心 | JplDe::ePluto |
| 月球 | JplDe::eMoon |
| 太阳 | JplDe::eSun |
| 太阳系质心 | JplDe::eSSBarycenter |
| 地月系质心 | JplDe::eEMBarycenter |
读取SPK星历数据
使用SPKParser类读取SPICE SPK星历内核文件。
功能特点
- 支持SPICE SPK格式(.bsp文件)
- 直接从二进制文件读取数据,无需依赖CSPICE库
使用示例
#include "ast/SPKParser.hpp"
#include "ast/Vector.hpp"
#include "ast/JulianDate.hpp"
#include <iostream>
#include <iomanip>
#include <clocale>
AST_USING_NAMESPACE
int main()
{
// 设置UTF-8编码,确保中文正确显示
setlocale(LC_ALL, ".UTF-8");
// 创建SPK解析器对象
SPKParser spkParser;
// 打开SPK星历文件(请替换为实际文件路径)
std::string spkFilePath = "./data/Test/kernels/spk/de430.bsp";
errc_t err = spkParser.parse(spkFilePath);
if (err != eNoError) {
std::cerr << "无法解析SPK星历文件: " << spkFilePath << std::endl;
std::cerr << "错误码: " << err << std::endl;
}
std::cout << "成功打开SPK星历文件" << std::endl;
// 打印文件注释信息
std::cout << "\n=== SPK文件注释 ===" << std::endl;
spkParser.printComment();
// 获取SPK段描述符信息
const auto& descriptors = spkParser.getDescriptors();
std::cout << "\n=== SPK段信息 ===" << std::endl;
std::cout << "段数量: " << descriptors.size() << std::endl;
for (size_t i = 0; i < descriptors.size(); ++i) {
const auto& desc = descriptors[i];
std::cout << "\n段 " << (i + 1) << ":" << std::endl;
std::cout << " 目标体ID: " << desc.target << std::endl;
std::cout << " 中心体ID: " << desc.center << std::endl;
std::cout << " 参考系ID: " << desc.frame << std::endl;
std::cout << " 数据类型: " << desc.type << std::endl;
std::cout << " 时间范围: " << desc.start_time << " 至 " << desc.end_time << " (ET秒)" << std::endl;
}
// 使用J2000.0 TDB时刻(ET=0)作为示例时间
double et = 0.0; // J2000.0 TDB时刻,即2000年1月1日12:00:00 TDB
// 定义一些常用的NAIF天体ID
const int SUN_ID = 10;
const int EARTH_ID = 399;
const int MOON_ID = 301;
const int MARS_BARYCENTER_ID = 4; // 火星系质心ID
// 获取地球的位置和速度(相对于地月系质心)
Vector3d pos, vel;
err = spkParser.getPosVelNative(et, EARTH_ID, pos, vel);
if (err == eNoError) {
std::cout << "\n=== J2000.0时刻地球状态(相对于地月系质心) ===" << std::endl;
std::cout << "位置 (m):" << std::endl;
std::cout << " X: " << std::setprecision(8) << pos.x() << std::endl;
std::cout << " Y: " << std::setprecision(8) << pos.y() << std::endl;
std::cout << " Z: " << std::setprecision(8) << pos.z() << std::endl;
std::cout << "速度 (m/s):" << std::endl;
std::cout << " Vx: " << std::setprecision(6) << vel.x() << std::endl;
std::cout << " Vy: " << std::setprecision(6) << vel.y() << std::endl;
std::cout << " Vz: " << std::setprecision(6) << vel.z() << std::endl;
// 计算距离和速度大小
double distance = pos.norm() / 1000.0; // 转换为km
double speed = vel.norm(); // m/s
std::cout << "距地月系质心距离: " << std::setprecision(6) << distance << " km" << std::endl;
std::cout << "速度大小: " << std::setprecision(4) << speed << " m/s" << std::endl;
} else {
std::cerr << "获取地球状态失败,错误码: " << err << std::endl;
}
// 获取火星系质心的位置(相对于太阳系质心)
err = spkParser.getPosNative(et, MARS_BARYCENTER_ID, pos);
if (err == eNoError) {
std::cout << "\n=== J2000.0 TDB时刻火星系质心位置(相对于太阳系质心) ===" << std::endl;
std::cout << "位置 (m):" << std::endl;
std::cout << " X: " << std::setprecision(8) << pos.x() << std::endl;
std::cout << " Y: " << std::setprecision(8) << pos.y() << std::endl;
std::cout << " Z: " << std::setprecision(8) << pos.z() << std::endl;
} else {
std::cerr << "获取火星系质心位置失败,错误码: " << err << std::endl;
}
// 查找特定目标和时间的SPK段描述符
const SPK_Descriptor* desc = spkParser.findSpkDescriptor(EARTH_ID, et);
if (desc != nullptr) {
std::cout << "\n=== 地球在ET=" << et << "的SPK段信息 ===" << std::endl;
std::cout << "目标体ID: " << desc->target << std::endl;
std::cout << "中心体ID: " << desc->center << std::endl;
std::cout << "参考系ID: " << desc->frame << std::endl;
std::cout << "数据类型: " << desc->type << std::endl;
} else {
std::cout << "\n未找到地球在ET=" << et << "的SPK段" << std::endl;
}
std::cout << "\n示例程序执行完毕" << std::endl;
}NAIF天体ID
SPK文件使用NAIF ID标识天体:
- 0: 太阳系质心
- 1: 水星系质心
- 2: 金星系质心
- 3: 地月系质心
- 4: 火星系质心
- 5: 木星系质心
- 6: 土星系质心
- 7: 天王星系质心
- 8: 海王星系质心
- 9: 冥王星系质心
- 10: 太阳
- 199: 水星
- 299: 金星
- 399: 地球
- 301: 月球
- 499: 火星
- 599: 木星
- 699: 土星
- 799: 天王星
- 899: 海王星
- 999: 冥王星
注意事项
- SPK文件可以从NAIF获取
- 目前仅支持部分SPK数据类型
- 返回的SPK星历数据为原始坐标,未进行任何坐标系转换。请查阅所用星历文件的文档,确认数据所在的参考系
- 如果需要在多线程环境中使用,每个线程都需要创建一个SPKParser实例