package alerts // The band plan behind InferMode, and why it is written out segment by segment. // // A cluster line carries no mode, so it has to be inferred — and OpsLog was // inferring it TWICE, in two places, from two different tables. The frontend // knew that 10.130-10.150 is the 30 m data segment; this side only knew a CW // range that stopped at 10.130 and called everything after it SSB. So a spot at // 10131.5 showed as DATA in the cluster list and raised an alert saying SSB. // Reported with a screenshot of exactly that, on RI1FJL. // // The two tables are now the same table, transcribed from the frontend's // (frontend/src/lib/spot.ts) with its segment boundaries kept intact. They stay // two files because they are two languages, and the test next door is what // keeps them one answer. // modeSeg is one stretch of a band, in Hz, and what is worked there. type modeSeg struct { loHz, hiHz int64 mode string } // bandPlan is scanned IN ORDER, so a narrow watering hole listed before the // wide segment it sits inside wins — FT8 at 14.074 before the 14.070-14.100 // data block. Order is the whole mechanism here; sorting this table by // frequency would quietly turn every FT8 hole into "DATA". var bandPlan = []modeSeg{ {1_800_000, 1_838_000, "CW"}, {1_838_000, 1_840_000, "FT8"}, {1_840_000, 2_000_000, "SSB"}, {3_573_000, 3_576_000, "FT8"}, {3_500_000, 3_580_000, "CW"}, {3_580_000, 3_600_000, "DATA"}, {3_600_000, 4_000_000, "SSB"}, {5_300_000, 5_500_000, "SSB"}, {7_074_000, 7_077_000, "FT8"}, {7_047_500, 7_048_500, "FT4"}, {7_000_000, 7_040_000, "CW"}, {7_040_000, 7_100_000, "DATA"}, {7_100_000, 7_300_000, "SSB"}, // 30 m: CW to 10.130, data above it — and nothing else. No SSB on this band. {10_100_000, 10_130_000, "CW"}, {10_130_000, 10_150_000, "DATA"}, {14_074_000, 14_077_000, "FT8"}, {14_080_000, 14_081_500, "FT4"}, {14_000_000, 14_070_000, "CW"}, {14_070_000, 14_100_000, "DATA"}, {14_100_000, 14_350_000, "SSB"}, {18_100_000, 18_103_000, "FT8"}, {18_068_000, 18_095_000, "CW"}, {18_095_000, 18_110_000, "DATA"}, {18_110_000, 18_168_000, "SSB"}, {21_074_000, 21_077_000, "FT8"}, {21_140_000, 21_143_000, "FT4"}, {21_000_000, 21_070_000, "CW"}, {21_070_000, 21_150_000, "DATA"}, {21_150_000, 21_450_000, "SSB"}, {24_915_000, 24_917_000, "FT8"}, {24_890_000, 24_915_000, "CW"}, {24_915_000, 24_940_000, "DATA"}, {24_940_000, 24_990_000, "SSB"}, {28_074_000, 28_077_000, "FT8"}, {28_180_000, 28_183_000, "FT4"}, {28_000_000, 28_070_000, "CW"}, {28_070_000, 28_300_000, "DATA"}, {28_300_000, 29_700_000, "SSB"}, {50_313_000, 50_316_000, "FT8"}, {50_318_000, 50_321_000, "FT4"}, {50_000_000, 50_100_000, "CW"}, {50_100_000, 50_500_000, "SSB"}, {144_174_000, 144_177_000, "FT8"}, {144_000_000, 144_150_000, "CW"}, {144_150_000, 144_500_000, "SSB"}, } // modeFromFrequency returns what the band plan says is worked at freqHz, or "" // where it says nothing. // // Empty rather than a guess: a spot outside every listed segment is on a band // this table does not cover, and answering "SSB" for it is how a 30 m data spot // came to raise an SSB alert. func modeFromFrequency(freqHz int64) string { for _, s := range bandPlan { if freqHz >= s.loHz && freqHz < s.hiHz { return s.mode } } return "" }