diff --git a/docs/algo-reports/2026-08-01-full-recalibration.md b/docs/algo-reports/2026-08-01-full-recalibration.md new file mode 100644 index 00000000..885a0f54 --- /dev/null +++ b/docs/algo-reports/2026-08-01-full-recalibration.md @@ -0,0 +1,65 @@ +# Full Recalibration Report — 2026-08-01 + +> Auto-generated by `scripts/recalibrate.py`. The companion JSON file at `priv/algo/band_weights.json` is the machine-readable output that Elixir loads at runtime. This report is the human-readable audit trail. + +Connection: `postgres://prop:***@10.0.19.30:6432/prop` +Generated: `2026-08-01T21:30:41+00:00` + +## Data sources + +- **PSKR** (VHF/UHF, label = `spot_count`): bands [50, 144, 432, 1296, 2304, 3400, 10000], 1,726,757 samples +- **Contacts ↔ HRRR** (microwave, label = `distance_km`): 12 bands, 74,072 matched contacts + +## Per-band evidence + +| Band | Source | n | label avg | ρ_tc | ρ_dpc | ρ_pr | ρ_pwat | ρ_grad | +|------|--------|---:|----------:|-----:|------:|-----:|-------:|-------:| +| 50 MHz | pskr | 1,633,976 | 2.24 | +0.113 | +0.102 | +0.044 | +0.114 | -0.033 | +| 144 MHz | pskr | 87,724 | 3.07 | +0.057 | +0.101 | +0.140 | +0.117 | +0.004 | +| 222 MHz | contacts | 7,517 | 229.17 | -0.082 | +0.078 | -0.012 | +0.069 | +0.041 | +| 432 MHz | pskr | 4,152 | 1.62 | +0.094 | -0.205 | +0.123 | -0.188 | +0.207 | +| 902 MHz | contacts | 1,753 | 172.23 | -0.070 | +0.094 | +0.077 | +0.047 | -0.041 | +| 1296 MHz | contacts | 2,951 | 160.98 | -0.035 | +0.100 | +0.023 | +0.052 | -0.072 | +| 2304 MHz | contacts | 718 | 154.72 | -0.053 | +0.169 | +0.082 | +0.128 | -0.094 | +| 3400 MHz | contacts | 334 | 154.14 | -0.052 | +0.149 | -0.025 | +0.145 | +0.076 | +| 5760 MHz | contacts | 320 | 127.92 | -0.058 | +0.071 | +0.151 | +0.097 | -0.020 | +| 10000 MHz | contacts | 47,260 | 208.25 | -0.001 | -0.024 | -0.089 | -0.029 | +0.030 | +| 24000 MHz | contacts | 3,330 | 95.36 | -0.215 | -0.333 | -0.204 | -0.366 | +0.005 | +| 47000 MHz | contacts | 661 | 62.80 | -0.121 | -0.187 | -0.246 | -0.220 | -0.027 | +| 75000 MHz | contacts | 93 | 49.90 | -0.688 | -0.696 | -0.774 | -0.636 | +0.495 | +| 122000 MHz | contacts | 63 | 16.26 | +0.038 | -0.130 | -0.042 | -0.128 | +0.356 | + +## Derived per-band weights + +| Band | n | source | humidity | time_of_day | td_depression | refractivity | sky | season | wind | rain | pwat | pressure | +|------|---:|--------|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:| +| 50 MHz | 1,633,976 | pskr | 0.2039 | 0.0184 | 0.1632 | 0.0823 | 0.0679 | 0.1466 | 0.0679 | 0.0116 | 0.1853 | 0.0528 | +| 144 MHz | 87,724 | pskr | 0.2020 | 0.0213 | 0.1617 | 0.0527 | 0.0673 | 0.1271 | 0.0673 | 0.0115 | 0.1836 | 0.1055 | +| 222 MHz | 7,517 | contacts | 0.1947 | 0.0273 | 0.1815 | 0.1000 | 0.0756 | 0.1325 | 0.0756 | 0.0129 | 0.1565 | 0.0434 | +| 432 MHz | 4,152 | pskr | 0.1869 | 0.0225 | 0.1496 | 0.1460 | 0.0623 | 0.1008 | 0.0623 | 0.0106 | 0.1699 | 0.0892 | +| 902 MHz | 1,753 | contacts | 0.2167 | 0.0302 | 0.1787 | 0.0988 | 0.0744 | 0.1103 | 0.0744 | 0.0127 | 0.1256 | 0.0782 | +| 1296 MHz | 2,951 | contacts | 0.2289 | 0.0345 | 0.1510 | 0.1361 | 0.0763 | 0.1029 | 0.0763 | 0.0130 | 0.1350 | 0.0462 | +| 2304 MHz | 718 | contacts | 0.1916 | 0.0289 | 0.1530 | 0.1344 | 0.0639 | 0.0861 | 0.0639 | 0.0344 | 0.1742 | 0.0698 | +| 3400 MHz | 334 | contacts | 0.1983 | 0.0298 | 0.1574 | 0.1217 | 0.0661 | 0.0891 | 0.0661 | 0.0503 | 0.1802 | 0.0411 | +| 5760 MHz | 320 | contacts | 0.1621 | 0.0299 | 0.1591 | 0.0676 | 0.0662 | 0.0893 | 0.0662 | 0.0797 | 0.1696 | 0.1101 | +| 10000 MHz | 47,260 | contacts | 0.1262 | 0.0380 | 0.1010 | 0.0986 | 0.0841 | 0.1134 | 0.0841 | 0.1431 | 0.1147 | 0.0967 | +| 24000 MHz | 3,330 | contacts | 0.1514 | 0.0410 | 0.1211 | 0.0402 | 0.0504 | 0.0748 | 0.0504 | 0.2270 | 0.1376 | 0.1061 | +| 47000 MHz | 661 | contacts | 0.1402 | 0.0528 | 0.1122 | 0.0522 | 0.0467 | 0.0756 | 0.0467 | 0.2385 | 0.1275 | 0.1075 | + +## Changes vs prior `band_weights.json` + +Largest weight moves (≥0.5 pp), sorted by magnitude: + +| Band | Factor | Prior | New | Δ | +|------|--------|------:|----:|--:| +| 47000 MHz | refractivity | 0.0688 | 0.0522 | -0.0166 | +| 3400 MHz | refractivity | 0.1090 | 0.1217 | +0.0127 | +| 2304 MHz | refractivity | 0.1439 | 0.1344 | -0.0095 | +| 5760 MHz | refractivity | 0.0764 | 0.0676 | -0.0088 | +| 24000 MHz | refractivity | 0.0453 | 0.0402 | -0.0051 | + +## Applying these weights + +These weights are **live scoring inputs, not documentation**. `BandConfig.weights/1` consults `BandWeights.lookup/1` (which reads this JSON) *before* falling back to the in-source `:weights` override or the global `@weights` default. This script still never edits `band_config.ex` — it only rewrites the JSON. + +`BandWeights` caches the parsed file in `:persistent_term` on first read, so a running node keeps serving the *previous* weights until it restarts. To put this run into effect, deploy (the file ships under `priv/`) or call `BandWeights.reset/0` on every node. diff --git a/priv/algo/band_weights.json b/priv/algo/band_weights.json index d00d85ad..b50904d1 100644 --- a/priv/algo/band_weights.json +++ b/priv/algo/band_weights.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-05-25T19:44:49+00:00", + "generated_at": "2026-08-01T21:30:41+00:00", "generated_by": "scripts/recalibrate.py", "schema_version": 1, "global_weights": { @@ -22,9 +22,10 @@ 432, 1296, 2304, + 3400, 10000 ], - "total_samples": 411619 + "total_samples": 1726757 }, "contacts": { "bands": [ @@ -41,152 +42,152 @@ 75000, 122000 ], - "total_samples": 81571 + "total_samples": 74072 } }, "band_overrides": { "50": { "weights": { - "humidity": 0.1252, - "time_of_day": 0.0273, - "td_depression": 0.1511, - "refractivity": 0.0764, - "sky": 0.1006, - "season": 0.2171, - "wind": 0.1006, - "rain": 0.0171, - "pwat": 0.1197, - "pressure": 0.0649 + "humidity": 0.2039, + "time_of_day": 0.0184, + "td_depression": 0.1632, + "refractivity": 0.0823, + "sky": 0.0679, + "season": 0.1466, + "wind": 0.0679, + "rain": 0.0116, + "pwat": 0.1853, + "pressure": 0.0528 }, - "n_samples": 396474, + "n_samples": 1633976, "source": "pskr" }, "144": { "weights": { - "humidity": 0.1865, - "time_of_day": 0.0197, - "td_depression": 0.1492, - "refractivity": 0.1106, - "sky": 0.0621, - "season": 0.1173, - "wind": 0.0621, - "rain": 0.0106, - "pwat": 0.1695, - "pressure": 0.1125 + "humidity": 0.202, + "time_of_day": 0.0213, + "td_depression": 0.1617, + "refractivity": 0.0527, + "sky": 0.0673, + "season": 0.1271, + "wind": 0.0673, + "rain": 0.0115, + "pwat": 0.1836, + "pressure": 0.1055 }, - "n_samples": 13710, + "n_samples": 87724, "source": "pskr" }, "222": { "weights": { - "humidity": 0.2002, - "time_of_day": 0.0271, - "td_depression": 0.1804, - "refractivity": 0.101, - "sky": 0.0751, - "season": 0.1316, - "wind": 0.0751, - "rain": 0.0128, - "pwat": 0.1535, - "pressure": 0.0432 + "humidity": 0.1947, + "time_of_day": 0.0273, + "td_depression": 0.1815, + "refractivity": 0.1, + "sky": 0.0756, + "season": 0.1325, + "wind": 0.0756, + "rain": 0.0129, + "pwat": 0.1565, + "pressure": 0.0434 }, - "n_samples": 7518, + "n_samples": 7517, "source": "contacts" }, "432": { "weights": { - "humidity": 0.153, - "time_of_day": 0.0256, - "td_depression": 0.17, - "refractivity": 0.1659, - "sky": 0.0708, - "season": 0.1145, - "wind": 0.0708, - "rain": 0.012, - "pwat": 0.1376, - "pressure": 0.0799 + "humidity": 0.1869, + "time_of_day": 0.0225, + "td_depression": 0.1496, + "refractivity": 0.146, + "sky": 0.0623, + "season": 0.1008, + "wind": 0.0623, + "rain": 0.0106, + "pwat": 0.1699, + "pressure": 0.0892 }, - "n_samples": 1013, + "n_samples": 4152, "source": "pskr" }, "902": { "weights": { - "humidity": 0.2204, - "time_of_day": 0.0299, - "td_depression": 0.1764, - "refractivity": 0.0967, - "sky": 0.0734, - "season": 0.1089, - "wind": 0.0734, - "rain": 0.0125, - "pwat": 0.1273, - "pressure": 0.081 + "humidity": 0.2167, + "time_of_day": 0.0302, + "td_depression": 0.1787, + "refractivity": 0.0988, + "sky": 0.0744, + "season": 0.1103, + "wind": 0.0744, + "rain": 0.0127, + "pwat": 0.1256, + "pressure": 0.0782 }, - "n_samples": 1754, + "n_samples": 1753, "source": "contacts" }, "1296": { "weights": { - "humidity": 0.2259, - "time_of_day": 0.034, - "td_depression": 0.1528, - "refractivity": 0.1429, - "sky": 0.0753, - "season": 0.1015, - "wind": 0.0753, - "rain": 0.0128, - "pwat": 0.1327, - "pressure": 0.0468 + "humidity": 0.2289, + "time_of_day": 0.0345, + "td_depression": 0.151, + "refractivity": 0.1361, + "sky": 0.0763, + "season": 0.1029, + "wind": 0.0763, + "rain": 0.013, + "pwat": 0.135, + "pressure": 0.0462 }, "n_samples": 2951, "source": "contacts" }, "2304": { "weights": { - "humidity": 0.1886, - "time_of_day": 0.0284, - "td_depression": 0.1503, - "refractivity": 0.1474, - "sky": 0.0629, - "season": 0.0848, - "wind": 0.0629, - "rain": 0.0338, - "pwat": 0.1714, - "pressure": 0.0695 + "humidity": 0.1916, + "time_of_day": 0.0289, + "td_depression": 0.153, + "refractivity": 0.1344, + "sky": 0.0639, + "season": 0.0861, + "wind": 0.0639, + "rain": 0.0344, + "pwat": 0.1742, + "pressure": 0.0698 }, - "n_samples": 719, + "n_samples": 718, "source": "contacts" }, "3400": { "weights": { - "humidity": 0.2001, - "time_of_day": 0.0301, - "td_depression": 0.1601, - "refractivity": 0.1102, - "sky": 0.0667, - "season": 0.0899, - "wind": 0.0667, - "rain": 0.0507, - "pwat": 0.1818, - "pressure": 0.0437 + "humidity": 0.1983, + "time_of_day": 0.0298, + "td_depression": 0.1574, + "refractivity": 0.1217, + "sky": 0.0661, + "season": 0.0891, + "wind": 0.0661, + "rain": 0.0503, + "pwat": 0.1802, + "pressure": 0.0411 }, - "n_samples": 335, + "n_samples": 334, "source": "contacts" }, "5760": { "weights": { - "humidity": 0.1753, + "humidity": 0.1621, "time_of_day": 0.0299, - "td_depression": 0.1589, - "refractivity": 0.0491, - "sky": 0.0661, - "season": 0.0892, - "wind": 0.0661, - "rain": 0.0796, - "pwat": 0.1708, - "pressure": 0.1151 + "td_depression": 0.1591, + "refractivity": 0.0676, + "sky": 0.0662, + "season": 0.0893, + "wind": 0.0662, + "rain": 0.0797, + "pwat": 0.1696, + "pressure": 0.1101 }, - "n_samples": 321, + "n_samples": 320, "source": "contacts" }, "10000": { @@ -202,39 +203,39 @@ "pwat": 0.1147, "pressure": 0.0967 }, - "n_samples": 54161, + "n_samples": 47260, "source": "contacts" }, "24000": { "weights": { - "humidity": 0.1483, - "time_of_day": 0.0402, - "td_depression": 0.1187, - "refractivity": 0.0517, - "sky": 0.0494, - "season": 0.0733, - "wind": 0.0494, - "rain": 0.2224, - "pwat": 0.1348, - "pressure": 0.112 + "humidity": 0.1514, + "time_of_day": 0.041, + "td_depression": 0.1211, + "refractivity": 0.0402, + "sky": 0.0504, + "season": 0.0748, + "wind": 0.0504, + "rain": 0.227, + "pwat": 0.1376, + "pressure": 0.1061 }, - "n_samples": 3808, + "n_samples": 3330, "source": "contacts" }, "47000": { "weights": { - "humidity": 0.1403, + "humidity": 0.1402, "time_of_day": 0.0528, - "td_depression": 0.1123, - "refractivity": 0.0517, - "sky": 0.0468, - "season": 0.0757, - "wind": 0.0468, - "rain": 0.2387, + "td_depression": 0.1122, + "refractivity": 0.0522, + "sky": 0.0467, + "season": 0.0756, + "wind": 0.0467, + "rain": 0.2385, "pwat": 0.1275, "pressure": 0.1075 }, - "n_samples": 759, + "n_samples": 661, "source": "contacts" } }