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). All functions are IMMUTABLE STRICT PARALLEL SAFE.
For higher precision, v0.3.0 adds optional _de() variants that use JPL DE440/441 ephemeris files. See Functions: DE Ephemeris.
planet_heliocentric
Section titled “planet_heliocentric”Computes the heliocentric ecliptic J2000 position of a solar system body using VSOP87 series C (heliocentric, ecliptic, rectangular). Returns position in Astronomical Units.
Signature
Section titled “Signature”planet_heliocentric(body_id int4, t timestamptz) → heliocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
body_id | int4 | Planet identifier (see table below) |
t | timestamptz | Evaluation time |
Body IDs
Section titled “Body IDs”| ID | Body |
|---|---|
| 0 | Sun (returns origin: 0, 0, 0) |
| 1 | Mercury |
| 2 | Venus |
| 3 | Earth |
| 4 | Mars |
| 5 | Jupiter |
| 6 | Saturn |
| 7 | Uranus |
| 8 | Neptune |
Returns
Section titled “Returns”A heliocentric position in AU (ecliptic J2000 frame). For body_id = 0 (Sun), all components are zero.
Example
Section titled “Example”-- Distance of each planet from the SunSELECT 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_auFROM generate_series(1, 8) AS body_id;-- Earth's position over one year at weekly intervalsSELECT t, helio_x(h) AS x_au, helio_y(h) AS y_au, helio_z(h) AS z_auFROM generate_series( '2024-01-01'::timestamptz, '2025-01-01'::timestamptz, interval '7 days' ) AS t, planet_heliocentric(3, t) AS h;planet_observe
Section titled “planet_observe”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.
Signature
Section titled “Signature”planet_observe(body_id int4, obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
body_id | int4 | Planet identifier (1-8, same as planet_heliocentric excluding 0 and 3) |
obs | observer | Observer location on Earth |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range (km), and range rate (km/s).
Example
Section titled “Example”-- 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_auFROM planet_observe(4, '51.4769N 0.0005W 11m'::observer, now()) AS t;-- All planets' current positions from BoulderSELECT 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 elFROM unnest(ARRAY[1,2,4,5,6,7,8]) AS body_id, planet_observe(body_id, '40.0N 105.3W 1655m'::observer, now()) AS tORDER BY topo_elevation(t) DESC;sun_observe
Section titled “sun_observe”Computes the topocentric position of the Sun from an Earth-based observer.
Signature
Section titled “Signature”sun_observe(obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
obs | observer | Observer location on Earth |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range (km), and range rate (km/s).
Example
Section titled “Example”-- Sun position right nowSELECT topo_azimuth(t) AS az, topo_elevation(t) AS el, topo_range(t) / 149597870.7 AS dist_auFROM 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 elFROM 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 sORDER BY topo_elevation(s) DESCLIMIT 1;moon_observe
Section titled “moon_observe”Computes the topocentric position of the Moon from an Earth-based observer. Uses the ELP2000-82B lunar theory (Chapront-Touze & Chapront, 1983).
Signature
Section titled “Signature”moon_observe(obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
obs | observer | Observer location on Earth |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range (km), and range rate (km/s). The Moon’s range is typically 356,500 to 406,700 km.
Example
Section titled “Example”-- Current Moon position and distanceSELECT topo_azimuth(t) AS az, topo_elevation(t) AS el, topo_range(t) AS range_kmFROM moon_observe('40.0N 105.3W 1655m'::observer, now()) AS t;-- Moon's path across the sky tonight at 5-minute intervalsSELECT 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_kmFROM 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 mWHERE topo_elevation(m) > 0;planet_equatorial
Section titled “planet_equatorial”Computes the geocentric apparent equatorial coordinates (RA/Dec) of a planet at a given time using VSOP87. The heliocentric ecliptic position is converted to geocentric equatorial and precessed to the date of observation via IAU 1976 precession.
Signature
Section titled “Signature”planet_equatorial(body_id int4, t timestamptz) → equatorialParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
body_id | int4 | Planet identifier (1-8, same as planet_heliocentric excluding 0 and 3) |
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”An equatorial with RA (hours), Dec (degrees), and distance (km) from Earth’s center.
Example
Section titled “Example”-- Current RA/Dec of all planetsSELECT 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(eq_ra(e)::numeric, 4) AS ra_h, round(eq_dec(e)::numeric, 4) AS dec_deg, round(eq_distance(e)::numeric, 0) AS dist_kmFROM unnest(ARRAY[1,2,4,5,6,7,8]) AS body_id, planet_equatorial(body_id, now()) AS e;sun_equatorial
Section titled “sun_equatorial”Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Sun at a given time using VSOP87.
Signature
Section titled “Signature”sun_equatorial(t timestamptz) → equatorialParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”An equatorial with RA (hours), Dec (degrees), and distance (km) from Earth’s center.
Example
Section titled “Example”-- Sun's current RA/DecSELECT round(eq_ra(e)::numeric, 4) AS ra_hours, round(eq_dec(e)::numeric, 4) AS dec_deg, round(eq_distance(e)::numeric, 0) AS dist_kmFROM sun_equatorial(now()) AS e;moon_equatorial
Section titled “moon_equatorial”Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Moon at a given time using ELP2000-82B.
Signature
Section titled “Signature”moon_equatorial(t timestamptz) → equatorialParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”An equatorial with RA (hours), Dec (degrees), and distance (km) from Earth’s center.
Example
Section titled “Example”-- Moon's current RA/Dec and distanceSELECT round(eq_ra(e)::numeric, 4) AS ra_hours, round(eq_dec(e)::numeric, 4) AS dec_deg, round(eq_distance(e)::numeric, 0) AS dist_kmFROM moon_equatorial(now()) AS e;-- Moon's RA/Dec path over one lunation at daily intervalsSELECT t::date AS date, round(eq_ra(e)::numeric, 3) AS ra_h, round(eq_dec(e)::numeric, 3) AS dec_degFROM generate_series( now(), now() + interval '29 days', interval '1 day' ) AS t, moon_equatorial(t) AS e;planet_observe_apparent
Section titled “planet_observe_apparent”Computes the topocentric position of a planet with single-iteration light-time correction. The planet’s position is evaluated at the retarded time (observation time minus light travel time), while Earth’s position is evaluated at the observation time. Uses VSOP87.
Signature
Section titled “Signature”planet_observe_apparent(body_id int4, obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
body_id | int4 | Planet identifier (1-8, excluding 0 and 3) |
obs | observer | Observer location on Earth |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range (km), and range rate (km/s). The range reflects the geometric distance at the retarded time.
Example
Section titled “Example”-- Compare geometric vs light-time corrected Mars observationSELECT round(topo_azimuth(g)::numeric, 4) AS az_geo, round(topo_azimuth(a)::numeric, 4) AS az_apparent, round(topo_elevation(g)::numeric, 4) AS el_geo, round(topo_elevation(a)::numeric, 4) AS el_apparentFROM planet_observe(4, '40.0N 105.3W 1655m'::observer, now()) AS g, planet_observe_apparent(4, '40.0N 105.3W 1655m'::observer, now()) AS a;sun_observe_apparent
Section titled “sun_observe_apparent”Computes the topocentric position of the Sun with light-time correction (approximately 8.3 minutes). Uses VSOP87.
Signature
Section titled “Signature”sun_observe_apparent(obs observer, t timestamptz) → topocentricParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
obs | observer | Observer location on Earth |
t | timestamptz | Observation time |
Returns
Section titled “Returns”A topocentric with azimuth, elevation, range (km), and range rate (km/s).
Example
Section titled “Example”-- Sun position with light-time correctionSELECT round(topo_azimuth(t)::numeric, 4) AS az, round(topo_elevation(t)::numeric, 4) AS elFROM sun_observe_apparent('40.0N 105.3W 1655m'::observer, now()) AS t;planet_equatorial_apparent
Section titled “planet_equatorial_apparent”Computes the geocentric apparent equatorial coordinates (RA/Dec) of a planet with light-time correction. The planet is evaluated at the retarded time. Uses VSOP87.
Signature
Section titled “Signature”planet_equatorial_apparent(body_id int4, t timestamptz) → equatorialParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
body_id | int4 | Planet identifier (1-8, excluding 0 and 3) |
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”An equatorial with RA (hours), Dec (degrees), and distance (km), corrected for light travel time.
Example
Section titled “Example”-- Light-time corrected RA/Dec of JupiterSELECT round(eq_ra(e)::numeric, 4) AS ra_hours, round(eq_dec(e)::numeric, 4) AS dec_deg, round(eq_distance(e)::numeric, 0) AS dist_kmFROM planet_equatorial_apparent(5, now()) AS e;moon_equatorial_apparent
Section titled “moon_equatorial_apparent”Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Moon with light-time correction (approximately 1.3 seconds). Uses ELP2000-82B.
Signature
Section titled “Signature”moon_equatorial_apparent(t timestamptz) → equatorialParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
t | timestamptz | Evaluation time |
Returns
Section titled “Returns”An equatorial with RA (hours), Dec (degrees), and distance (km), corrected for light travel time.
Example
Section titled “Example”-- Compare geometric vs light-time corrected Moon RA/DecSELECT round(eq_ra(g)::numeric, 6) AS ra_geo, round(eq_ra(a)::numeric, 6) AS ra_apparent, round(eq_dec(g)::numeric, 6) AS dec_geo, round(eq_dec(a)::numeric, 6) AS dec_apparentFROM moon_equatorial(now()) AS g, moon_equatorial_apparent(now()) AS a;