TLE转换为轨道六根数(开普勒根数)的C++实现
·
1. 头文件和数据结构定义
1.1 头文件定义 (tle2kepler.h)
#ifndef TLE2KEPLER_H
#define TLE2KEPLER_H
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <sstream>
#include <iomanip>
#include <stdexcept>
// 数学常数定义
const double PI = 3.14159265358979323846;
const double TWO_PI = 2.0 * PI;
const double DEG_TO_RAD = PI / 180.0;
const double RAD_TO_DEG = 180.0 / PI;
const double MU = 398600.4418; // 地球引力常数 (km^3/s^2)
const double J2 = 1.08262668e-3; // 地球扁率J2项
const double EARTH_RADIUS = 6378.137; // 地球赤道半径 (km)
const double OMEGA_EARTH = 7.2921151467e-5; // 地球自转角速度 (rad/s)
// 轨道六根数结构体
struct KeplerElements {
double semi_major_axis; // 半长轴 a (km)
double eccentricity; // 偏心率 e
double inclination; // 轨道倾角 i (度)
double raan; // 升交点赤经 Ω (度)
double argument_of_perigee; // 近地点幅角 ω (度)
double true_anomaly; // 真近点角 ν (度)
double mean_anomaly; // 平近点角 M (度)
double epoch; // 历元 (儒略日)
// 辅助参数
double mean_motion; // 平均运动 (rev/day)
double bstar; // 阻力系数
int revolution_number; // 在轨圈数
int satellite_catalog_number; // 卫星目录号
};
// TLE两行元素结构体
struct TLE {
std::string line1;
std::string line2;
std::string name; // 卫星名称
// 解析后的数据
int satellite_number; // 卫星编号
char classification; // 分类等级
int launch_year; // 发射年份
int launch_number; // 发射序号
std::string launch_piece; // 发射碎片编号
int epoch_year; // 历元年
double epoch_day; // 历元日
double mean_motion_dot; // 平均运动一阶导数
double mean_motion_ddot; // 平均运动二阶导数
double bstar_drag; // BSTAR阻力系数
int ephemeris_type; // 星历类型
int element_number; // 元素编号
double inclination; // 轨道倾角 (度)
double raan; // 升交点赤经 (度)
double eccentricity; // 偏心率
double argument_of_perigee; // 近地点幅角 (度)
double mean_anomaly; // 平近点角 (度)
double mean_motion; // 平均运动 (rev/day)
int revolution_number; // 在轨圈数
};
// 主转换类
class TLE2Kepler {
private:
// 内部转换函数
static double calculateSemiMajorAxis(double mean_motion);
static double meanToTrueAnomaly(double mean_anomaly, double eccentricity);
static double eccentricToTrueAnomaly(double eccentric_anomaly, double eccentricity);
static double solveKeplerEquation(double mean_anomaly, double eccentricity);
// 解析辅助函数
static double parseFloat(const std::string& str, int start, int length,
double defaultValue = 0.0, double scale = 1.0);
static int parseInt(const std::string& str, int start, int length,
int defaultValue = 0);
public:
// 解析TLE字符串
static bool parseTLE(const std::string& tleLine1,
const std::string& tleLine2,
TLE& tleData);
static bool parseTLE(const std::string& tleName,
const std::string& tleLine1,
const std::string& tleLine2,
TLE& tleData);
// 从TLE计算开普勒根数
static KeplerElements convertTLEtoKepler(const TLE& tleData);
// 从TLE字符串直接计算
static KeplerElements convertTLEtoKepler(const std::string& line1,
const std::string& line2);
// 验证TLE格式
static bool validateTLE(const std::string& line1, const std::string& line2);
// 计算平均运动
static double calculateMeanMotion(double semi_major_axis);
// 轨道周期计算
static double calculateOrbitalPeriod(double semi_major_axis);
// 从平均运动计算半长轴
static double meanMotionToSemiMajorAxis(double mean_motion);
// 输出格式化
static void printKeplerElements(const KeplerElements& kepler);
static void printTLEData(const TLE& tle);
// 坐标转换工具函数
static void keplerToECI(const KeplerElements& kepler, double time,
double& x, double& y, double& z,
double& vx, double& vy, double& vz);
};
2. TLE解析实现
2.1 TLE解析实现 (tle2kepler.cpp)
#include "tle2kepler.h"
// 解析浮点数
double TLE2Kepler::parseFloat(const std::string& str, int start, int length,
double defaultValue, double scale) {
if (start < 0 || start + length > static_cast<int>(str.length())) {
return defaultValue;
}
std::string sub = str.substr(start, length);
// 去除前导空格
size_t pos = sub.find_first_not_of(' ');
if (pos == std::string::npos) {
return defaultValue;
}
sub = sub.substr(pos);
// 检查是否为空
if (sub.empty()) {
return defaultValue;
}
// 处理指数表示
size_t e_pos = sub.find('-', 1);
if (e_pos != std::string::npos && e_pos > 0 &&
sub[e_pos-1] != 'E' && sub[e_pos-1] != 'e') {
sub.insert(e_pos, "E");
}
try {
double value = std::stod(sub) * scale;
return value;
} catch (const std::exception&) {
return defaultValue;
}
}
// 解析整数
int TLE2Kepler::parseInt(const std::string& str, int start, int length,
int defaultValue) {
if (start < 0 || start + length > static_cast<int>(str.length())) {
return defaultValue;
}
std::string sub = str.substr(start, length);
// 去除前导空格
size_t pos = sub.find_first_not_of(' ');
if (pos == std::string::npos) {
return defaultValue;
}
sub = sub.substr(pos);
try {
return std::stoi(sub);
} catch (const std::exception&) {
return defaultValue;
}
}
// 解析TLE
bool TLE2Kepler::parseTLE(const std::string& tleLine1,
const std::string& tleLine2,
TLE& tleData) {
return parseTLE("", tleLine1, tleLine2, tleData);
}
bool TLE2Kepler::parseTLE(const std::string& tleName,
const std::string& tleLine1,
const std::string& tleLine2,
TLE& tleData) {
// 验证行长度
if (tleLine1.length() < 69 || tleLine2.length() < 69) {
std::cerr << "Error: TLE lines are too short" << std::endl;
return false;
}
tleData.name = tleName;
tleData.line1 = tleLine1;
tleData.line2 = tleLine2;
// 解析第一行
tleData.satellite_number = parseInt(tleLine1, 2, 5);
tleData.classification = tleLine1[7];
tleData.launch_year = parseInt(tleLine1, 9, 2);
tleData.launch_number = parseInt(tleLine1, 11, 3);
// 发射碎片编号
std::string launch_piece_str = tleLine1.substr(14, 3);
size_t pos = launch_piece_str.find_last_not_of(' ');
tleData.launch_piece = (pos != std::string::npos) ?
launch_piece_str.substr(0, pos + 1) : "";
// 历元年份
tleData.epoch_year = parseInt(tleLine1, 18, 2);
tleData.epoch_day = parseFloat(tleLine1, 20, 12);
// 平均运动一阶导数
tleData.mean_motion_dot = parseFloat(tleLine1, 33, 10, 0.0, 2.0);
// 平均运动二阶导数
std::string mdd_str = tleLine1.substr(44, 6);
double mdd_value = parseFloat(tleLine1, 44, 6, 0.0, 1.0);
// 检查指数
std::string exp_str = tleLine1.substr(50, 2);
int exponent = parseInt(exp_str, 0, 2, 0);
if (mdd_str[0] == '-') {
tleData.mean_motion_ddot = -mdd_value * std::pow(10.0, exponent);
} else {
tleData.mean_motion_ddot = mdd_value * std::pow(10.0, exponent);
}
// BSTAR阻力系数
std::string bstar_str = tleLine1.substr(53, 6);
double bstar_value = parseFloat(tleLine1, 53, 6, 0.0, 1.0);
std::string bstar_exp_str = tleLine1.substr(59, 2);
int bstar_exponent = parseInt(bstar_exp_str, 0, 2, 0);
if (bstar_str[0] == '-') {
tleData.bstar_drag = -bstar_value * std::pow(10.0, bstar_exponent);
} else {
tleData.bstar_drag = bstar_value * std::pow(10.0, bstar_exponent);
}
tleData.ephemeris_type = parseInt(tleLine1, 62, 1);
tleData.element_number = parseInt(tleLine1, 64, 4);
// 解析第二行
tleData.inclination = parseFloat(tleLine2, 8, 8);
tleData.raan = parseFloat(tleLine2, 17, 8);
// 偏心率(需要除以10000000)
tleData.eccentricity = parseFloat(tleLine2, 26, 7, 0.0, 1e-7);
tleData.argument_of_perigee = parseFloat(tleLine2, 34, 8);
tleData.mean_anomaly = parseFloat(tleLine2, 43, 8);
tleData.mean_motion = parseFloat(tleLine2, 52, 11);
tleData.revolution_number = parseInt(tleLine2, 63, 5);
return true;
}
// 验证TLE格式
bool TLE2Kepler::validateTLE(const std::string& line1, const std::string& line2) {
if (line1.length() < 69 || line2.length() < 69) {
return false;
}
if (line1[0] != '1' || line2[0] != '2') {
return false;
}
// 验证校验和
auto calculateChecksum = const std::string& line -> int {
int sum = 0;
for (size_t i = 0; i < 68; i++) {
char c = line[i];
if (c >= '0' && c <= '9') {
sum += (c - '0');
} else if (c == '-') {
sum += 1;
}
}
return sum % 10;
};
int checksum1 = parseInt(line1, 68, 1);
int checksum2 = parseInt(line2, 68, 1);
if (calculateChecksum(line1) != checksum1) {
std::cerr << "Warning: Line 1 checksum mismatch" << std::endl;
}
if (calculateChecksum(line2) != checksum2) {
std::cerr << "Warning: Line 2 checksum mismatch" << std::endl;
}
return true;
}
3. 开普勒方程求解
3.1 开普勒方程求解 (kepler_solver.cpp)
#include "tle2kepler.h"
// 求解开普勒方程 M = E - e*sin(E)
double TLE2Kepler::solveKeplerEquation(double mean_anomaly, double eccentricity) {
// 转换为弧度
double M = mean_anomaly * DEG_TO_RAD;
double e = eccentricity;
if (e < 0.0 || e >= 1.0) {
return M; // 无效偏心率,返回平近点角
}
// 初始猜测:E = M
double E = M;
// 牛顿-拉夫森迭代
double tolerance = 1e-12;
int max_iterations = 50;
for (int i = 0; i < max_iterations; i++) {
double f = E - e * sin(E) - M;
double f_prime = 1.0 - e * cos(E);
if (std::abs(f_prime) < 1e-12) {
break; // 避免除零
}
double delta = f / f_prime;
E -= delta;
if (std::abs(delta) < tolerance) {
break;
}
}
return E; // 返回偏近点角(弧度)
}
// 从平近点角计算真近点角
double TLE2Kepler::meanToTrueAnomaly(double mean_anomaly, double eccentricity) {
if (eccentricity < 0.0 || eccentricity >= 1.0) {
return mean_anomaly; // 无效偏心率
}
// 求解开普勒方程得到偏近点角
double E = solveKeplerEquation(mean_anomaly, eccentricity);
// 从偏近点角计算真近点角
return eccentricToTrueAnomaly(E, eccentricity);
}
// 从偏近点角计算真近点角
double TLE2Kepler::eccentricToTrueAnomaly(double eccentric_anomaly, double eccentricity) {
if (eccentricity < 0.0 || eccentricity >= 1.0) {
return eccentric_anomaly * RAD_TO_DEG;
}
double e = eccentricity;
double E = eccentric_anomaly;
// 计算真近点角
double sinE = sin(E);
double cosE = cos(E);
double sin_nu = sqrt(1.0 - e*e) * sinE / (1.0 - e * cosE);
double cos_nu = (cosE - e) / (1.0 - e * cosE);
double nu = atan2(sin_nu, cos_nu);
// 确保角度在[0, 2π)范围内
if (nu < 0.0) {
nu += TWO_PI;
}
return nu * RAD_TO_DEG; // 转换为度
}
4. 轨道参数计算
4.1 轨道参数计算 (orbital_calculations.cpp)
#include "tle2kepler.h"
// 从平均运动计算半长轴
double TLE2Kepler::calculateSemiMajorAxis(double mean_motion) {
if (mean_motion <= 0.0) {
return 0.0;
}
// 平均运动单位:转/天,需要转换为弧度/秒
double n = mean_motion * TWO_PI / 86400.0; // 弧度/秒
// 开普勒第三定律: a^3 = μ / n^2
double a = std::pow(MU / (n * n), 1.0/3.0);
return a;
}
// 从平均运动计算半长轴(另一种方法)
double TLE2Kepler::meanMotionToSemiMajorAxis(double mean_motion) {
if (mean_motion <= 0.0) {
return 0.0;
}
// 更精确的考虑地球扁率的公式
double n = mean_motion * TWO_PI / 86400.0; // 转换为弧度/秒
// 考虑J2项的一阶近似
double a0 = std::pow(MU / (n * n), 1.0/3.0);
// 迭代求解考虑J2影响的半长轴
double a = a0;
double tolerance = 1e-6;
int max_iterations = 10;
for (int i = 0; i < max_iterations; i++) {
double p = a * (1.0 - 0.0); // 简化,假设偏心率为0
double n0 = sqrt(MU / (a * a * a));
// J2项修正
double delta_n = 1.5 * J2 * (EARTH_RADIUS * EARTH_RADIUS) * n0 *
(1.0 - 0.0 * 0.0) / (p * p); // 简化倾角
double n_corrected = n0 + delta_n;
double a_new = std::pow(MU / (n_corrected * n_corrected), 1.0/3.0);
if (std::abs(a_new - a) < tolerance) {
a = a_new;
break;
}
a = a_new;
}
return a;
}
// 计算平均运动
double TLE2Kepler::calculateMeanMotion(double semi_major_axis) {
if (semi_major_axis <= 0.0) {
return 0.0;
}
double n = sqrt(MU / (semi_major_axis * semi_major_axis * semi_major_axis));
// 转换为转/天
return n * 86400.0 / TWO_PI;
}
// 计算轨道周期
double TLE2Kepler::calculateOrbitalPeriod(double semi_major_axis) {
if (semi_major_axis <= 0.0) {
return 0.0;
}
double period = TWO_PI * sqrt(semi_major_axis * semi_major_axis * semi_major_axis / MU);
return period; // 秒
}
5. 主转换函数
5.1 转换函数实现 (conversion.cpp)
#include "tle2kepler.h"
// 主转换函数:从TLE到开普勒根数
KeplerElements TLE2Kepler::convertTLEtoKepler(const TLE& tleData) {
KeplerElements kepler;
// 基本参数
kepler.satellite_catalog_number = tleData.satellite_number;
kepler.mean_motion = tleData.mean_motion;
kepler.inclination = tleData.inclination;
kepler.raan = tleData.raan;
kepler.eccentricity = tleData.eccentricity;
kepler.argument_of_perigee = tleData.argument_of_perigee;
kepler.mean_anomaly = tleData.mean_anomaly;
kepler.revolution_number = tleData.revolution_number;
kepler.bstar = tleData.bstar_drag;
// 计算历元(儒略日简化计算)
int year = tleData.epoch_year;
if (year < 57) { // 1957-2056
year += 2000;
} else {
year += 1900;
}
// 简化计算:年份 + 年积日
kepler.epoch = static_cast<double>(year) + tleData.epoch_day;
// 计算半长轴
kepler.semi_major_axis = calculateSemiMajorAxis(tleData.mean_motion);
// 计算真近点角
kepler.true_anomaly = meanToTrueAnomaly(tleData.mean_anomaly, tleData.eccentricity);
return kepler;
}
// 直接从TLE字符串转换
KeplerElements TLE2Kepler::convertTLEtoKepler(const std::string& line1,
const std::string& line2) {
TLE tleData;
if (!parseTLE(line1, line2, tleData)) {
throw std::runtime_error("Failed to parse TLE");
}
return convertTLEtoKepler(tleData);
}
6. 坐标转换和输出
6.1 坐标转换 (coordinate_conversion.cpp)
#include "tle2kepler.h"
// 开普勒根数转地心惯性坐标系(简化版本)
void TLE2Kepler::keplerToECI(const KeplerElements& kepler, double time,
double& x, double& y, double& z,
double& vx, double& vy, double& vz) {
// 提取开普勒根数
double a = kepler.semi_major_axis;
double e = kepler.eccentricity;
double i = kepler.inclination * DEG_TO_RAD;
double Omega = kepler.raan * DEG_TO_RAD;
double omega = kepler.argument_of_perigee * DEG_TO_RAD;
double nu = kepler.true_anomaly * DEG_TO_RAD;
// 计算参数
double p = a * (1.0 - e * e); // 半通径
if (p <= 0.0) {
x = y = z = vx = vy = vz = 0.0;
return;
}
// 计算位置在轨道平面内的坐标
double r = p / (1.0 + e * cos(nu));
double xp = r * cos(nu);
double yp = r * sin(nu);
// 计算速度在轨道平面内的分量
double mu = MU;
double h = sqrt(mu * p);
double vxp = -mu / h * sin(nu);
double vyp = mu / h * (e + cos(nu));
// 旋转矩阵
double cos_omega = cos(omega);
double sin_omega = sin(omega);
double cos_Omega = cos(Omega);
double sin_Omega = sin(Omega);
double cos_i = cos(i);
double sin_i = sin(i);
// 位置坐标转换
x = (cos_omega * cos_Omega - sin_omega * sin_Omega * cos_i) * xp +
(-sin_omega * cos_Omega - cos_omega * sin_Omega * cos_i) * yp;
y = (cos_omega * sin_Omega + sin_omega * cos_Omega * cos_i) * xp +
(-sin_omega * sin_Omega + cos_omega * cos_Omega * cos_i) * yp;
z = (sin_omega * sin_i) * xp + (cos_omega * sin_i) * yp;
// 速度坐标转换
vx = (cos_omega * cos_Omega - sin_omega * sin_Omega * cos_i) * vxp +
(-sin_omega * cos_Omega - cos_omega * sin_Omega * cos_i) * vyp;
vy = (cos_omega * sin_Omega + sin_omega * cos_Omega * cos_i) * vxp +
(-sin_omega * sin_Omega + cos_omega * cos_Omega * cos_i) * vyp;
vz = (sin_omega * sin_i) * vxp + (cos_omega * sin_i) * vyp;
}
6.2 输出格式化 (output_formatter.cpp)
#include "tle2kepler.h"
// 输出开普勒根数
void TLE2Kepler::printKeplerElements(const KeplerElements& kepler) {
std::cout << std::fixed << std::setprecision(6);
std::cout << "\n========== Kepler Orbital Elements ==========\n";
std::cout << "Satellite Catalog Number: " << kepler.satellite_catalog_number << "\n";
std::cout << "Epoch: " << kepler.epoch << " (simplified JD)\n";
std::cout << "Semi-major axis (a): " << kepler.semi_major_axis << " km\n";
std::cout << "Eccentricity (e): " << kepler.eccentricity << "\n";
std::cout << "Inclination (i): " << kepler.inclination << " deg\n";
std::cout << "Right Ascension of Ascending Node (Ω): " << kepler.raan << " deg\n";
std::cout << "Argument of Perigee (ω): " << kepler.argument_of_perigee << " deg\n";
std::cout << "True Anomaly (ν): " << kepler.true_anomaly << " deg\n";
std::cout << "Mean Anomaly (M): " << kepler.mean_anomaly << " deg\n";
std::cout << "Mean Motion: " << kepler.mean_motion << " rev/day\n";
std::cout << "BSTAR Drag Coefficient: " << kepler.bstar << "\n";
std::cout << "Revolution Number: " << kepler.revolution_number << "\n";
// 计算并显示轨道周期
double period = calculateOrbitalPeriod(kepler.semi_major_axis);
double period_min = period / 60.0;
std::cout << "Orbital Period: " << period << " s (" << period_min << " min)\n";
// 计算轨道高度
double perigee = kepler.semi_major_axis * (1.0 - kepler.eccentricity) - EARTH_RADIUS;
double apogee = kepler.semi_major_axis * (1.0 + kepler.eccentricity) - EARTH_RADIUS;
std::cout << "Perigee Height: " << perigee << " km\n";
std::cout << "Apogee Height: " << apogee << " km\n";
std::cout << "==============================================\n";
}
// 输出TLE数据
void TLE2Kepler::printTLEData(const TLE& tle) {
std::cout << std::fixed << std::setprecision(8);
std::cout << "\n========== Parsed TLE Data ==========\n";
if (!tle.name.empty()) {
std::cout << "Satellite Name: " << tle.name << "\n";
}
std::cout << "Satellite Number: " << tle.satellite_number << "\n";
std::cout << "Classification: " << tle.classification << "\n";
std::cout << "Launch Year: " << tle.launch_year << "\n";
std::cout << "Launch Number: " << tle.launch_number << "\n";
std::cout << "Launch Piece: " << tle.launch_piece << "\n";
std::cout << "Epoch Year: " << tle.epoch_year << "\n";
std::cout << "Epoch Day: " << tle.epoch_day << "\n";
std::cout << "Mean Motion (n): " << tle.mean_motion << " rev/day\n";
std::cout << "Mean Motion First Derivative (n'): " << tle.mean_motion_dot << "\n";
std::cout << "Mean Motion Second Derivative (n''): " << tle.mean_motion_ddot << "\n";
std::cout << "BSTAR Drag: " << tle.bstar_drag << "\n";
std::cout << "Inclination (i): " << tle.inclination << " deg\n";
std::cout << "RAAN (Ω): " << tle.raan << " deg\n";
std::cout << "Eccentricity (e): " << tle.eccentricity << "\n";
std::cout << "Argument of Perigee (ω): " << tle.argument_of_perigee << " deg\n";
std::cout << "Mean Anomaly (M): " << tle.mean_anomaly << " deg\n";
std::cout << "Revolution Number: " << tle.revolution_number << "\n";
std::cout << "======================================\n";
}
参考代码 tle转换为六根数的c++源代码 www.youwenfan.com/contentcsv/71159.html
7. 实用工具函数
7.1 儒略日计算 (julian_date.cpp)
#include "tle2kepler.h"
// 儒略日计算工具
class JulianDate {
public:
// 计算儒略日
static double toJulian(int year, int month, int day,
int hour = 0, int minute = 0,
double second = 0.0) {
if (month <= 2) {
year -= 1;
month += 12;
}
int A = year / 100;
int B = 2 - A + A / 4;
double JD = static_cast<int>(365.25 * (year + 4716)) +
static_cast<int>(30.6001 * (month + 1)) +
day + B - 1524.5;
// 添加时间
double time = hour + minute / 60.0 + second / 3600.0;
JD += time / 24.0;
return JD;
}
// 从儒略日计算年月日
static void fromJulian(double JD, int& year, int& month, int& day,
int& hour, int& minute, double& second) {
JD += 0.5;
int Z = static_cast<int>(JD);
double F = JD - Z;
int A = 0;
if (Z < 2299161) {
A = Z;
} else {
int alpha = static_cast<int>((Z - 1867216.25) / 36524.25);
A = Z + 1 + alpha - alpha / 4;
}
int B = A + 1524;
int C = static_cast<int>((B - 122.1) / 365.25);
int D = static_cast<int>(365.25 * C);
int E = static_cast<int>((B - D) / 30.6001);
day = B - D - static_cast<int>(30.6001 * E);
month = (E < 14) ? E - 1 : E - 13;
year = (month > 2) ? C - 4716 : C - 4715;
// 计算时间
double time = F * 24.0;
hour = static_cast<int>(time);
time = (time - hour) * 60.0;
minute = static_cast<int>(time);
second = (time - minute) * 60.0;
}
};
8. 示例和使用程序
8.1 主程序示例 (main.cpp)
#include "tle2kepler.h"
#include <fstream>
#include <vector>
// 示例TLE数据
const std::string EXAMPLE_TLE_NAME = "ISS (ZARYA)";
const std::string EXAMPLE_TLE_LINE1 = "1 25544U 98067A 22001.00000000 .00000000 00000-0 00000-0 0 9999";
const std::string EXAMPLE_TLE_LINE2 = "2 25544 51.6416 33.2520 0006926 359.9521 71.0405 15.49764999300001";
// 国际空间站TLE
const std::string ISS_TLE_NAME = "ISS (ZARYA)";
const std::string ISS_TLE_LINE1 = "1 25544U 98067A 22001.00000000 .00000000 00000-0 00000-0 0 9999";
const std::string ISS_TLE_LINE2 = "2 25544 51.6416 33.2520 0006926 359.9521 71.0405 15.49764999300001";
// GPS卫星TLE
const std::string GPS_TLE_NAME = "GPS BIIR-2 (PRN 13)";
const std::string GPS_TLE_LINE1 = "1 24876U 97035A 22001.00000000 .00000000 00000-0 00000-0 0 9999";
const std::string GPS_TLE_LINE2 = "2 24876 55.8093 266.9644 0190932 272.4905 85.8105 2.00562541123456";
// 测试函数
void testTLEConversion() {
std::cout << "Testing TLE to Kepler Elements Conversion\n";
std::cout << "=========================================\n";
// 测试ISS
std::cout << "\n1. International Space Station (ISS)\n";
TLE issTLE;
TLE2Kepler::parseTLE(ISS_TLE_NAME, ISS_TLE_LINE1, ISS_TLE_LINE2, issTLE);
TLE2Kepler::printTLEData(issTLE);
KeplerElements issKepler = TLE2Kepler::convertTLEtoKepler(issTLE);
TLE2Kepler::printKeplerElements(issKepler);
// 测试GPS卫星
std::cout << "\n2. GPS Satellite\n";
TLE gpsTLE;
TLE2Kepler::parseTLE(GPS_TLE_NAME, GPS_TLE_LINE1, GPS_TLE_LINE2, gpsTLE);
TLE2Kepler::printTLEData(gpsTLE);
KeplerElements gpsKepler = TLE2Kepler::convertTLEtoKepler(gpsTLE);
TLE2Kepler::printKeplerElements(gpsKepler);
// 测试开普勒方程
std::cout << "\n3. Testing Kepler Equation Solver\n";
double test_mean_anomaly = 180.0; // 度
double test_eccentricity = 0.1;
double true_anomaly = TLE2Kepler::meanToTrueAnomaly(test_mean_anomaly, test_eccentricity);
std::cout << "Mean Anomaly: " << test_mean_anomaly << " deg\n";
std::cout << "Eccentricity: " << test_eccentricity << "\n";
std::cout << "True Anomaly: " << true_anomaly << " deg\n";
// 测试半长轴计算
std::cout << "\n4. Testing Semi-major Axis Calculation\n";
double test_mean_motion = 15.0; // rev/day
double semi_major_axis = TLE2Kepler::calculateSemiMajorAxis(test_mean_motion);
double orbital_period = TLE2Kepler::calculateOrbitalPeriod(semi_major_axis);
std::cout << "Mean Motion: " << test_mean_motion << " rev/day\n";
std::cout << "Semi-major Axis: " << semi_major_axis << " km\n";
std::cout << "Orbital Period: " << orbital_period << " s ("
<< orbital_period/60.0 << " min)\n";
}
// 从文件读取TLE
std::vector<TLE> readTLEFile(const std::string& filename) {
std::vector<TLE> tle_list;
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "Error: Could not open file " << filename << std::endl;
return tle_list;
}
std::string line;
std::string name, line1, line2;
while (std::getline(file, line)) {
if (line.empty()) continue;
if (line[0] == '1' && line.length() > 10) {
line1 = line;
} else if (line[0] == '2' && line.length() > 10) {
line2 = line;
if (!line1.empty()) {
TLE tle;
TLE2Kepler::parseTLE(name, line1, line2, tle);
tle_list.push_back(tle);
// 重置
name.clear();
line1.clear();
line2.clear();
}
} else {
// 这可能是卫星名称行
name = line;
}
}
file.close();
return tle_list;
}
// 批量转换
void batchConversion(const std::string& filename) {
std::vector<TLE> tle_list = readTLEFile(filename);
std::cout << "\nBatch Conversion Results\n";
std::cout << "=======================\n";
std::cout << "Found " << tle_list.size() << " TLEs in file.\n\n";
for (size_t i = 0; i < tle_list.size(); i++) {
const TLE& tle = tle_list[i];
std::cout << "\n[" << (i+1) << "] " << tle.name << "\n";
try {
KeplerElements kepler = TLE2Kepler::convertTLEtoKepler(tle);
std::cout << " Semi-major axis: " << kepler.semi_major_axis << " km\n";
std::cout << " Eccentricity: " << kepler.eccentricity << "\n";
std::cout << " Inclination: " << kepler.inclination << " deg\n";
std::cout << " Type: ";
// 判断轨道类型
double perigee = kepler.semi_major_axis * (1.0 - kepler.eccentricity) - EARTH_RADIUS;
if (perigee < 2000) {
std::cout << "LEO (Low Earth Orbit)";
} else if (perigee < 35786) {
std::cout << "MEO (Medium Earth Orbit)";
} else if (fabs(kepler.inclination) < 1.0) {
std::cout << "GEO (Geostationary Orbit)";
} else {
std::cout << "HEO (High Earth Orbit)";
}
std::cout << "\n";
} catch (const std::exception& e) {
std::cout << " Error: " << e.what() << "\n";
}
}
}
// 交互式程序
void interactiveProgram() {
std::cout << "TLE to Kepler Elements Converter\n";
std::cout << "================================\n";
while (true) {
std::cout << "\nOptions:\n";
std::cout << "1. Convert TLE from file\n";
std::cout << "2. Enter TLE manually\n";
std::cout << "3. Run example conversions\n";
std::cout << "4. Exit\n";
std::cout << "Select option: ";
int choice;
std::cin >> choice;
std::cin.ignore(); // 清除换行符
switch (choice) {
case 1: {
std::cout << "Enter filename: ";
std::string filename;
std::getline(std::cin, filename);
batchConversion(filename);
break;
}
case 2: {
std::string name, line1, line2;
std::cout << "Enter satellite name (optional): ";
std::getline(std::cin, name);
std::cout << "Enter TLE line 1: ";
std::getline(std::cin, line1);
std::cout << "Enter TLE line 2: ";
std::getline(std::cin, line2);
if (TLE2Kepler::validateTLE(line1, line2)) {
try {
TLE tle;
TLE2Kepler::parseTLE(name, line1, line2, tle);
TLE2Kepler::printTLEData(tle);
KeplerElements kepler = TLE2Kepler::convertTLEtoKepler(tle);
TLE2Kepler::printKeplerElements(kepler);
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << "\n";
}
} else {
std::cout << "Invalid TLE format\n";
}
break;
}
case 3:
testTLEConversion();
break;
case 4:
std::cout << "Goodbye!\n";
return;
default:
std::cout << "Invalid choice. Please try again.\n";
}
}
}
int main(int argc, char* argv[]) {
if (argc > 1) {
// 命令行模式
std::string filename = argv[1];
batchConversion(filename);
} else {
// 交互模式
interactiveProgram();
}
return 0;
}
9. CMake配置文件
cmake_minimum_required(VERSION 3.10)
project(TLE2Kepler)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置编译器选项
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3 -Wall)
else()
add_compile_options(-O0 -g -Wall)
endif()
# 源文件列表
set(SOURCES
src/tle2kepler.cpp
src/kepler_solver.cpp
src/orbital_calculations.cpp
src/conversion.cpp
src/coordinate_conversion.cpp
src/output_formatter.cpp
src/julian_date.cpp
src/main.cpp
)
# 头文件
set(HEADERS
include/tle2kepler.h
)
# 可执行文件
add_executable(tle2kepler ${SOURCES} ${HEADERS})
# 安装目标
install(TARGETS tle2kepler DESTINATION bin)
install(FILES ${HEADERS} DESTINATION include/tle2kepler)
10. 使用示例和测试数据
10.1 示例TLE文件 (sample.tle)
ISS (ZARYA)
1 25544U 98067A 22001.00000000 .00000000 00000-0 00000-0 0 9999
2 25544 51.6416 33.2520 0006926 359.9521 71.0405 15.49764999300001
GPS BIIR-2 (PRN 13)
1 24876U 97035A 22001.00000000 .00000000 00000-0 00000-0 0 9999
2 24876 55.8093 266.9644 0190932 272.4905 85.8105 2.00562541123456
NOAA 19
1 33591U 09005A 22001.00000000 .00000000 00000-0 00000-0 0 9999
2 33591 99.1762 100.5563 0014088 108.9315 251.3132 14.12404331745634
HST
1 20580U 90037B 22001.00000000 .00000000 00000-0 00000-0 0 9999
2 20580 28.4693 284.8043 0002817 299.7637 123.0579 15.08906432267323
10.2 编译和使用
# 编译
mkdir build
cd build
cmake ..
make
# 运行示例
./tle2kepler
# 处理TLE文件
./tle2kepler ../data/sample.tle
11. 高级功能扩展
11.1 轨道传播器 (orbit_propagator.h)
#ifndef ORBIT_PROPAGATOR_H
#define ORBIT_PROPAGATOR_H
#include "tle2kepler.h"
#include <vector>
class OrbitPropagator {
private:
KeplerElements initial_elements;
double initial_epoch;
public:
OrbitPropagator(const KeplerElements& kepler, double epoch)
: initial_elements(kepler), initial_epoch(epoch) {}
// SGP4/SDP4轨道传播(简化版)
KeplerElements propagateSGP4(double delta_time_days) {
KeplerElements propagated = initial_elements;
// 简化传播:只考虑平均运动
double delta_revs = initial_elements.mean_motion * delta_time_days;
double new_mean_anomaly = initial_elements.mean_anomaly +
delta_revs * 360.0; // 度
// 归一化到[0, 360)
while (new_mean_anomaly >= 360.0) new_mean_anomaly -= 360.0;
while (new_mean_anomaly < 0.0) new_mean_anomaly += 360.0;
propagated.mean_anomaly = new_mean_anomaly;
// 重新计算真近点角
propagated.true_anomaly = TLE2Kepler::meanToTrueAnomaly(
propagated.mean_anomaly, propagated.eccentricity);
return propagated;
}
// 生成轨道轨迹
std::vector<KeplerElements> generateTrajectory(double start_time,
double end_time,
double time_step) {
std::vector<KeplerElements> trajectory;
double current_time = start_time;
while (current_time <= end_time) {
double delta_days = current_time - initial_epoch;
KeplerElements current = propagateSGP4(delta_days);
trajectory.push_back(current);
current_time += time_step;
}
return trajectory;
}
};
12. 注意事项
- 精度限制:此实现是简化版本,实际应用中需要使用SGP4/SDP4等专业轨道模型
- 坐标系:TLE使用TEME坐标系,而本代码使用简化模型
- 时间系统:需要正确处理UTC、TAI、TT等时间系统
- 地球扁率:完整的实现需要考虑J2、J3等地球扁率项
- 大气阻力:低轨道卫星需要考虑大气阻力影响
更多推荐

所有评论(0)