Functions: Satellite
Functions for propagating TLEs, converting coordinate frames, computing ground tracks, and predicting satellite passes. These form the core satellite tracking pipeline in pg_orbit.
sgp4_propagate
Section titled “sgp4_propagate”Propagates a TLE to a given time using the SGP4 (near-earth) or SDP4 (deep-space) algorithm. The algorithm is selected automatically based on orbital period: elements with a period >= 225 minutes use SDP4.
Signature
Section titled “Signature”sgp4_propagate(tle tle, t timestamptz) → eci_positionParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Two-Line Element set to propagate |
t | timestamptz | Target epoch for propagation |
Returns
Section titled “Returns”An eci_position in the TEME reference frame. Position in km, velocity in km/s.
Errors
Section titled “Errors”Raises an exception if SGP4/SDP4 returns a fatal error code (e.g., satellite decay, eccentricity out of range, mean motion near zero). Use sgp4_propagate_safe if you need NULL-on-error behavior.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT eci_x(pos) AS x_km, eci_y(pos) AS y_km, eci_z(pos) AS z_km, eci_speed(pos) AS speed_kmsFROM iss, sgp4_propagate(tle, '2024-01-02 12:00:00+00') AS pos;sgp4_propagate_safe
Section titled “sgp4_propagate_safe”Identical to sgp4_propagate, but returns NULL instead of raising an exception on propagation errors. This is the batch-safe variant for processing large TLE catalogs where some elements may be stale or invalid.
Signature
Section titled “Signature”sgp4_propagate_safe(tle tle, t timestamptz) → eci_positionParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Two-Line Element set to propagate |
t | timestamptz | Target epoch for propagation |
Returns
Section titled “Returns”An eci_position, or NULL if propagation fails.
Example
Section titled “Example”-- Propagate an entire catalog, skipping failed elementsSELECT norad_id, eci_x(pos) AS x_km, eci_y(pos) AS y_km, eci_z(pos) AS z_kmFROM satellite_catalog, sgp4_propagate_safe(tle, now()) AS posWHERE pos IS NOT NULL;sgp4_propagate_series
Section titled “sgp4_propagate_series”Generates a time series of TEME ECI positions for a single TLE over a time range. Returns one row per time step. This is significantly faster than calling sgp4_propagate inside a generate_series because the SGP4 initializer runs once.
Signature
Section titled “Signature”sgp4_propagate_series( tle tle, start_time timestamptz, end_time timestamptz, step interval) → TABLE(t timestamptz, x float8, y float8, z float8, vx float8, vy float8, vz float8)Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Two-Line Element set |
start_time | timestamptz | Start of the time range |
end_time | timestamptz | End of the time range (inclusive if aligned to step) |
step | interval | Time between samples |
Returns
Section titled “Returns”A set of rows with timestamp and TEME position/velocity components. Position in km, velocity in km/s.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT t, x, y, z, vx, vy, vzFROM iss, sgp4_propagate_series(tle, '2024-01-02 00:00:00+00', '2024-01-02 01:00:00+00', interval '1 minute');tle_distance
Section titled “tle_distance”Computes the Euclidean distance between two satellites at a given time. Both TLEs are propagated to the target time and the 3D distance between their TEME positions is returned.
Signature
Section titled “Signature”tle_distance(a tle, b tle, t timestamptz) → float8Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
a | tle | First satellite |
b | tle | Second satellite |
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”Distance in kilometers. Raises an exception if either TLE fails to propagate.
Example
Section titled “Example”-- Distance between two satellites at a specific timeSELECT tle_distance(sat_a.tle, sat_b.tle, '2024-06-15 12:00:00+00') AS dist_kmFROM satellite_catalog sat_a, satellite_catalog sat_bWHERE sat_a.norad_id = 25544 -- ISS AND sat_b.norad_id = 48274; -- CSS (Tianhe)eci_to_geodetic
Section titled “eci_to_geodetic”Converts a TEME ECI position to WGS-84 geodetic coordinates. The timestamp is required to compute the Earth’s rotation angle (Greenwich Apparent Sidereal Time).
Signature
Section titled “Signature”eci_to_geodetic(pos eci_position, t timestamptz) → geodeticParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
pos | eci_position | TEME ECI position |
t | timestamptz | Time of the position (for sidereal time computation) |
Returns
Section titled “Returns”A geodetic with WGS-84 latitude, longitude, and altitude.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT geo_lat(g) AS lat, geo_lon(g) AS lon, geo_alt(g) AS alt_kmFROM iss, eci_to_geodetic(sgp4_propagate(tle, now()), now()) AS g;eci_to_topocentric
Section titled “eci_to_topocentric”Converts a TEME ECI position to topocentric (observer-relative) coordinates. Computes azimuth, elevation, slant range, and range rate.
Signature
Section titled “Signature”eci_to_topocentric(pos eci_position, obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
pos | eci_position | TEME ECI position and velocity |
obs | observer | Observer location |
t | timestamptz | Time of the position (for sidereal time computation) |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range, and range rate.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT topo_azimuth(tc) AS az, topo_elevation(tc) AS el, topo_range(tc) AS range_km, topo_range_rate(tc) AS range_rate_kmsFROM iss, eci_to_topocentric( sgp4_propagate(tle, now()), '40.0N 105.3W 1655m'::observer, now() ) AS tc;subsatellite_point
Section titled “subsatellite_point”Returns the nadir (directly below the satellite) point on the WGS-84 ellipsoid for a given TLE at a given time. This is a convenience function equivalent to propagating and then converting to geodetic, but with altitude set to the satellite altitude.
Signature
Section titled “Signature”subsatellite_point(tle tle, t timestamptz) → geodeticParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”A geodetic with the latitude, longitude, and altitude of the satellite above the WGS-84 ellipsoid.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT geo_lat(sp) AS nadir_lat, geo_lon(sp) AS nadir_lon, geo_alt(sp) AS altitude_kmFROM iss, subsatellite_point(tle, now()) AS sp;ground_track
Section titled “ground_track”Generates a time series of subsatellite points (nadir ground track) for a satellite over a time range. Each row contains the timestamp, latitude, longitude, and altitude.
Signature
Section titled “Signature”ground_track( tle tle, start_time timestamptz, end_time timestamptz, step interval) → TABLE(t timestamptz, lat float8, lon float8, alt float8)Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
start_time | timestamptz | Start of the time range |
end_time | timestamptz | End of the time range |
step | interval | Time between samples |
Returns
Section titled “Returns”A set of rows with timestamp, latitude (degrees), longitude (degrees), and altitude (km).
Example
Section titled “Example”-- ISS ground track for one orbit (~92 minutes) at 30-second resolutionWITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT t, lat, lon, altFROM iss, ground_track(tle, now(), now() + interval '92 minutes', interval '30 seconds');observe
Section titled “observe”Propagates a TLE and computes topocentric look angles in a single call. Equivalent to eci_to_topocentric(sgp4_propagate(tle, t), obs, t), but avoids the intermediate allocation.
Signature
Section titled “Signature”observe(tle tle, obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
obs | observer | Observer location |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range, and range rate.
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT topo_azimuth(o) AS az, topo_elevation(o) AS el, topo_range(o) AS range_kmFROM iss, observe(tle, '40.0N 105.3W 1655m'::observer, now()) AS o;observe_safe
Section titled “observe_safe”Identical to observe, but returns NULL instead of raising an exception on propagation errors. Use this when processing large TLE catalogs in batch.
Signature
Section titled “Signature”observe_safe(tle tle, obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
obs | observer | Observer location |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric, or NULL if propagation fails.
Example
Section titled “Example”-- Find all satellites above the horizon right now, skipping stale TLEsSELECT norad_id, topo_azimuth(o) AS az, topo_elevation(o) AS elFROM satellite_catalog, observe_safe(tle, '40.0N 105.3W 1655m'::observer, now()) AS oWHERE o IS NOT NULL AND topo_elevation(o) > 0ORDER BY topo_elevation(o) DESC;next_pass
Section titled “next_pass”Finds the next satellite pass over an observer location. Searches forward from the given start time up to 7 days.
Signature
Section titled “Signature”next_pass(tle tle, obs observer, start timestamptz) → pass_eventParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
obs | observer | Observer location |
start | timestamptz | Time to begin searching from |
Returns
Section titled “Returns”A pass_event with AOS, maximum elevation, LOS, azimuths, and duration. Returns NULL if no pass is found within 7 days (possible for equatorial observers looking for high-inclination satellites, or vice versa).
Example
Section titled “Example”WITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT pass_aos_time(p) AS rise, pass_max_elevation(p) AS max_el, pass_los_time(p) AS set, pass_duration(p) AS durationFROM iss, next_pass(tle, '40.0N 105.3W 1655m'::observer, now()) AS p;predict_passes
Section titled “predict_passes”Finds all satellite passes over an observer within a time window, optionally filtered by minimum elevation. Returns a set of pass_event records.
Signature
Section titled “Signature”predict_passes( tle tle, obs observer, start_time timestamptz, end_time timestamptz, min_el float8 DEFAULT 0.0) → SETOF pass_eventParameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
tle | tle | Satellite TLE | |
obs | observer | Observer location | |
start_time | timestamptz | Start of the search window | |
end_time | timestamptz | End of the search window | |
min_el | float8 | 0.0 | Minimum peak elevation in degrees. Passes whose maximum elevation is below this threshold are excluded. |
Returns
Section titled “Returns”A set of pass_event records, ordered by AOS time.
Example
Section titled “Example”-- All ISS passes above 20 degrees in the next 3 daysWITH iss AS ( SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 90252 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle)SELECT pass_aos_time(p) AS rise, pass_max_elevation(p) AS max_el, pass_aos_azimuth(p) AS rise_az, pass_los_azimuth(p) AS set_az, pass_duration(p) AS durFROM iss, predict_passes(tle, '40.0N 105.3W 1655m'::observer, now(), now() + interval '3 days', 20.0) AS p;pass_visible
Section titled “pass_visible”Returns true if at least one satellite pass occurs over the observer during the given time window.
Signature
Section titled “Signature”pass_visible(tle tle, obs observer, start_time timestamptz, end_time timestamptz) → booleanParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
tle | tle | Satellite TLE |
obs | observer | Observer location |
start_time | timestamptz | Start of the search window |
end_time | timestamptz | End of the search window |
Returns
Section titled “Returns”true if any pass (elevation > 0) occurs in the window; false otherwise. This is faster than predict_passes when you only need a yes/no answer because it stops searching after the first pass is found.
Example
Section titled “Example”-- Which satellites from the catalog pass over Boulder tonight?SELECT norad_id, nameFROM satellite_catalogWHERE pass_visible(tle, '40.0N 105.3W 1655m'::observer, '2024-06-15 02:00:00+00', '2024-06-15 10:00:00+00');