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