Update CLAUDE.md and docs reference pages for v0.9.0

- CLAUDE.md: 82→106 functions, 8→9 types, 16→18 test suites, new file listings
- New functions-refraction.mdx: Bennett refraction, P/T correction, apparent elevation, refracted passes
- types.mdx: add equatorial type (24 bytes, apparent RA/Dec/distance of date)
- functions-satellite.mdx: add eci_to_equatorial, eci_to_equatorial_geo, predict_passes_refracted
- functions-solar-system.mdx: add 7 equatorial + light-time apparent functions
- functions-stars-comets.mdx: add proper motion, equatorial, apparent functions
- functions-de.mdx: add planet_equatorial_de, moon_equatorial_de
- astro.config.mjs: add refraction page to sidebar
This commit is contained in:
Ryan Malloy 2026-02-21 18:23:59 -07:00
parent 0863b0e08c
commit e15428d610
8 changed files with 1011 additions and 23 deletions

View File

@ -1,9 +1,9 @@
# pg_orrery — A Database Orrery for PostgreSQL # pg_orrery — A Database Orrery for PostgreSQL
## What This Is ## What This Is
A database orrery — celestial mechanics types and functions for PostgreSQL. Native C extension using PGXS, 82 SQL functions, 8 custom types, covering satellites (SGP4/SDP4), planets (VSOP87 + optional JPL DE441), Moon (ELP2000-82B), 19 planetary moons (L1.2/TASS17/GUST86/MarsSat), stars, comets, asteroids (MPC catalog), Jupiter radio bursts, and interplanetary Lambert transfers. A database orrery — celestial mechanics types and functions for PostgreSQL. Native C extension using PGXS, 106 SQL functions, 9 custom types, covering satellites (SGP4/SDP4), planets (VSOP87 + optional JPL DE441), Moon (ELP2000-82B), 19 planetary moons (L1.2/TASS17/GUST86/MarsSat), stars (with proper motion), comets, asteroids (MPC catalog), Jupiter radio bursts, interplanetary Lambert transfers, equatorial RA/Dec coordinates, atmospheric refraction, and light-time correction.
**Current version:** 0.8.0 on branch `phase/spgist-orbital-trie` **Current version:** 0.9.0 on branch `phase/spgist-orbital-trie`
**Repository:** https://git.supported.systems/warehack.ing/pg_orrery **Repository:** https://git.supported.systems/warehack.ing/pg_orrery
**Documentation:** https://pg-orrery.warehack.ing **Documentation:** https://pg-orrery.warehack.ing
@ -11,7 +11,7 @@ A database orrery — celestial mechanics types and functions for PostgreSQL. Na
```bash ```bash
make PG_CONFIG=/usr/bin/pg_config # Compile with PGXS make PG_CONFIG=/usr/bin/pg_config # Compile with PGXS
sudo make install PG_CONFIG=/usr/bin/pg_config # Install extension sudo make install PG_CONFIG=/usr/bin/pg_config # Install extension
make installcheck PG_CONFIG=/usr/bin/pg_config # Run 16 regression test suites make installcheck PG_CONFIG=/usr/bin/pg_config # Run 18 regression test suites
``` ```
Requires: PostgreSQL 17 development headers, GCC, Make. Requires: PostgreSQL 17 development headers, GCC, Make.
@ -27,7 +27,7 @@ Image: `git.supported.systems/warehack.ing/pg_orrery:pg17`
## Project Layout ## Project Layout
``` ```
pg_orrery.control # Extension metadata (version 0.8.0) pg_orrery.control # Extension metadata (version 0.9.0)
Makefile # PGXS build + Docker targets Makefile # PGXS build + Docker targets
sql/ sql/
pg_orrery--0.1.0.sql # v0.1.0: satellite types/functions/operators pg_orrery--0.1.0.sql # v0.1.0: satellite types/functions/operators
@ -38,6 +38,7 @@ sql/
pg_orrery--0.6.0.sql # v0.6.0: conjunction screening pg_orrery--0.6.0.sql # v0.6.0: conjunction screening
pg_orrery--0.7.0.sql # v0.7.0: GiST improvements pg_orrery--0.7.0.sql # v0.7.0: GiST improvements
pg_orrery--0.8.0.sql # v0.8.0: orbital_elements type + MPC parser (82 functions) pg_orrery--0.8.0.sql # v0.8.0: orbital_elements type + MPC parser (82 functions)
pg_orrery--0.9.0.sql # v0.9.0: equatorial type, refraction, proper motion, light-time (106 functions)
pg_orrery--0.1.0--0.2.0.sql # Migration: v0.1.0 → v0.2.0 (adds solar system) pg_orrery--0.1.0--0.2.0.sql # Migration: v0.1.0 → v0.2.0 (adds solar system)
pg_orrery--0.2.0--0.3.0.sql # Migration: v0.2.0 → v0.3.0 (adds DE ephemeris) pg_orrery--0.2.0--0.3.0.sql # Migration: v0.2.0 → v0.3.0 (adds DE ephemeris)
pg_orrery--0.3.0--0.4.0.sql # Migration: v0.3.0 → v0.4.0 pg_orrery--0.3.0--0.4.0.sql # Migration: v0.3.0 → v0.4.0
@ -45,6 +46,7 @@ sql/
pg_orrery--0.5.0--0.6.0.sql # Migration: v0.5.0 → v0.6.0 pg_orrery--0.5.0--0.6.0.sql # Migration: v0.5.0 → v0.6.0
pg_orrery--0.6.0--0.7.0.sql # Migration: v0.6.0 → v0.7.0 pg_orrery--0.6.0--0.7.0.sql # Migration: v0.6.0 → v0.7.0
pg_orrery--0.7.0--0.8.0.sql # Migration: v0.7.0 → v0.8.0 (orbital_elements type) pg_orrery--0.7.0--0.8.0.sql # Migration: v0.7.0 → v0.8.0 (orbital_elements type)
pg_orrery--0.8.0--0.9.0.sql # Migration: v0.8.0 → v0.9.0 (equatorial, refraction, proper motion, light-time)
src/ src/
pg_orrery.c # PG_MODULE_MAGIC + _PG_init() (GUC registration) pg_orrery.c # PG_MODULE_MAGIC + _PG_init() (GUC registration)
types.h # All struct definitions + constants + DE body ID mapping types.h # All struct definitions + constants + DE body ID mapping
@ -55,7 +57,7 @@ src/
observer_type.c # Observer type with flexible string parsing observer_type.c # Observer type with flexible string parsing
sgp4_funcs.c # sgp4_propagate(), _safe(), _series(), tle_distance() sgp4_funcs.c # sgp4_propagate(), _safe(), _series(), tle_distance()
coord_funcs.c # eci_to_geodetic(), eci_to_topocentric(), ground_track() coord_funcs.c # eci_to_geodetic(), eci_to_topocentric(), ground_track()
pass_funcs.c # next_pass(), predict_passes(), pass_visible() pass_funcs.c # next_pass(), predict_passes(), predict_passes_refracted(), pass_visible()
gist_tle.c # GiST operator class (&&, <->) gist_tle.c # GiST operator class (&&, <->)
# --- Solar System (v0.2.0) --- # --- Solar System (v0.2.0) ---
vsop87.c / vsop87.h # VSOP87 planetary ephemeris (Bretagnon 1988) vsop87.c / vsop87.h # VSOP87 planetary ephemeris (Bretagnon 1988)
@ -63,11 +65,13 @@ src/
precession.c / precession.h # IAU 1976 precession (Lieske 1979) precession.c / precession.h # IAU 1976 precession (Lieske 1979)
sidereal_time.c / .h # GMST calculation (Vallado Eq. 3-47) sidereal_time.c / .h # GMST calculation (Vallado Eq. 3-47)
elliptic_to_rectangular.c/.h # Orbital element conversions elliptic_to_rectangular.c/.h # Orbital element conversions
planet_funcs.c # planet_observe(), planet_heliocentric(), sun/moon_observe() planet_funcs.c # planet_observe(), planet_heliocentric(), sun/moon_observe(), _equatorial(), _apparent()
star_funcs.c # star_observe(), star_observe_safe() star_funcs.c # star_observe(), star_observe_safe(), star_equatorial(), star_observe_pm(), star_equatorial_pm()
kepler_funcs.c # kepler_propagate(), comet_observe() kepler_funcs.c # kepler_propagate(), comet_observe()
kepler.h # Shared Kepler solver interface (kepler_position()) kepler.h # Shared Kepler solver interface (kepler_position())
orbital_elements_type.c # orbital_elements type, MPC parser, small_body_observe() orbital_elements_type.c # orbital_elements type, MPC parser, small_body_observe/equatorial/apparent()
equatorial_funcs.c # equatorial type I/O, accessors, satellite/planet/sun/moon RA/Dec
refraction_funcs.c # atmospheric_refraction(), _ext(), topo_elevation_apparent()
l12.c / l12.h # L1.2 Galilean moon theory (Lieske 1998) l12.c / l12.h # L1.2 Galilean moon theory (Lieske 1998)
tass17.c / tass17.h # TASS 1.7 Saturn moon theory (Vienne & Duriez 1995) tass17.c / tass17.h # TASS 1.7 Saturn moon theory (Vienne & Duriez 1995)
gust86.c / gust86.h # GUST86 Uranus moon theory (Laskar & Jacobson 1987) gust86.c / gust86.h # GUST86 Uranus moon theory (Laskar & Jacobson 1987)
@ -117,20 +121,22 @@ All types are fixed-size, `STORAGE = plain`, `ALIGNMENT = double`. No TOAST over
| `pass_event` | 48 | AOS/MAX/LOS times + max_el + AOS/LOS azimuth | | `pass_event` | 48 | AOS/MAX/LOS times + max_el + AOS/LOS azimuth |
| `heliocentric` | 24 | x, y, z in AU (ecliptic J2000 frame) | | `heliocentric` | 24 | x, y, z in AU (ecliptic J2000 frame) |
| `orbital_elements` | 72 | Classical Keplerian elements for comets/asteroids (epoch, q, e, inc, omega, Omega, tp, H, G) | | `orbital_elements` | 72 | Classical Keplerian elements for comets/asteroids (epoch, q, e, inc, omega, Omega, tp, H, G) |
| `equatorial` | 24 | Apparent RA (hours), Dec (degrees), distance (km) — of date |
## Function Domains (82 total) ## Function Domains (106 total)
| Domain | Theory | Key Functions | Count | | Domain | Theory | Key Functions | Count |
|--------|--------|---------------|-------| |--------|--------|---------------|-------|
| Satellite | SGP4/SDP4 (Brouwer 1959) | `observe()`, `predict_passes()`, `ground_track()` | 22 | | Satellite | SGP4/SDP4 (Brouwer 1959) | `observe()`, `predict_passes()`, `eci_to_equatorial()` | 25 |
| Planets | VSOP87 (Bretagnon 1988) | `planet_observe()`, `planet_heliocentric()` | 3 | | Planets | VSOP87 (Bretagnon 1988) | `planet_observe()`, `planet_equatorial()`, `planet_observe_apparent()` | 7 |
| Sun/Moon | VSOP87 + ELP2000-82B | `sun_observe()`, `moon_observe()` | 2 | | Sun/Moon | VSOP87 + ELP2000-82B | `sun_observe()`, `moon_observe()`, `sun/moon_equatorial()` | 6 |
| Planetary moons | L1.2, TASS17, GUST86, MarsSat | `galilean_observe()`, `saturn_moon_observe()` | 4 | | Planetary moons | L1.2, TASS17, GUST86, MarsSat | `galilean_observe()`, `saturn_moon_observe()` | 4 |
| Stars | J2000 + IAU 1976 precession | `star_observe()`, `star_observe_safe()` | 2 | | Stars | J2000 + IAU 1976 precession | `star_observe()`, `star_equatorial()`, `star_observe_pm()` | 5 |
| Comets/asteroids | Two-body Keplerian + MPC | `small_body_observe()`, `oe_from_mpc()`, `kepler_propagate()` | 16 | | Comets/asteroids | Two-body Keplerian + MPC | `small_body_observe()`, `small_body_equatorial()`, `oe_from_mpc()` | 19 |
| Refraction | Bennett (1982) | `atmospheric_refraction()`, `predict_passes_refracted()` | 4 |
| Jupiter radio | Carr et al. (1983) | `jupiter_burst_probability()` | 3 | | Jupiter radio | Carr et al. (1983) | `jupiter_burst_probability()` | 3 |
| Transfers | Lambert (Izzo 2015) | `lambert_transfer()`, `lambert_c3()` | 2 | | Transfers | Lambert (Izzo 2015) | `lambert_transfer()`, `lambert_c3()` | 2 |
| DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `moon_observe_de()` | 11 | | DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `planet_equatorial_de()` | 13 |
| GiST index | Altitude-band approximation | `&&` (overlap), `<->` (distance) | 8 | | GiST index | Altitude-band approximation | `&&` (overlap), `<->` (distance) | 8 |
| Diagnostics | -- | `pg_orrery_ephemeris_info()` | 1 | | Diagnostics | -- | `pg_orrery_ephemeris_info()` | 1 |
@ -187,6 +193,7 @@ All functions are `PARALLEL SAFE`. VSOP87/ELP82B functions are `IMMUTABLE` (comp
#define GAUSS_K 0.01720209895 /* AU^(3/2)/day */ #define GAUSS_K 0.01720209895 /* AU^(3/2)/day */
#define OBLIQUITY_J2000 0.40909280422232897 /* 23.4392911 deg in radians */ #define OBLIQUITY_J2000 0.40909280422232897 /* 23.4392911 deg in radians */
#define J2000_JD 2451545.0 /* 2000 Jan 1.5 TT */ #define J2000_JD 2451545.0 /* 2000 Jan 1.5 TT */
#define C_LIGHT_AU_DAY 173.1446327 /* speed of light in AU/day */
``` ```
## JPL DE Ephemeris (Optional) ## JPL DE Ephemeris (Optional)
@ -231,6 +238,8 @@ Every `_de()` function mirrors an existing VSOP87 function:
| `saturn_moon_observe_de()` | `saturn_moon_observe()` | STABLE | | `saturn_moon_observe_de()` | `saturn_moon_observe()` | STABLE |
| `uranus_moon_observe_de()` | `uranus_moon_observe()` | STABLE | | `uranus_moon_observe_de()` | `uranus_moon_observe()` | STABLE |
| `mars_moon_observe_de()` | `mars_moon_observe()` | STABLE | | `mars_moon_observe_de()` | `mars_moon_observe()` | STABLE |
| `planet_equatorial_de()` | `planet_equatorial()` | STABLE |
| `moon_equatorial_de()` | `moon_equatorial()` | STABLE |
| `pg_orrery_ephemeris_info()` | — | STABLE | | `pg_orrery_ephemeris_info()` | — | STABLE |
## Vendored SGP4/SDP4 ## Vendored SGP4/SDP4
@ -252,7 +261,7 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado
## Testing ## Testing
16 regression test suites via `make installcheck`: 18 regression test suites via `make installcheck`:
| Suite | What it tests | | Suite | What it tests |
|-------|--------------| |-------|--------------|
@ -268,14 +277,16 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado
| moon_observe | Galilean/Saturn/Uranus/Mars moons, Io phase, Jupiter CML, burst probability | | moon_observe | Galilean/Saturn/Uranus/Mars moons, Io phase, Jupiter CML, burst probability |
| lambert_transfer | Lambert solver, lambert_c3, pork chop grid, error handling | | lambert_transfer | Lambert solver, lambert_c3, pork chop grid, error handling |
| de_ephemeris | DE function fallback to VSOP87, cross-provider consistency, error handling | | de_ephemeris | DE function fallback to VSOP87, cross-provider consistency, error handling |
| vallado_518 | 518 Vallado test vectors (AIAA 2006-6753-Rev1), per-satellite breakdown |
| od_fit | Orbit determination from ECI/topocentric/angles-only observations | | od_fit | Orbit determination from ECI/topocentric/angles-only observations |
| orbital_elements | orbital_elements type I/O, MPC parser, small_body_observe/heliocentric |
| spgist_tle | SP-GiST orbital trie index operations | | spgist_tle | SP-GiST orbital trie index operations |
| orbital_elements | orbital_elements type I/O, MPC parser, small_body_observe/heliocentric |
| equatorial | equatorial type I/O, RA/Dec for planets/stars/satellites, proper motion, light-time |
| refraction | Bennett refraction, P/T correction, apparent elevation, refracted pass prediction |
| vallado_518 | 518 Vallado test vectors (AIAA 2006-6753-Rev1), per-satellite breakdown |
### PG Version Matrix ### PG Version Matrix
Test all 16 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker: Test all 18 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker:
```bash ```bash
make test-matrix # Full matrix (PG 14-18) make test-matrix # Full matrix (PG 14-18)
@ -299,9 +310,9 @@ Logs saved to `test/matrix-logs/pg${ver}.log`. The script reuses the Dockerfile
**Live:** https://pg-orrery.warehack.ing **Live:** https://pg-orrery.warehack.ing
Starlight docs at `docs/` — 42 MDX pages covering all domains. Starlight docs at `docs/` — 44 MDX pages covering all domains.
Sections: Getting Started, Guides (9 domain walkthroughs incl. DE ephemeris), Workflow Translation (Skyfield/Horizons/GMAT/Radio Jupiter Pro comparisons), Reference (all 82 functions incl. DE variants + orbital_elements), Architecture (Hamilton's principles, constant custody, observation pipeline), Performance (benchmarks). Sections: Getting Started, Guides (9 domain walkthroughs incl. DE ephemeris), Workflow Translation (Skyfield/Horizons/GMAT/Radio Jupiter Pro comparisons), Reference (all 106 functions incl. DE variants, equatorial, refraction), Architecture (Hamilton's principles, constant custody, observation pipeline), Performance (benchmarks).
### Local Development ### Local Development
```bash ```bash

View File

@ -96,6 +96,7 @@ export default defineConfig({
{ label: "Functions: Stars & Comets", slug: "reference/functions-stars-comets" }, { label: "Functions: Stars & Comets", slug: "reference/functions-stars-comets" },
{ label: "Functions: Radio", slug: "reference/functions-radio" }, { label: "Functions: Radio", slug: "reference/functions-radio" },
{ label: "Functions: Transfers", slug: "reference/functions-transfers" }, { label: "Functions: Transfers", slug: "reference/functions-transfers" },
{ label: "Functions: Refraction", slug: "reference/functions-refraction" },
{ label: "Functions: DE Ephemeris", slug: "reference/functions-de" }, { label: "Functions: DE Ephemeris", slug: "reference/functions-de" },
{ label: "Functions: Orbit Determination", slug: "reference/functions-od" }, { label: "Functions: Orbit Determination", slug: "reference/functions-od" },
{ label: "Operators & Indexes", slug: "reference/operators-gist" }, { label: "Operators & Indexes", slug: "reference/operators-gist" },

View File

@ -303,6 +303,71 @@ mars_moon_observe_de(moon_id int4, obs observer, t timestamptz) → topocentric
--- ---
## planet_equatorial_de
Computes the geocentric apparent equatorial coordinates (RA/Dec) of a planet using JPL DE ephemeris. Falls back to VSOP87 plus the equatorial conversion when DE is unavailable.
### Signature
```sql
planet_equatorial_de(body_id int4, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `body_id` | `int4` | Planet identifier (1-8, excluding 0 and 3) |
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Compare DE vs VSOP87 equatorial coordinates for Mars
SELECT round(eq_ra(planet_equatorial(4, now()))::numeric, 6) AS ra_vsop87,
round(eq_ra(planet_equatorial_de(4, now()))::numeric, 6) AS ra_de,
round(eq_dec(planet_equatorial(4, now()))::numeric, 6) AS dec_vsop87,
round(eq_dec(planet_equatorial_de(4, now()))::numeric, 6) AS dec_de;
```
---
## moon_equatorial_de
Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Moon using JPL DE ephemeris. Falls back to ELP2000-82B plus the equatorial conversion when DE is unavailable.
### Signature
```sql
moon_equatorial_de(t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Moon RA/Dec via DE
SELECT 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_km
FROM moon_equatorial_de(now()) AS e;
```
---
## pg_orrery_ephemeris_info ## pg_orrery_ephemeris_info
Returns diagnostic information about the current ephemeris provider. Returns diagnostic information about the current ephemeris provider.

View File

@ -0,0 +1,209 @@
---
title: "Functions: Atmospheric Refraction"
sidebar:
order: 7
---
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
Functions for computing atmospheric refraction corrections using Bennett's (1982) empirical formula. Earth's atmosphere bends light from celestial objects, making them appear higher above the horizon than their true geometric position. Near the horizon, refraction is approximately 0.57 degrees --- enough to extend satellite visibility windows by roughly 35 seconds at AOS and LOS, and to make the Sun appear above the horizon when it has already geometrically set.
---
## atmospheric_refraction
Computes the atmospheric refraction correction in degrees for a given geometric elevation using Bennett's (1982) formula under standard atmosphere conditions (pressure 1010 mbar, temperature 10 C). The domain is clamped at -1 degree to avoid singularity in the cotangent term.
### Signature
```sql
atmospheric_refraction(elevation_deg float8) → float8
```
### Parameters
| Parameter | Type | Unit | Description |
|-----------|------|------|-------------|
| `elevation_deg` | `float8` | degrees | Geometric elevation of the object above the horizon |
### Returns
Refraction correction in degrees. Always positive --- add this value to the geometric elevation to get the apparent elevation. At the horizon (0 degrees), refraction is approximately 0.57 degrees. It drops rapidly with increasing elevation and is negligible above 45 degrees.
<Aside type="note">
The domain guard at -1 degree prevents numerical blowup in the cotangent. Objects below -1 degree geometric elevation are deeply below the horizon and refraction is not physically meaningful there.
</Aside>
### Example
```sql
-- Refraction at various elevations
SELECT elevation,
round(atmospheric_refraction(elevation)::numeric, 4) AS refraction_deg
FROM unnest(ARRAY[-1, 0, 5, 10, 20, 45, 90]) AS elevation;
```
```sql
-- How much does refraction shift the Sun at sunset?
SELECT round(atmospheric_refraction(0)::numeric, 4) AS horizon_refraction_deg;
```
---
## atmospheric_refraction_ext
Computes atmospheric refraction with a pressure and temperature correction factor applied to Bennett's formula, following the Meeus formulation. Useful for high-altitude observatories or extreme weather conditions where standard atmosphere assumptions break down.
### Signature
```sql
atmospheric_refraction_ext(elevation_deg float8, pressure_mbar float8, temp_celsius float8) → float8
```
### Parameters
| Parameter | Type | Unit | Description |
|-----------|------|------|-------------|
| `elevation_deg` | `float8` | degrees | Geometric elevation of the object above the horizon |
| `pressure_mbar` | `float8` | mbar | Atmospheric pressure at the observer |
| `temp_celsius` | `float8` | C | Air temperature at the observer |
### Returns
Refraction correction in degrees, adjusted for the given pressure and temperature. The correction factor is `(P / 1010) * (283 / (273 + T))` applied to the standard Bennett formula result.
### Example
```sql
-- Refraction at Mauna Kea summit (4205m, ~620 mbar, -2C)
SELECT round(atmospheric_refraction_ext(5.0, 620.0, -2.0)::numeric, 4) AS refraction_mauna_kea,
round(atmospheric_refraction(5.0)::numeric, 4) AS refraction_standard;
```
```sql
-- Compare standard vs corrected refraction across a range of elevations
SELECT elevation,
round(atmospheric_refraction(elevation)::numeric, 4) AS standard,
round(atmospheric_refraction_ext(elevation, 850.0, -10.0)::numeric, 4) AS high_altitude_cold
FROM unnest(ARRAY[0, 2, 5, 10, 30]) AS elevation;
```
---
## topo_elevation_apparent
Convenience function that returns the apparent elevation of an object by adding the atmospheric refraction correction to the geometric elevation stored in a `topocentric` value. The result is in degrees.
### Signature
```sql
topo_elevation_apparent(topocentric) → float8
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| (unnamed) | `topocentric` | A topocentric observation result from any `*_observe` function |
### Returns
Apparent elevation in degrees --- the geometric elevation plus the Bennett refraction correction under standard atmosphere. Always higher than the geometric `topo_elevation()` value.
### Example
```sql
-- Compare geometric vs apparent elevation for the Moon
SELECT round(topo_elevation(t)::numeric, 3) AS geometric_el,
round(topo_elevation_apparent(t)::numeric, 3) AS apparent_el,
round(topo_elevation_apparent(t) - topo_elevation(t)::numeric, 4) AS refraction_correction
FROM moon_observe('40.0N 105.3W 1655m'::observer, now()) AS t;
```
```sql
-- Find objects that are geometrically below horizon but visible due to refraction
SELECT norad_id,
round(topo_elevation(o)::numeric, 3) AS geometric_el,
round(topo_elevation_apparent(o)::numeric, 3) AS apparent_el
FROM satellite_catalog,
observe_safe(tle, '40.0N 105.3W 1655m'::observer, now()) AS o
WHERE o IS NOT NULL
AND topo_elevation(o) < 0
AND topo_elevation_apparent(o) > 0;
```
---
## predict_passes_refracted
Predicts satellite passes using a refracted horizon threshold instead of the geometric horizon. The geometric threshold is set to -0.569 degrees, which corresponds to the apparent horizon after atmospheric refraction. This means satellites become visible approximately 35 seconds earlier at AOS and remain visible approximately 35 seconds later at LOS compared to `predict_passes`.
### Signature
```sql
predict_passes_refracted(
tle tle,
obs observer,
start_time timestamptz,
end_time timestamptz,
min_el float8 DEFAULT 0.0
) → SETOF pass_event
```
### 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
A set of `pass_event` records, ordered by AOS time. Each pass will show slightly earlier AOS and later LOS times compared to `predict_passes` due to the refracted horizon.
<Aside type="tip">
The refracted threshold of -0.569 degrees geometric matches what visual observers actually experience --- the atmosphere bends satellite light so it is visible even when the satellite is geometrically below the horizon. Use this function for scheduling visual observations, antenna pointing, or any application where the physical visibility window matters.
</Aside>
### Example
```sql
-- Compare geometric vs refracted pass predictions for the ISS
WITH iss AS (
SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
2 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 dur
FROM iss,
predict_passes_refracted(tle, '40.0N 105.3W 1655m'::observer,
now(), now() + interval '24 hours', 10.0) AS p;
```
```sql
-- How much extra visibility does refraction add?
WITH iss AS (
SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle
),
geo AS (
SELECT pass_duration(p) AS dur
FROM iss, predict_passes(tle, '40.0N 105.3W 1655m'::observer,
now(), now() + interval '24 hours') AS p
LIMIT 1
),
refr AS (
SELECT pass_duration(p) AS dur
FROM iss, predict_passes_refracted(tle, '40.0N 105.3W 1655m'::observer,
now(), now() + interval '24 hours') AS p
LIMIT 1
)
SELECT geo.dur AS geometric_duration,
refr.dur AS refracted_duration
FROM geo, refr;
```

View File

@ -527,3 +527,118 @@ FROM satellite_catalog
WHERE pass_visible(tle, '40.0N 105.3W 1655m'::observer, WHERE pass_visible(tle, '40.0N 105.3W 1655m'::observer,
'2024-06-15 02:00:00+00', '2024-06-15 10:00:00+00'); '2024-06-15 02:00:00+00', '2024-06-15 10:00:00+00');
``` ```
---
## eci_to_equatorial
Converts a TEME ECI position to topocentric apparent equatorial coordinates (RA/Dec) for a given observer. The observer's position is subtracted from the satellite's ECI vector to produce parallax-corrected coordinates. For LEO satellites, observer parallax is approximately 1 degree.
### Signature
```sql
eci_to_equatorial(pos eci_position, obs observer, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `pos` | `eci_position` | TEME ECI position and velocity |
| `obs` | `observer` | Observer location on Earth |
| `t` | `timestamptz` | Time of the position (for sidereal time computation) |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from the observer's perspective.
### Example
```sql
WITH iss AS (
SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle
)
SELECT round(eq_ra(e)::numeric, 4) AS ra_hours,
round(eq_dec(e)::numeric, 4) AS dec_deg,
round(eq_distance(e)::numeric, 1) AS dist_km
FROM iss,
eci_to_equatorial(
sgp4_propagate(tle, now()),
'40.0N 105.3W 1655m'::observer,
now()
) AS e;
```
---
## eci_to_equatorial_geo
Converts a TEME ECI position to geocentric apparent equatorial coordinates (RA/Dec). This is the direction of the position vector as seen from Earth's center, independent of any observer location.
### Signature
```sql
eci_to_equatorial_geo(pos eci_position, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `pos` | `eci_position` | TEME ECI position |
| `t` | `timestamptz` | Time of the position |
### Returns
An `equatorial` with geocentric RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Geocentric RA/Dec of the ISS
WITH iss AS (
SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle AS tle
)
SELECT round(eq_ra(e)::numeric, 4) AS ra_hours,
round(eq_dec(e)::numeric, 4) AS dec_deg
FROM iss,
eci_to_equatorial_geo(sgp4_propagate(tle, now()), now()) AS e;
```
---
## predict_passes_refracted
Predicts satellite passes using a refracted horizon threshold (-0.569 degrees geometric) instead of the geometric horizon. Atmospheric refraction makes satellites visible approximately 35 seconds earlier at AOS and later at LOS.
<Aside type="tip">
See [Functions: Atmospheric Refraction](/reference/functions-refraction/) for the full documentation on this function and the underlying refraction model.
</Aside>
### Signature
```sql
predict_passes_refracted(
tle tle,
obs observer,
start_time timestamptz,
end_time timestamptz,
min_el float8 DEFAULT 0.0
) → SETOF pass_event
```
### 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 |
### Returns
A set of `pass_event` records with refraction-extended visibility windows.

View File

@ -228,3 +228,262 @@ FROM generate_series(
moon_observe('40.0N 105.3W 1655m'::observer, t) AS m moon_observe('40.0N 105.3W 1655m'::observer, t) AS m
WHERE topo_elevation(m) > 0; WHERE topo_elevation(m) > 0;
``` ```
---
## 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
```sql
planet_equatorial(body_id int4, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `body_id` | `int4` | Planet identifier (1-8, same as `planet_heliocentric` excluding 0 and 3) |
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Current RA/Dec of all planets
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(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_km
FROM unnest(ARRAY[1,2,4,5,6,7,8]) AS body_id,
planet_equatorial(body_id, now()) AS e;
```
---
## sun_equatorial
Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Sun at a given time using VSOP87.
### Signature
```sql
sun_equatorial(t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Sun's current RA/Dec
SELECT 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_km
FROM sun_equatorial(now()) AS e;
```
---
## moon_equatorial
Computes the geocentric apparent equatorial coordinates (RA/Dec) of the Moon at a given time using ELP2000-82B.
### Signature
```sql
moon_equatorial(t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- Moon's current RA/Dec and distance
SELECT 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_km
FROM moon_equatorial(now()) AS e;
```
```sql
-- Moon's RA/Dec path over one lunation at daily intervals
SELECT t::date AS date,
round(eq_ra(e)::numeric, 3) AS ra_h,
round(eq_dec(e)::numeric, 3) AS dec_deg
FROM generate_series(
now(), now() + interval '29 days', interval '1 day'
) AS t,
moon_equatorial(t) AS e;
```
---
## 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
```sql
planet_observe_apparent(body_id int4, obs observer, t timestamptz) → topocentric
```
### 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
A `topocentric` with azimuth, elevation, range (km), and range rate (km/s). The range reflects the geometric distance at the retarded time.
<Aside type="note">
For the inner planets, light-time correction changes the apparent position by a few arcseconds to a few tens of arcseconds. For the outer planets, the effect can be several arcminutes. Use `planet_observe()` when light-time correction is not needed (faster, single VSOP87 evaluation per body).
</Aside>
### Example
```sql
-- Compare geometric vs light-time corrected Mars observation
SELECT 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_apparent
FROM 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
Computes the topocentric position of the Sun with light-time correction (approximately 8.3 minutes). Uses VSOP87.
### Signature
```sql
sun_observe_apparent(obs observer, t timestamptz) → topocentric
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `obs` | `observer` | Observer location on Earth |
| `t` | `timestamptz` | Observation time |
### Returns
A `topocentric` with azimuth, elevation, range (km), and range rate (km/s).
### Example
```sql
-- Sun position with light-time correction
SELECT round(topo_azimuth(t)::numeric, 4) AS az,
round(topo_elevation(t)::numeric, 4) AS el
FROM sun_observe_apparent('40.0N 105.3W 1655m'::observer, now()) AS t;
```
---
## 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
```sql
planet_equatorial_apparent(body_id int4, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `body_id` | `int4` | Planet identifier (1-8, excluding 0 and 3) |
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km), corrected for light travel time.
### Example
```sql
-- Light-time corrected RA/Dec of Jupiter
SELECT 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_km
FROM planet_equatorial_apparent(5, now()) AS e;
```
---
## 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
```sql
moon_equatorial_apparent(t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km), corrected for light travel time.
<Aside type="note">
The Moon's light-time correction is approximately 1.3 seconds. This produces a sub-arcsecond shift in apparent position --- negligible for most applications, but included for completeness and consistency with the other `_apparent()` functions.
</Aside>
### Example
```sql
-- Compare geometric vs light-time corrected Moon RA/Dec
SELECT 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_apparent
FROM moon_equatorial(now()) AS g,
moon_equatorial_apparent(now()) AS a;
```

View File

@ -34,7 +34,7 @@ star_observe(ra_hours float8, dec_deg float8, obs observer, t timestamptz) → t
A `topocentric` with azimuth and elevation in degrees. `topo_range` is 0 (infinite distance). `topo_range_rate` is 0. A `topocentric` with azimuth and elevation in degrees. `topo_range` is 0 (infinite distance). `topo_range_rate` is 0.
<Aside type="note"> <Aside type="note">
This function does not account for proper motion, parallax, aberration, or atmospheric refraction. For stars with significant proper motion (e.g., Barnard's Star), the J2000 coordinates should be corrected externally before calling this function. This function does not account for proper motion, parallax, aberration, or atmospheric refraction. For stars with significant proper motion (e.g., Barnard's Star at 10.3 arcsec/yr), use `star_observe_pm` instead, which applies proper motion, parallax, and radial velocity corrections using the Hipparcos/Gaia convention.
</Aside> </Aside>
### Example ### Example
@ -396,3 +396,278 @@ FROM asteroid_catalog,
WHERE topo_elevation(t) > 20 WHERE topo_elevation(t) > 20
ORDER BY topo_elevation(t) DESC; ORDER BY topo_elevation(t) DESC;
``` ```
---
## star_equatorial
Computes the apparent equatorial coordinates (RA/Dec) of a star at a given time by precessing J2000 catalog coordinates to the date of observation via IAU 1976 precession. Does not account for proper motion.
### Signature
```sql
star_equatorial(ra_hours float8, dec_deg float8, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Unit | Description |
|-----------|------|------|-------------|
| `ra_hours` | `float8` | hours | Right Ascension in J2000 (0-24) |
| `dec_deg` | `float8` | degrees | Declination in J2000 (-90 to +90) |
| `t` | `timestamptz` | | Evaluation time |
### Returns
An `equatorial` with RA (hours) and Dec (degrees) precessed to the date of observation. Distance is 0 (infinite).
### Example
```sql
-- Precessed RA/Dec of Sirius at current date
SELECT round(eq_ra(e)::numeric, 6) AS ra_hours,
round(eq_dec(e)::numeric, 6) AS dec_deg
FROM star_equatorial(6.7525, -16.7161, now()) AS e;
```
---
## star_observe_pm
Computes the topocentric position of a star with full proper motion, parallax, and radial velocity corrections. The proper motion convention follows Hipparcos/Gaia: `pm_ra` is mu_alpha * cos(delta) in milliarcseconds per year. Cos(dec) is clamped near the poles to avoid division by zero.
### Signature
```sql
star_observe_pm(
ra_hours float8,
dec_deg float8,
pm_ra_masyr float8,
pm_dec_masyr float8,
parallax_mas float8,
rv_kms float8,
obs observer,
t timestamptz
) → topocentric
```
### Parameters
| Parameter | Type | Unit | Description |
|-----------|------|------|-------------|
| `ra_hours` | `float8` | hours | J2000 Right Ascension (0-24) |
| `dec_deg` | `float8` | degrees | J2000 Declination (-90 to +90) |
| `pm_ra_masyr` | `float8` | mas/yr | Proper motion in RA (mu_alpha * cos(delta), Hipparcos/Gaia convention) |
| `pm_dec_masyr` | `float8` | mas/yr | Proper motion in Declination |
| `parallax_mas` | `float8` | mas | Trigonometric parallax (0 if unknown) |
| `rv_kms` | `float8` | km/s | Radial velocity (0 if unknown) |
| `obs` | `observer` | | Observer location |
| `t` | `timestamptz` | | Observation time |
### Returns
A `topocentric` with azimuth, elevation, range (km from parallax, or 0 if parallax is 0), and range rate (km/s).
<Aside type="caution">
A NOTICE is raised if the propagation interval exceeds 200 years from J2000, as proper motion becomes unreliable over long timescales due to unmodeled orbital motion and galactic effects.
</Aside>
### Example
```sql
-- Observe Barnard's Star (large proper motion: 10.3 arcsec/yr total)
-- Hipparcos: RA 17h 57m 48.5s, Dec +4d 41m 36.2s
-- pm_ra = -798.58 mas/yr, pm_dec = 10328.12 mas/yr
-- parallax = 548.31 mas, rv = -110.6 km/s
SELECT round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el,
round(topo_range(t)::numeric, 0) AS dist_km
FROM star_observe_pm(
17.9635, 4.6934, -- J2000 RA/Dec
-798.58, 10328.12, -- proper motion (mas/yr)
548.31, -110.6, -- parallax (mas), RV (km/s)
'40.0N 105.3W 1655m'::observer, now()
) AS t;
```
---
## star_equatorial_pm
Computes the apparent equatorial coordinates of a star with proper motion, parallax, and radial velocity corrections. Returns precessed coordinates of date. Distance is derived from parallax if greater than zero.
### Signature
```sql
star_equatorial_pm(
ra_hours float8,
dec_deg float8,
pm_ra_masyr float8,
pm_dec_masyr float8,
parallax_mas float8,
rv_kms float8,
t timestamptz
) → equatorial
```
### Parameters
| Parameter | Type | Unit | Description |
|-----------|------|------|-------------|
| `ra_hours` | `float8` | hours | J2000 Right Ascension (0-24) |
| `dec_deg` | `float8` | degrees | J2000 Declination (-90 to +90) |
| `pm_ra_masyr` | `float8` | mas/yr | Proper motion in RA (mu_alpha * cos(delta)) |
| `pm_dec_masyr` | `float8` | mas/yr | Proper motion in Declination |
| `parallax_mas` | `float8` | mas | Trigonometric parallax (0 if unknown) |
| `rv_kms` | `float8` | km/s | Radial velocity (0 if unknown) |
| `t` | `timestamptz` | | Evaluation time |
### Returns
An `equatorial` with RA (hours) and Dec (degrees) corrected for proper motion and precessed to date. Distance in km from parallax (0 if parallax is 0 or unknown).
### Example
```sql
-- RA/Dec of Barnard's Star, corrected for proper motion
SELECT round(eq_ra(e)::numeric, 6) AS ra_hours,
round(eq_dec(e)::numeric, 6) AS dec_deg,
round(eq_distance(e)::numeric, 0) AS dist_km
FROM star_equatorial_pm(
17.9635, 4.6934,
-798.58, 10328.12,
548.31, -110.6,
now()
) AS e;
```
```sql
-- Track the motion of Barnard's Star over 50 years
SELECT extract(year from t) AS year,
round(eq_ra(e)::numeric, 6) AS ra_h,
round(eq_dec(e)::numeric, 6) AS dec_deg
FROM generate_series(
'2000-01-01'::timestamptz,
'2050-01-01'::timestamptz,
interval '10 years'
) AS t,
star_equatorial_pm(17.9635, 4.6934, -798.58, 10328.12, 548.31, -110.6, t) AS e;
```
---
## small_body_equatorial
Computes the geocentric apparent equatorial coordinates (RA/Dec) of a comet or asteroid from its `orbital_elements`. The body is propagated on a Keplerian orbit, and Earth's position is obtained from VSOP87.
### Signature
```sql
small_body_equatorial(oe orbital_elements, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `oe` | `orbital_elements` | Bundled orbital elements |
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km) from Earth's center.
### Example
```sql
-- RA/Dec of Ceres
WITH ceres AS (
SELECT oe_from_mpc(
'00001 3.33 0.12 K24AM 60.07966 73.42937 80.26860 10.58664 0.0789126 0.21406048 2.7660961 0 MPO838504 8738 115 1801-2024 0.65 M-v 30k MPCLINUX 0000 (1) Ceres 20240825'
) AS oe
)
SELECT 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_km
FROM ceres,
small_body_equatorial(oe, now()) AS e;
```
---
## small_body_observe_apparent
Computes the topocentric position of a comet or asteroid with single-iteration light-time correction. The body is propagated at the retarded time (observation time minus light travel time), while Earth's position is evaluated at the observation time via VSOP87.
### Signature
```sql
small_body_observe_apparent(oe orbital_elements, obs observer, t timestamptz) → topocentric
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `oe` | `orbital_elements` | Bundled orbital elements |
| `obs` | `observer` | Observer location on Earth |
| `t` | `timestamptz` | Observation time |
### Returns
A `topocentric` with azimuth, elevation, range (km), and range rate (km/s), corrected for light travel time.
### Example
```sql
-- Observe Ceres with light-time correction from Boulder
WITH ceres AS (
SELECT oe_from_mpc(
'00001 3.33 0.12 K24AM 60.07966 73.42937 80.26860 10.58664 0.0789126 0.21406048 2.7660961 0 MPO838504 8738 115 1801-2024 0.65 M-v 30k MPCLINUX 0000 (1) Ceres 20240825'
) AS oe
)
SELECT round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el,
round((topo_range(t) / 149597870.7)::numeric, 4) AS dist_au
FROM ceres,
small_body_observe_apparent(oe, '40.0N 105.3W 1655m'::observer, now()) AS t;
```
---
## small_body_equatorial_apparent
Computes the geocentric apparent equatorial coordinates (RA/Dec) of a comet or asteroid with light-time correction. The body is propagated at the retarded time.
### Signature
```sql
small_body_equatorial_apparent(oe orbital_elements, t timestamptz) → equatorial
```
### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `oe` | `orbital_elements` | Bundled orbital elements |
| `t` | `timestamptz` | Evaluation time |
### Returns
An `equatorial` with RA (hours), Dec (degrees), and distance (km), corrected for light travel time.
### Example
```sql
-- Light-time corrected RA/Dec of Ceres
WITH ceres AS (
SELECT oe_from_mpc(
'00001 3.33 0.12 K24AM 60.07966 73.42937 80.26860 10.58664 0.0789126 0.21406048 2.7660961 0 MPO838504 8738 115 1801-2024 0.65 M-v 30k MPCLINUX 0000 (1) Ceres 20240825'
) AS oe
)
SELECT 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_km
FROM ceres,
small_body_equatorial_apparent(oe, now()) AS e;
```

View File

@ -6,7 +6,7 @@ sidebar:
import { Aside, Tabs, TabItem } from "@astrojs/starlight/components"; import { Aside, Tabs, TabItem } from "@astrojs/starlight/components";
pg_orrery defines eight fixed-size base types and one SQL composite type that represent the core data structures of orbital mechanics. Each base type has a fixed on-disk size, a text I/O format for readability, and accessor functions for extracting individual fields. pg_orrery defines nine fixed-size base types and one SQL composite type that represent the core data structures of orbital mechanics. Each base type has a fixed on-disk size, a text I/O format for readability, and accessor functions for extracting individual fields.
## tle ## tle
@ -338,6 +338,59 @@ FROM ceres;
--- ---
## equatorial
**Size:** 24 bytes
Apparent equatorial coordinates of date. Stores three double-precision values: right ascension (radians internally, displayed as hours in the range [0, 24)), declination (radians internally, displayed as degrees in the range [-90, 90]), and distance in km.
For solar system bodies, these are J2000 coordinates precessed to the date of observation via IAU 1976 precession. For satellites, these are TEME frame RA/Dec, which approximates coordinates of date to arcsecond accuracy.
### Input Format
A parenthesized tuple of three values:
```
(ra_hours,dec_degrees,distance_km)
```
```sql
SELECT '(4.29220000,20.60000000,885412345.678)'::equatorial;
```
### Accessor Functions
| Function | Return Type | Unit | Description |
|----------|-------------|------|-------------|
| `eq_ra(equatorial)` | `float8` | hours | Right ascension [0, 24) |
| `eq_dec(equatorial)` | `float8` | degrees | Declination [-90, 90] |
| `eq_distance(equatorial)` | `float8` | km | Distance (0 for stars without parallax) |
```sql
-- Geocentric RA/Dec of Jupiter
SELECT eq_ra(e) AS ra_hours,
eq_dec(e) AS dec_deg,
eq_distance(e) AS dist_km
FROM planet_equatorial(5, now()) AS e;
```
```sql
-- Compare RA/Dec of all planets
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(eq_ra(e)::numeric, 4) AS ra_h,
round(eq_dec(e)::numeric, 4) AS dec_deg
FROM unnest(ARRAY[1,2,4,5,6,7,8]) AS body_id,
planet_equatorial(body_id, now()) AS e;
```
---
## observer_window ## observer_window
**Type:** SQL composite (variable-length) **Type:** SQL composite (variable-length)