Skip to content

Observation Engine

Status & scope

  • Module: lens/observation/
  • Milestone: Phase 2 (complete)

Purpose

Satellite propagation (SGP4), coverage surface computation, and collection window analysis. Real TLE data from CelesTrak. Two coverage modes: elevation-angle (wide-area sensors) and ground-track swath (optical imaging).

Public API

parse_tle_file(path) → list[SatelliteInfo]

  • Parse TLE text (2-line or 3-line CelesTrak format).

propagate(satellites, start, end, time_step_seconds) → PropagationResult

  • SGP4 propagation. ECI → geodetic (WGS84). Returns position tuples.

elevation_angle(observer_lat/lon/alt, sat_lat/lon/alt) → float

  • Degrees above horizon. Simplified spherical approximation.

coverage_surface(satellites, bbox, start, end, ...) → CoverageSurface

Two modes controlled by swath_width_km: - swath_width_km > 0: Ground-track swath. Cell covered if subsatellite point within half-swath distance (haversine). For optical imaging sensors. - swath_width_km == 0: Elevation-angle mode. Cell covered if sat above min_elevation_deg. For comms/SIGINT/wide-area.

collection_windows(satellites, target_lat/lon, start, end) → CollectionWindows

  • Per-satellite visibility intervals. Gap analysis (max gap, avg gap).

Sensor Swath Reference

Sensor Swath Width Altitude Use
Planet Dove 24 km 475 km 3m optical
Planet SkySat 20 km 500 km 0.5m optical
Maxar WorldView 13 km 617 km 0.3m optical
NOAA weather ~2000 km 850 km Weather imaging
Starlink (proxy) N/A 550 km Comms (elevation mode)

Dataclasses

SatellitePosition (frozen)

Field Type
timestamp datetime
lat, lon float (degrees)
alt_km float
satellite_name, satellite_id str

CoverageCell (frozen)

Field Type
lat, lon float
coverage_pct float (0–100)
avg_satellites float
max_gap_seconds float

CollectionWindow (frozen)

Field Type
satellite_name, satellite_id str
start, end datetime
max_elevation_deg float
duration_seconds float

File Layout

lens/observation/
  __init__.py
  propagator.py      ← TLE parsing, SGP4, coordinate conversion
  coverage.py        ← coverage_surface (swath + elevation modes), collection_windows
  sky_mask.py        ← Terrain-masked horizon from DEM
  cost_models.py     ← coverage_as_cost, sky_mask_penalty

Data Files

data/tle/
  starlink.tle       ← 9,840 Starlink sats
  planet.tle         ← 72 Planet (SkySat + Dove)
  weather.tle        ← 70 NOAA weather sats
  stations.tle       ← ISS, Tiangong, etc.
  demo_subset.tle    ← Curated subset for fast demos

Test References

  • tests/test_propagator.py — SGP4, TLE parsing, coordinate conversion
  • tests/test_coverage.py — coverage surface, collection windows, gap analysis
  • tests/test_sky_mask.py — terrain-masked horizon

DO NOT

  • Use elevation-angle mode for optical imaging analysis — use swath mode
  • Assume TLEs are static — orbital elements decay, 12h refresh minimum
  • Propagate more than 7 days from TLE epoch — accuracy degrades rapidly

Depends on: component.prism.cost-primitives, component.prism.universal-lens-parser