Skip to content

Functions: Solar System

Functions for computing planetary positions, observing the Sun, Moon, and planets from an Earth-based observer. Planetary positions use the VSOP87 theory (Bretagnon & Francou, 1988). Lunar position uses ELP2000-82B (Chapront-Touze & Chapront, 1983).


Computes the heliocentric ecliptic J2000 position of a solar system body using VSOP87 series C (heliocentric, ecliptic, rectangular). Returns position in Astronomical Units.

planet_heliocentric(body_id int4, t timestamptz) → heliocentric
ParameterTypeDescription
body_idint4Planet identifier (see table below)
ttimestamptzEvaluation time
IDBody
0Sun (returns origin: 0, 0, 0)
1Mercury
2Venus
3Earth
4Mars
5Jupiter
6Saturn
7Uranus
8Neptune

A heliocentric position in AU (ecliptic J2000 frame). For body_id = 0 (Sun), all components are zero.

-- Distance of each planet from the Sun
SELECT body_id,
CASE body_id
WHEN 1 THEN 'Mercury' WHEN 2 THEN 'Venus'
WHEN 3 THEN 'Earth' WHEN 4 THEN 'Mars'
WHEN 5 THEN 'Jupiter' WHEN 6 THEN 'Saturn'
WHEN 7 THEN 'Uranus' WHEN 8 THEN 'Neptune'
END AS planet,
round(helio_distance(planet_heliocentric(body_id, now()))::numeric, 6) AS dist_au
FROM generate_series(1, 8) AS body_id;
-- Earth's position over one year at weekly intervals
SELECT t,
helio_x(h) AS x_au,
helio_y(h) AS y_au,
helio_z(h) AS z_au
FROM generate_series(
'2024-01-01'::timestamptz,
'2025-01-01'::timestamptz,
interval '7 days'
) AS t,
planet_heliocentric(3, t) AS h;

Computes the topocentric position of a planet as seen from an Earth-based observer. Internally computes the heliocentric positions of both Earth and the target planet, applies geometric transformation to geocentric, then converts to topocentric coordinates.

planet_observe(body_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Planet identifier (1-8, same as planet_heliocentric excluding 0 and 3)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation, range (km), and range rate (km/s).

-- Where is Mars tonight from Greenwich?
SELECT topo_azimuth(t) AS az_deg,
topo_elevation(t) AS el_deg,
topo_range(t) / 149597870.7 AS dist_au
FROM planet_observe(4, '51.4769N 0.0005W 11m'::observer, now()) AS t;
-- All planets' current positions from Boulder
SELECT body_id,
CASE body_id
WHEN 1 THEN 'Mercury' WHEN 2 THEN 'Venus'
WHEN 4 THEN 'Mars' WHEN 5 THEN 'Jupiter'
WHEN 6 THEN 'Saturn' WHEN 7 THEN 'Uranus'
WHEN 8 THEN 'Neptune'
END AS planet,
round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el
FROM unnest(ARRAY[1,2,4,5,6,7,8]) AS body_id,
planet_observe(body_id, '40.0N 105.3W 1655m'::observer, now()) AS t
ORDER BY topo_elevation(t) DESC;

Computes the topocentric position of the Sun from an Earth-based observer.

sun_observe(obs observer, t timestamptz) → topocentric
ParameterTypeDescription
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation, range (km), and range rate (km/s).

-- Sun position right now
SELECT topo_azimuth(t) AS az,
topo_elevation(t) AS el,
topo_range(t) / 149597870.7 AS dist_au
FROM sun_observe('40.0N 105.3W 1655m'::observer, now()) AS t;
-- Find today's solar noon (maximum elevation)
SELECT t,
round(topo_elevation(s)::numeric, 2) AS el
FROM generate_series(
now()::date::timestamptz,
now()::date::timestamptz + interval '24 hours',
interval '1 minute'
) AS t,
sun_observe('40.0N 105.3W 1655m'::observer, t) AS s
ORDER BY topo_elevation(s) DESC
LIMIT 1;

Computes the topocentric position of the Moon from an Earth-based observer. Uses the ELP2000-82B lunar theory (Chapront-Touze & Chapront, 1983).

moon_observe(obs observer, t timestamptz) → topocentric
ParameterTypeDescription
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation, range (km), and range rate (km/s). The Moon’s range is typically 356,500 to 406,700 km.

-- Current Moon position and distance
SELECT topo_azimuth(t) AS az,
topo_elevation(t) AS el,
topo_range(t) AS range_km
FROM moon_observe('40.0N 105.3W 1655m'::observer, now()) AS t;
-- Moon's path across the sky tonight at 5-minute intervals
SELECT t,
round(topo_azimuth(m)::numeric, 1) AS az,
round(topo_elevation(m)::numeric, 1) AS el,
round(topo_range(m)::numeric, 0) AS range_km
FROM generate_series(
'2024-06-15 02:00:00+00',
'2024-06-15 10:00:00+00',
interval '5 minutes'
) AS t,
moon_observe('40.0N 105.3W 1655m'::observer, t) AS m
WHERE topo_elevation(m) > 0;