fix(pskr): drop spots with <6-char grids on either end

A 4-char locator covers ~70 km × 100 km, which dwarfs HRRR's 3 km
native cell and any midpoint we'd derive for the calibration corpus.
Storing those samples gives the recalibrator geometry that's
indistinguishable from noise.

fetch_grid/2 now returns {:error, {:short_grid, key, grid}} for any
locator under 6 chars after Maidenhead validation. The spot is
dropped before it reaches the aggregator, so neither pskr_spots_hourly
nor pskr_calibration_samples ever see it.
This commit is contained in:
Graham McIntire 2026-05-05 09:29:25 -05:00
parent b08fc5e449
commit 1a3dc4fa0a
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
2 changed files with 25 additions and 11 deletions

View file

@ -152,16 +152,26 @@ defmodule Microwaveprop.Pskr do
}
end
# Keep locators at the precision the spotter reported. Maidenhead
# validity already enforces minimum 4 chars + even length + the
# right alphabet at each position, so anything that passes is a
# legal 4/6/8/10-char locator we can store as-is. Uppercase for
# consistent indexing — the unique key is case-sensitive.
# Require ≥ 6-char locators on both ends. 4-char grids cover
# ~70 km × 100 km, so the midpoint and path distance error
# dwarfs any HRRR cell match (3 km native) and the resulting
# calibration sample geometry is meaningless. Drop the spot
# entirely rather than store a low-precision row.
#
# Maidenhead validity enforces even length + correct alphabet
# per position, so a passing string is a legal 6/8/10-char
# locator we can store as-is. Uppercase for consistent indexing
# — the unique key is case-sensitive.
defp fetch_grid(json, key) do
case Map.get(json, key) do
grid when is_binary(grid) ->
upper = String.upcase(grid)
if Maidenhead.valid?(upper), do: {:ok, upper}, else: {:error, {:bad_grid, key, grid}}
cond do
not Maidenhead.valid?(upper) -> {:error, {:bad_grid, key, grid}}
String.length(upper) < 6 -> {:error, {:short_grid, key, grid}}
true -> {:ok, upper}
end
other ->
{:error, {:missing_grid, key, other}}

View file

@ -36,12 +36,16 @@ defmodule Microwaveprop.PskrTest do
assert DateTime.to_unix(spot.transmit_time) == 1_662_407_697
end
test "accepts 4-char grids verbatim" do
json = @sample |> Map.merge(%{"sl" => "EM12", "rl" => "DM43"}) |> Jason.encode!()
test "rejects 4-char grids on either end (insufficient precision)" do
# A 4-char locator is ~70 km × 100 km — the midpoint and
# distance error swamps any HRRR cell match (3 km native).
# Drop the spot rather than store a calibration sample whose
# geometry is meaningless.
sender_short = @sample |> Map.put("sl", "EM12") |> Jason.encode!()
receiver_short = @sample |> Map.put("rl", "DM43") |> Jason.encode!()
assert {:ok, spot} = Pskr.parse_spot(json)
assert spot.sender_grid == "EM12"
assert spot.receiver_grid == "DM43"
assert {:error, _} = Pskr.parse_spot(sender_short)
assert {:error, _} = Pskr.parse_spot(receiver_short)
end
test "preserves extended-square (8-char) precision" do