Differentiable SGP4 in PyTorch.
This repository contains the implementation described in:
Acciarini, Baydin, Izzo, Closing the gap between SGP4 and high-precision propagation via differentiable programming, Acta Astronautica (2025), https://doi.org/10.1016/j.actaastro.2024.10.063.
- A PyTorch implementation of SGP4 with autograd support.
- Gradients of propagated states with respect to time and TLE-derived parameters.
- Parsing, writing and conversion of both TLEs and CCSDS OMMs (JSON/XML/KVN/CSV).
- Single-object and batched propagation APIs.
- A hybrid model (
mldsgp4) for learning corrections around SGP4 dynamics.
Primary use cases include state transition matrix estimation, covariance transformation/propagation, gradient-based orbit estimation, and ML-augmented orbit prediction.
From PyPI:
pip install dsgp4From conda-forge:
conda install conda-forge::dsgp4
# or
mamba install dsgp4From source:
git clone https://github.com/esa/dSGP4.git
cd dSGP4
pip install -e .import torch
import dsgp4
tle = dsgp4.TLE([
"1 25544U 98067A 24060.50000000 .00016717 00000-0 30134-3 0 9990",
"2 25544 51.6403 124.7938 0005102 220.2782 248.4427 15.50010353440289",
])
# Initialize once, then reuse for multiple propagations.
dsgp4.initialize_tle(tle, gravity_constant_name="wgs-84")
# tsince is in minutes from TLE epoch.
tsince = torch.tensor([0.0, 10.0, 20.0])
state = dsgp4.propagate(tle, tsince)
# state shape: (N, 2, 3) when tsince has N elements
# state[:, 0, :] -> position [km], state[:, 1, :] -> velocity [km/s]
print(state.shape)Space-Track distributes the same SGP4 mean elements in the CCSDS OMM (Orbit Mean-Elements Message) format, which dSGP4 reads in all its four serializations (JSON, XML, KVN and CSV):
import torch
import dsgp4
omm = dsgp4.OMM({
"OBJECT_NAME": "ISS (ZARYA)",
"OBJECT_ID": "1998-067A",
"EPOCH": "2024-02-29T12:00:00.000000",
"MEAN_MOTION": "15.50010353",
"ECCENTRICITY": "0.0005102",
"INCLINATION": "51.6403",
"RA_OF_ASC_NODE": "124.7938",
"ARG_OF_PERICENTER": "220.2782",
"MEAN_ANOMALY": "248.4427",
"NORAD_CAT_ID": "25544",
"BSTAR": "0.00030134",
"MEAN_MOTION_DOT": "0.00016717",
"MEAN_MOTION_DDOT": "0",
})
# OMM objects are used exactly like TLE ones:
dsgp4.initialize_tle(omm)
state = dsgp4.propagate(omm, torch.tensor([0.0, 10.0]))
# whole files (one message or many) are read with:
omms = dsgp4.omm.load("gp.json")
# and the two formats convert into each other:
tle = omm.to_tle()
omm = tle.to_omm()Unlike a TLE, an OMM is not constrained by two fixed-width lines: objects whose catalog number
is above 339999 (i.e. beyond what the Alpha-5 convention can encode) can only be represented
this way, and to_tle() raises a ValueError for them.
import torch
import dsgp4
tle = dsgp4.TLE([
"1 25544U 98067A 24060.50000000 .00016717 00000-0 30134-3 0 9990",
"2 25544 51.6403 124.7938 0005102 220.2782 248.4427 15.50010353440289",
])
time_min = torch.tensor(15.0, requires_grad=True)
state = dsgp4.propagate(tle, time_min, initialized=False)
# Example scalar objective: x-position at time_min.
loss = state[0, 0]
loss.backward()
print(time_min.grad)import torch
import dsgp4
tles = [
dsgp4.TLE([
"1 25544U 98067A 24060.50000000 .00016717 00000-0 30134-3 0 9990",
"2 25544 51.6403 124.7938 0005102 220.2782 248.4427 15.50010353440289",
]),
dsgp4.TLE([
"1 40967U 15058A 24060.50000000 .00000033 00000-0 00000+0 0 9992",
"2 40967 0.0187 89.2881 0002035 82.1068 220.3980 1.00270014 30754",
]),
]
times = torch.tensor([5.0, 30.0])
states = dsgp4.propagate_batch(tles, times, initialized=False)
print(states.shape) # (2, 2, 3)- Time input (
tsince) is in minutes from the TLE epoch. - Output units are km (position) and km/s (velocity).
- Supported gravity models:
wgs-72,wgs-84,wgs-72old. - Deep-space propagation is supported.
- Default torch dtype is set to
float64when importingdsgp4.
Run tests:
pytest -q- Full docs: https://esa.github.io/dSGP4
- Tutorials and examples are in
doc/notebooks/.
If you use dsgp4, please cite:
@article{acciarini2024closing,
title = {Closing the gap between SGP4 and high-precision propagation via differentiable programming},
journal = {Acta Astronautica},
volume = {226},
pages = {694-701},
year = {2025},
issn = {0094-5765},
doi = {https://doi.org/10.1016/j.actaastro.2024.10.063},
url = {https://www.sciencedirect.com/science/article/pii/S0094576524006374},
author = {Giacomo Acciarini and Atılım Güneş Baydin and Dario Izzo},
keywords = {SGP4, Orbital propagation, Differentiable programming, Machine learning, Spacecraft collision avoidance, Kessler, Kessler syndrome, AI for space, Applied machine learning for space}
}The project originated from work at the University of Oxford AI4Science Lab.
We thank Dr. T.S. Kelso for support and validation guidance against the official Space-Track SGP4 release: https://www.space-track.org/documentation#/sgp4.
dSGP4 is distributed under GNU GPL v3. Contact the authors for alternative licensing options.