aethersdr / aethersdr/AetherSDR
[RFC] Band plans conflate preferred mode with usage — six segments mislabelled digi-only, and the schema that caused it
@NF0T is already working on this.
Since Aug 1, 2026.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 299
Description
Preflight
- I have read GOVERNANCE.md and confirmed this change requires an RFC
- I have searched existing issues and this RFC has not been proposed before
- I have not opened a PR for this change yet
Problem
#4610 reported that iaru-region1.json labelled 80m 3600–3620 kHz as digi-only when the IARU R1 chart calls it all-modes. #4635 fixed that row. While verifying a suspected mirror of it in ssa-sweden.json, I checked every narrow-band-coloured segment in the R1 file against the authoritative chart (effective 16 Oct 2020) and found #4610 was one instance of a systematic transcription error, not a one-off.
The chart has two distinct columns: preferred mode and usage. Wherever a row reads "All modes" in the mode column with "Digimodes" in the usage column, our JSON collapsed both into the label and encoded the segment as digi-only with the narrow-band red #c03030:
iaru-region1.json |
Current | IARU R1 chart (eff. 16 Oct 2020) |
|---|---|---|
:8 1.840–1.843 |
DIGI #c03030 |
2700 All modes (1) Digimodes |
:15 3.600–3.620 |
✅ corrected by #4635 | 2700 All modes (1) |
:24 7.050–7.060 |
DIGI #c03030 |
2700 All modes Digimodes, automatically controlled data stations (unattended) |
:34 14.101–14.112 |
DIGI #c03030 |
2700 All modes Digimodes, automatically controlled data stations (unattended) |
:40 18.111–18.120 |
DIGI #c03030 |
2700 All modes Digimodes, automatically controlled data stations (unattended) |
:53 24.931–24.940 |
DIGI #c03030 |
2700 All modes Digimodes, automatically controlled data stations (unattended) |
:62 29.200–29.300 |
DIGI #c03030 |
unrestricted All modes Digimodes, automatically controlled data stations (unattended) |
Six rows carry the exact defect #4610 described and remain unfixed. ssa-sweden.json mirrors all eight rows at identical frequencies (:8, :15, :24, :34, :40, :45, :53, :62).
Two rows need care rather than a blanket correction:
:4521.110–21.120 readsAll modes … Digimodes, automatically controlled data stations (unattended), (not SSB). This segment genuinely is restricted, just not the way we've painted it. PlainALLwould be wrong here.ssa-sweden.jsonis a national overlay. SSA's published plan (Bandplan Kortvåg v2.61) independently agrees that 3600–3620 isAlla moder, Digimoderand that 21110–21120 isAlla moder, utom SSB, so the corrections carry over. But that document is dated 2017-10-25 and predates the 2020 R1 plan, and the two disagree elsewhere in the same block (SSA has CW-exclusive to 3580; the 2020 chart starts narrow-band at 3570, which is what our file encodes). Only rows where both charts agree should be changed. I would not touch the 3.570 boundary on the strength of the older document.
iaru-region2.json and iaru-region3.json are governed by different charts and are out of scope here.
None of this is functional: BandPlanManager parses label into Segment::label and SpectrumWidget paints it. Nothing keys TX gating, mode selection, or contiguousRegionsForBand off the string. It is advisory display data — which is exactly why it needs to be right, because an operator reading the panadapter is the only consumer.
Proposal
Two parts. The first is a data fix; the second is the schema change that stops it recurring, and is the part needing approval.
Part 1 — correct the mislabelled rows
Change the six confirmed rows in iaru-region1.json (and their ssa-sweden.json mirrors) from DIGI / #c03030 to the all-modes label and #ff8000, matching what #4635 did for 3600–3620. Handle 21.110–21.120 separately once Part 2 lands, since its restriction is real.
Part 2 — usage field (the RFC)
Add an optional usage string to the band-plan segment schema, mirroring the chart's own two-column structure:
{"low": 3.600, "high": 3.620, "label": "ALL", "usage": "Digimodes, unattended data stations",
"license": "", "color": "#ff8000"},
label carries the preferred mode and is what gets painted. usage carries the annotation and surfaces on hover. Absent usage, behaviour is unchanged — the field is additive and every existing plan file stays valid.
This is the right shape because it is the chart's own shape, and because it explains structure in our data that currently looks redundant. iaru-region1.json:13-14 holds two adjacent segments both labelled CW with identical colour, which reads as a pointless division; the chart shows why the boundary exists — 3510–3560 is plain CW, 3560–3570 is CW contest preferred, with 3560 kHz the CW QRP centre of activity. The split encodes a usage distinction the schema cannot currently express. Six more adjacent-identical pairs exist across the plan files and I expect most have the same explanation.
The hover surface already exists. SpectrumWidget.cpp:10340-10356 already hit-tests the band-plan row on mouseMoveEvent and shows a QToolTip for band-plan spots, calling hideText() when no spot is within 5 px. Segment usage becomes a fall-through in that same block — no new interaction, no new widget, no change to what a click does.
Cross-platform impact
None differential. This is resource data plus a QToolTip call in shared GUI code.
- Linux: no change beyond the tooltip content.
- macOS: no change beyond the tooltip content.
- Windows: no change beyond the tooltip content.
The tooltip path at SpectrumWidget.cpp:10346 is already exercised on all three platforms for spots, so no new platform surface is introduced.
Alternatives considered
Merge the redundant rows — e.g. collapse 3.600–3.800 into one ALL entry. Rejected. It removes real chart boundaries and would, applied consistently, delete the CW QRP centre-of-activity distinction at 3560 kHz. It also cannot express (not SSB) at 21.110–21.120.
Encode usage in the label with the existing slash convention — ALL/DIGI, following SSB/DIGI, BCN/DIGI, CW/NB, ALL/FM. This is the cheapest fix and needs no schema change or approval. Rejected as the primary answer because it does not scale: the annotations are full phrases ("automatically controlled data stations (unattended)", "SSB contest preferred", "(not SSB)"), the painted label is width-constrained (SpectrumWidget.cpp:14821 skips labels under 20 px and appends the licence class only above 60 px), and cramming usage into label is what produced this defect in the first place. Worth noting it remains the fallback if the schema change is not wanted — it would fix the six rows today at the cost of leaving the underlying conflation in place.
Coalesce adjacent identical segments in the renderer — skip the separator at SpectrumWidget.cpp:14817 and the duplicate label draw when the previous segment matches. Rejected as a solution to this problem: it hides the symptom of missing usage data rather than supplying it. It may still be worth doing afterwards for genuinely redundant pairs, as a separate cosmetic change.
Implementation scope
Files affected
resources/bandplans/iaru-region1.json,resources/bandplans/ssa-sweden.json— data corrections plususagevaluessrc/models/BandPlanManager.h—QString usageonSegmentsrc/models/BandPlanManager.cpp:148— parse the optional key alongsidelabelsrc/gui/SpectrumWidget.cpp:10340-10356— segment fall-through in the existing band-row tooltip blocktests/— a new test asserting the shipped resource, which is the gap that let this survive
New dependencies: none.
Known risks
- Low. The field is additive and optional; plans without it behave exactly as today.
- The remaining four plan files (
iaru-region2,iaru-region3,arrl-us,rac-canada) would carry nousageinitially. That is acceptable — they degrade to current behaviour — but it does mean hover is informative on some plans and silent on others until they are transcribed against their own charts. - Verifying R2/R3/ARRL/RAC against their governing charts is deliberately not in this scope. Each needs its own reference document and its own issue.
Test gap worth naming. tests/band_plan_license_filter_test.cpp builds synthetic segments via setSegmentsForTest and never loads a resource file, so no test in the suite would have caught any of these rows — including the one #4610 reported. A resource-asserting test is the durable fix and should land with Part 1.
How this was verified
Reproducible without hardware:
curl -sL -o r1.pdf https://www.iaru-r1.org/wp-content/uploads/2021/06/hf_r1_bandplan.pdf
pdftotext -raw r1.pdf - | grep -E "^(1840|7050|7053|18111|21110|24931|29200) "
grep -n '#c03030' resources/bandplans/iaru-region1.json
-raw rather than -layout: the chart's column alignment shears under layout mode in the 14 MHz and 21 MHz blocks, which will mislead a careless read of 14101–14112 in particular.
73,
Ryan NF0T
👨🏼💻 Co-authored by Claude Opus 5
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.