mako_sgp4/common.rs
1//! Module to handle common constants, coordinate types, and utility functions shared across
2//! GP parsing and SGP4 propagation.
3
4// ------------------
5// External Libraries
6// ------------------
7use std::f64::consts::PI;
8
9// ------------------
10// Internal Libraries
11// ------------------
12
13// -------
14// Structs
15// -------
16
17/// World Geodetic System (WGS) parameters
18///
19/// This struct contains the important Earth parameters defined by different WGS
20/// standards (e.g. WGS-72, WGS-84).
21///
22/// # Examples
23/// ```rust
24/// use mako_sgp4::common::WGS72;
25///
26/// // WGS-72 is the default Earth model for TLE / SGP4
27/// let wgs = WGS72;
28/// assert!((wgs.mu - 398600.8).abs() < 1e-9);
29/// assert!((wgs.r_earth_eq - 6378.135).abs() < 1e-9);
30/// ```
31///
32/// # References
33/// - [Revisiting Spacetrack Report #3: Rev 3 by Vallado et al](https://celestrak.org/publications/AIAA/2006-6753/AIAA-2006-6753-Rev3.pdf)
34#[derive(Default, Clone, Copy)]
35pub struct Wgs {
36 /// Earth's standard gravitational parameter \[km^3/s^2\]
37 pub mu: f64,
38
39 /// Earth's equatorial radius \[km\]
40 pub r_earth_eq: f64,
41
42 /// Earth's flattening \[\]
43 pub flattening: f64,
44
45 /// Earth's J2 harmonic \[\]
46 pub j2: f64,
47
48 /// k2 constant \[Earth Radii^2\]
49 pub k2: f64,
50
51 /// Earth's J3 harmonic \[\]
52 pub j3: f64,
53
54 /// Earth's J4 harmonic \[\]
55 pub j4: f64,
56
57 /// k4 constant \[Earth Radii^4\]
58 pub k4: f64,
59
60 /// The square root of the standard gravitational parameter \[Earth radii^1.5 / min\]
61 pub ke: f64,
62}
63
64/// Satellite state vector
65///
66/// Position \[km\] and velocity \[km/s\] of a satellite in a specified coordinate frame.
67/// SGP4 propagation returns this type in [`CoordinateFrame::TEME`].
68///
69/// # Examples
70/// ```rust
71/// use mako_sgp4::common::{CoordinateFrame, StateVector};
72///
73/// // Define a TEME state (position in km, velocity in km/s)
74/// let state = StateVector {
75/// r_x: 1.0,
76/// r_y: 0.0,
77/// r_z: 0.0,
78/// v_x: 0.0,
79/// v_y: 7.5,
80/// v_z: 0.0,
81/// coordinate_frame: CoordinateFrame::TEME,
82/// };
83///
84/// // Assert the frame used by SGP4
85/// assert_eq!(state.coordinate_frame, CoordinateFrame::TEME);
86/// ```
87///
88/// # References
89#[derive(Default, Clone, Copy)]
90pub struct StateVector {
91 /// Position X component \[km\]
92 pub r_x: f64,
93
94 /// Position Y component \[km\]
95 pub r_y: f64,
96
97 /// Position Z component \[km\]
98 pub r_z: f64,
99
100 /// Velocity X component \[km/s\]
101 pub v_x: f64,
102
103 /// Velocity Y component \[km/s\]
104 pub v_y: f64,
105
106 /// Velocity Z component \[km/s\]
107 pub v_z: f64,
108
109 /// Coordinate frame of the state vector
110 pub coordinate_frame: CoordinateFrame,
111}
112
113// -----
114// Enums
115// -----
116
117/// Coordinate frames
118///
119/// Represents the coordinate frame used for a [`StateVector`].
120///
121/// # Examples
122/// ```rust
123/// use mako_sgp4::common::CoordinateFrame;
124///
125/// // SGP4 state vectors are TEME; J2000 is the enum default
126/// let frame_teme = CoordinateFrame::TEME;
127/// let frame_j2000 = CoordinateFrame::J2000;
128///
129/// assert_eq!(frame_j2000, CoordinateFrame::default());
130/// assert_ne!(frame_teme, frame_j2000);
131/// ```
132///
133/// # References
134#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
135pub enum CoordinateFrame {
136 /// J2000, an Earth-centered inertial (ECI) coordinate frame
137 #[default]
138 J2000,
139
140 /// True Equator Mean Equinox (TEME), an Earth-centered inertial (ECI) coordinate frame
141 TEME,
142}
143
144// ------
145// Traits
146// ------
147
148// ---------
149// Constants
150// ---------
151
152/// Fundamental and derived constants for WGS-72
153///
154/// Earth model parameters used as the default for TLE/GP processing with SGP4.
155///
156/// - `mu`: 398600.8 - standard gravitational parameter \[km^3 / s^2\]
157/// - `r_earth_eq`: 6378.135 - Earth's equatorial radius \[km\]
158/// - `flattening`: 1 / 298.26 - Earth's flattening
159/// - `j2`: 0.001082616 - second zonal harmonic (Earth's oblateness)
160/// - `k2`: 0.000541308 - `0.5 * j2` \[Earth radii^2\]
161/// - `j3`: -0.00000253881 - third zonal harmonic (pear-shaped component)
162/// - `j4`: -0.00000165597 - fourth zonal harmonic
163/// - `k4`: 0.00000062098875 - `-3/8 * j4` \[Earth radii^4\]
164/// - `ke`: 0.07436691613317 - `60 * sqrt(mu / r_earth_eq^3)`, square root of `mu` \[Earth radii^1.5 / min\]
165///
166/// # Examples
167/// ```rust
168/// use mako_sgp4::common::WGS72;
169///
170/// // TLE / SGP4 default Earth model
171/// assert!((WGS72.mu - 398600.8).abs() < 1e-9);
172/// ```
173///
174/// # References
175/// - [Revisiting Spacetrack Report #3: Rev 3 by Vallado et al](https://celestrak.org/publications/AIAA/2006-6753/AIAA-2006-6753-Rev3.pdf)
176pub const WGS72: Wgs = Wgs {
177 mu: 398600.8,
178 r_earth_eq: 6378.135,
179 flattening: 1. / 298.26,
180 j2: 0.001082616,
181 k2: 0.000541308,
182 j3: -0.00000253881,
183 j4: -0.00000165597,
184 k4: 0.00000062098875,
185 ke: 0.07436691613317,
186};
187
188/// Fundamental and derived constants for WGS-84
189///
190/// Earth model parameters for the WGS-84 geodetic system.
191///
192/// - `mu`: 398600.5 - standard gravitational parameter \[km^3 / s^2\]
193/// - `r_earth_eq`: 6378.137 - Earth's equatorial radius \[km\]
194/// - `flattening`: 1 / 298.257223563 - Earth's flattening
195/// - `j2`: 0.00108262998905 - second zonal harmonic (Earth's oblateness)
196/// - `k2`: 0.000541314994525 - `0.5 * j2` \[Earth radii^2\]
197/// - `j3`: -0.00000253215306 - third zonal harmonic (pear-shaped component)
198/// - `j4`: -0.00000161098761 - fourth zonal harmonic
199/// - `k4`: 0.0000006041203538 - `-3/8 * j4` \[Earth radii^4\]
200/// - `ke`: 0.07436685316871 - `60 * sqrt(mu / r_earth_eq^3)`, square root of `mu` \[Earth radii^1.5 / min\]
201///
202/// # Examples
203/// ```rust
204/// use mako_sgp4::common::{WGS72, WGS84};
205///
206/// // WGS-84 differs from the TLE default (WGS-72)
207/// assert!((WGS84.mu - 398600.5).abs() < 1e-9);
208/// assert_ne!(WGS84.mu, WGS72.mu);
209/// ```
210///
211/// # References
212/// - [Revisiting Spacetrack Report #3: Rev 3 by Vallado et al](https://celestrak.org/publications/AIAA/2006-6753/AIAA-2006-6753-Rev3.pdf)
213pub const WGS84: Wgs = Wgs {
214 mu: 398600.5,
215 r_earth_eq: 6378.137,
216 flattening: 1. / 298.257223563,
217 j2: 0.00108262998905,
218 k2: 0.000541314994525,
219 j3: -0.00000253215306,
220 j4: -0.00000161098761,
221 k4: 0.0000006041203538,
222 ke: 0.07436685316871,
223};
224
225// ---------
226// Functions
227// ---------
228
229/// Convert an angle from degrees to radians
230///
231/// Multiplies the input angle by `pi / 180`.
232///
233/// # Arguments
234/// * `theta` - The angle in degrees
235///
236/// # Returns
237/// * `theta_rad` - The angle in radians
238///
239/// # Examples
240/// ```rust
241/// use std::f64::consts::PI;
242/// use mako_sgp4::common::deg2rad;
243///
244/// // Define a right angle in degrees
245/// let theta = 90.0;
246///
247/// // Convert to radians
248/// let theta_rad = deg2rad(theta);
249///
250/// // Assert 90 deg is pi/2
251/// assert!((theta_rad - PI / 2.0).abs() < 1e-12);
252/// ```
253pub fn deg2rad(theta: f64) -> f64 {
254 // Convert to radians
255 PI / 180. * theta
256}
257
258/// Calculate the orbital period from semi-major axis and gravitational parameter
259///
260/// Uses Kepler's third law: `T = 2 pi sqrt(a^3 / mu)`, returned in minutes.
261///
262/// # Arguments
263/// * `a` - The semi-major axis \[km\]
264/// * `mu` - The standard gravitational parameter \[km^3 / s^2\]
265///
266/// # Returns
267/// * `period` - The period in minutes \[min\]
268///
269/// # Examples
270/// ```rust
271/// use mako_sgp4::common::{WGS72, calc_period};
272///
273/// // Circular orbit at Earth's equatorial radius (WGS-72)
274/// let period = calc_period(WGS72.r_earth_eq, WGS72.mu);
275///
276/// // Period is about 84.5 minutes
277/// assert!((period - 84.489).abs() < 1e-3);
278/// ```
279///
280/// # References
281/// - [Revisiting Spacetrack Report #3: Rev 3 by Vallado et al](https://celestrak.org/publications/AIAA/2006-6753/AIAA-2006-6753-Rev3.pdf)
282pub fn calc_period(a: f64, mu: f64) -> f64 {
283 // Calculate time period in minutes
284 2. * PI * (a.powi(3) / mu).sqrt() / 60.
285}
286
287// ----------
288// Unit Tests
289// ----------