"""
SGP4/SDP4 Analytical Propagator.
"""
from __future__ import annotations
from typing import Any
import numpy as np
from sgp4.api import Satrec
from .base import Propagator
[docs]
class Sgp4Propagator(Propagator):
"""
SGP4/SDP4 Analytical Propagator.
Wraps the `sgp4` library to propagate orbits using Two-Line Elements (TLEs).
State output is typically in the TEME frame.
Parameters
----------
line1 : str
First line of the TLE.
line2 : str
Second line of the TLE.
"""
def __init__(self, line1: str, line2: str) -> None:
self.sat = Satrec.twoline2rv(line1, line2)
# TLE Epoch Julian Date
self.jdsatepoch = self.sat.jdsatepoch
self.jdsatepochF = self.sat.jdsatepochF
[docs]
def propagate(
self, r_i: np.ndarray, v_i: np.ndarray, dt: float, **kwargs: Any
) -> tuple[np.ndarray, np.ndarray]:
"""
Propagates the satellite state from TLE epoch forward by dt.
Note: initial position/velocity input (r_i, v_i) is IGNORED,
as SGP4 is fully determined by the initialized TLE.
Parameters
----------
r_i : np.ndarray
Ignored initial position.
v_i : np.ndarray
Ignored initial velocity.
dt : float
Propagation time relative to TLE epoch (s).
**kwargs : dict
Additional arguments.
Returns
-------
tuple[np.ndarray, np.ndarray]
(r_f, v_f).
r_f : Position in TEME frame (m).
v_f : Velocity in TEME frame (m/s).
"""
# SGP4 takes time in minutes from epoch
minutes_from_epoch = dt / 60.0
# sgp4 evaluation
# returns (error_code, position, velocity)
# position in km, velocity in km/s (TEME)
err, r_km, v_kms = self.sat.sgp4(
self.jdsatepoch, self.jdsatepochF + minutes_from_epoch / 1440.0
)
if err != 0:
raise RuntimeError(f"SGP4 error code {err}: Propagation failed.")
# Convert to SI units [m, m/s]
r_f = np.array(r_km) * 1000.0
v_f = np.array(v_kms) * 1000.0
return r_f, v_f
[docs]
def propagate_to_jd(self, jd_f: float, jd_f_frac: float = 0.0) -> tuple[np.ndarray, np.ndarray]:
"""
Propagate to a specific Julian Date.
Parameters
----------
jd_f : float
Final Julian Date (integer part).
jd_f_frac : float, optional
Final Julian Date (fractional part). Default is 0.0.
Returns
-------
tuple[np.ndarray, np.ndarray]
(r_f, v_f) in TEME frame (m, m/s).
Raises
------
RuntimeError
If SGP4 propagation fails.
"""
err, r_km, v_kms = self.sat.sgp4(jd_f, jd_f_frac)
if err != 0:
raise RuntimeError(f"SGP4 error code {err}")
return np.array(r_km) * 1000.0, np.array(v_kms) * 1000.0