Skip to content

Two-Line Element Sets, OMMs, 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 https://www.space-track.org (registration required) and https://celestrak.org (no registration needed).

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

Notes

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

Notes

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

a list of TLE objects or a single TLE if lines for only 1 are passed in

Example
tles = satkit.TLE.from_file("gps-ops.txt")
for tle in tles:
    print(tle.name, tle.satnum)

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

a list of TLE objects or a single TLE if lines for only 1 are passed in

Example
lines = [
    "0 ISS (ZARYA)",
    "1 25544U 98067A   21264.51782528  .00002893  00000-0  58680-4 0  9991",
    "2 25544  51.6442 208.5856 0001458  47.2277  50.1624 15.48919419302878"
]
tle = satkit.TLE.from_lines(lines)
print(tle.name)
# ISS (ZARYA)

from_url(url) staticmethod

Load TLE(s) from a URL

Fetches the content at the given URL and parses it as TLE lines. Works with any URL that returns plain-text TLE data.

Parameters:

Name Type Description Default
url str

URL to fetch TLE data from

required

Returns:

Type Description
list[TLE] | TLE

Single TLE or list of TLEs parsed from the response

Example
tles = sk.TLE.from_url("https://celestrak.org/NORAD/elements/gp.php?GROUP=stations&FORMAT=tle")

to_2line()

Output as 2 canonical TLE Lines

Returns:

Type Description
list[str]

2 canonical TLE Lines

Example
lines = tle.to_2line()
print(lines[0])
# 1 25544U 98067A  ...
print(lines[1])
# 2 25544  51.6442 ...

to_3line()

Output as 2 canonical TLE lines preceded by a name line (3-line element set)

Returns:

Type Description
list[str]

3-line element set, name line then 2 canonical TLE lines

Example
lines = tle.to_3line()
for line in lines:
    print(line)

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]

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 inclination, eccentricity, RAAN, argument of perigee, mean anomaly, mean motion, and drag (bstar) to the provided states. The solver is built on top of the numeris linear algebra crate.

The results dictionary includes the following keys: status (a :class:tlefitstatus), converged (bool), orig_norm, best_norm, grad_norm, n_iter, n_res_evals.

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["converged"]:
    print("Fit successful")

sgp4(tle, tm, **kwargs)

SGP-4 propagator for TLE

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
tuple[NDArray[float64], NDArray[float64]]

position and velocity in meters and meters/second, respectively, in the TEME frame at each of the "Ntime" input times and each of the "Ntle" tles. Additional return value if errflag is True: list[sgp4_error] with error conditions for each TLE and time output.

Notes
  • 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.
  • 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)
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)

omm_from_url(url)

Load OMM(s) from a URL as a list of dictionaries

Fetches the content at the given URL and auto-detects JSON vs XML format. Returns a list of dictionaries that can be passed directly to :func:sgp4.

Parameters:

Name Type Description Default
url str

URL to fetch OMM data from (e.g. CelesTrak or Space-Track endpoint)

required

Returns:

Type Description
list[dict]

list[dict]: List of OMM dictionaries with standard CCSDS keys (OBJECT_NAME, EPOCH, MEAN_MOTION, ECCENTRICITY, etc.)

Example
import satkit as sk

omms = sk.omm_from_url("https://celestrak.org/NORAD/elements/gp.php?GROUP=stations&FORMAT=json")
pos, vel = sk.sgp4(omms[0], sk.time(2024, 1, 1))