Core modules: - tle.py: NORAD decoding (Alpha-5 + Super-5, matching get_el.c), 3LE/2LE parsing, TLERecord dataclass with epoch-based dedup - config.py: TOML config + env var overlay (XDG-compliant paths) - cache.py: File-based cache with staleness checking - catalog.py: Multi-source merge with MergeStats tracking - regime.py: LEO/MEO/GEO/HEO classification by mean motion Source downloaders (httpx): - celestrak.py: Active catalog + supplemental GP groups - satnogs.py: JSON API with 3LE conversion - spacetrack.py: POST auth flow, bulk GP download Output formatters: - sql.py: pg_orrery-compatible INSERT generation (E'' strings) - tle_file.py: Standard 3LE text output - json_out.py: JSON with orbital metadata and regime CLI (Click + Rich): - download: Cache TLEs from all sources - build: Merge + output SQL/3LE/JSON (pipes to psql) - load: Direct DB load via psycopg (optional [pg] extra) - info: Cache stats and configuration display 58 tests covering NORAD decoding (all 4 encoding cases), parsing, merge/dedup, SQL escaping, regime classification.
36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
"""Orbital regime classification based on mean motion.
|
|
|
|
Thresholds match the bench/load_bench.sh SQL query:
|
|
LEO: mean_motion > 11.25 rev/day (period < 128 min, alt < ~2000 km)
|
|
MEO: mean_motion > 1.8 rev/day (period < 800 min)
|
|
GEO: mean_motion > 0.9 rev/day (near-synchronous)
|
|
HEO: everything else (Molniya, tundra, GTO, etc.)
|
|
"""
|
|
|
|
from .tle import TLERecord
|
|
|
|
|
|
def classify_regime(mean_motion: float) -> str:
|
|
"""Classify orbital regime from mean motion (revs/day)."""
|
|
if mean_motion > 11.25:
|
|
return "LEO"
|
|
if mean_motion > 1.8:
|
|
return "MEO"
|
|
if mean_motion > 0.9:
|
|
return "GEO"
|
|
return "HEO"
|
|
|
|
|
|
def classify_record(rec: TLERecord) -> str:
|
|
"""Classify a TLERecord's orbital regime."""
|
|
return classify_regime(rec.mean_motion)
|
|
|
|
|
|
def regime_summary(records: dict[int, TLERecord]) -> dict[str, int]:
|
|
"""Count objects per regime."""
|
|
counts: dict[str, int] = {"LEO": 0, "MEO": 0, "GEO": 0, "HEO": 0}
|
|
for rec in records.values():
|
|
regime = classify_record(rec)
|
|
counts[regime] = counts.get(regime, 0) + 1
|
|
return counts
|