Downloading & Visualizing TLE Data For Starlink Satellites
Slow Page
This page may load slowly due to the embedded interactive 3D plot. Please be patient while it loads.
This example demonstrates how to download Two-Line Element (TLE) data from the CelesTrak dataset using the Brahe library, and then visualize the complete Starlink satellite constellation in an interactive 3D plot.
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.
| import time
import brahe as bh
bh.initialize_eop()
|
Download Starlink TLEs
We'll use the CelesTrak client to fetch the latest GP data for all Starlink satellites, then convert each record into an SGP4 propagator:
| client = bh.celestrak.CelestrakClient()
records = client.get_gp(group="starlink")
propagators = [record.to_sgp_propagator(60.0) for record in records]
# Filter out any re-enerting spacecraft with < 350 km semi-major axis
# This can sometimes cause numerical issues with the propagator for very low orbit
# when eccentricity becomes negative.
propagators = [
prop for prop in propagators if prop.semi_major_axis >= (bh.R_EARTH + 350.0e3)
]
|
Inspect Satellite Data
Let's examine the properties of the first satellite to understand the orbital parameters:
| # Inspect the first satellite
first_sat = propagators[0]
print(f"\nFirst satellite: {first_sat.get_name()}")
print(f"Epoch: {first_sat.epoch}")
print(f"Semi-major axis: {first_sat.semi_major_axis / 1000:.1f} km")
print(f"Inclination: {first_sat.inclination:.1f} degrees")
print(f"Eccentricity: {first_sat.eccentricity:.6f}")
|
Visualize in 3D
We'll create an interactive 3D visualization of the entire Starlink constellation using Plotly. We'll use the Natural Earth 50m texture for a realistic Earth representation:
| fig = bh.plot_trajectory_3d(
[], # Empty trajectory list; we'll add markers for each satellite
units="km",
show_earth=True,
earth_texture="natural_earth_50m",
backend="plotly",
view_azimuth=45.0,
view_elevation=30.0,
view_distance=3.0,
sphere_resolution_lon=600, # Reduce sphere texture resolution for performance
sphere_resolution_lat=300,
)
|
Finally, we'll add points for all satellites at the current epoch:
| # Get the current time for display
epc = bh.Epoch.now()
# For each satellite, add a marker at the current position
for prop in propagators:
state = prop.state_eci(epc)
fig.add_scatter3d(
x=[state[0] / 1000],
y=[state[1] / 1000],
z=[state[2] / 1000],
mode="markers",
marker=dict(size=2, color="white"),
name=prop.get_name(),
showlegend=False,
)
|
The resulting plot shows the complete Starlink constellation orbiting Earth. The interactive visualization allows you to rotate, zoom, and pan to explore the satellite positions from different angles.
Full Code Example
| visualizing_starlink.py |
|---|
| import time
import brahe as bh
bh.initialize_eop()
# Download GP data for all Starlink satellites from CelesTrak
# Uses CelestrakClient to query the "starlink" group, then converts
# each GP record into an SGP4 propagator with a 60-second step size
print("Downloading Starlink GP records from CelesTrak...")
start_time = time.time()
client = bh.celestrak.CelestrakClient()
records = client.get_gp(group="starlink")
propagators = [record.to_sgp_propagator(60.0) for record in records]
# Filter out any re-enerting spacecraft with < 350 km semi-major axis
# This can sometimes cause numerical issues with the propagator for very low orbit
# when eccentricity becomes negative.
propagators = [
prop for prop in propagators if prop.semi_major_axis >= (bh.R_EARTH + 350.0e3)
]
elapsed = time.time() - start_time
print(
f"Initialized propagators for {len(propagators)} Starlink satellites in {elapsed:.2f} seconds."
)
# Inspect the first satellite
first_sat = propagators[0]
print(f"\nFirst satellite: {first_sat.get_name()}")
print(f"Epoch: {first_sat.epoch}")
print(f"Semi-major axis: {first_sat.semi_major_axis / 1000:.1f} km")
print(f"Inclination: {first_sat.inclination:.1f} degrees")
print(f"Eccentricity: {first_sat.eccentricity:.6f}")
# Create interactive 3D plot with Earth texture
print("\nCreating 3D visualization of satellites...")
ts = time.time()
fig = bh.plot_trajectory_3d(
[], # Empty trajectory list; we'll add markers for each satellite
units="km",
show_earth=True,
earth_texture="natural_earth_50m",
backend="plotly",
view_azimuth=45.0,
view_elevation=30.0,
view_distance=3.0,
sphere_resolution_lon=600, # Reduce sphere texture resolution for performance
sphere_resolution_lat=300,
)
te = time.time() - ts
print(f"Created base 3D plot in {te:.2f} seconds.")
ts = time.time()
# Get the current time for display
epc = bh.Epoch.now()
# For each satellite, add a marker at the current position
for prop in propagators:
state = prop.state_eci(epc)
fig.add_scatter3d(
x=[state[0] / 1000],
y=[state[1] / 1000],
z=[state[2] / 1000],
mode="markers",
marker=dict(size=2, color="white"),
name=prop.get_name(),
showlegend=False,
)
te = time.time() - ts
print(f"Added satellite markers in {te:.2f} seconds.")
|
See Also