Update CLAUDE.md for v0.10.0, gitignore bench catalogs, add roadmap
- CLAUDE.md: 106 -> 114 functions, 18 -> 19 test suites, add aberration suite, DE apparent variants, equatorial spatial domain to tables - .gitignore: ignore downloaded TLE catalogs in bench/ (alpha5, celestrak, satnogs, spacetrack, supgp, mega/merged, cookies) - docs/TODO-v0.10.0.md: rewrite as post-v0.10.0 roadmap with next version candidates (make_orbital_elements, galilean_equatorial, equatorial GiST index, nutation, Delta T, rise/set) - Track bench/build_catalog.py and agent thread message 001
This commit is contained in:
parent
b0741c553b
commit
db1f478e4f
15
.gitignore
vendored
15
.gitignore
vendored
@ -25,6 +25,21 @@ test/test_od_math
|
||||
test/test_od_iod
|
||||
test/test_od_gauss
|
||||
|
||||
# Bench — downloaded TLE catalogs (large, ephemeral)
|
||||
# Already-tracked files (active.tle, spacetrack_full*.tle) are unaffected.
|
||||
bench/alpha5.tle
|
||||
bench/celestrak_*.tle
|
||||
bench/mega_catalog.tle
|
||||
bench/merged_catalog.tle
|
||||
bench/satnogs*.tle
|
||||
bench/spacetrack_all_onorbit.tle
|
||||
bench/spacetrack_everything.tle
|
||||
bench/supgp_*.tle
|
||||
bench/tle_api_catalog.tle
|
||||
bench/cookies*.txt
|
||||
bench/load_mega_catalog.sql
|
||||
bench/load_merged_catalog.sql
|
||||
|
||||
# Docs site
|
||||
docs/node_modules/
|
||||
docs/dist/
|
||||
|
||||
22
CLAUDE.md
22
CLAUDE.md
@ -1,9 +1,9 @@
|
||||
# pg_orrery — A Database Orrery for PostgreSQL
|
||||
|
||||
## What This Is
|
||||
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.
|
||||
A database orrery — celestial mechanics types and functions for PostgreSQL. Native C extension using PGXS, 114 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 and annual parallax), comets, asteroids (MPC catalog), Jupiter radio bursts, interplanetary Lambert transfers, equatorial RA/Dec coordinates with angular separation, atmospheric refraction, annual stellar aberration, and light-time correction.
|
||||
|
||||
**Current version:** 0.9.0 on branch `phase/spgist-orbital-trie`
|
||||
**Current version:** 0.10.0
|
||||
**Repository:** https://git.supported.systems/warehack.ing/pg_orrery
|
||||
**Documentation:** https://pg-orrery.warehack.ing
|
||||
|
||||
@ -11,7 +11,7 @@ A database orrery — celestial mechanics types and functions for PostgreSQL. Na
|
||||
```bash
|
||||
make PG_CONFIG=/usr/bin/pg_config # Compile with PGXS
|
||||
sudo make install PG_CONFIG=/usr/bin/pg_config # Install extension
|
||||
make installcheck PG_CONFIG=/usr/bin/pg_config # Run 18 regression test suites
|
||||
make installcheck PG_CONFIG=/usr/bin/pg_config # Run 19 regression test suites
|
||||
```
|
||||
|
||||
Requires: PostgreSQL 17 development headers, GCC, Make.
|
||||
@ -123,7 +123,7 @@ All types are fixed-size, `STORAGE = plain`, `ALIGNMENT = double`. No TOAST over
|
||||
| `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 (106 total)
|
||||
## Function Domains (114 total)
|
||||
|
||||
| Domain | Theory | Key Functions | Count |
|
||||
|--------|--------|---------------|-------|
|
||||
@ -134,9 +134,10 @@ All types are fixed-size, `STORAGE = plain`, `ALIGNMENT = double`. No TOAST over
|
||||
| Stars | J2000 + IAU 1976 precession | `star_observe()`, `star_equatorial()`, `star_observe_pm()` | 5 |
|
||||
| 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 |
|
||||
| Equatorial spatial | Vincenty formula | `eq_angular_distance()`, `eq_within_cone()`, `<->` | 2 |
|
||||
| Jupiter radio | Carr et al. (1983) | `jupiter_burst_probability()` | 3 |
|
||||
| Transfers | Lambert (Izzo 2015) | `lambert_transfer()`, `lambert_c3()` | 2 |
|
||||
| DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `planet_equatorial_de()` | 13 |
|
||||
| DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `planet_equatorial_de()`, `*_apparent_de()` | 19 |
|
||||
| GiST index | Altitude-band approximation | `&&` (overlap), `<->` (distance) | 8 |
|
||||
| Diagnostics | -- | `pg_orrery_ephemeris_info()` | 1 |
|
||||
|
||||
@ -240,6 +241,12 @@ Every `_de()` function mirrors an existing VSOP87 function:
|
||||
| `mars_moon_observe_de()` | `mars_moon_observe()` | STABLE |
|
||||
| `planet_equatorial_de()` | `planet_equatorial()` | STABLE |
|
||||
| `moon_equatorial_de()` | `moon_equatorial()` | STABLE |
|
||||
| `planet_observe_apparent_de()` | `planet_observe_apparent()` | STABLE |
|
||||
| `sun_observe_apparent_de()` | `sun_observe_apparent()` | STABLE |
|
||||
| `moon_observe_apparent_de()` | `moon_observe_apparent()` | STABLE |
|
||||
| `planet_equatorial_apparent_de()` | `planet_equatorial_apparent()` | STABLE |
|
||||
| `moon_equatorial_apparent_de()` | `moon_equatorial_apparent()` | STABLE |
|
||||
| `small_body_observe_apparent_de()` | `small_body_observe_apparent()` | STABLE |
|
||||
| `pg_orrery_ephemeris_info()` | — | STABLE |
|
||||
|
||||
## Vendored SGP4/SDP4
|
||||
@ -261,7 +268,7 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado
|
||||
|
||||
## Testing
|
||||
|
||||
18 regression test suites via `make installcheck`:
|
||||
19 regression test suites via `make installcheck`:
|
||||
|
||||
| Suite | What it tests |
|
||||
|-------|--------------|
|
||||
@ -282,11 +289,12 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado
|
||||
| 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 |
|
||||
| aberration | Annual aberration magnitude, DE apparent fallback, angular distance, cone search, stellar parallax |
|
||||
| vallado_518 | 518 Vallado test vectors (AIAA 2006-6753-Rev1), per-satellite breakdown |
|
||||
|
||||
### PG Version Matrix
|
||||
|
||||
Test all 18 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker:
|
||||
Test all 19 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker:
|
||||
|
||||
```bash
|
||||
make test-matrix # Full matrix (PG 14-18)
|
||||
|
||||
173
bench/build_catalog.py
Executable file
173
bench/build_catalog.py
Executable file
@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Build a merged TLE catalog from multiple sources for pg_orrery benchmarks.
|
||||
|
||||
Usage:
|
||||
# Merge existing TLE files into SQL
|
||||
./build_catalog.py bench/spacetrack_everything.tle bench/celestrak_active.tle ...
|
||||
|
||||
# Pipe to psql
|
||||
./build_catalog.py bench/*.tle | PGPORT=5499 psql -d contrib_regression
|
||||
|
||||
# Or generate SQL file
|
||||
./build_catalog.py bench/*.tle > bench/load_catalog.sql
|
||||
|
||||
Deduplication: when the same NORAD ID appears in multiple files, the entry
|
||||
with the newest epoch wins. This means CelesTrak SupGP data (fresher epochs)
|
||||
automatically overrides stale Space-Track entries.
|
||||
|
||||
Alpha-5 NORAD IDs (T0002 etc.) are handled transparently — they parse into
|
||||
integers >100,000 via the same logic as Bill Gray's get_el.c.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
# Alpha-5 NORAD decoding — mirrors get_norad_number() in src/sgp4/get_el.c
|
||||
_ALPHA5_SKIP = {'I', 'O'} # skipped in Alpha-5 encoding
|
||||
|
||||
def decode_norad(s):
|
||||
"""Decode a 5-character NORAD field to integer. Handles Alpha-5."""
|
||||
s = s.strip()
|
||||
if not s:
|
||||
return None
|
||||
first = s[0]
|
||||
if first.isdigit():
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
return None
|
||||
elif first.isalpha() and first.isupper():
|
||||
# Alpha-5: letter + 4 digits
|
||||
val = ord(first) - ord('A')
|
||||
if first > 'I':
|
||||
val -= 1
|
||||
if first > 'O':
|
||||
val -= 1
|
||||
try:
|
||||
return val * 10000 + int(s[1:]) + 100000
|
||||
except ValueError:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def parse_3le_file(filepath):
|
||||
"""Parse a 3LE (or 2LE) file into a dict of norad_str -> (line1, line2, name, epoch)."""
|
||||
objects = {}
|
||||
try:
|
||||
lines = open(filepath, errors='replace').readlines()
|
||||
except FileNotFoundError:
|
||||
print(f"# SKIP {filepath}: not found", file=sys.stderr)
|
||||
return objects
|
||||
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i].rstrip('\r\n')
|
||||
|
||||
if line.startswith('1 ') and i + 1 < len(lines) and lines[i + 1].rstrip('\r\n').startswith('2 '):
|
||||
line1 = line.rstrip('\r\n')
|
||||
line2 = lines[i + 1].rstrip('\r\n')
|
||||
|
||||
# Look back for name line (3LE format)
|
||||
name = ''
|
||||
if i > 0:
|
||||
prev = lines[i - 1].rstrip('\r\n')
|
||||
if prev and not prev.startswith(('1 ', '2 ')):
|
||||
name = prev.strip()
|
||||
|
||||
# Extract NORAD ID (works for both standard and Alpha-5)
|
||||
norad_field = line1[2:7]
|
||||
norad_int = decode_norad(norad_field)
|
||||
if norad_int is None:
|
||||
i += 2
|
||||
continue
|
||||
|
||||
norad_str = str(norad_int)
|
||||
|
||||
# Extract epoch (column 18-32 of line 1)
|
||||
try:
|
||||
epoch = float(line1[18:32].strip())
|
||||
except (ValueError, IndexError):
|
||||
epoch = 0.0
|
||||
|
||||
# Keep the entry with the newest epoch
|
||||
if norad_str not in objects or epoch > objects[norad_str][3]:
|
||||
objects[norad_str] = (line1, line2, name, epoch)
|
||||
|
||||
i += 2
|
||||
else:
|
||||
i += 1
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Parse --table-name option
|
||||
table_name = 'bench_catalog'
|
||||
files = []
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i] == '--table' and i + 1 < len(sys.argv):
|
||||
table_name = sys.argv[i + 1]
|
||||
i += 2
|
||||
elif sys.argv[i].startswith('--table='):
|
||||
table_name = sys.argv[i].split('=', 1)[1]
|
||||
i += 1
|
||||
else:
|
||||
files.append(sys.argv[i])
|
||||
i += 1
|
||||
|
||||
# Merge all sources (later files override earlier for same NORAD ID if newer epoch)
|
||||
mega = {}
|
||||
for filepath in files:
|
||||
objs = parse_3le_file(filepath)
|
||||
new = updated = 0
|
||||
for k, v in objs.items():
|
||||
if k not in mega:
|
||||
new += 1
|
||||
mega[k] = v
|
||||
elif v[3] > mega[k][3]:
|
||||
updated += 1
|
||||
mega[k] = v
|
||||
basename = os.path.basename(filepath)
|
||||
print(f"-- {basename}: {len(objs)} objects ({new} new, {updated} updated)", file=sys.stderr)
|
||||
|
||||
print(f"-- Total: {len(mega)} unique objects", file=sys.stderr)
|
||||
|
||||
# Emit SQL
|
||||
print(f"-- pg_orrery benchmark catalog ({len(mega)} objects)")
|
||||
print(f"-- Generated from {len(files)} TLE source files")
|
||||
print(f"-- Sources: {', '.join(os.path.basename(f) for f in files)}")
|
||||
print()
|
||||
print(f"DROP TABLE IF EXISTS {table_name};")
|
||||
print(f"CREATE TABLE {table_name} (")
|
||||
print(f" id serial,")
|
||||
print(f" name text,")
|
||||
print(f" tle tle")
|
||||
print(f");")
|
||||
print()
|
||||
|
||||
count = 0
|
||||
for norad_str in sorted(mega.keys(), key=lambda x: int(x)):
|
||||
line1, line2, name, epoch = mega[norad_str]
|
||||
|
||||
if not name:
|
||||
name = f'NORAD {norad_str}'
|
||||
|
||||
name_sql = name.replace("'", "''").replace('\\', '\\\\')
|
||||
tle_str = f"{line1}\\n{line2}"
|
||||
|
||||
print(f"INSERT INTO {table_name} (name, tle) VALUES ('{name_sql}', E'{tle_str}');")
|
||||
count += 1
|
||||
|
||||
print()
|
||||
print(f"-- Loaded {count} objects")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
138
docs/TODO-v0.10.0.md
Normal file
138
docs/TODO-v0.10.0.md
Normal file
@ -0,0 +1,138 @@
|
||||
# pg_orrery — Post-v0.10.0 Roadmap
|
||||
|
||||
## Current State
|
||||
|
||||
**Version:** v0.10.0 (tagged 2026-02-22)
|
||||
**Branch:** `phase/spgist-orbital-trie` merged to `main`
|
||||
**Functions:** 114 SQL functions, 9 custom types, 19 test suites, 1 new operator
|
||||
**Docs:** https://pg-orrery.warehack.ing
|
||||
|
||||
### What v0.10.0 shipped
|
||||
- Annual stellar aberration in all `_apparent()` functions (~20 arcsec)
|
||||
- 6 new `_apparent_de()` variants with VSOP87 fallback
|
||||
- `eq_angular_distance()` + `eq_within_cone()` + `<->` operator on equatorial
|
||||
- Stellar annual parallax in `star_observe_pm()` / `star_equatorial_pm()`
|
||||
|
||||
### Astrolock integration status
|
||||
Thread: `docs/agent-threads/v090-astrolock-upgrade/`
|
||||
- v0.9.0 fully deployed to both local and production servers
|
||||
- v0.10.0 upgrade path communicated (message 003)
|
||||
- Pending their upgrade — aberration improvement is automatic
|
||||
|
||||
## Remaining Housekeeping
|
||||
|
||||
- [x] Merge `phase/spgist-orbital-trie` to `main`
|
||||
- [ ] Clean up `bench/` — gitignore the untracked TLE catalog files (alpha5, celestrak, satnogs, spacetrack, supgp, tle_api, merged, mega)
|
||||
- [ ] Update "From Skyfield" workflow page for v0.9.0/v0.10.0 RA/Dec + aberration parity
|
||||
- [ ] Add timing numbers for equatorial, refraction, aberration functions to benchmarks page
|
||||
- [ ] Update CLAUDE.md function count: 106 -> 114, test suites: 18 -> 19
|
||||
- [ ] Update docs llms.txt and llms-full.txt for v0.10.0 functions
|
||||
|
||||
## Feature Candidates — Next Version
|
||||
|
||||
### Tier 1 — High value, low effort
|
||||
|
||||
#### A. `make_orbital_elements()` constructor
|
||||
**Requested by:** astrolock-api (message 002, question 1)
|
||||
|
||||
SQL constructor from 9 floats. Lets users compose orbital_elements from individual table columns without `format()`/cast workaround.
|
||||
|
||||
```sql
|
||||
make_orbital_elements(epoch_jd, q_au, e, inc_rad, omega_rad, node_rad, tp_jd, h_mag, g_slope)
|
||||
-> orbital_elements
|
||||
```
|
||||
|
||||
Complexity: ~30 lines in `orbital_elements_type.c`. One new function.
|
||||
|
||||
#### B. `galilean_equatorial()` and moon family equatorial functions
|
||||
**Requested by:** astrolock-api (message 002, question 2)
|
||||
|
||||
Geocentric RA/Dec for planetary moons. Follows `planet_equatorial()` pattern — convert geocentric ecliptic position to equatorial J2000, precess to date.
|
||||
|
||||
New functions (~4):
|
||||
- `galilean_equatorial(int4, timestamptz) -> equatorial`
|
||||
- `saturn_moon_equatorial(int4, timestamptz) -> equatorial`
|
||||
- `uranus_moon_equatorial(int4, timestamptz) -> equatorial`
|
||||
- `mars_moon_equatorial(int4, timestamptz) -> equatorial`
|
||||
|
||||
Plus DE variants (~4 more).
|
||||
|
||||
Complexity: ~100 lines. Follows established pattern.
|
||||
|
||||
#### C. GiST/SP-GiST index on equatorial type
|
||||
The `<->` operator and `eq_within_cone()` exist but have no index support. For cone-search queries over large catalogs, an index would enable:
|
||||
|
||||
```sql
|
||||
-- Indexed: "what's within 10 deg of Jupiter?"
|
||||
SELECT * FROM star_catalog
|
||||
WHERE position <-> planet_equatorial(5, NOW()) < 10.0;
|
||||
```
|
||||
|
||||
Approach: GiST with bounding-box approximation in RA/Dec space, or SP-GiST with HEALPix-style recursive decomposition.
|
||||
|
||||
Complexity: Medium (~300-500 lines). The SP-GiST infrastructure from TLE index is reusable.
|
||||
|
||||
### Tier 2 — Medium value, medium risk
|
||||
|
||||
#### D. Nutation correction (~9 arcsec)
|
||||
IAU 1980 nutation (106 terms) or simplified IAU 2000B.
|
||||
|
||||
Currently: TEME uses 4 of 106 terms. Equatorial output uses IAU 1976 precession only (no nutation).
|
||||
|
||||
Value: ~9 arcsec correction in equatorial coordinates. Matters for sub-arcminute accuracy — telescope GoTo mounts and catalog cross-matching.
|
||||
|
||||
Scope: New `nutation.c` + modify `precess_j2000_to_date()` to include nutation matrix.
|
||||
Risk: Touches the precession pipeline used by every equatorial function.
|
||||
|
||||
#### E. Delta T (TDB - UTC)
|
||||
The "affects everything" change. Currently all time is treated as UTC with no TT/TDB distinction.
|
||||
|
||||
Requires IERS lookup table or polynomial approximation (Espenak & Meeus 2006).
|
||||
|
||||
Scope: Touch `sidereal_time.h`, propagation pipelines, all observation functions.
|
||||
Risk: High — affects every time conversion. Needs careful regression testing.
|
||||
Value: Improves accuracy for historical epochs (pre-2000) and future predictions (post-2030).
|
||||
|
||||
Already noted as deferred at `sidereal_time.h:22-26`.
|
||||
|
||||
#### F. Rise/set prediction for solar system objects
|
||||
Like `predict_passes()` but for planets, Sun, and Moon. Binary search for horizon crossings.
|
||||
|
||||
Use cases: sunrise/sunset, moonrise/moonset, planet visibility windows.
|
||||
Complexity: Medium. The pass prediction binary search machinery exists but needs adaptation for much slower angular rates.
|
||||
|
||||
### Tier 3 — Future / deferred
|
||||
|
||||
- **Perturbed asteroid propagation** — secular perturbation terms for orbital_elements (currently two-body Keplerian)
|
||||
- **Eclipse prediction** — Moon shadow cone intersection with observer
|
||||
- **Satellite sunlit visibility** — extend `pass_visible()` with Earth shadow geometry
|
||||
- **Constellation identification** — equatorial position to IAU constellation boundary lookup
|
||||
- **Coordinate frame transforms** — ICRS/FK5/galactic/ecliptic conversion functions
|
||||
|
||||
## Suggested Next Phase
|
||||
|
||||
```
|
||||
Housekeeping (bench cleanup, docs, CLAUDE.md)
|
||||
|
|
||||
v
|
||||
Feature A: make_orbital_elements() — 30 lines, unblocks Craft comets
|
||||
Feature B: moon family equatorial — 100 lines, unblocks Craft Galilean moons
|
||||
|
|
||||
v
|
||||
Feature C: equatorial GiST index — enables indexed cone search
|
||||
Feature D: nutation — closes largest remaining accuracy gap (~9 arcsec)
|
||||
|
|
||||
v
|
||||
Feature E: Delta T — high risk, needs its own careful phase
|
||||
Feature F: rise/set — new domain, independent
|
||||
```
|
||||
|
||||
A + B could ship as v0.11.0. C + D as v0.12.0.
|
||||
|
||||
## Verification
|
||||
|
||||
- All 19 existing regression suites must continue to pass
|
||||
- New test suites for each feature
|
||||
- PG 14-18 matrix (`make test-matrix`)
|
||||
- Cross-check against JPL Horizons for nutation accuracy
|
||||
- Astrolock integration smoke test after each db upgrade
|
||||
@ -0,0 +1,196 @@
|
||||
# Message 001
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| From | pg-orrery |
|
||||
| To | astrolock-api |
|
||||
| Date | 2026-02-21T18:30:00-07:00 |
|
||||
| Re | pg_orrery v0.9.0 released — 24 new functions for Craft |
|
||||
|
||||
---
|
||||
|
||||
## What shipped
|
||||
|
||||
pg_orrery v0.9.0 is tagged and pushed. Docker image at `git.supported.systems/warehack.ing/pg_orrery:pg17`. Tested across PG 14-18. Docs live at https://pg-orrery.warehack.ing.
|
||||
|
||||
**24 new SQL functions** in 4 feature areas:
|
||||
|
||||
### 1. Equatorial RA/Dec output (12 functions)
|
||||
|
||||
New `equatorial` type (24 bytes: RA in hours, Dec in degrees, distance in km). Apparent coordinates of date — what telescope GoTo mounts and sky apps expect.
|
||||
|
||||
```sql
|
||||
-- Planets, Sun, Moon — geocentric RA/Dec
|
||||
SELECT eq_ra(planet_equatorial(5, NOW())) AS jupiter_ra_hours,
|
||||
eq_dec(planet_equatorial(5, NOW())) AS jupiter_dec_deg;
|
||||
|
||||
SELECT eq_ra(sun_equatorial(NOW())), eq_dec(sun_equatorial(NOW()));
|
||||
SELECT eq_ra(moon_equatorial(NOW())), eq_dec(moon_equatorial(NOW()));
|
||||
|
||||
-- Satellites — topocentric (observer parallax-corrected) and geocentric
|
||||
SELECT eq_ra(eci_to_equatorial(
|
||||
sgp4_propagate(tle_from_lines(l1, l2), NOW()),
|
||||
observer_from_geodetic(lat, lon, alt_m),
|
||||
NOW()
|
||||
)) AS sat_ra_hours;
|
||||
|
||||
SELECT eq_ra(eci_to_equatorial_geo(
|
||||
sgp4_propagate(tle_from_lines(l1, l2), NOW()),
|
||||
NOW()
|
||||
)) AS sat_ra_geo;
|
||||
|
||||
-- Comets/asteroids from orbital_elements
|
||||
SELECT eq_ra(small_body_equatorial(oe, NOW())) AS ra_hours
|
||||
FROM asteroids;
|
||||
|
||||
-- Stars (precesses J2000 catalog coords to date)
|
||||
SELECT eq_ra(star_equatorial(ra_hours, dec_deg, NOW()));
|
||||
|
||||
-- Accessors
|
||||
eq_ra(equatorial) -> float8 -- hours [0, 24)
|
||||
eq_dec(equatorial) -> float8 -- degrees [-90, 90]
|
||||
eq_distance(equatorial) -> float8 -- km
|
||||
```
|
||||
|
||||
**Why this matters for Craft:** The sky engine currently returns only alt/az from `topo_elevation()`/`topo_azimuth()`. RA/Dec enables:
|
||||
- CesiumJS sky layer with equatorial grid overlay
|
||||
- Telescope GoTo integration (mounts speak RA/Dec)
|
||||
- Cross-matching objects against star catalogs
|
||||
- Proper sky chart rendering in the web UI
|
||||
|
||||
### 2. Atmospheric refraction (4 functions)
|
||||
|
||||
Bennett (1982) formula. Objects near the horizon appear ~0.57 deg higher than their geometric position.
|
||||
|
||||
```sql
|
||||
-- Basic: standard atmosphere
|
||||
SELECT atmospheric_refraction(0.0); -- 0.57 deg at horizon
|
||||
|
||||
-- Extended: with pressure (mbar) and temperature (C)
|
||||
SELECT atmospheric_refraction_ext(0.0, 700.0, -20.0); -- high altitude, cold
|
||||
|
||||
-- Apparent elevation (geometric + refraction correction)
|
||||
SELECT topo_elevation_apparent(planet_observe(5, obs, NOW()));
|
||||
|
||||
-- Refracted pass prediction (horizon at -0.569 deg geometric)
|
||||
SELECT * FROM predict_passes_refracted(
|
||||
tle, obs, start_ts, end_ts
|
||||
);
|
||||
```
|
||||
|
||||
**Why this matters for Craft:**
|
||||
- `predict_passes_refracted()` finds passes ~35 seconds earlier/later than geometric — more accurate AOS/LOS times for rotor pre-positioning
|
||||
- `topo_elevation_apparent()` gives what the observer actually *sees*, not the geometric truth
|
||||
- The pass finder currently uses `predict_passes()` — drop-in replacement with `predict_passes_refracted()` for better accuracy
|
||||
|
||||
### 3. Light-time corrected apparent positions (6 functions)
|
||||
|
||||
Single-iteration light-time correction. Shows where an object *was* when its light left, not where it *is now*. Jupiter: ~35-52 minutes of light travel time.
|
||||
|
||||
```sql
|
||||
-- Planet apparent position (light-time corrected)
|
||||
SELECT topo_elevation(planet_observe_apparent(5, obs, NOW())) AS jupiter_apparent;
|
||||
SELECT topo_elevation(sun_observe_apparent(obs, NOW())) AS sun_apparent;
|
||||
|
||||
-- Equatorial apparent (light-time corrected RA/Dec)
|
||||
SELECT eq_ra(planet_equatorial_apparent(5, NOW()));
|
||||
SELECT eq_ra(moon_equatorial_apparent(NOW()));
|
||||
|
||||
-- Comets/asteroids
|
||||
SELECT * FROM small_body_observe_apparent(oe, obs, NOW());
|
||||
SELECT eq_ra(small_body_equatorial_apparent(oe, NOW()));
|
||||
```
|
||||
|
||||
**Why this matters for Craft:** The sky engine's `planet_observe()` returns geometric position. For telescope pointing accuracy, `planet_observe_apparent()` gives the correction. Matters most for outer planets.
|
||||
|
||||
### 4. Stellar proper motion (2 functions)
|
||||
|
||||
Stars move. Barnard's Star drifts ~10 arcseconds/year. For high-proper-motion stars, catalog J2000 coords drift noticeably over decades.
|
||||
|
||||
```sql
|
||||
-- Observe with proper motion (Hipparcos/Gaia convention)
|
||||
SELECT topo_elevation(star_observe_pm(
|
||||
ra_hours, dec_deg,
|
||||
pm_ra_masyr, -- mu_alpha * cos(delta), mas/yr
|
||||
pm_dec_masyr, -- mu_delta, mas/yr
|
||||
parallax_mas, -- 0 to skip parallax
|
||||
rv_kms, -- 0 to skip radial velocity
|
||||
obs, NOW()
|
||||
));
|
||||
|
||||
-- RA/Dec with proper motion
|
||||
SELECT eq_ra(star_equatorial_pm(
|
||||
ra_hours, dec_deg, pm_ra, pm_dec, plx, rv, NOW()
|
||||
));
|
||||
```
|
||||
|
||||
**Why this matters for Craft:** If Craft's star catalog has Hipparcos/Gaia proper motion columns, these functions give positions corrected for stellar drift. The existing `star_observe()` assumes static J2000 — fine for most stars, but Barnard's Star is off by ~2.6 arcmin over 25 years.
|
||||
|
||||
## Upgrade path
|
||||
|
||||
### 1. Rebuild the database image
|
||||
|
||||
Craft's `packages/db/Dockerfile` pulls pg_orrery source via `additional_contexts`. Point it at the v0.9.0 tag or the latest `phase/spgist-orbital-trie`:
|
||||
|
||||
```bash
|
||||
cd ~/claude/ham/satellite/astrolock
|
||||
docker compose build db
|
||||
```
|
||||
|
||||
### 2. Install/upgrade the extension
|
||||
|
||||
```sql
|
||||
-- If already on 0.8.0:
|
||||
ALTER EXTENSION pg_orrery UPDATE TO '0.9.0';
|
||||
|
||||
-- Or fresh install:
|
||||
CREATE EXTENSION pg_orrery VERSION '0.9.0';
|
||||
```
|
||||
|
||||
### 3. Quick smoke test
|
||||
|
||||
```sql
|
||||
-- RA/Dec works?
|
||||
SELECT eq_ra(planet_equatorial(5, NOW())) AS jupiter_ra,
|
||||
eq_dec(planet_equatorial(5, NOW())) AS jupiter_dec;
|
||||
|
||||
-- Refraction works?
|
||||
SELECT atmospheric_refraction(0.0); -- should be ~0.57
|
||||
|
||||
-- Refracted passes?
|
||||
SELECT count(*) FROM predict_passes_refracted(
|
||||
tle_from_lines(l1, l2),
|
||||
observer_from_geodetic(36.0, -86.0, 200.0),
|
||||
NOW(), NOW() + interval '7 days'
|
||||
);
|
||||
```
|
||||
|
||||
## Suggested integration points (for astrolock-api to evaluate)
|
||||
|
||||
These are suggestions, not requirements — Craft knows its own priorities:
|
||||
|
||||
1. **RA/Dec in `whats_up` response** — Add `ra` and `dec` fields alongside `altitude_deg`/`azimuth_deg`. The SQL change is small: add `eq_ra(planet_equatorial(...))` to the planet CTE, `eq_ra(eci_to_equatorial(...))` to the satellite CTE, etc.
|
||||
|
||||
2. **Replace `predict_passes()` with `predict_passes_refracted()`** in `pass_finder.py` — Drop-in replacement, same return signature, better AOS/LOS accuracy.
|
||||
|
||||
3. **Use `planet_observe_apparent()` for telescope pointing** — When the rotor is tracking a planet, the apparent position is what the mount should point at.
|
||||
|
||||
4. **Proper motion for bright star catalog** — If `star` table has Gaia/Hipparcos proper motion columns, swap `star_observe_safe()` for `star_observe_pm()` in the star CTE.
|
||||
|
||||
5. **DE ephemeris RA/Dec** — If DE441 is loaded, `planet_equatorial_de()` gives sub-arcsecond RA/Dec. Two new functions: `planet_equatorial_de()`, `moon_equatorial_de()`.
|
||||
|
||||
## Reference
|
||||
|
||||
- Full docs: https://pg-orrery.warehack.ing
|
||||
- New refraction page: https://pg-orrery.warehack.ing/reference/functions-refraction/
|
||||
- Updated types page: https://pg-orrery.warehack.ing/reference/types/ (equatorial type)
|
||||
- LLM reference: https://pg-orrery.warehack.ing/llms-full.txt (all 106 function signatures)
|
||||
|
||||
---
|
||||
|
||||
**Next steps for recipient:**
|
||||
- [ ] Review which v0.9.0 features are worth integrating
|
||||
- [ ] Rebuild db image with pg_orrery v0.9.0
|
||||
- [ ] Run `ALTER EXTENSION pg_orrery UPDATE TO '0.9.0'`
|
||||
- [ ] Decide priority order for integration (RA/Dec, refracted passes, apparent positions, proper motion)
|
||||
- [ ] Reply with questions, concerns, or an integration plan
|
||||
Loading…
x
Reference in New Issue
Block a user