Vulcan
Aerospace Engineering Utilities Built on Janus
Loading...
Searching...
No Matches
StateConversions.hpp
Go to the documentation of this file.
1// Vulcan State Conversions
2// Cartesian <-> Keplerian orbital element transformations
3#pragma once
4
5#include <cmath>
6#include <janus/janus.hpp>
7#include <utility>
11
13
26template <typename Scalar>
28cartesian_to_keplerian(const Vec3<Scalar> &r, const Vec3<Scalar> &v,
29 double mu = constants::earth::mu) {
31
32 const Scalar r_mag = janus::norm(r);
33 const Scalar v_mag = janus::norm(v);
34
35 // Specific angular momentum vector
36 const Vec3<Scalar> h = janus::cross(r, v);
37 const Scalar h_mag = janus::norm(h);
38
39 // Node vector (K x h) - points to ascending node
40 Vec3<Scalar> n;
41 n << -h(1), h(0), Scalar(0.0);
42 const Scalar n_mag = janus::norm(n);
43
44 // Eccentricity vector
45 const Scalar r_dot_v = janus::dot(r, v);
46 const Vec3<Scalar> e_vec =
47 ((v_mag * v_mag - mu / r_mag) * r - r_dot_v * v) / mu;
48 oe.e = janus::norm(e_vec);
49
50 // Specific mechanical energy
51 const Scalar energy = v_mag * v_mag / 2.0 - mu / r_mag;
52
53 // Semi-major axis (negative for hyperbolic)
54 oe.a = -mu / (2.0 * energy);
55
56 // Inclination [0, pi]
57 oe.i = janus::acos(janus::clamp(h(2) / h_mag, Scalar(-1.0), Scalar(1.0)));
58
59 // RAAN [0, 2pi] - handle equatorial case
60 const Scalar n_mag_safe = janus::where(n_mag < 1e-10, Scalar(1.0), n_mag);
61 Scalar Omega_temp =
62 janus::acos(janus::clamp(n(0) / n_mag_safe, Scalar(-1.0), Scalar(1.0)));
63 oe.Omega = janus::where(n(1) < 0.0, 2.0 * M_PI - Omega_temp, Omega_temp);
64 oe.Omega = janus::where(n_mag < 1e-10, Scalar(0.0), oe.Omega);
65
66 // Argument of periapsis [0, 2pi] - handle circular/equatorial case
67 const Scalar e_safe = janus::where(oe.e < 1e-10, Scalar(1.0), oe.e);
68 const Scalar n_dot_e = janus::dot(n, e_vec);
69 Scalar omega_temp = janus::acos(janus::clamp(
70 n_dot_e / (n_mag_safe * e_safe), Scalar(-1.0), Scalar(1.0)));
71 oe.omega =
72 janus::where(e_vec(2) < 0.0, 2.0 * M_PI - omega_temp, omega_temp);
73 oe.omega = janus::where(oe.e < 1e-10, Scalar(0.0), oe.omega);
74 oe.omega = janus::where(n_mag < 1e-10, Scalar(0.0), oe.omega);
75
76 // True anomaly [0, 2pi]
77 const Scalar e_dot_r = janus::dot(e_vec, r);
78 Scalar nu_temp = janus::acos(
79 janus::clamp(e_dot_r / (e_safe * r_mag), Scalar(-1.0), Scalar(1.0)));
80 oe.nu = janus::where(r_dot_v < 0.0, 2.0 * M_PI - nu_temp, nu_temp);
81 oe.nu = janus::where(oe.e < 1e-10, Scalar(0.0), oe.nu);
82
83 return oe;
84}
85
96template <typename Scalar>
97std::pair<Vec3<Scalar>, Vec3<Scalar>>
99 double mu = constants::earth::mu) {
100
101 // Semi-latus rectum
102 const Scalar p = oe.a * (1.0 - oe.e * oe.e);
103
104 // Position magnitude at true anomaly
105 const Scalar r_mag = p / (1.0 + oe.e * janus::cos(oe.nu));
106
107 const Scalar cos_nu = janus::cos(oe.nu);
108 const Scalar sin_nu = janus::sin(oe.nu);
109
110 // Position in perifocal (PQW) frame
111 Vec3<Scalar> r_pqw;
112 r_pqw << r_mag * cos_nu, r_mag * sin_nu, Scalar(0.0);
113
114 // Velocity in perifocal frame
115 const Scalar sqrt_mu_p = janus::sqrt(mu / p);
116 Vec3<Scalar> v_pqw;
117 v_pqw << -sqrt_mu_p * sin_nu, sqrt_mu_p * (oe.e + cos_nu), Scalar(0.0);
118
119 // Rotation matrix from perifocal to inertial (ECI)
120 const Scalar cos_O = janus::cos(oe.Omega);
121 const Scalar sin_O = janus::sin(oe.Omega);
122 const Scalar cos_i = janus::cos(oe.i);
123 const Scalar sin_i = janus::sin(oe.i);
124 const Scalar cos_w = janus::cos(oe.omega);
125 const Scalar sin_w = janus::sin(oe.omega);
126
127 Mat3<Scalar> R;
128 R(0, 0) = cos_O * cos_w - sin_O * sin_w * cos_i;
129 R(0, 1) = -cos_O * sin_w - sin_O * cos_w * cos_i;
130 R(0, 2) = sin_O * sin_i;
131 R(1, 0) = sin_O * cos_w + cos_O * sin_w * cos_i;
132 R(1, 1) = -sin_O * sin_w + cos_O * cos_w * cos_i;
133 R(1, 2) = -cos_O * sin_i;
134 R(2, 0) = sin_w * sin_i;
135 R(2, 1) = cos_w * sin_i;
136 R(2, 2) = cos_i;
137
138 Vec3<Scalar> r = R * r_pqw;
139 Vec3<Scalar> v = R * v_pqw;
140
141 return {r, v};
142}
143
144} // namespace vulcan::orbital::elements
constexpr double mu
Gravitational parameter (GM) [m^3/s^2].
Definition Constants.hpp:13
Definition StateConversions.hpp:12
OrbitalElements< Scalar > cartesian_to_keplerian(const Vec3< Scalar > &r, const Vec3< Scalar > &v, double mu=constants::earth::mu)
Convert Cartesian state to Keplerian elements.
Definition StateConversions.hpp:28
std::pair< Vec3< Scalar >, Vec3< Scalar > > keplerian_to_cartesian(const OrbitalElements< Scalar > &oe, double mu=constants::earth::mu)
Convert Keplerian elements to Cartesian state.
Definition StateConversions.hpp:98
Classical Keplerian orbital elements.
Definition OrbitalTypes.hpp:20
Scalar a
Semi-major axis [m].
Definition OrbitalTypes.hpp:21
Scalar Omega
Right ascension of ascending node (RAAN) [rad].
Definition OrbitalTypes.hpp:24
Scalar omega
Argument of periapsis [rad].
Definition OrbitalTypes.hpp:25
Scalar e
Eccentricity [-].
Definition OrbitalTypes.hpp:22
Scalar nu
True anomaly [rad].
Definition OrbitalTypes.hpp:26
Scalar i
Inclination [rad].
Definition OrbitalTypes.hpp:23