package main import ( "testing" "hamlog/internal/sat" ) // The dial arithmetic has to be the exact inverse of the correction, or every // touch of the knob would nudge the nominal frequency a little further off and // the uplink would walk across the passband over a pass. func TestSatNominalFromDialRoundTrip(t *testing.T) { // A range of range rates: hard approach, drifting, hard recession. ±8 km/s // covers a low orbit overhead. for _, rate := range []float64{-8, -3.2, -0.4, 0, 0.4, 3.2, 8} { p := sat.Position{RangeRate: rate} for _, nominal := range []int64{29_450_000, 145_900_000, 435_850_000, 10_489_675_000} { sh := sat.Doppler(p, nominal, 0) factor := -rate / satLightKmS got := satNominalFromDial(sh.DownHz, factor) if diff := got - nominal; diff > 1 || diff < -1 { t.Errorf("rate %.1f km/s, %d Hz: heard %d, came back as %d (%+d)", rate, nominal, sh.DownHz, got, diff) } } } } // SAT_MODE is what goes on a QSL card, and the letters are the uplink's then // the downlink's — the order operators write and the order ADIF wants. func TestSatModeLetters(t *testing.T) { for _, tc := range []struct { name string up, down int64 want string }{ {"FO-29: 2 m up, 70 cm down", 145_950_000, 435_850_000, "V/U"}, {"AO-91: 70 cm up, 2 m down", 435_250_000, 145_960_000, "U/V"}, {"AO-7 mode A: 2 m up, 10 m down", 145_900_000, 29_450_000, "V/A"}, {"QO-100: 13 cm up, 3 cm down", 2_400_175_000, 10_489_675_000, "S/X"}, {"receive only", 0, 145_800_000, ""}, } { if got := satModeLetters(tc.up, tc.down); got != tc.want { t.Errorf("%s: got %q, wanted %q", tc.name, got, tc.want) } } }