022a(core): almanac loader — Yuma/SEM parsers, visibility, cached fetch #38
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/022a-almanac-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the almanac core (step 022a) so satellite selection can use "what's actually in the sky" instead of raw ICD ranges. Per the owner's direction, the 022 items are not tracked in the backlog index — the work order (with outcome) lives directly in
docs/done/022a-almanac-core.md.Scope (verified live 2026-09-29)
(0.30 + 4.4117e-3)·π = 0.956338matches Yuma's radians exactly); SEM record = 14 tokens (PRN, SVN, URA, ecc, incl, RA-rate, sqrtA, Ω0, argP, M0, af0, af1, health, config).New code
src/gengnss/core/almanac.py(headless, stdlib only):parse_yuma/parse_sem→AlmanacData(tolerant: garbled blocks/tokens skipped, 3-per-line and 1-per-line SEM layouts,ValueErroronly when nothing parses)parse_almanac_text— content-sniffing dispatch (JSON{/ Yuma / SEM)AlmanacData.to_json/from_json— round-trip-safe interchange format for GLONASS/hand-curated datanominal_almanac(system)— full ICD constellation from the registry (documented "ICD ranges, not live status")fetch_almanac(url, cache_dir, max_age_h, opener=…)— injectable opener, 4 attempts with backoff, atomic staleness-checked JSON cache (GENGNSS_CACHE_DIRoverride)gps_week_epoch/almanac_reference_epoch— mod-1024 week-rollover resolutionsrc/gengnss/core/visibility.py:Ω(t) = Ω0 + (Ω̇−ωe)·tk − ωe·ToAwithtk = t−ToA(Yuma/gpstk convention — the first draft used the week-epoch reference and was corrected by the geometry tests)subpoint,look_angles(spherical-observer ENU), `visible_satellites(lat, lon, when, min_elevation)No new runtime dependencies.
Tests (
tests/test_almanac.py, network-free — fixtures mirror the live formats)14 tests: Yuma/SEM parse + cross-format element agreement (±1e-6 relative on the same week); truncated/binary input tolerance; JSON round trip incl. GLONASS channels; closed-form subpoint geometry at ToA (±0.5°); observer-at-subpoint → >80° elevation; synthetic 31-sat walker visibility bounds (5–13 visible at mid-latitudes, unhealthy never visible, |lat| ≤ 55.5°); week-rollover resolution; cache reuse/staleness/offline-error behavior.
ruffclean;pytest: 223 passed, 8 skipped. No backlog-index changes (022 untracked by owner decision).