fix(position-estimation): large uncertainty for weight-dominated single-anchor solves (#3616)#3617
Conversation
…le-anchor solves (#3616) The SNR weight model (10^(snr/10)) is correct — higher SNR yields higher weight, pulling the estimate toward that anchor — so the "inverted weighting" hypothesis does not hold. The real bug was in the uncertainty calculation. When one strong anchor dominates the SNR weights and the other anchor is weak and far (e.g. +10 dB vs -12 dB, ~4 km apart), the weighted centroid collapses onto the strong anchor and the far/weak anchor contributes almost nothing to the weighted RMS. The Kish effective sample size (nEff) lands just above 1 (~1.01), so the old `nEff <= 1` branch was skipped and the estimate reported a spuriously tight sub-km radius — a confident, wrong "inside the reporter's house" estimate. Fix: blend the radio-range default toward the statistical radius using nEff. At nEff = 1 (a lone or weight-dominated anchor) uncertainty is the full 5 km radio-range default; it reaches the pure statistical estimate only at nEff >= 2 (a balanced multi-anchor solve). The issue's case now reports ~4.94 km (unreliable) instead of ~0.31 km. Balanced multi-anchor estimates are unchanged. Closes #3616 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR Review —
|
Add a deep-dive page documenting how MeshMonitor computes a node's position-estimate accuracy circle (uncertaintyKm), for publication on meshmonitor.org: - the observation weight model: time-decay (24h half-life) × SNR linear power (10^(SNR/10)), with an SNR→weight reference table - the SNR/time weighted centroid (the estimated position) - the accuracy radius: weighted RMS spread, Kish effective sample size, and the n_eff confidence blend toward the radio-range default (the #3616/#3617 refinement that prevents falsely-confident single-anchor circles) - ASCII pipeline/geometry/blend diagrams and three worked examples (single anchor, strong+weak/far dominated, balanced multi-anchor) - a formula reference and guidance on reading the circle / tuning the max-acceptable-accuracy cutoff Links it from the existing Position Estimation page and adds it to the Maps & Visualization sidebar. Docs build verified (no dead links). Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Issue #3616 hypothesized that the SNR weighting in position estimation was inverted, collapsing weak-signal nodes onto the anchor. After reading
positionEstimationService.tsend-to-end, the weighting is correct — the real bug is in the uncertainty calculation.Root cause (investigation)
The weight model is
10^(snrDb/10)(observationWeight, lines 77-84):-12 dB → 0.063,0 dB → 1,+10 dB → 10. Higher SNR → higher weight → pulled toward that anchor. Not inverted.The actual bug:
solveNodePositioncomputed uncertainty asWith skewed weights (one strong anchor + one far weak -12 dB anchor, the exact symptom), the weighted centroid collapses onto the strong anchor, the far/weak anchor barely contributes to the weighted RMS, and the Kish effective sample size
nEfflands just above 1 (~1.01). That skips the 5 km single-anchor branch and thermsKm/sqrt(nEff)formula reports a spuriously tight sub-km radius — a confident, wrong "inside the reporter's house" estimate.So this is the uncertainty-calc bug (hypothesis b/c), not inverted weighting (hypothesis a).
Fix
Blend the radio-range default toward the statistical radius using
nEff:nEff = 1(lone or weight-dominated anchor) → full 5 km radio-range default.nEff >= 2(balanced multi-anchor) → pure statistical estimate (unchanged).confidence = clamp(nEff - 1, 0, 1)).The weight model is left as-is (it is physically correct). No sign was flipped.
Before / after — issue's case (strong +10 dB anchor + weak −12 dB anchor ~4 km apart) | | latitude | nEff | uncertaintyKm |
|---|---|---|---|
| Before | 10.0002 (at anchor) | 1.013 | 0.31 km (falsely confident) |
| After | 10.0002 (at anchor) | 1.013 | 4.94 km (correctly unreliable) |
The estimate still collapses onto the dominant anchor (the max-likelihood point for an effectively-single observation), but now carries a large uncertainty radius flagging it as unreliable.
A truly lone −12 dB anchor still reports exactly 5 km. Balanced tight 4-anchor clusters stay confident (<1 km), unchanged.
Tests
Added to
positionEstimationService.test.ts:weight(-12) < weight(0) < weight(+10)with independently-computed values (0.063 / 1 / 10).uncertaintyKm === 5.uncertaintyKm > 4(not a sub-km confident circle).uncertaintyKm < 1(no regression to confident estimates).Verification
tsc -p tsconfig.server.json --noEmit: no new errors (the only errors are 5 pre-existing unrelated ones inTelemetryChart.tsx).Closes #3616
🤖 Generated with Claude Code