Vulcan
Aerospace Engineering Utilities Built on Janus
Loading...
Searching...
No Matches
AnalyticalEphemeris.hpp
Go to the documentation of this file.
1// Vulcan Analytical Ephemeris
2// Low-precision Sun and Moon positions using Meeus/Vallado algorithms
3#pragma once
4
5#include <janus/janus.hpp>
6#include <utility>
10
12
13// =============================================================================
14// Sun Ephemeris
15// =============================================================================
16
27template <typename Scalar>
28std::pair<Scalar, Scalar> sun_ra_dec(const Scalar &jd) {
29 using janus::asin;
30 using janus::atan2;
31 using janus::cos;
32 using janus::sin;
33
34 // Julian centuries since J2000.0
35 const Scalar T = time::jd_to_j2000_centuries(jd);
36
37 // Mean longitude of the Sun [deg -> rad]
38 const Scalar lambda_M =
39 (280.460 + 36000.771 * T) * constants::angle::deg2rad;
40
41 // Mean anomaly [deg -> rad]
42 const Scalar M =
43 (357.5291092 + 35999.05034 * T) * constants::angle::deg2rad;
44
45 // Ecliptic longitude [rad]
46 const Scalar lambda_ec =
47 lambda_M + (1.914666471 * sin(M) + 0.019994643 * sin(2.0 * M)) *
49
50 // Obliquity of the ecliptic [rad]
51 const Scalar epsilon =
52 (23.439291 - 0.0130042 * T) * constants::angle::deg2rad;
53
54 // Right ascension and declination
55 const Scalar sin_lambda = sin(lambda_ec);
56 const Scalar cos_lambda = cos(lambda_ec);
57 const Scalar cos_eps = cos(epsilon);
58 const Scalar sin_eps = sin(epsilon);
59
60 const Scalar ra = atan2(cos_eps * sin_lambda, cos_lambda);
61 const Scalar dec = asin(sin_eps * sin_lambda);
62
63 return {ra, dec};
64}
65
73template <typename Scalar> Scalar sun_distance(const Scalar &jd) {
74 const Scalar T = time::jd_to_j2000_centuries(jd);
75 const Scalar M =
76 (357.5291092 + 35999.05034 * T) * constants::angle::deg2rad;
77
78 // Distance in AU
79 const Scalar r_au = 1.000140612 - 0.016708617 * janus::cos(M) -
80 0.000139589 * janus::cos(2.0 * M);
81
82 return r_au * constants::sun::AU;
83}
84
92template <typename Scalar> Vec3<Scalar> sun_position_eci(const Scalar &jd) {
93 auto [ra, dec] = sun_ra_dec(jd);
94 const Scalar r = sun_distance(jd);
95
96 const Scalar cos_dec = janus::cos(dec);
97
98 Vec3<Scalar> pos;
99 pos(0) = r * cos_dec * janus::cos(ra);
100 pos(1) = r * cos_dec * janus::sin(ra);
101 pos(2) = r * janus::sin(dec);
102
103 return pos;
104}
105
113template <typename Scalar> Vec3<Scalar> sun_unit_vector_eci(const Scalar &jd) {
114 auto [ra, dec] = sun_ra_dec(jd);
115 const Scalar cos_dec = janus::cos(dec);
116
117 Vec3<Scalar> u;
118 u(0) = cos_dec * janus::cos(ra);
119 u(1) = cos_dec * janus::sin(ra);
120 u(2) = janus::sin(dec);
121
122 return u;
123}
124
125// =============================================================================
126// Moon Ephemeris
127// =============================================================================
128
141template <typename Scalar> Vec3<Scalar> moon_position_eci(const Scalar &jd) {
142 // Julian centuries from J2000.0
143 const Scalar T = time::jd_to_j2000_centuries(jd);
144 const Scalar T2 = T * T;
145 const Scalar T3 = T2 * T;
146 const Scalar T4 = T3 * T;
147
148 // Moon's mean longitude (degrees)
149 const Scalar Lp = 218.3164477 + 481267.88123421 * T - 0.0015786 * T2 +
150 T3 / 538841.0 - T4 / 65194000.0;
151
152 // Mean elongation of the Moon (degrees)
153 const Scalar D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 +
154 T3 / 545868.0 - T4 / 113065000.0;
155
156 // Sun's mean anomaly (degrees)
157 const Scalar M =
158 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;
159
160 // Moon's mean anomaly (degrees)
161 const Scalar Mp = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 +
162 T3 / 69699.0 - T4 / 14712000.0;
163
164 // Moon's argument of latitude (degrees)
165 const Scalar F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2 -
166 T3 / 3526000.0 + T4 / 863310000.0;
167
168 // Convert to radians
169 const Scalar D_rad = D * constants::angle::deg2rad;
170 const Scalar M_rad = M * constants::angle::deg2rad;
171 const Scalar Mp_rad = Mp * constants::angle::deg2rad;
172 const Scalar F_rad = F * constants::angle::deg2rad;
173
174 // Longitude perturbations (simplified - main terms only)
175 const Scalar dL = 6288774.0 * janus::sin(Mp_rad) +
176 1274027.0 * janus::sin(2.0 * D_rad - Mp_rad) +
177 658314.0 * janus::sin(2.0 * D_rad) +
178 213618.0 * janus::sin(2.0 * Mp_rad) -
179 185116.0 * janus::sin(M_rad) -
180 114332.0 * janus::sin(2.0 * F_rad);
181
182 // Latitude perturbations (simplified)
183 const Scalar dB = 5128122.0 * janus::sin(F_rad) +
184 280602.0 * janus::sin(Mp_rad + F_rad) +
185 277693.0 * janus::sin(Mp_rad - F_rad) +
186 173237.0 * janus::sin(2.0 * D_rad - F_rad);
187
188 // Distance perturbations (simplified)
189 const Scalar dR = -20905355.0 * janus::cos(Mp_rad) -
190 3699111.0 * janus::cos(2.0 * D_rad - Mp_rad) -
191 2955968.0 * janus::cos(2.0 * D_rad) -
192 569925.0 * janus::cos(2.0 * Mp_rad);
193
194 // Ecliptic longitude and latitude (degrees)
195 const Scalar lambda = Lp + dL / 1000000.0;
196 const Scalar beta = dB / 1000000.0;
197
198 // Distance (km, then convert to m)
199 const Scalar dist_km = 385000.56 + dR / 1000.0;
200 const Scalar dist = dist_km * 1000.0;
201
202 // Convert to radians
203 const Scalar lambda_rad = lambda * constants::angle::deg2rad;
204 const Scalar beta_rad = beta * constants::angle::deg2rad;
205
206 // Mean obliquity of the ecliptic
207 const Scalar epsilon =
208 (23.439291 - 0.0130042 * T) * constants::angle::deg2rad;
209
210 // Ecliptic to equatorial transformation
211 const Scalar cos_lambda = janus::cos(lambda_rad);
212 const Scalar sin_lambda = janus::sin(lambda_rad);
213 const Scalar cos_beta = janus::cos(beta_rad);
214 const Scalar sin_beta = janus::sin(beta_rad);
215 const Scalar cos_eps = janus::cos(epsilon);
216 const Scalar sin_eps = janus::sin(epsilon);
217
218 Vec3<Scalar> r_moon;
219 r_moon(0) = dist * cos_beta * cos_lambda;
220 r_moon(1) = dist * (cos_eps * cos_beta * sin_lambda - sin_eps * sin_beta);
221 r_moon(2) = dist * (sin_eps * cos_beta * sin_lambda + cos_eps * sin_beta);
222
223 return r_moon;
224}
225
233template <typename Scalar> Scalar moon_distance(const Scalar &jd) {
234 Vec3<Scalar> pos = moon_position_eci(jd);
235 return janus::norm(pos);
236}
237
238// =============================================================================
239// ECEF Conversions
240// =============================================================================
241
249template <typename Scalar> Vec3<Scalar> sun_position_ecef(const Scalar &jd) {
250 Vec3<Scalar> r_eci = sun_position_eci(jd);
251
252 // Greenwich Mean Sidereal Time
253 const Scalar T = time::jd_to_j2000_centuries(jd);
254 const Scalar gmst_deg = 280.46061837 + 360.98564736629 * (jd - 2451545.0) +
255 0.000387933 * T * T - T * T * T / 38710000.0;
256 const Scalar gmst_rad = gmst_deg * constants::angle::deg2rad;
257
258 // Rotate ECI to ECEF
259 const Scalar cos_gmst = janus::cos(gmst_rad);
260 const Scalar sin_gmst = janus::sin(gmst_rad);
261
262 Vec3<Scalar> r_ecef;
263 r_ecef(0) = cos_gmst * r_eci(0) + sin_gmst * r_eci(1);
264 r_ecef(1) = -sin_gmst * r_eci(0) + cos_gmst * r_eci(1);
265 r_ecef(2) = r_eci(2);
266
267 return r_ecef;
268}
269
277template <typename Scalar> Vec3<Scalar> moon_position_ecef(const Scalar &jd) {
278 Vec3<Scalar> r_eci = moon_position_eci(jd);
279
280 const Scalar T = time::jd_to_j2000_centuries(jd);
281 const Scalar gmst_deg = 280.46061837 + 360.98564736629 * (jd - 2451545.0) +
282 0.000387933 * T * T - T * T * T / 38710000.0;
283 const Scalar gmst_rad = gmst_deg * constants::angle::deg2rad;
284
285 const Scalar cos_gmst = janus::cos(gmst_rad);
286 const Scalar sin_gmst = janus::sin(gmst_rad);
287
288 Vec3<Scalar> r_ecef;
289 r_ecef(0) = cos_gmst * r_eci(0) + sin_gmst * r_eci(1);
290 r_ecef(1) = -sin_gmst * r_eci(0) + cos_gmst * r_eci(1);
291 r_ecef(2) = r_eci(2);
292
293 return r_ecef;
294}
295
296} // namespace vulcan::orbital::ephemeris::analytical
constexpr double deg2rad
Degrees to radians conversion factor.
Definition Constants.hpp:156
constexpr double AU
Astronomical Unit [m] - exact IAU 2012 definition.
Definition Constants.hpp:125
Definition AnalyticalEphemeris.hpp:11
Vec3< Scalar > sun_position_ecef(const Scalar &jd)
Sun position in ECEF.
Definition AnalyticalEphemeris.hpp:249
Vec3< Scalar > moon_position_ecef(const Scalar &jd)
Moon position in ECEF.
Definition AnalyticalEphemeris.hpp:277
Scalar moon_distance(const Scalar &jd)
Moon distance from Earth.
Definition AnalyticalEphemeris.hpp:233
std::pair< Scalar, Scalar > sun_ra_dec(const Scalar &jd)
Compute Sun's right ascension and declination.
Definition AnalyticalEphemeris.hpp:28
Vec3< Scalar > sun_unit_vector_eci(const Scalar &jd)
Sun unit direction vector in ECI.
Definition AnalyticalEphemeris.hpp:113
Vec3< Scalar > moon_position_eci(const Scalar &jd)
Moon position in ECI (geocentric equatorial).
Definition AnalyticalEphemeris.hpp:141
Scalar sun_distance(const Scalar &jd)
Earth-Sun distance.
Definition AnalyticalEphemeris.hpp:73
Vec3< Scalar > sun_position_eci(const Scalar &jd)
Sun position in ECI frame (J2000 equatorial).
Definition AnalyticalEphemeris.hpp:92
constexpr Scalar jd_to_j2000_centuries(const Scalar &jd)
Convert Julian Date to Julian centuries since J2000.0.
Definition JulianDate.hpp:140