021(gui): per-signal satellite palettes — realistic ICD IDs + GLONASS FDMA picker #36

Merged
ykp merged 1 commit from feat/021-gui-satellite-palettes into main 2026-09-29 18:57:38 +02:00
Owner

Implements backlog step 021 per the user-approved design (per-signal grids; GLONASS slot+k view with by-channel mode; no preset dropdowns). Work order archived to docs/done/021-gui-satellite-palettes.md.

What it adds

Per-signal satellite palettes. Every signal row in Signal selection gains a ▾ toggle opening an accordion grid of real ICD satellite IDs — GPS PRN1–32, Galileo E01–E36, BeiDou C1–C63, GLONASS R1–R24 (8-column checkboxes; one grid open at a time keeps the window compact; BeiDou's 63 IDs fit 8 rows). The text entry stays as the advanced field (ranges, R2:-4 overrides) and remains the single source of truth: grid edits write compact spec strings through the existing trace, and external changes (typed specs, scenario load) re-sync the open grid.

GLONASS FDMA picker (the interesting part):

  • Slot view: checkboxes labeled with the registry's nominal channel — R2 (k-4), R10 (k0), R22 (k+4) — grouped by orbital plane (1–8 / 9–16 / 17–24); antipodal pairs (i, i+4) share a channel.
  • One per channel helper: FDMA channels are the scarce resource (24 slots / 12 nominal channels); keeps the lowest slot per channel so you don't accidentally simulate a co-channel antipodal pair.
  • By-channel (k) view (toggle per grid): check frequency channels directly — labeled k-7 (1598.062 MHz) -> R1 style with the band carrier from glonass_carrier_hz and the lowest slot via glonass_channel_to_slot; ICD test channels (-6, -5) excluded; checking a channel selects its slot with the nominal k implied.
  • Non-nominal channels are preserved: grid rebuilds emit slot:chan (2:-9,10) so editing never silently re-assigns a channel.

All logic is registry-driven (no duplicated literal tables): new headless-safe helpers in controllers.py — satellite_palette, glonass_channel_to_slot, glonass_channel_palette, glonass_one_per_channel, spec_string_for_satellites.

Tests

  • tests/test_gui_palettes.py (headless): exact ICD ID sets per system; GLONASS nominal-k labels + plane grouping (antipodal pairing verified within planes); channel→slot mapping incl. test-channel → None; spec round-trips through parse_sat_spec for all systems; non-nominal 2:-9 preservation; one-per-channel rule (incl. explicit-channel override); grid selections ≡ typed specs.
  • tests/test_gui_app.py (gui-marked, run in CI with display): accordion behavior, grid↔model sync both ways, GLONASS slot/by-channel/one-per-channel flows, scenario-load re-sync.
  • ruff clean; pytest: 209 passed, 8 skipped (gui-marked skip headless; run in CI with a display).

Docs

README GUI sentence extended; docs/backlog/000-overview.md 021 row added (done on merge).

Implements backlog step **021** per the user-approved design (per-signal grids; GLONASS slot+k view with by-channel mode; no preset dropdowns). Work order archived to `docs/done/021-gui-satellite-palettes.md`. ## What it adds **Per-signal satellite palettes.** Every signal row in Signal selection gains a `▾` toggle opening an accordion grid of real ICD satellite IDs — GPS `PRN1–32`, Galileo `E01–E36`, BeiDou `C1–C63`, GLONASS `R1–R24` (8-column checkboxes; one grid open at a time keeps the window compact; BeiDou's 63 IDs fit 8 rows). The text entry stays as the advanced field (ranges, `R2:-4` overrides) and remains the single source of truth: grid edits write compact spec strings through the existing trace, and external changes (typed specs, scenario load) re-sync the open grid. **GLONASS FDMA picker** (the interesting part): - Slot view: checkboxes labeled with the registry's **nominal channel** — `R2 (k-4)`, `R10 (k0)`, `R22 (k+4)` — grouped by orbital plane (1–8 / 9–16 / 17–24); antipodal pairs (*i*, *i+4*) share a channel. - **One per channel** helper: FDMA channels are the scarce resource (24 slots / 12 nominal channels); keeps the lowest slot per channel so you don't accidentally simulate a co-channel antipodal pair. - **By-channel (k) view** (toggle per grid): check frequency channels directly — labeled `k-7 (1598.062 MHz) -> R1` style with the band carrier from `glonass_carrier_hz` and the lowest slot via `glonass_channel_to_slot`; ICD test channels (-6, -5) excluded; checking a channel selects its slot with the nominal k implied. - Non-nominal channels are preserved: grid rebuilds emit `slot:chan` (`2:-9,10`) so editing never silently re-assigns a channel. All logic is registry-driven (no duplicated literal tables): new headless-safe helpers in `controllers.py` — `satellite_palette`, `glonass_channel_to_slot`, `glonass_channel_palette`, `glonass_one_per_channel`, `spec_string_for_satellites`. ## Tests - `tests/test_gui_palettes.py` (headless): exact ICD ID sets per system; GLONASS nominal-k labels + plane grouping (antipodal pairing verified within planes); channel→slot mapping incl. test-channel → None; spec round-trips through `parse_sat_spec` for all systems; non-nominal `2:-9` preservation; one-per-channel rule (incl. explicit-channel override); grid selections ≡ typed specs. - `tests/test_gui_app.py` (gui-marked, run in CI with display): accordion behavior, grid↔model sync both ways, GLONASS slot/by-channel/one-per-channel flows, scenario-load re-sync. - `ruff` clean; `pytest`: **209 passed, 8 skipped** (gui-marked skip headless; run in CI with a display). ## Docs README GUI sentence extended; `docs/backlog/000-overview.md` 021 row added (done on merge).
021(gui): per-signal satellite palettes — realistic ICD IDs + GLONASS FDMA picker
All checks were successful
ci / test (3.12) (push) Successful in 1m11s
ci / test (3.14) (push) Successful in 1m17s
ci / test (3.9) (push) Successful in 2m41s
ci / test (3.12) (pull_request) Successful in 2m42s
ci / test (3.14) (pull_request) Successful in 2m24s
ci / test (3.9) (pull_request) Successful in 2m27s
2fee5bbe5c
Implements docs/done/021-gui-satellite-palettes.md (user-approved design:
per-signal grids, GLONASS slot+k view with by-channel mode, no presets).

- each signal row gains a "▾ satellites" toggle opening an accordion
  satellite palette (8-column checkbox grid, real ICD IDs: PRN1-32,
  E01-E36, C1-C63, R1-R24); one grid open at a time keeps the window
  compact; the text entry stays as the advanced field and single source
  of truth (grid writes go through the existing spec-var trace)
- grid <-> model sync: populate from selections on open; re-sync on
  external changes (typed specs, scenario load); selecting a satellite
  auto-checks its signal
- GLONASS slot view: labels carry the registry nominal channel
  ("R2 (k-4)"), planes grouped, All/None/One-per-channel helpers
  (antipodal pairs share a channel -> keep the lowest slot per channel);
  by-channel (k) view: nominal channels k=-7..+6 minus ICD test channels,
  labeled with band carrier (glonass_carrier_hz) + lowest slot
  (glonass_channel_to_slot)
- non-nominal channels survive grid edits: rebuilt specs emit slot:chan
  (e.g. "2:-9,10") via spec_string_for_satellites
- controllers helpers (registry-driven, headless-safe):
  satellite_palette, glonass_channel_to_slot, glonass_channel_palette,
  glonass_one_per_channel, spec_string_for_satellites

Tests: tests/test_gui_palettes.py (headless: exact ICD ID sets, nominal
k/plane annotations, channel->slot mapping incl. test-channel exclusion,
spec round trips with non-nominal preservation, one-per-channel rule,
grid selections == typed specs) + gui-marked accordion/GLONASS-flow
tests in tests/test_gui_app.py. ruff clean; pytest 209 passed, 8 skipped
(gui tests skip headless).
ykp merged commit 227e296e67 into main 2026-09-29 18:57:38 +02:00
ykp deleted branch feat/021-gui-satellite-palettes 2026-09-29 18:57:38 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ykp/gengnss!36
No description provided.