#include "OribtModelOperator.h" #include #include #include #include #include #include #include #include OrbitElements::OrbitElements() : semiMajorAxis(0), eccentricity(0), inclination(0), longitudeOfAscendingNode(0), argumentOfPeriapsis(0), trueAnomaly(0) {} /** 六根数轨道拟合模型************************************************************************************/ OrbitEstimator::OrbitEstimator() {} void OrbitEstimator::estimateOrbit(const SatellitePos& node) { // 根据轨道节点估算轨道六根数的具体算法 elements = estimateKeplerianElements(node); } void OrbitEstimator::saveToXml(const QString& filename) const { QDomDocument doc("OrbitElements"); QDomElement root = doc.createElement("OrbitElements"); doc.appendChild(root); QDomElement elem; elem = doc.createElement("SemiMajorAxis"); elem.appendChild(doc.createTextNode(QString::number(elements.semiMajorAxis))); root.appendChild(elem); elem = doc.createElement("Eccentricity"); elem.appendChild(doc.createTextNode(QString::number(elements.eccentricity))); root.appendChild(elem); elem = doc.createElement("Inclination"); elem.appendChild(doc.createTextNode(QString::number(elements.inclination))); root.appendChild(elem); elem = doc.createElement("LongitudeOfAscendingNode"); elem.appendChild(doc.createTextNode(QString::number(elements.longitudeOfAscendingNode))); root.appendChild(elem); elem = doc.createElement("ArgumentOfPeriapsis"); elem.appendChild(doc.createTextNode(QString::number(elements.argumentOfPeriapsis))); root.appendChild(elem); elem = doc.createElement("TrueAnomaly"); elem.appendChild(doc.createTextNode(QString::number(elements.trueAnomaly))); root.appendChild(elem); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Cannot open file for writing:" << filename; return; } QTextStream out(&file); doc.save(out, 4); // Indent by 4 spaces file.close(); } bool OrbitEstimator::loadFromXml(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Cannot open file for reading:" << filename; return false; } QDomDocument doc; if (!doc.setContent(&file)) { file.close(); return false; } file.close(); QDomElement root = doc.documentElement(); QDomNodeList nodeList = root.elementsByTagName("*"); for (int i = 0; i < nodeList.count(); ++i) { QDomElement element = nodeList.at(i).toElement(); if (element.tagName() == "SemiMajorAxis") { elements.semiMajorAxis = element.text().toDouble(); } else if (element.tagName() == "Eccentricity") { elements.eccentricity = element.text().toDouble(); } else if (element.tagName() == "Inclination") { elements.inclination = element.text().toDouble(); } else if (element.tagName() == "LongitudeOfAscendingNode") { elements.longitudeOfAscendingNode = element.text().toDouble(); } else if (element.tagName() == "ArgumentOfPeriapsis") { elements.argumentOfPeriapsis = element.text().toDouble(); } else if (element.tagName() == "TrueAnomaly") { elements.trueAnomaly = element.text().toDouble(); } } return true; } SatellitePos OrbitEstimator::calculateNode(double time) const { // 根据轨道六根数计算轨道节点的具体算法 return calculateKeplerianNode(elements, time); } SatellitePos OrbitEstimator::predictNode(double time) { return calculateNode(time); } OrbitElements OrbitEstimator::estimateKeplerianElements(const SatellitePos& node) { // 示例:简单地将所有值设为0 OrbitElements elements; elements.semiMajorAxis = 0; elements.eccentricity = 0; elements.inclination = 0; elements.longitudeOfAscendingNode = 0; elements.argumentOfPeriapsis = 0; elements.trueAnomaly = 0; return elements; } SatellitePos OrbitEstimator::calculateKeplerianNode(const OrbitElements& elements, double time) const { const double G = 6.67430e-11; // 引力常数 m^3 kg^-1 s^-2 const double M_Earth = 5.972e24; // 地球质量 kg const double mu = G * M_Earth; // 地球引力参数 m^3 s^-2 double a = elements.semiMajorAxis; double e = elements.eccentricity; double i = elements.inclination; double Omega = elements.longitudeOfAscendingNode; double omega = elements.argumentOfPeriapsis; // 计算平均运动 double n = std::sqrt(mu / (a * a * a)); // 计算从参考时刻到给定时间的平均异常 double t_ref = 0.0; // 参考时刻,假设为0 double M = n * (time - t_ref); // 求解开普勒方程 E - e*sin(E) = M 使用牛顿迭代法 double E = M; // 初始猜测 double tolerance = 1e-8; int maxIterations = 100; for (int iter = 0; iter < maxIterations; ++iter) { double f = E - e * std::sin(E) - M; double df = 1 - e * std::cos(E); double delta = f / df; E -= delta; if (std::abs(delta) < tolerance) { break; } } // 计算偏近点角 ν double sin_nu = std::sqrt(1 - e * e) * std::sin(E) / (1 - e * std::cos(E)); double cos_nu = (std::cos(E) - e) / (1 - e * std::cos(E)); double nu = std::atan2(sin_nu, cos_nu); // 计算半径 r double r = a * (1 - e * std::cos(E)); // 计算位置向量在轨道平面上的分量 double Px_prime = r * std::cos(nu); double Py_prime = r * std::sin(nu); // 计算速度向量在轨道平面上的分量 double h = std::sqrt(mu * a * (1 - e * e)); // 角动量 double Vx_prime = -(h / r) * std::sin(nu); double Vy_prime = (h / r) * (std::cos(nu) + e); // 将轨道平面坐标系转换到惯性坐标系 double cos_Omega = std::cos(Omega); double sin_Omega = std::sin(Omega); double cos_omega = std::cos(omega); double sin_omega = std::sin(omega); double cos_i = std::cos(i); double sin_i = std::sin(i); double Px = Px_prime * (cos_Omega * cos_omega - sin_Omega * sin_omega * cos_i) + Py_prime * (-cos_Omega * sin_omega - sin_Omega * cos_omega * cos_i); double Py = Px_prime * (sin_Omega * cos_omega + cos_Omega * sin_omega * cos_i) + Py_prime * (-sin_Omega * sin_omega + cos_Omega * cos_omega * cos_i); double Pz = Px_prime * sin_omega * sin_i + Py_prime * cos_omega * sin_i; double Vx = Vx_prime * (cos_Omega * cos_omega - sin_Omega * sin_omega * cos_i) + Vy_prime * (-cos_Omega * sin_omega - sin_Omega * cos_omega * cos_i); double Vy = Vx_prime * (sin_Omega * cos_omega + cos_Omega * sin_omega * cos_i) + Vy_prime * (-sin_Omega * sin_omega + cos_Omega * cos_omega * cos_i); double Vz = Vx_prime * sin_omega * sin_i + Vy_prime * cos_omega * sin_i; SatellitePos node; node.time = time; node.Px = Px; node.Py = Py; node.Pz = Pz; node.Vx = Vx; node.Vy = Vy; node.Vz = Vz; return node; } double OrbitEstimator::solveKeplerEquation(double M, double e) const { double E = M; // 初始猜测 double tolerance = 1e-8; int maxIterations = 100; for (int iter = 0; iter < maxIterations; ++iter) { double f = E - e * std::sin(E) - M; double df = 1 - e * std::cos(E); double delta = f / df; E -= delta; if (std::abs(delta) < tolerance) { break; } } return E; } /** 多项式轨道拟合模型************************************************************************************/ void PolynomialOrbitModel::fitPolynomial(const QList& nodes, int degree) { QList times; QList positionsX; QList positionsY; QList positionsZ; QList velocitiesX; QList velocitiesY; QList velocitiesZ; for (const auto& node : nodes) { times.append(node.time); positionsX.append(node.Px); positionsY.append(node.Py); positionsZ.append(node.Pz); velocitiesX.append(node.Vx); velocitiesY.append(node.Vy); velocitiesZ.append(node.Vz); } qDebug() << "fit degree " << degree; coefficientsX = leastSquaresFit(times, positionsX, degree); coefficientsY = leastSquaresFit(times, positionsY, degree); coefficientsZ = leastSquaresFit(times, positionsZ, degree); coefficientsVx = leastSquaresFit(times, velocitiesX, degree); coefficientsVy = leastSquaresFit(times, velocitiesY, degree); coefficientsVz = leastSquaresFit(times, velocitiesZ, degree); } SatellitePos PolynomialOrbitModel::predictPosition(double time) { double Px = 0.0; double Py = 0.0; double Pz = 0.0; double Vx = 0.0; double Vy = 0.0; double Vz = 0.0; for (int i = 0; i < coefficientsX.size(); ++i) { Px += coefficientsX(i) * std::pow(time, i); Py += coefficientsY(i) * std::pow(time, i); Pz += coefficientsZ(i) * std::pow(time, i); Vx += coefficientsVx(i) * std::pow(time, i); Vy += coefficientsVy(i) * std::pow(time, i); Vz += coefficientsVz(i) * std::pow(time, i); } SatellitePos predictedNode; predictedNode.time = time; predictedNode.Px = Px; predictedNode.Py = Py; predictedNode.Pz = Pz; predictedNode.Vx = Vx; predictedNode.Vy = Vy; predictedNode.Vz = Vz; return predictedNode; } Eigen::VectorXd PolynomialOrbitModel::leastSquaresFit(const QList& x, const QList& y, int degree) { int n = x.size(); Eigen::MatrixXd A=Eigen::MatrixXd::Zero(n, degree + 1); for (int i = 0; i < n; ++i) { for (int j = 0; j <= degree; ++j) { A(i, j) = std::pow(x[i], j); } } Eigen::VectorXd b(y.count()); for (long i = 0; i < y.count(); i++) { b(i) = y[i]; } Eigen::VectorXd coefficients = A.colPivHouseholderQr().solve(b); //Eigen::Vector2d coefficientsVector = Eigen::Vector2d::Zero(degree); //coefficientsVector = coefficients.array(); return coefficients; } void PolynomialOrbitModel::saveCoefficientsToXml(QDomElement& parent, const Eigen::VectorXd& coefficients, const QString& tagName) const { QDomDocument doc = parent.ownerDocument(); QDomElement coeffElement = doc.createElement(tagName); for (int i = 0; i < coefficients.size(); ++i) { QDomElement valueElement = doc.createElement("Value"); valueElement.appendChild(doc.createTextNode(QString::number(coefficients(i)))); coeffElement.appendChild(valueElement); } parent.appendChild(coeffElement); } bool PolynomialOrbitModel::loadCoefficientsFromXml(const QDomElement& parent, Eigen::VectorXd& coefficients, const QString& tagName) { QDomNodeList coeffNodes = parent.elementsByTagName(tagName); if (coeffNodes.isEmpty()) { qWarning() << "Tag" << tagName << "not found in XML."; return false; } QDomElement coeffElement = coeffNodes.at(0).toElement(); QDomNodeList valueNodes = coeffElement.elementsByTagName("Value"); int size = valueNodes.count(); coefficients.resize(size); for (int i = 0; i < size; ++i) { QDomElement valueElement = valueNodes.at(i).toElement(); coefficients(i) = valueElement.text().toDouble(); } return true; } void PolynomialOrbitModel::saveToXml(const QString& filename) const { QDomDocument doc("PolynomialOrbitModel"); QDomElement root = doc.createElement("PolynomialOrbitModel"); doc.appendChild(root); saveCoefficientsToXml(root, coefficientsX, "CoefficientsX"); saveCoefficientsToXml(root, coefficientsY, "CoefficientsY"); saveCoefficientsToXml(root, coefficientsZ, "CoefficientsZ"); saveCoefficientsToXml(root, coefficientsVx, "CoefficientsVx"); saveCoefficientsToXml(root, coefficientsVy, "CoefficientsVy"); saveCoefficientsToXml(root, coefficientsVz, "CoefficientsVz"); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Cannot open file for writing:" << filename; return; } QTextStream out(&file); doc.save(out, 4); // Indent by 4 spaces file.close(); } bool PolynomialOrbitModel::loadFromXml(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Cannot open file for reading:" << filename; return false; } QDomDocument doc; if (!doc.setContent(&file)) { file.close(); return false; } file.close(); QDomElement root = doc.documentElement(); if (!loadCoefficientsFromXml(root, coefficientsX, "CoefficientsX")) return false; if (!loadCoefficientsFromXml(root, coefficientsY, "CoefficientsY")) return false; if (!loadCoefficientsFromXml(root, coefficientsZ, "CoefficientsZ")) return false; if (!loadCoefficientsFromXml(root, coefficientsVx, "CoefficientsVx")) return false; if (!loadCoefficientsFromXml(root, coefficientsVy, "CoefficientsVy")) return false; if (!loadCoefficientsFromXml(root, coefficientsVz, "CoefficientsVz")) return false; return true; } SatellitePos PolynomialOrbitModel::predictNode(double time) { return predictPosition(time); } /** 两行根数************************************************************************************/ TwoLineElements::TwoLineElements() {} bool TwoLineElements::loadFromTleFile(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Cannot open file for reading:" << filename; return false; } QTextStream in(&file); line1 = in.readLine().toStdString(); line2 = in.readLine().toStdString(); if (line1.empty() || line2.empty()) { qDebug() << "Invalid TLE data in file:" << filename; return false; } file.close(); parseTleLines(); return true; } void TwoLineElements::parseTleLines() { // 解析第一行 // 示例:1 25544U 98067A 23044.15434167 .00001971 00000-0 39389-4 0 9994 // 第二行 // 示例:2 25544 51.6416 243.5887 0001672 130.5360 325.0288 15.49472743275958 // 这里仅做基本解析,实际应用中需要更严格的验证和错误处理 } double TwoLineElements::meanMotion() const { // 第二行第53-63位是平均运动(每分钟转数) return std::stod(line2.substr(52, 11)); } double TwoLineElements::semiMajorAxis() const { const double G = 6.67430e-11; // 引力常数 m^3 kg^-1 s^-2 const double M_Earth = 5.972e24; // 地球质量 kg const double mu = G * M_Earth; // 地球引力参数 m^3 s^-2 double n = meanMotion() * 2 * M_PI / 60; // 转换为弧度/秒 return std::cbrt(mu / (n * n)); } double TwoLineElements::eccentricity() const { // 第二行第9-16位是离心率(小数点省略) return std::stod("0." + line2.substr(8, 7)); } double TwoLineElements::inclination() const { // 第二行第20-25位是倾斜角(度) return std::stod(line2.substr(19, 5)); } double TwoLineElements::longitudeOfAscendingNode() const { // 第二行第34-42位是升交点赤经(度) return std::stod(line2.substr(33, 9)); } double TwoLineElements::argumentOfPeriapsis() const { // 第二行第45-52位是近地点幅角(度) return std::stod(line2.substr(44, 8)); } double TwoLineElements::meanAnomaly() const { // 第二行第64-72位是平均近点角(度) return std::stod(line2.substr(63, 9)); } double TwoLineElements::revolutionNumberAtEpoch() const { // 第二行第64-72位是绕地次数 return std::stod(line2.substr(63, 5)); } double TwoLineElements::epochTime() const { // 第一行第20-32位是历元时间 int year = std::stoi(line1.substr(18, 2)) + 2000; double dayOfYear = std::stod(line1.substr(20, 12)); int month = 1, day = 1; while (dayOfYear > 0) { int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { daysInMonth[1] = 29; } if (dayOfYear <= daysInMonth[month - 1]) { day = static_cast(dayOfYear); break; } dayOfYear -= daysInMonth[month - 1]; month++; } QDate date(year, month, day); QTime time(0, 0, 0); QDateTime dateTime(date, time); return dateTime.toSecsSinceEpoch() + (dayOfYear - day) * 86400; } SatellitePos TwoLineElements::calculateNode(double time) const { return calculateKeplerianNode(time); } SatellitePos TwoLineElements::predictNode(double time) { return calculateNode(time); } SatellitePos TwoLineElements::calculateKeplerianNode(double time) const { const double G = 6.67430e-11; // 引力常数 m^3 kg^-1 s^-2 const double M_Earth = 5.972e24; // 地球质量 kg const double mu = G * M_Earth; // 地球引力参数 m^3 s^-2 double a = semiMajorAxis(); double e = eccentricity(); double i = inclination() * M_PI / 180.0; double Omega = longitudeOfAscendingNode() * M_PI / 180.0; double omega = argumentOfPeriapsis() * M_PI / 180.0; double M0 = meanAnomaly() * M_PI / 180.0; // 计算平均运动 double n = std::sqrt(mu / (a * a * a)); // 计算从参考时刻到给定时间的平均异常 double t_ref = epochTime(); // 参考时刻 double M = M0 + n * (time - t_ref); // 求解开普勒方程 E - e*sin(E) = M 使用牛顿迭代法 double E = solveKeplerEquation(M, e); // 计算偏近点角 ν double sin_nu = std::sqrt(1 - e * e) * std::sin(E) / (1 - e * std::cos(E)); double cos_nu = (std::cos(E) - e) / (1 - e * std::cos(E)); double nu = std::atan2(sin_nu, cos_nu); // 计算半径 r double r = a * (1 - e * std::cos(E)); // 计算位置向量在轨道平面上的分量 double Px_prime = r * std::cos(nu); double Py_prime = r * std::sin(nu); // 计算速度向量在轨道平面上的分量 double h = std::sqrt(mu * a * (1 - e * e)); // 角动量 double Vx_prime = -(h / r) * std::sin(nu); double Vy_prime = (h / r) * (std::cos(nu) + e); // 将轨道平面坐标系转换到惯性坐标系 double cos_Omega = std::cos(Omega); double sin_Omega = std::sin(Omega); double cos_omega = std::cos(omega); double sin_omega = std::sin(omega); double cos_i = std::cos(i); double sin_i = std::sin(i); double Px = Px_prime * (cos_Omega * cos_omega - sin_Omega * sin_omega * cos_i) + Py_prime * (-cos_Omega * sin_omega - sin_Omega * cos_omega * cos_i); double Py = Px_prime * (sin_Omega * cos_omega + cos_Omega * sin_omega * cos_i) + Py_prime * (-sin_Omega * sin_omega + cos_Omega * cos_omega * cos_i); double Pz = Px_prime * sin_omega * sin_i + Py_prime * cos_omega * sin_i; double Vx = Vx_prime * (cos_Omega * cos_omega - sin_Omega * sin_omega * cos_i) + Vy_prime * (-cos_Omega * sin_omega - sin_Omega * cos_omega * cos_i); double Vy = Vx_prime * (sin_Omega * cos_omega + cos_Omega * sin_omega * cos_i) + Vy_prime * (-sin_Omega * sin_omega + cos_Omega * cos_omega * cos_i); double Vz = Vx_prime * sin_omega * sin_i + Vy_prime * cos_omega * sin_i; SatellitePos node; node.time = time; node.Px = Px; node.Py = Py; node.Pz = Pz; node.Vx = Vx; node.Vy = Vy; node.Vz = Vz; return node; } double TwoLineElements::solveKeplerEquation(double M, double e) const { double E = M; // 初始猜测 double tolerance = 1e-8; int maxIterations = 100; for (int iter = 0; iter < maxIterations; ++iter) { double f = E - e * std::sin(E) - M; double df = 1 - e * std::cos(E); double delta = f / df; E -= delta; if (std::abs(delta) < tolerance) { break; } } return E; } /** 轨道节点文件读写************************************************************************************/ QList loadNodesFromXml(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Cannot open file for reading:" << filename; return {}; } QDomDocument doc; if (!doc.setContent(&file)) { file.close(); return {}; } file.close(); QDomElement root = doc.documentElement(); QDomNodeList gpsParamNodes = root.elementsByTagName("GPSParam"); QList loadedNodes; for (int i = 0; i < gpsParamNodes.count(); ++i) { QDomElement paramElement = gpsParamNodes.at(i).toElement(); SatellitePos node; node.time = convertToMilliseconds(paramElement.firstChildElement("TimeStamp").text().toStdString()); node.Px = paramElement.firstChildElement("xPosition").text().toDouble(); node.Py = paramElement.firstChildElement("yPosition").text().toDouble(); node.Pz = paramElement.firstChildElement("zPosition").text().toDouble(); node.Vx = paramElement.firstChildElement("xVelocity").text().toDouble(); node.Vy = paramElement.firstChildElement("yVelocity").text().toDouble(); node.Vz = paramElement.firstChildElement("zVelocity").text().toDouble(); loadedNodes.append(node); } return loadedNodes; } void saveNodesToXml(const QString& filename, const QList& inposes) { QDomDocument doc("GPSData"); QDomElement root = doc.createElement("GPS"); doc.appendChild(root); for (const auto& node : inposes) { QDomElement paramElement = doc.createElement("GPSParam"); QDomElement timeStampElement = doc.createElement("TimeStamp"); timeStampElement.appendChild(doc.createTextNode(QString::number(node.time))); paramElement.appendChild(timeStampElement); QDomElement xPositionElement = doc.createElement("xPosition"); xPositionElement.appendChild(doc.createTextNode(QString::number(node.Px))); paramElement.appendChild(xPositionElement); QDomElement yPositionElement = doc.createElement("yPosition"); yPositionElement.appendChild(doc.createTextNode(QString::number(node.Py))); paramElement.appendChild(yPositionElement); QDomElement zPositionElement = doc.createElement("zPosition"); zPositionElement.appendChild(doc.createTextNode(QString::number(node.Pz))); paramElement.appendChild(zPositionElement); QDomElement xVelocityElement = doc.createElement("xVelocity"); xVelocityElement.appendChild(doc.createTextNode(QString::number(node.Vx))); paramElement.appendChild(xVelocityElement); QDomElement yVelocityElement = doc.createElement("yVelocity"); yVelocityElement.appendChild(doc.createTextNode(QString::number(node.Vy))); paramElement.appendChild(yVelocityElement); QDomElement zVelocityElement = doc.createElement("zVelocity"); zVelocityElement.appendChild(doc.createTextNode(QString::number(node.Vz))); paramElement.appendChild(zVelocityElement); root.appendChild(paramElement); } QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Cannot open file for writing:" << filename; return; } QTextStream out(&file); doc.save(out, 4); // Indent by 4 spaces file.close(); } OrbitModelAbstract::OrbitModelAbstract() { } OrbitModelAbstract::~OrbitModelAbstract() { } SatellitePos OrbitModelAbstract::predictNode(double time) { return SatellitePos(); }