SGP4/SDP4
This package implements the interface to the SGP4/SDP4 propagator provided by SatelliteToolboxSgp4.jl.
Algorithm
The SGP4/SDP4 implementation was built using [1, 2, 3].
Initialization
We must initialize the SGP4/SDP4 propagator with a two-line element set (TLE) using the following function:
Propagators.init(Val(:SGP4), tle::TLE; kwargs...) -> OrbitPropagatorSgp4which creates a SGP4/SDP4 propagator structure OrbitPropagatorSgp4 with the tle. The following keyword selects the gravitational constants for the propagation algorithm:
sgp4c::Sgp4Constants: SGP4 orbit propagator constants (seeSgp4Constants). (Default:SGP4C_WGS84)
The package [SatelliteToolboxSgp4.jl] contains some pre-built constants for this propagator:
| SGP4/SDP4 Propagator Constants | Description | Type |
|---|---|---|
SGP4C_WGS84 | Constants based on WGS-84 | Float64 |
SGP4C_WGS72 | Constants based on WGS-72 | Float64 |
The type used in the propagation will be the same as used to define the constants in the structure sgp4c. The constants in another number type can be obtained with the converting constructor, e.g. Sgp4Constants{Float32}(SGP4C_WGS84).
The package SatelliteToolboxTle.jl defines the type TLE, which is re-exported here. It contains some useful functionalities, such as TLE fetching from online services. For more information, refer to the package documentation.
julia> tle = tle""" AMAZONIA 1 1 47699U 21015A 23083.68657856 -.00000044 10000-8 43000-4 0 9990 2 47699 98.4304 162.1097 0001247 136.2017 223.9283 14.40814394108652"""TLE: AMAZONIA 1 (Epoch = 2023-03-24T16:28:40.388): ├─ Line 1 │ Satellite Number : 47699 │ Classification : U │ International Designator : 21015A │ Epoch Year : 23 │ Epoch Day : 83.68657856 │ ṅ/2 : -4.4e-7 rev/day² │ n̈/6 : 1.0e-9 rev/day³ │ B* : 4.3e-5 1/ER │ Ephemeris Type : 0 │ Element Set Number : 999 └─ Line 2 Inclination : 98.4304° RA of the Ascending Node : 162.1097° Eccentricity : 0.0001247 Arg. of Perigee : 136.2017° Mean Anomaly : 223.9283° Mean Motion : 14.40814394 rev/day Revolution Number : 10865julia> Propagators.init(Val(:SGP4), tle)OrbitPropagatorSgp4{Float64, Float64} (SGP4 Orbit Propagator): ├─ Mean Elements │ Epoch : 2.46003e6 (2023-03-24T16:28:40.388) │ Semi-Major Axis : 7133.946314 km │ Mean Motion : 14.40814394 rev/day │ Eccentricity : 0.0001247 │ Inclination : 98.4304° │ RA of Asc. Node : 162.1097° │ Arg. of Periapsis : 136.2017° │ Mean Anomaly : 223.9283° │ B* : 4.3e-5 1/ER ├─ Constants │ R₀ : 6378.137 km │ XKE : 0.07436685317 er^(3/2)/min │ J₂ : 0.001082629989 │ J₃ : -2.53215306e-6 │ J₄ : -1.61098761e-6 └─ Propagation Last Instant : 0.0 min
We also support initializing an SGP4/SDP4 propagator passing the TLE information in individual terms:
Propagators.init(Val(:SGP4), epoch::Number, n₀::Number, e₀::Number, i₀::Number, Ω₀::Number, ω₀::Number, M₀::Number, bstar::Number; kwargs...) -> OrbitPropagatorSgp4where:
epoch::Number: Epoch of the orbital elements [Julian Day].n₀::Number: SGP type "mean" mean motion at epoch [rad/s].e₀::Number: "Mean" eccentricity at epoch.i₀::Number: "Mean" inclination at epoch [rad].Ω₀::Number: "Mean" longitude of the ascending node at epoch [rad].ω₀::Number: "Mean" argument of perigee at epoch [rad].M₀::Number: "Mean" mean anomaly at epoch [rad].bstar::Number: Drag parameter (B*).
The keywords kwargs... are the same as in the first version of this function.
Finally, the propagator can be initialized with an Orbit Mean-Elements Message (OMM) whose mean element theory is SGP4:
Propagators.init(Val(:SGP4), omm::OrbitMeanElementsMessage; kwargs...) -> OrbitPropagatorSgp4The mean motion is obtained from the field MEAN_MOTION or, if it is absent, from the semi-major axis and the gravitational coefficient, and the drag term is set to 0 if the field BSTAR is absent. The keywords kwargs... are the same as in the first version of this function.
The package SatelliteToolboxOrbitDataMessages.jl defines the type OrbitMeanElementsMessage and the functions to read, parse, and fetch the messages, and it is re-exported here.
julia> omm = parse_omm( """ <?xml version="1.0" encoding="utf-8"?> <ndm><omm id="CCSDS_OMM_VERS" version="3.0"> <header><CREATION_DATE>2025-12-30T23:36:37</CREATION_DATE><ORIGINATOR>18 SPCS</ORIGINATOR></header> <body><segment> <metadata><OBJECT_NAME>AMAZONIA 1</OBJECT_NAME><OBJECT_ID>2021-015A</OBJECT_ID><CENTER_NAME>EARTH</CENTER_NAME><REF_FRAME>TEME</REF_FRAME><TIME_SYSTEM>UTC</TIME_SYSTEM><MEAN_ELEMENT_THEORY>SGP4</MEAN_ELEMENT_THEORY></metadata> <data> <meanElements><EPOCH>2025-12-30T18:12:04.533984</EPOCH><MEAN_MOTION>14.40772474</MEAN_MOTION><ECCENTRICITY>0.00011240</ECCENTRICITY><INCLINATION>98.3721</INCLINATION><RA_OF_ASC_NODE>75.0877</RA_OF_ASC_NODE><ARG_OF_PERICENTER>97.3772</ARG_OF_PERICENTER><MEAN_ANOMALY>262.7545</MEAN_ANOMALY></meanElements> <tleParameters><EPHEMERIS_TYPE>0</EPHEMERIS_TYPE><CLASSIFICATION_TYPE>U</CLASSIFICATION_TYPE><NORAD_CAT_ID>47699</NORAD_CAT_ID><ELEMENT_SET_NO>999</ELEMENT_SET_NO><REV_AT_EPOCH>25439</REV_AT_EPOCH><BSTAR>0.00015330000000</BSTAR><MEAN_MOTION_DOT>0.00000447</MEAN_MOTION_DOT><MEAN_MOTION_DDOT>0.0000000000000</MEAN_MOTION_DDOT></tleParameters> </data> </segment></body> </omm></ndm> """ )OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : 18 SPCS ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data ├─ Mean Keplerian Elements │ Epoch : 2025-12-30T18:12:04.533984 │ Mean Motion : 14.40772474 rev/day │ Eccentricity : 0.0001124 │ Inclination : 98.3721° │ RA of Asc. Node : 75.0877° │ Arg. of Pericenter : 97.3772° │ Mean Anomaly : 262.7545° └─ TLE Related Parameters Ephemeris Type : 0 Classification Type : U NORAD Cat ID : 47699 Element Set Number : 999 Rev at Epoch : 25439 B* : 0.0001533 1/ER ∂(Mean Motion)/∂t : 4.47e-6 rev/day² ∂²(Mean Motion)/∂t² : 0.0 rev/day³julia> Propagators.init(Val(:SGP4), omm)OrbitPropagatorSgp4{Float64, Float64} (SGP4 Orbit Propagator): ├─ Mean Elements │ Epoch : 2.46104e6 (2025-12-30T18:12:04.534) │ Semi-Major Axis : 7134.084691 km │ Mean Motion : 14.40772474 rev/day │ Eccentricity : 0.0001124 │ Inclination : 98.3721° │ RA of Asc. Node : 75.0877° │ Arg. of Periapsis : 97.3772° │ Mean Anomaly : 262.7545° │ B* : 0.0001533 1/ER ├─ Constants │ R₀ : 6378.137 km │ XKE : 0.07436685317 er^(3/2)/min │ J₂ : 0.001082629989 │ J₃ : -2.53215306e-6 │ J₄ : -1.61098761e-6 └─ Propagation Last Instant : 0.0 min
Fitting Mean Elements
We can use the function:
Propagators.fit_mean_elements([sink::Type, ]::Val{:SGP4}, vjd::AbstractVector{Tjd}, vr_teme::AbstractVector{Tv}, vv_teme::AbstractVector{Tv}; kwargs...) -> sink, SMatrix{7, 7, T}, NamedTupleto fit a set of SGP4 mean elements using the osculating elements represented by a set of position vectors vr_teme [m] and a set of velocity vectors vv_teme [m / s] represented in the True-Equator, Mean-Equinox reference frame (TEME) at instants in the array vjd [Julian Day, UTC]. The mean elements are returned as an object of type sink, which can be a TLE or an OrbitMeanElementsMessage. If sink is omitted, an OrbitMeanElementsMessage is returned.
It returns the fitted mean elements, the final covariance matrix of the least-square algorithm, and a NamedTuple with its statistics: converged, iterations, position_rmse [m], velocity_rmse [m / s], and total_rmse.
This algorithm was based on [4].
This algorithm version will allocate a new SGP4 propagator with the constants sgp4c. If the allocation must be avoided, use the function Propagators.fit_mean_elements! instead.
The following keywords are available to configure the fitting process:
sgp4c::Sgp4Constants: SGP4 orbit propagator constants (seeSgp4Constants), whose number typeTis used in the fitting. It is only available in the allocating function. (Default:SGP4C_WGS84)atol::Number: Tolerance for the residual absolute value. If the residual is lower thanatolat any iteration, the computation loop stops. (Default: 2e-4)rtol::Number: Tolerance for the relative difference between the residuals. If the relative difference between the residuals in two consecutive iterations is lower thanrtol, the computation loop stops. (Default: 2e-4)estimate_bstar::Bool: Iftrue, the algorithm will try to estimate the B* parameter. Otherwise, it will be set to 0 or to the value in the initial guess. (Default:true)include_covariance::Bool: Iftrue, the covariance of the mean position and velocity obtained by the least-square algorithm is stored in the covariance matrix section of the output, represented in the TEME reference frame. It is only used whensinkisOrbitMeanElementsMessage. (Default:true)initial_guess::Union{Nothing, AbstractVector, TLE, OrbitMeanElementsMessage}: Initial guess for the fitting process. If it isnothing, the algorithm will obtain an initial estimate from the osculating elements invr_temeandvv_teme. (Default:nothing)jacobian_method::AbstractJacobianMethod: Method used to compute the Jacobian matrix. It can beFiniteDiffJacobian()for finite differences orForwardDiffJacobian()for ForwardDiff.jl automatic differentiation. (Default:FiniteDiffJacobian())jacobian_perturbation::Number: Initial state perturbation to compute the finite-difference when calculating the Jacobian matrix. (Default: 1e-3)jacobian_perturbation_tol::Number: Tolerance to accept the perturbation when calculating the Jacobian matrix. If the computed perturbation is lower thanjacobian_perturbation_tol, we increase it until its absolute value is higher thanjacobian_perturbation_tol. (Default: 1e-7)max_iterations::Int: Maximum number of iterations allowed for the least-square fitting. (Default: 50)mean_elements_epoch::Union{Number, DateTime}: Epoch of the fitted mean elements, represented by a Julian Day [UTC] or aDateTime[UTC]. (Default:vjd[end])template::Union{Nothing, sink, NamedTuple}: Source of the metadata of the output. If it is an object of typesink, its metadata is copied. If it is aNamedTuple, its entries are passed as keywords to the constructor ofsinkon top of the default metadata, e.g.(; name = "AMAZONIA 1", satellite_number = 47699)for aTLEor(; object_name = "AMAZONIA 1", object_id = "2021-015A", norad_cat_id = 47699)for anOrbitMeanElementsMessage. (Default:nothing)verbose::Bool: Iftrue, the algorithm prints debugging information tostdout. (Default:true)weight_vector::AbstractVector: Vector with the measurements weights for the least-square algorithm. We assemble the weight matrixWas a diagonal matrix with the elements inweight_vectorat its diagonal. (Default:@SVector(ones(Bool, 6)))
julia> vr_teme = [ [-6792.402703741442, 2192.6458461287293, 0.18851758695295118] .* 1000, [-6357.88873265975, 2391.9476768911686, 2181.838771262736] .* 1000 ];julia> vv_teme = [ [0.3445760107690598, 1.0395135806993514, 7.393686131436984] .* 1000, [2.5285015912807003, 0.27812476784300005, 7.030323100703928] .* 1000 ];julia> vjd = [ 2.46002818657856e6, 2.460028190050782e6 ];julia> omm, P, stats = Propagators.fit_mean_elements(Val(:SGP4), vjd, vr_teme, vv_teme; estimate_bstar = false)ACTION: Fitting the mean elements. Iteration Position RMSE Velocity RMSE Total RMSE RMSE Variation [km] [km / s] [ ] PROGRESS: 1 13.589 0.00473939 13.589 --- PROGRESS: 2 0.000902827 4.59551e-06 0.000902839 -99.9934 % PROGRESS: 3 5.80328e-09 4.38304e-07 4.38343e-07 -99.9514 % (OMM: UNDEFINED [UNDEFINED] (Epoch = 2023-03-24T16:33:40.388), [1.0858656073289727 -0.024687650690061822 … -0.07518401717497411 -5701.149921125949; -0.02468765069515278 1.0179970390752602 … 0.022969178921837436 1742.0303943064114; … ; -0.07518401717443697 0.022969178922001787 … 0.06514639076610358 4945.076064431256; -5701.149921093163 1742.0303943214715 … 4945.076064438029 3.754926862323227e8], (converged = true, iterations = 3, position_rmse = 5.803278389782464e-6, velocity_rmse = 0.00043830421111141945, total_rmse = 0.00043834262799558185))julia> ommOrbitMeanElementsMessage: ├─ Header │ Creation Date : 2026-09-09T23:39:29.477 │ Originator : SatelliteToolboxSgp4.jl ├─ Metadata │ Object Name : UNDEFINED │ Object ID : UNDEFINED │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data ├─ Mean Keplerian Elements │ Epoch : 2023-03-24T16:33:40.388 │ Mean Motion : 14.408141572426263 rev/day │ Eccentricity : 0.00012463364072265955 │ Inclination : 98.4303999965365° │ RA of Asc. Node : 162.11312239004525° │ Arg. of Pericenter : 136.15040637093372° │ Mean Anomaly : 241.9793402770317° ├─ TLE Related Parameters │ Ephemeris Type : 0 │ Classification Type : U │ NORAD Cat ID : 9999 │ Element Set Number : 0 │ Rev at Epoch : 0 │ B* : 0.0 1/ER │ ∂(Mean Motion)/∂t : 0.0 rev/day² │ ∂²(Mean Motion)/∂t² : 0.0 rev/day³ └─ Covariance Matrix Ref. Frame : TEME CX_X : 1.0858656073289727 km² CY_X : -0.02468765069515278 km² CY_Y : 1.0179970390752602 km² CZ_X : 0.05023262240842293 km² CZ_Y : -0.018268381835362873 km² CZ_Z : 1.029392839278491 km² CX_DOT_X : 0.029137264243658333 km²/s CX_DOT_Y : -0.007924415502066634 km²/s CX_DOT_Z : 0.016557057339731274 km²/s CX_DOT_X_DOT : 0.007622981124452393 km²/s² CY_DOT_X : -0.019971517901669327 km²/s CY_DOT_Y : 0.00936499755647425 km²/s CY_DOT_Z : -0.012882030446835025 km²/s CY_DOT_X_DOT : -0.005889598825445197 km²/s² CY_DOT_Y_DOT : 0.0045854587718331015 km²/s² CZ_DOT_X : -0.07518401717443697 km²/s CZ_DOT_Y : 0.022969178922001787 km²/s CZ_DOT_Z : -0.045496198074863034 km²/s CZ_DOT_X_DOT : -0.022248080294371354 km²/s² CZ_DOT_Y_DOT : 0.017239367163023475 km²/s² CZ_DOT_Z_DOT : 0.06514639076610358 km²/s²julia> stats(converged = true, iterations = 3, position_rmse = 5.803278389782464e-6, velocity_rmse = 0.00043830421111141945, total_rmse = 0.00043834262799558185)julia> tle, P, stats = Propagators.fit_mean_elements(TLE, Val(:SGP4), vjd, vr_teme, vv_teme; estimate_bstar = false)ACTION: Fitting the mean elements. Iteration Position RMSE Velocity RMSE Total RMSE RMSE Variation [km] [km / s] [ ] PROGRESS: 1 13.589 0.00473939 13.589 --- PROGRESS: 2 0.000902827 4.59551e-06 0.000902839 -99.9934 % PROGRESS: 3 5.80328e-09 4.38304e-07 4.38343e-07 -99.9514 % (TLE: UNDEFINED [9999] (Epoch = 2023-03-24T16:33:40.388), [1.0858656073289727 -0.024687650690061822 … -0.07518401717497411 -5701.149921125949; -0.02468765069515278 1.0179970390752602 … 0.022969178921837436 1742.0303943064114; … ; -0.07518401717443697 0.022969178922001787 … 0.06514639076610358 4945.076064431256; -5701.149921093163 1742.0303943214715 … 4945.076064438029 3.754926862323227e8], (converged = true, iterations = 3, position_rmse = 5.803278389782464e-6, velocity_rmse = 0.00043830421111141945, total_rmse = 0.00043834262799558185))julia> tleTLE: UNDEFINED (Epoch = 2023-03-24T16:33:40.388): ├─ Line 1 │ Satellite Number : 9999 │ Classification : U │ International Designator : 999999 │ Epoch Year : 23 │ Epoch Day : 83.69005078703704 │ ṅ/2 : 0.0 rev/day² │ n̈/6 : 0.0 rev/day³ │ B* : 0.0 1/ER │ Ephemeris Type : 0 │ Element Set Number : 0 └─ Line 2 Inclination : 98.4303999965365° RA of the Ascending Node : 162.11312239004525° Eccentricity : 0.00012463364072265955 Arg. of Perigee : 136.15040637093372° Mean Anomaly : 241.9793402770317° Mean Motion : 14.408141572426263 rev/day Revolution Number : 0
References
- [1] Hoots, F. R., Roehrich, R. L (1980). Models for Propagation of NORAD Elements Set. Spacetrack Report No. 3.
- [2] Vallado, D. A., Crawford, P., Hujsak, R., Kelso, T. S (2006). Revisiting Spacetrack Report #3: Rev1. AIAA.
- [3] SGP4 Source code of STRF, which the C code was converted by Paul. S. Crawford and Andrew R. Brooks.
- [4] Vallado, D. A., Crawford, P (2008). SGP4 Orbit Determination. AIAA.