Skip to main content

satorbit

Satellite orbit tools for Python: TLE propagation, SP3 parsing, and coordinate transformations.

Originally developed at KNMI (Royal Netherlands Meteorological Institute) as part of swxtools.

Installation

pip install satorbit

Features

  • TLE handling: Query space-track.org, parse TLE data, and propagate orbits using SGP4
  • SP3 parsing: Read SP3 precise orbit files into pandas DataFrames
  • OEM parsing: Read CCSDS Orbit Ephemeris Message (OEM) files, e.g. EME2000 L1 ephemerides
  • Coordinate transforms: Convert between ITRF, geodetic, GCRS, GSE, and Quasi-Dipole coordinates
  • Orbit interpolation: High-accuracy 7th-order Lagrange interpolation with automatic handling of geodetic, magnetic, and solar angle coordinates
  • Keplerian mechanics: Simulate orbits with J2 perturbation effects

Usage

TLE Propagation

import pandas as pd
from satorbit import geodetic_orbit_from_tle

# Generate orbit positions for a satellite over a time range
times = pd.date_range("2024-01-01", "2024-01-02", freq="1min")
orbit = geodetic_orbit_from_tle(norad_id=25544, times=times)  # ISS
print(orbit[['lat', 'lon', 'height']])

API calls to space-track.org are automatically rate-limited (2s between requests) and TLE results are cached in memory with merge-on-overlap, so iterating over consecutive daily ranges only hits the API once per satellite.

SP3 File Parsing

from satorbit import sp3_to_itrf_df

df = sp3_to_itrf_df("orbit.sp3")
print(df[['x_itrf', 'y_itrf', 'z_itrf']])

Coordinate Transformations

from satorbit import itrf_to_geodetic, geodetic_to_qd

# Convert ITRF to geodetic coordinates
df_geo = itrf_to_geodetic(df_orbit)

# Convert to Quasi-Dipole magnetic coordinates
df_qd = geodetic_to_qd(df_geo)

L1 ephemerides: OEM parsing and GSE

Read a CCSDS OEM file (such as an L1 Halo/Lissajous spacecraft ephemeris in EME2000) and convert it to the Geocentric Solar Ecliptic (GSE) frame:

from satorbit import oem_to_df, eme2000_to_gse

# Parse an EME2000 OEM file into a UTC-indexed DataFrame
df = oem_to_df("SWFO_DefEphem.oem")
print(df.attrs["ref_frame"], df.attrs["object_name"])  # EME2000 SWFO

# Convert to GSE (adds x/y/z_gse and vx/vy/vz_gse columns, km and km/s)
df_gse = eme2000_to_gse(df)
print(df_gse[["x_gse", "y_gse", "z_gse"]])  # x_gse ~ +1.45e6 km at L1

The GSE X-axis points along the geometric Earth–Sun line, the Z-axis is the ecliptic north pole, and the frame is built with astropy (get_body_barycentric and BarycentricMeanEcliptic). The frame is purely geometric (no aberration), following the convention of Fränz & Harper (2002).

GSE rotates with the Earth–Sun line (~1°/day), so velocity depends on the convention. By default eme2000_to_gse returns the velocity in the GSE frame (the time derivative of the GSE position, including the frame-rotation term), matching the convention used by itrs_to_gcrs. Pass include_frame_rotation=False to instead rotate the inertial velocity vector into the GSE axes. gse_to_eme2000 is the inverse transform.

Orbit Interpolation

from satorbit import interpolate_orbit_to_datetimeindex

# Interpolate an orbit DataFrame to new timestamps
# Works with ITRF, geodetic, quasi-dipole, MLT, and solar angle columns
new_times = pd.date_range("2024-01-01", "2024-01-02", freq="1s")
df_interpolated = interpolate_orbit_to_datetimeindex(df_orbit, new_times)

Spherical and angular columns (lon, lat, height, lat_qd, lon_qd, mlt, solar_elevation, solar_azimuth) are automatically converted to Cartesian representation before interpolation, avoiding singularities at the antimeridian and poles. This allows expensive coordinate transformations to be computed once at coarse cadence and then accurately interpolated to any timestamp.

Keplerian Orbit Simulation

import numpy as np
from satorbit import simulate_orbit, unperturbed_orbitalperiod

kepler = {
    "semimajoraxis": 7000,  # km
    "eccentricity": 0.001,
    "inclination": np.radians(98),
    "argumentofperigee": np.radians(90),
    "raan": np.radians(0),
    "initial_mean_anomaly": 0,
    "mu": 398600.4415,
    "re": 6378.1363,
    "j2": 1082.6357e-6
}

period = unperturbed_orbitalperiod(kepler)
times = np.linspace(0, period, 100)
orbit = simulate_orbit(kepler, times)

Configuration

For TLE queries from space-track.org, either create ~/.spacetrackorg.txt:

[default]
username = your_username
password = your_password

Or set credentials programmatically:

from satorbit import set_credentials

set_credentials("your_username", "your_password")

License

Apache License 2.0 - see LICENSE

Acknowledgements

Developed with support from ESA through the Swarm Data Innovation and Science Cluster (Swarm DISC).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

satorbit-0.5.0.tar.gz (125.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

satorbit-0.5.0-py3-none-any.whl (30.6 kB view details)

Uploaded Python 3

File details

Details for the file satorbit-0.5.0.tar.gz.

File metadata

  • Download URL: satorbit-0.5.0.tar.gz
  • Upload date:
  • Size: 125.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for satorbit-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4f3f36e2c0ea85c4501130db4b661b01094d14424541f418fa70d96ceea95c10
MD5 df398244ff5f0db7575846cb9554ad87
BLAKE2b-256 76ab4dc161f244bc6b42f2d3307ef0b379fab4a7686f1ef2b26e5100d549ad04

See more details on using hashes here.

File details

Details for the file satorbit-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: satorbit-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 30.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for satorbit-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bc2da8122846a079d20394dd4faa7ee2c5186d404e4b1e9aa89e55d49c398e44
MD5 ebddda23b93dbed85eb6e3304cfe76af
BLAKE2b-256 b8cfa4b1c4a8f68447f68aac3a914796193380b0de196bb3ab6ca3f7b3b5ee01

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.1

2 files

This release

0.5.0 This release

2 files

0.4.0

2 files

0.3.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page