Two-Line Element Sets and SGP4¶
TLE
¶
Two-Line Element Set (TLE) representing a satellite ephemeris
Structure representing a Two-Line Element Set (TLE), a satellite ephemeris format from the 1970s that is still somehow in use today and can be used to calculate satellite position and velocity in the "TEME" frame (not-quite GCRF) using the "Simplified General Perturbations-4" (SGP-4) mathematical model that is also included in this package.
For details, see: https://en.wikipedia.org/wiki/Two-line_element_set
The TLE format is still commonly used to represent satellite ephemerides, and satellite ephemerides catalogs in this format are publicly available at www.space-track.org (registration required)
TLEs sometimes have a "line 0" that includes the name of the satellite
satnum
property
writable
¶
Satellite number, or equivalently the NORAD ID
raan
property
writable
¶
Right Ascension of Ascending Node, in degrees
eccen
property
writable
¶
Satellite eccentricity, in range [0,1]
mean_anomaly
property
writable
¶
Mean anomaly in degrees
mean_motion
property
writable
¶
Mean motion in revs / day
inclination
property
writable
¶
Inclination, in degrees
epoch
property
writable
¶
TLE epoch
arg_of_perigee
property
writable
¶
Argument of Perigee, in degrees
mean_motion_dot
property
writable
¶
1/2 of first derivative of mean motion, in revs/day^2
Note
the "1/2" is because that is how number is stored in the TLE
mean_motion_dot_dot
property
writable
¶
1/6 of 2nd derivative of mean motion, in revs/day^3
Note
The "1/6" is because that is how number is stored in the TLE
name
property
writable
¶
The name of the satellite
bstar
property
writable
¶
Drag of the satellite
should be rho0 * Cd * A / 2 / m
Units (which are strange) is multiples of 1 / Earth radius
from_file(filename)
staticmethod
¶
Load TLEs from input text file Return a list of TLES loaded from input text file.
If the file contains lines only represent a single TLE, the TLE will be output, rather than a list with a single TLE element
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
name of text file lines for TLE(s) to load |
required |
Returns:
| Type | Description |
|---|---|
list[TLE] | TLE
|
list[TLE] | TLE: a list of TLE objects or a single TLE of lines for |
list[TLE] | TLE
|
only 1 are passed in |
from_lines(lines)
staticmethod
¶
Return a list of TLES loaded from input list of lines
If the file contains lines only represent a single TLE, the TLE will
be output, rather than a list with a single TLE element
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
list[str]
|
list of strings with lines for TLE(s) to load |
required |
Returns:
| Type | Description |
|---|---|
list[TLE] | TLE
|
list[TLE] | TLE: a list of TLE objects or a single TLE of lines for |
list[TLE] | TLE
|
only 1 are passed in |
to_2line()
¶
to_3line()
¶
fit_from_states(states, times, epoch)
staticmethod
¶
Perform non-linear least squares fit of TLE parameters to a list of GCRF states
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
states
|
list[ndarray]
|
List of GCRF states to fit to. Each state is a 6-element vector. The first 3 values are positions in meters. The last 3 values are velocities in meters / second. |
required |
times
|
list[time] | list[datetime]
|
List of times corresponding to the states |
required |
epoch
|
time | datetime
|
Epoch time for the TLE. Must be within range of times. |
required |
Returns:
| Type | Description |
|---|---|
tuple[TLE, dict]
|
tuple[TLE, dict]: Fitted TLE and fitting results in a dictionary |
Notes:
* SGP4 propagator is used to match TLE to the states
* Input GCRF states are rotated into TEME frame used by SGP4
* First and second derivatives of mean motion are ignored, as they are not
used by SGP4
* Non-linear Levenberg-Marquardt optimization is performed to fit the TLE parameters to the provided states.
TLE parameters used in fit include:
* Inclination
* Eccentricity
* Right Ascension of Ascending Node
* Argument of Perigee
* Mean Anomaly
* Mean motion
* Drag (bstar)
* Rust crate "rmpfit" is used to perform the optimization
(https://crates.io/crates/rmpfit)
* Results dictionary includes the following keys:
* `success` : "mpsuccess" value describing result of minimization
* `best_norm`: Final chi-squared value
* `orig_norm`: Initial chi-squared value
* `n_iter`: Number of iterations performed
* `n_fev`: Number of function evaluations performed
* `n_par`: Total number of parameters being optimized
* `n_free`: Number of free parameters
* `n_pegged`: Number of pegged parameters
* `n_func`: Number of residuals
* `resid`: Final residuals
* `xerror`: Final parameter uncertainties (1-sigma)
* `covar`: Final parameter covariance matrix
Example
import numpy as np
# Given a list of GCRF states and times
states = [np.array([pos0[0], pos0[1], pos0[2], vel0[0], vel0[1], vel0[2]])]
times = [satkit.time(2024, 1, 1)]
epoch = satkit.time(2024, 1, 1)
tle, results = satkit.TLE.fit_from_states(states, times, epoch)
if results["success"] == satkit.mpsuccess.MP_OK_CHI:
print("Fit successful")
sgp4(tle, tm, **kwargs)
¶
SGP-4 propagator for TLE
Note
Run Simplified General Perturbations (SGP)-4 propagator on Two-Line Element Set to output satellite position and velocity at given time in the "TEME" coordinate system
A detailed description is at: https://celestrak.org/publications/AIAA/2008-6770/AIAA-2008-6770.pdf
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tle
|
TLE | list[TLE] | dict
|
TLE or OMM (or list of TLES) on which to operate |
required |
tm
|
time | list[time] | list[datetime] | ArrayLike[time] | ArrayLike[datetime]
|
time(s) at which to compute position and velocity |
required |
Other Parameters:
| Name | Type | Description |
|---|---|---|
gravconst |
sgp4_gravconst
|
gravity constant to use. Default is gravconst.wgs72 |
opsmode |
sgp4_opsmode
|
opsmode.afspc (Air Force Space Command) or opsmode.improved. Default is opsmode.afspc |
errflag |
bool
|
whether or not to output error conditions for each TLE and time output. Default is False (this is likely rarely needed, but can be useful for debugging) (this may also flag a typing error ... I can't figure out how to get rid of it) |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
tuple[npt.ArrayLike[np.float64], npt.ArrayLike[np.float64]]: position and velocity |
NDArray[float64]
|
in meters and meters/second, respectively, |
tuple[NDArray[float64], NDArray[float64]]
|
in the TEME frame at each of the "Ntime" input times and each of the "Ntle" tles |
tuple[NDArray[float64], NDArray[float64]]
|
Additional return value if errflag is True: |
tuple[NDArray[float64], NDArray[float64]]
|
list[sgp4_error]: list of errors for each TLE and time output, if errflag is True |
Note 1
Now supports propagation of OMM (Orbital Mean-Element Message) dictionaries The dictionaries must follow the structure used by https://www.celestrak.org or https://www.space-track.org.
Note 2
The "TEME" frame of the SGP4 state vectors is not a truly inertial frame. It is a "True Equator Mean Equinox" frame, which is a non-rotating frame with respect to the mean equator and mean equinox of the epoch of the TLE. It is close to a true inertial frame, but can be offset by small amounts due to precession and nutation.
Example
lines = [
"0 INTELSAT 902",
"1 26900U 01039A 06106.74503247 .00000045 00000-0 10000-3 0 8290",
"2 26900 0.0164 266.5378 0003319 86.1794 182.2590 1.00273847 16981"
]
tle = satkit.TLE.single_from_lines(lines)
# Compute TEME position & velocity at epoch
pteme, vteme = satkit.sgp4(tle, tle.epoch)
# Rotate to ITRF frame
q = satkit.frametransform.qteme2itrf(tm)
pitrf = q * pteme
vitrf = q * vteme - np.cross(np.array([0, 0, satkit.univ.omega_earth]), pitrf)
# convert to ITRF coordinate object
coord = satkit.itrfcoord.from_vector(pitrf)
# Print ITRF coordinate object location
print(coord)
# ITRFCoord(lat: -0.0363 deg, lon: -2.2438 deg, hae: 35799.51 km)
Example 2
import requests
import json
# Query ephemeris for the International Space Station (ISS)
url = 'https://celestrak.org/NORAD/elements/gp.php?CATNR=25544&FORMAT=json'
with requests.get(url) as response:
omm = response.json()
# Get a representative time from the output
epoch = sk.time(omm[0]['EPOCH'])
# Compute TEME position & velocity at epoch
pteme, vteme = satkit.sgp4(omm[0], epoch)