prop/docs/algo-reports/2026-08-01-full-recalibration.md
Graham McIntire 0a3976bc79
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m44s
algo: recalibrate per-band weights from prod corpus (2026-08-01)
First full recalibration since 2026-05-24. Corpus is 1,726,757 PSKR
samples (50/144/432 MHz) plus 74,072 contacts joined to hrrr_profiles
(microwave), yielding overrides for 12 bands.

The 6m fit moved most, and coherently: humidity 0.125 -> 0.204 and pwat
0.120 -> 0.185, paid for by season 0.217 -> 0.147. 6m contributes 1.63M
of the 1.73M PSKR samples, so ten weeks of new spot density pulled the
band off a seasonal prior and onto direct moisture signal. Next largest
is 144 MHz refractivity 0.111 -> 0.053.

75 GHz (n=93) and 122 GHz (n=63) appear in the evidence table but get
no overrides -- they fall under MIN_N_FOR_FIT, which is correct; 75 GHz
reports rho_pr of -0.774 on 93 samples, which is noise, not physics.

Caveat: the refractivity multipliers are numerically unstable. They are
computed as |band_rho_grad| / |ref_rho_grad| against the 10 GHz
reference, whose rho_grad is +0.030 -- an order of magnitude smaller
than the other reference correlations. Two runs minutes apart moved
47 GHz refractivity 0.0688 -> 0.0522 (-24% relative) purely on new rows
landing between queries. The stable factors barely moved. These weights
are live once deployed, so this commit is isolated from the script fixes
to keep it independently revertable.
2026-08-01 16:35:11 -05:00

4.6 KiB
Raw Blame History

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.