Skip to content

Visualizing GPS Satellite Orbits

In this example we'll show how to visualize the orbits of GPS satellites using Brahe. We'll download the latest TLE data for the GPS constellation from CelesTrak, propagate each satellite for one orbit, and create an interactive 3D plot showing their trajectories around Earth.


Initialize Earth Orientation Parameters

Before starting, we need to import brahe and ensure that we have Earth orientation parameters initialized. We'll use initialize_eop(), which provides a CachingEOPProvider to deliver up-to-date Earth orientation parameters.

1
2
3
4
5
import time

import brahe as bh

bh.initialize_eop()

Download GPS TLEs

We'll use the CelesTrak client to fetch the latest GP data for all GPS satellites, then convert each record into an SGP4 propagator:

1
2
3
client = bh.celestrak.CelestrakClient()
records = client.get_gp(group="gps-ops")
propagators = [r.to_sgp_propagator(60.0) for r in records]

Propagate orbits

Next, we'll propagate each satellite for one full orbit based on its semi-major axis:

1
2
3
4
# Propagate each satellite one orbit
for prop in propagators:
    orbital_period = bh.orbital_period(prop.semi_major_axis)
    prop.propagate_to(prop.epoch + orbital_period)

The line

    orbital_period = bh.orbital_period(prop.semi_major_axis)
computes the or orbital period of the satellite by converting the semi-major axis associated with the SGP4Propagator into an orbital period using Brahe's orbital_period function.

It then propagates the satellite to one full orbit past its epoch using the propagate_to method to ensure that the trajectory contains position data for one complete orbit.

to_sgp_propagator builds a propagator without TLE round-tripping

GPRecord.to_sgp_propagator (API) constructs an SGPPropagator directly from the record's OMM orbital elements rather than serializing them through fixed-width TLE text first, so no numeric precision is lost to the TLE format. Its argument is the propagator step size in seconds (60 s here), which sets the spacing of the recorded trajectory states - the markers the 3D plot below draws. Each propagator is initialized at its own record's epoch, and GP epochs differ across a constellation, so "one orbital period past prop.epoch" is a slightly different absolute time span for every satellite. Propagate all satellites to a shared epoch first for any analysis that compares the constellation at one instant.

Visualize in 3D

We'll create an interactive 3D visualization of the entire GPS constellation using Plotly. We'll use the Natural Earth 50m texture for a realistic Earth representation:

fig = bh.plot_trajectory_3d(
    [
        {
            "trajectory": prop.trajectory,
            "mode": "markers",
            "size": 2,
            "label": prop.get_name(),
        }
        for prop in propagators
    ],
    units="km",
    show_body=True,
    texture="natural_earth_50m",
    backend="plotly",
    view_azimuth=45.0,
    view_elevation=30.0,
    view_distance=2.0,
)

The resulting plot shows the complete GPS constellation orbiting Earth. The interactive visualization allows you to rotate, zoom, and pan to explore the satellite positions from different angles.

Full Code Example

Full Code
visualizing_gps.py
import time

import brahe as bh

bh.initialize_eop()

# Download GP data for all GPS satellites from CelesTrak
# Uses CelestrakClient to query the "gps-ops" group, then converts
# each GP record into an SGP4 propagator with a 60-second step size
print("Downloading GPS GP records from CelesTrak...")
start_time = time.time()
client = bh.celestrak.CelestrakClient()
records = client.get_gp(group="gps-ops")
propagators = [r.to_sgp_propagator(60.0) for r in records]
elapsed = time.time() - start_time
print(
    f"Initialized propagators for {len(propagators)} GPS satellites in {elapsed:.2f} seconds."
)

ts = time.time()
# Propagate each satellite one orbit
for prop in propagators:
    orbital_period = bh.orbital_period(prop.semi_major_axis)
    prop.propagate_to(prop.epoch + orbital_period)
te = time.time() - ts
print(f"Propagated all satellites to one orbit in {te:.2f} seconds.")

# Create interactive 3D plot with Earth texture
print("\nCreating 3D visualization of satellites...")
ts = time.time()
fig = bh.plot_trajectory_3d(
    [
        {
            "trajectory": prop.trajectory,
            "mode": "markers",
            "size": 2,
            "label": prop.get_name(),
        }
        for prop in propagators
    ],
    units="km",
    show_body=True,
    texture="natural_earth_50m",
    backend="plotly",
    view_azimuth=45.0,
    view_elevation=30.0,
    view_distance=2.0,
)
te = time.time() - ts
print(f"Created base 3D plot in {te:.2f} seconds.")

See Also