Program Listing for File ephemeris_basis.h¶
↰ Return to documentation for file (applications/ephemeris/ephemeris_basis.h)
#pragma once
#include <algorithm>
#include <cmath>
#include "lupnt/applications/ephemeris/lunanet_ephemeris.h"
#include "lupnt/core/constants.h"
#include "lupnt/core/definitions.h"
namespace lupnt {
inline MatXd ChebyshevBasis(const VecXd& t_k, double t_fit, int order) {
const int n = static_cast<int>(t_k.size());
MatXd T(n, order + 1);
T.col(0).setOnes();
if (order == 0) return T;
VecXd z = (2.0 / t_fit) * t_k;
T.col(1) = z;
for (int j = 2; j <= order; ++j) {
T.col(j) = 2.0 * z.array() * T.col(j - 1).array() - T.col(j - 2).array();
}
return T;
}
inline MatXd ChebyshevBasisDt(const VecXd& t_k, double t_fit, int order) {
const int n = static_cast<int>(t_k.size());
MatXd T = ChebyshevBasis(t_k, t_fit, order);
MatXd Tdot(n, order + 1);
Tdot.col(0).setZero();
if (order == 0) return Tdot;
const double dzdt = 2.0 / t_fit;
VecXd z = (2.0 / t_fit) * t_k;
Tdot.col(1).setConstant(dzdt);
for (int j = 2; j <= order; ++j) {
Tdot.col(j) = 2.0 * z.array() * Tdot.col(j - 1).array() + 2.0 * T.col(j - 1).array() * dzdt
- Tdot.col(j - 2).array();
}
return Tdot;
}
inline VecXd UnwrapAngles(const VecXd& angles) {
VecXd out = angles;
for (int i = 1; i < out.size(); ++i) {
while (out(i) - out(i - 1) > PI) out(i) -= 2.0 * PI;
while (out(i) - out(i - 1) < -PI) out(i) += 2.0 * PI;
}
return out;
}
inline VecXd CumTrapz(const VecXd& y, const VecXd& t) {
VecXd out = VecXd::Zero(y.size());
for (int i = 1; i < y.size(); ++i) {
out(i) = out(i - 1) + 0.5 * (y(i) + y(i - 1)) * (t(i) - t(i - 1));
}
return out;
}
inline Mat3d RtnMatrix(const Vec6d& rv) {
const Vec3d r = rv.head<3>();
const Vec3d v = rv.tail<3>();
const Vec3d R = r.normalized();
const Vec3d N = (r.cross(v)).normalized();
const Vec3d T = N.cross(R);
Mat3d M;
M.row(0) = R.transpose();
M.row(1) = T.transpose();
M.row(2) = N.transpose();
return M;
}
inline double Percentile95(VecXd v) {
std::sort(v.data(), v.data() + v.size());
int idx = std::max(0, static_cast<int>(std::ceil(0.95 * v.size())) - 1);
idx = std::min<int>(idx, static_cast<int>(v.size()) - 1);
return v(idx);
}
inline EphemerisFitErrorStats ComputeFitErrorStats(const MatXd& rv_fit, const MatXd& rv_ref) {
const int n = static_cast<int>(rv_ref.rows());
MatXd diff = rv_fit - rv_ref;
MatXd diff_rtn(n, 6);
for (int i = 0; i < n; ++i) {
const Vec6d rv_row = rv_ref.row(i).transpose();
const Mat3d M = RtnMatrix(rv_row);
diff_rtn.row(i).head<3>() = (M * diff.row(i).head<3>().transpose()).transpose();
diff_rtn.row(i).tail<3>() = (M * diff.row(i).tail<3>().transpose()).transpose();
}
EphemerisFitErrorStats stats;
for (int d = 0; d < 3; ++d) {
stats.rms_pos_m(d) = std::sqrt(diff_rtn.col(d).array().square().mean());
stats.rms_vel_mps(d) = std::sqrt(diff_rtn.col(3 + d).array().square().mean());
stats.p95_pos_m(d) = Percentile95(diff_rtn.col(d).array().abs().matrix());
stats.p95_vel_mps(d) = Percentile95(diff_rtn.col(3 + d).array().abs().matrix());
}
stats.rms_pos_m(3) = std::sqrt(diff_rtn.leftCols(3).array().square().sum() / n);
stats.rms_vel_mps(3) = std::sqrt(diff_rtn.rightCols(3).array().square().sum() / n);
VecXd pos_norm(n), vel_norm(n);
for (int i = 0; i < n; ++i) {
pos_norm(i) = diff_rtn.row(i).head<3>().norm();
vel_norm(i) = diff_rtn.row(i).tail<3>().norm();
}
stats.p95_pos_m(3) = Percentile95(pos_norm);
stats.p95_vel_mps(3) = Percentile95(vel_norm);
return stats;
}
} // namespace lupnt