|
<title>Aether — Feasibility & Reality Check</title>
|
|
<style>
|
|
:root{
|
|
--bg:#EEF2F3; --surface:#FFFFFF; --surface-2:#F6F9FA;
|
|
--ink:#10181C; --ink-muted:#54646B; --border:#D4DFE2;
|
|
--accent:#0B7C88; --accent-ink:#FFFFFF; --accent-soft:#E2F0F1;
|
|
--hard:#B23A2E; --hard-soft:#F6E4E1; --soft:#1F7A5B; --soft-soft:#E0F0E9;
|
|
--caution:#9C6F1C; --caution-soft:#F3E9D3;
|
|
--shadow:0 1px 2px rgba(16,24,28,.05),0 8px 28px rgba(16,24,28,.06);
|
|
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,Roboto,Helvetica,Arial,sans-serif;
|
|
--mono:ui-monospace,"SF Mono","Cascadia Code","JetBrains Mono",Menlo,Consolas,monospace;
|
|
--maxw:74ch;
|
|
}
|
|
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
|
|
--bg:#0C1215; --surface:#121D21; --surface-2:#172329;
|
|
--ink:#E7EEF0; --ink-muted:#94A3A9; --border:#26363C;
|
|
--accent:#33C2CE; --accent-ink:#04191C; --accent-soft:#102A2F;
|
|
--hard:#E86B5D; --hard-soft:#2E1A18; --soft:#4FC79E; --soft-soft:#122720;
|
|
--caution:#E0B15A; --caution-soft:#2A2214;
|
|
--shadow:0 1px 2px rgba(0,0,0,.3),0 10px 30px rgba(0,0,0,.35);
|
|
}}
|
|
:root[data-theme="dark"]{
|
|
--bg:#0C1215; --surface:#121D21; --surface-2:#172329;
|
|
--ink:#E7EEF0; --ink-muted:#94A3A9; --border:#26363C;
|
|
--accent:#33C2CE; --accent-ink:#04191C; --accent-soft:#102A2F;
|
|
--hard:#E86B5D; --hard-soft:#2E1A18; --soft:#4FC79E; --soft-soft:#122720;
|
|
--caution:#E0B15A; --caution-soft:#2A2214;
|
|
--shadow:0 1px 2px rgba(0,0,0,.3),0 10px 30px rgba(0,0,0,.35);
|
|
}
|
|
*{box-sizing:border-box}
|
|
html{-webkit-text-size-adjust:100%}
|
|
body{
|
|
margin:0; background:var(--bg); color:var(--ink);
|
|
font-family:var(--sans); font-size:1.0625rem; line-height:1.62;
|
|
font-feature-settings:"kern"; -webkit-font-smoothing:antialiased;
|
|
}
|
|
.wrap{max-width:920px; margin:0 auto; padding:clamp(20px,4vw,56px) clamp(18px,4vw,40px) 120px}
|
|
.col{max-width:var(--maxw)}
|
|
a{color:var(--accent); text-underline-offset:2px}
|
|
h1,h2,h3{text-wrap:balance; line-height:1.12; letter-spacing:-.01em}
|
|
.eyebrow{font-family:var(--mono); font-size:.72rem; letter-spacing:.16em; text-transform:uppercase; color:var(--accent); font-weight:600}
|
|
/* Masthead */
|
|
header{border-bottom:1px solid var(--border); padding-bottom:34px; margin-bottom:36px}
|
|
h1{font-size:clamp(2rem,4.6vw,3.05rem); font-weight:800; margin:.5rem 0 .5rem}
|
|
.thesis{font-size:clamp(1.12rem,2.2vw,1.4rem); line-height:1.4; color:var(--ink); font-weight:450; max-width:60ch; margin:0}
|
|
.thesis b{font-weight:700}
|
|
.meta{display:flex; flex-wrap:wrap; gap:8px 18px; margin-top:22px; font-family:var(--mono); font-size:.74rem; color:var(--ink-muted); letter-spacing:.02em}
|
|
.meta span{white-space:nowrap}
|
|
.meta b{color:var(--ink); font-weight:600}
|
|
/* Hero figure */
|
|
.figure{margin-top:30px; background:var(--surface); border:1px solid var(--border); border-radius:12px; padding:20px 22px 14px; box-shadow:var(--shadow)}
|
|
.figure .cap{font-family:var(--mono); font-size:.72rem; text-transform:uppercase; letter-spacing:.12em; color:var(--ink-muted); margin:0 0 4px}
|
|
.figure .sub{font-size:.92rem; color:var(--ink-muted); margin:.4rem 0 0}
|
|
.chartscroll{overflow-x:auto}
|
|
svg.chart{display:block; width:100%; min-width:420px; height:auto}
|
|
.bar-n{fill:var(--ink-muted); font-family:var(--mono); font-weight:700; font-size:15px}
|
|
.bar-v{fill:var(--ink); font-family:var(--mono); font-weight:700; font-size:15px}
|
|
.axis{fill:var(--ink-muted); font-family:var(--mono); font-size:12px}
|
|
/* Verdict banner */
|
|
.verdict{margin:34px 0; border:1px solid var(--border); border-left:4px solid var(--accent); background:var(--surface); border-radius:10px; padding:20px 22px; box-shadow:var(--shadow)}
|
|
.verdict .eyebrow{color:var(--accent)}
|
|
.verdict p{margin:.5rem 0 0; font-size:1.06rem; line-height:1.5}
|
|
/* Sections */
|
|
section{margin-top:52px}
|
|
h2{font-size:clamp(1.25rem,2.4vw,1.6rem); font-weight:750; margin:0 0 .3rem; display:flex; align-items:baseline; gap:.7rem}
|
|
h2 .num{font-family:var(--mono); font-size:.8em; color:var(--accent); font-weight:600}
|
|
.lede{color:var(--ink-muted); max-width:var(--maxw); margin:.2rem 0 1.3rem}
|
|
p{max-width:var(--maxw)} li{max-width:calc(var(--maxw) - 1.4rem)}
|
|
strong{font-weight:650}
|
|
code,.k{font-family:var(--mono); font-size:.9em; background:var(--surface-2); border:1px solid var(--border); border-radius:5px; padding:.06em .38em}
|
|
/* Invariants */
|
|
.facts{list-style:none; padding:0; margin:0; display:grid; gap:14px}
|
|
.facts li{display:grid; grid-template-columns:auto 1fr; gap:16px; align-items:start; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:16px 18px; max-width:none}
|
|
.facts .idx{font-family:var(--mono); font-weight:700; color:var(--accent); font-size:1.1rem; line-height:1.4}
|
|
.facts p{margin:0}
|
|
/* Q&A */
|
|
.qa{display:grid; gap:16px}
|
|
.qa .item{background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:16px 18px}
|
|
.q{font-weight:650; margin:0 0 .5rem; max-width:none}
|
|
.a{margin:0; color:var(--ink); max-width:none}
|
|
.tag{display:inline-block; font-family:var(--mono); font-size:.68rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; padding:.2em .5em; border-radius:5px; vertical-align:.08em; margin-right:.55em; white-space:nowrap}
|
|
.tag.no{background:var(--hard-soft); color:var(--hard)}
|
|
.tag.yes{background:var(--hard-soft); color:var(--hard)}
|
|
.tag.part{background:var(--caution-soft); color:var(--caution)}
|
|
.tag.ok{background:var(--soft-soft); color:var(--soft)}
|
|
/* Table */
|
|
.tablescroll{overflow-x:auto; border:1px solid var(--border); border-radius:10px; box-shadow:var(--shadow)}
|
|
table{border-collapse:collapse; width:100%; min-width:640px; background:var(--surface); font-size:.95rem}
|
|
th,td{text-align:left; padding:12px 14px; border-bottom:1px solid var(--border); vertical-align:top}
|
|
thead th{font-family:var(--mono); font-size:.7rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-muted); font-weight:600; background:var(--surface-2)}
|
|
tbody tr:last-child td{border-bottom:0}
|
|
td.id{font-family:var(--mono); font-weight:700; color:var(--ink-muted)}
|
|
.chip{display:inline-block; font-family:var(--mono); font-size:.66rem; font-weight:700; letter-spacing:.05em; padding:.18em .5em; border-radius:5px}
|
|
.chip.hard{background:var(--hard-soft); color:var(--hard)}
|
|
.chip.soft{background:var(--soft-soft); color:var(--soft)}
|
|
.chip.mix{background:var(--caution-soft); color:var(--caution)}
|
|
/* Ranked path */
|
|
ol.path{list-style:none; counter-reset:p; padding:0; margin:0; display:grid; gap:12px}
|
|
ol.path li{counter-increment:p; display:grid; grid-template-columns:auto 1fr; gap:16px; align-items:start; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:15px 18px; max-width:none}
|
|
ol.path li::before{content:counter(p,decimal-leading-zero); font-family:var(--mono); font-weight:700; color:var(--accent-ink); background:var(--accent); width:2rem; height:2rem; border-radius:7px; display:grid; place-items:center; font-size:.85rem}
|
|
ol.path li:first-child::before{box-shadow:0 0 0 4px var(--accent-soft)}
|
|
ol.path p{margin:0; max-width:none}
|
|
ol.path .lever{font-weight:650}
|
|
/* Tiers */
|
|
.tiers{display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:16px}
|
|
.tier{background:var(--surface); border:1px solid var(--border); border-top:3px solid var(--tc); border-radius:10px; padding:18px; box-shadow:var(--shadow)}
|
|
.tier.a{--tc:var(--soft)} .tier.b{--tc:var(--accent)} .tier.c{--tc:var(--caution)}
|
|
.tier h3{margin:.1rem 0 .5rem; font-size:1.05rem}
|
|
.tier .badge{font-family:var(--mono); font-size:.68rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--tc)}
|
|
.tier p{font-size:.92rem; color:var(--ink); margin:.3rem 0 0; max-width:none}
|
|
/* Constraints pills */
|
|
.constraints{display:grid; gap:12px; margin:6px 0 4px}
|
|
.cgroup{display:flex; flex-wrap:wrap; align-items:center; gap:8px}
|
|
.clabel{font-family:var(--mono); font-size:.66rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; padding:.24em .55em; border-radius:5px}
|
|
.clabel.bind{background:var(--hard-soft); color:var(--hard)}
|
|
.clabel.relax{background:var(--soft-soft); color:var(--soft)}
|
|
.pill{font-family:var(--mono); font-size:.76rem; padding:.28em .62em; border:1px solid var(--border); border-radius:999px; background:var(--surface); color:var(--ink)}
|
|
.pill.off{color:var(--ink-muted); text-decoration:line-through; opacity:.72}
|
|
/* CoA ladder list */
|
|
ul.coa{list-style:none; padding:0; margin:0; display:grid; gap:12px}
|
|
ul.coa li{display:grid; grid-template-columns:auto 1fr; gap:14px; align-items:start; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:14px 16px; max-width:none}
|
|
ul.coa p{margin:0; max-width:none}
|
|
ul.coa em{font-style:normal; font-family:var(--mono); font-size:.7rem; text-transform:uppercase; letter-spacing:.04em; color:var(--ink-muted); margin:0 .15em 0 .2em}
|
|
.cb{font-family:var(--mono); font-size:.72rem; font-weight:700; letter-spacing:.04em; padding:.32em .5em; border-radius:6px; white-space:nowrap; align-self:start}
|
|
.cb.soft{background:var(--soft-soft); color:var(--soft)}
|
|
.cb.accent{background:var(--accent-soft); color:var(--accent)}
|
|
.cb.caution{background:var(--caution-soft); color:var(--caution)}
|
|
/* Layer stack */
|
|
.stack{display:grid; gap:8px; margin:16px 0}
|
|
.layer{display:grid; grid-template-columns:6.5rem 1fr; gap:14px; align-items:center; border:1px solid var(--border); border-left:4px solid var(--lc); border-radius:9px; padding:11px 16px; background:var(--surface)}
|
|
.layer .lname{font-family:var(--mono); font-weight:700; font-size:.76rem; letter-spacing:.04em; color:var(--lc)}
|
|
.layer .lrole{color:var(--ink); font-size:.92rem}
|
|
.layer.uwb{--lc:var(--accent)} .layer.aco{--lc:var(--soft)} .layer.imu{--lc:var(--ink-muted)} .layer.opt{--lc:var(--caution)}
|
|
/* Bottom line */
|
|
.bottomline{margin-top:52px; background:var(--ink); color:var(--bg); border-radius:14px; padding:clamp(22px,4vw,34px)}
|
|
:root[data-theme="dark"] .bottomline,
|
|
:root:not([data-theme="light"]) .bottomline{background:var(--surface-2); color:var(--ink); border:1px solid var(--border)}
|
|
@media (prefers-color-scheme:light){:root:not([data-theme="dark"]) .bottomline{background:#0F1A1E; color:#EAF1F2}}
|
|
.bottomline .eyebrow{color:var(--accent)}
|
|
.bottomline p{max-width:64ch; margin:.6rem 0 0; font-size:1.08rem; line-height:1.55}
|
|
.bottomline b{color:var(--accent)}
|
|
/* Sources */
|
|
.sources{margin-top:48px; border-top:1px solid var(--border); padding-top:20px}
|
|
.sources ul{list-style:none; padding:0; margin:0; display:grid; gap:8px; font-size:.86rem}
|
|
.sources li{max-width:none}
|
|
.sources .lbl{font-family:var(--mono); font-weight:700; color:var(--ink-muted); margin-right:.5em}
|
|
.foot{margin-top:26px; font-family:var(--mono); font-size:.72rem; color:var(--ink-muted); letter-spacing:.02em}
|
|
@media (max-width:560px){
|
|
.facts li,ol.path li,ul.coa li{grid-template-columns:1fr; gap:6px}
|
|
.meta{gap:6px 14px}
|
|
}
|
|
</style>
|
|
|
|
<div class="wrap">
|
|
<header>
|
|
<div class="col">
|
|
<p class="eyebrow">Aether · UWB + IMU positioning mesh · reality check</p>
|
|
<h1>Can 4 phones survey themselves indoors?</h1>
|
|
<p class="thesis">An honest, physics-first read on the ask. Short version: the field trouble is not a code
|
|
defect — it is the predictable signature of an <b>over-stacked target</b>, and the decisive lever is
|
|
<b>provisioning, not more software</b>.</p>
|
|
<div class="meta">
|
|
<span><b>Scope</b> feasibility & mission</span>
|
|
<span><b>Basis</b> code · roadmap · 2 field captures · UWB-RTLS literature</span>
|
|
<span><b>Verdict</b> re-scope + provision</span>
|
|
</div>
|
|
</div>
|
|
|
|
<figure class="figure">
|
|
<p class="cap">The thesis, as one number</p>
|
|
<div class="chartscroll">
|
|
<svg class="chart" viewBox="0 0 640 250" role="img" aria-label="Spare inter-anchor constraints versus anchor count: zero at four anchors, one at five, then three, six and ten at eight.">
|
|
<line x1="60" y1="200" x2="620" y2="200" style="stroke:var(--border);stroke-width:1.5"/>
|
|
<text class="axis" x="618" y="224" text-anchor="end">anchors →</text>
|
|
<text class="axis" x="18" y="112" text-anchor="middle" transform="rotate(-90 18 112)">spare constraints</text>
|
|
<!-- n=4 : v=0 (the wall) -->
|
|
<rect x="92" y="196" width="72" height="4" style="fill:var(--hard)"/>
|
|
<text class="bar-v" x="128" y="188" text-anchor="middle" style="fill:var(--hard)">0</text>
|
|
<text class="bar-n" x="128" y="220" text-anchor="middle" style="fill:var(--hard)">4</text>
|
|
<text class="axis" x="128" y="240" text-anchor="middle" style="fill:var(--hard)">undetectable</text>
|
|
<!-- n=5 : v=1 -->
|
|
<rect x="196" y="185" width="72" height="15" rx="2" style="fill:var(--accent)"/>
|
|
<text class="bar-v" x="232" y="176" text-anchor="middle">1</text>
|
|
<text class="bar-n" x="232" y="220" text-anchor="middle">5</text>
|
|
<text class="axis" x="232" y="240" text-anchor="middle" style="fill:var(--accent)">detectable</text>
|
|
<!-- n=6 : v=3 -->
|
|
<rect x="300" y="155" width="72" height="45" rx="2" style="fill:var(--accent)"/>
|
|
<text class="bar-v" x="336" y="146" text-anchor="middle">3</text>
|
|
<text class="bar-n" x="336" y="220" text-anchor="middle">6</text>
|
|
<!-- n=7 : v=6 -->
|
|
<rect x="404" y="110" width="72" height="90" rx="2" style="fill:var(--accent)"/>
|
|
<text class="bar-v" x="440" y="101" text-anchor="middle">6</text>
|
|
<text class="bar-n" x="440" y="220" text-anchor="middle">7</text>
|
|
<!-- n=8 : v=10 -->
|
|
<rect x="508" y="50" width="72" height="150" rx="2" style="fill:var(--accent)"/>
|
|
<text class="bar-v" x="544" y="41" text-anchor="middle">10</text>
|
|
<text class="bar-n" x="544" y="220" text-anchor="middle">8</text>
|
|
</svg>
|
|
</div>
|
|
<p class="sub">Spare inter-anchor constraints = <span class="k">C(n,2) − (3n−6)</span>. At <b>4 anchors it is
|
|
exactly 0</b> — a biased or body-blocked link is mathematically undetectable. Every reliability property
|
|
the project wants begins at <b>5</b>.</p>
|
|
</figure>
|
|
</header>
|
|
|
|
<div class="verdict col">
|
|
<p class="eyebrow">Bottom line, up front</p>
|
|
<p>A cooperative, self-solving indoor UWB+IMU mesh is <strong>sound and buildable</strong>. The <em>reliable</em>
|
|
version is a <strong>static mesh of ≥5–6 geometrically- and vertically-diverse anchors</strong>, with NLOS
|
|
mitigation, solved-and-locked over time, a ranging schedule for clients, interior coverage, and
|
|
<strong>decimetre</strong> expectations. What the physics does <em>not</em> support is the maximalist reading of
|
|
today's ask — <strong>survey-free · sub-centimetre · phone-only · 4-anchor · widely-spaced · indoor · exterior
|
|
clients · live human traffic — all at once.</strong></p>
|
|
</div>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">01</span> The system as it stands</h2>
|
|
<p class="lede">What we are actually judging, from the code, the roadmap, capture4, and the layout video.</p>
|
|
<p><strong>4 anchors</strong>, one the root — physically 3 on tripods at ~1.2–1.45 m plus one low in a red cup at
|
|
~0.89 m, in a <strong>~2.3 m × 3.7 m</strong> footprint inside a small furnished living room.
|
|
<strong>Phone-class UWB</strong> (Galaxy-class anchors; Pixel observer), not dedicated RTLS hardware.
|
|
<strong>Survey-free</strong>: the frame is solved purely from inter-anchor ranges — for 4 anchors that is
|
|
<span class="k">6 ranges = 6 DOF</span>, an <strong>exactly-rigid graph with zero redundancy</strong>. In the
|
|
field, A3's cross-room links read <strong>+0.57 / +0.75 m long</strong> (a stable NLOS bias where the links
|
|
physically cross furniture), devices disagreed on the shape, the mesh didn't reliably lock, and one link went
|
|
dark. Production intent adds <strong>wider spacing</strong> and <strong>several clients wandering interior and
|
|
exterior</strong> through <strong>human line-of-sight blockage</strong>.</p>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">02</span> The physics that decides it</h2>
|
|
<p class="lede">Four UWB-positioning invariants — not Aether-specific, each externally sourced — govern every
|
|
answer below.</p>
|
|
<ul class="facts">
|
|
<li><span class="idx">i</span><p><strong>UWB is LoS-accurate, NLOS-biased.</strong> ~10 cm in clear line of
|
|
sight; a <strong>human body pushes it to ~0.5 m</strong>, positive-biased. Capture4's +0.57/+0.75 m is a
|
|
textbook NLOS bias, not a bug — and NLOS is the dominant indoor error source.</p></li>
|
|
<li><span class="idx">ii</span><p><strong>Range budget is finite; phones sit at the bottom of it.</strong>
|
|
Dedicated modules reach 50–100 m; phone-class HRP UWB is “several tens of metres, ~Bluetooth range,” and far
|
|
less through walls or bodies. Android AoA is coarse or absent.</p></li>
|
|
<li><span class="idx">iii</span><p><strong>Position error = ranging error × GDOP.</strong> Multilateration is
|
|
well-conditioned <strong>inside the convex hull</strong> of the anchors and blows up <strong>outside it</strong>;
|
|
it needs angular diversity and enclosed volume. A near-coplanar set is weak vertically and carries a mirror
|
|
ambiguity.</p></li>
|
|
<li><span class="idx">iv</span><p><strong>Redundancy buys reliability.</strong> The inter-anchor graph has spare
|
|
constraints only at <strong>N ≥ 5</strong>; at 4, a biased or blocked edge is undetectable. RTLS guidance:
|
|
4 is the floor, <strong>5–6 preferred</strong>, 8+ diminishing.</p></li>
|
|
</ul>
|
|
<p style="margin-top:14px">A fifth fact governs scale, not accuracy: <strong>two-way ranging scales poorly with
|
|
many tags</strong> unless coordinated by a <strong>TDMA schedule</strong> (or moved to TDoA).</p>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">03</span> Straight answers</h2>
|
|
<p class="lede">The questions as asked, answered without hedging.</p>
|
|
<div class="qa">
|
|
<div class="item"><p class="q">Can a 4-anchor phone mesh solve reliably <em>and</em> withstand clients + humans crossing LoS?</p>
|
|
<p class="a"><span class="tag no">No — not reliably</span>It can be solved in a clean moment and <em>held</em> (worth doing), but with zero redundancy any single blocked/biased link has nothing to out-vote it, and indoors a body may be sitting on one at any instant. There is no built-in error detection by construction.</p></div>
|
|
<div class="item"><p class="q">Can software solve it — developed, COTS, or a mix?</p>
|
|
<p class="a"><span class="tag part">Mitigate, not overcome</span>On a zero-redundancy graph, <em>no</em> estimator — robust least-squares, RANSAC, a neural NLOS classifier, factor graphs, anything COTS — can detect a lone biased edge; the residual is identically zero. That is an information limit. Software wins only <em>with</em> the right geometry, or by using time (average a static mesh) or extra sensors (IMU/observer).</p></div>
|
|
<div class="item"><p class="q">Is success guaranteed by adding hardware (more anchors)?</p>
|
|
<p class="a"><span class="tag ok">Highest-leverage lever</span>Near-sufficient — with caveats. 4→5 flips redundancy 0→1 (a biased edge becomes detectable); 6–8 gives graceful degradation and LoS diversity against blockage. But added anchors must bring <strong>geometric + height diversity</strong>, and many radios need a schedule. Boxes placed badly don't help.</p></div>
|
|
<div class="item"><p class="q">Is it the shape of the constellation?</p>
|
|
<p class="a"><span class="tag part">Secondarily</span>The set is near-coplanar (weak vertical + mirror ambiguity) and its small hull dooms exterior clients to runaway GDOP. But shape is downstream of the deeper issues — redundancy = 0 and uncorrected NLOS. Fix those and the shape problem largely dissolves.</p></div>
|
|
<div class="item"><p class="q">Could they be spaced <em>further</em> apart and still range/solve?</p>
|
|
<p class="a"><span class="tag no">Inverted indoors</span>Farther links mean lower SNR <em>and</em> more obstructions per link — indoors with phones, wider spacing makes reliability worse, not better. Wide spacing is an open-LoS / better-antenna property. Denser, well-placed anchors win.</p></div>
|
|
<div class="item"><p class="q">Is the indoor setting the cause?</p>
|
|
<p class="a"><span class="tag yes">Primarily, yes</span>Multipath, NLOS, and human-body blockage are the dominant error sources; the same 4 phones outdoors in clear LoS would solve far more reliably. “Indoor” is the difficulty multiplier; “4 anchors” and “no survey” remove the margin that would absorb it.</p></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="col"><h2><span class="num">04</span> Fundamental limits — hard vs soft</h2>
|
|
<p class="lede"><span class="chip hard">HARD</span> a physics/geometry/information wall no code crosses on this
|
|
hardware. <span class="chip soft">SOFT</span> addressable in software or protocol. The two problems the project
|
|
spent most on — agreement and accuracy — both sit on top of L1, which is hard.</p></div>
|
|
<div class="tablescroll">
|
|
<table>
|
|
<thead><tr><th>#</th><th>Limitation</th><th>Kind</th><th>Caps</th><th>Lever</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="id">L1</td><td><strong>4 anchors = 0 redundancy</strong> — a biased/blocked edge is undetectable</td><td><span class="chip hard">HARD</span></td><td>reliability of the anchor solve</td><td>≥5–6 anchors</td></tr>
|
|
<tr><td class="id">L2</td><td><strong>Near-coplanar</strong> — weak vertical, mirror ambiguity</td><td><span class="chip hard">HARD</span></td><td>vertical accuracy, lock stability</td><td>≥3 distinct heights</td></tr>
|
|
<tr><td class="id">L3</td><td><strong>Exterior clients</strong> outside the anchor hull</td><td><span class="chip hard">HARD</span></td><td>exterior accuracy</td><td>anchors <em>around</em> coverage</td></tr>
|
|
<tr><td class="id">L4</td><td><strong>Indoor NLOS / human blockage</strong> — time-varying bias & dropouts</td><td><span class="chip mix">SOFT·ish</span></td><td>instantaneous accuracy</td><td>NLOS reject · average+lock · redundancy</td></tr>
|
|
<tr><td class="id">L5</td><td><strong>Phone-class radios</strong> — short range, coarse AoA, thin CIR, session caps</td><td><span class="chip mix">HARD·ish</span></td><td>range, AoA, client capacity</td><td>dedicated anchors; phones as clients</td></tr>
|
|
<tr><td class="id">L6</td><td><strong>Many clients over TWR</strong> — channel capacity</td><td><span class="chip soft">SOFT</span></td><td>simultaneous clients / rate</td><td>TDMA schedule or TDoA</td></tr>
|
|
<tr><td class="id">L7</td><td><strong>Survey-free</strong> — no external scale reference</td><td><span class="chip mix">CHOICE</span></td><td>immunity to a wrong-scale edge</td><td>one known baseline, or redundancy</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">05</span> What actually moves the needle</h2>
|
|
<p class="lede">Ranked by leverage. The numbering is the priority order — do them roughly in sequence.</p>
|
|
<ol class="path">
|
|
<li><p><span class="lever">Provision ≥5–6 anchors with geometric + height diversity.</span> The biggest lever. Five flips redundancy to 1; six gives graceful degradation and LoS diversity. Place them convex around the coverage area at ≥3 heights — and this <em>activates the #63/#69 software that is inert on 4</em>.</p></li>
|
|
<li><p><span class="lever">Turn NLOS mitigation from stub to real (#62 → classifier).</span> Capture first-path/RSSI (started) and reject or down-weight blocked links — the standard technique. Accept that phone radios cap how good it gets.</p></li>
|
|
<li><p><span class="lever">Solve-once-and-lock the static mesh; average over time.</span> Anchors don't move: solve in a clean window, lock, re-solve only on a persistent change. Turns transient human blockage from a solve-killer into a non-event.</p></li>
|
|
<li><p><span class="lever">Add a ranging schedule (TDMA) — or move clients to TDoA.</span> Uncoordinated TWR hits a capacity wall for several clients (and is a prime suspect for the dark link). This is how COTS RTLS reaches many tags.</p></li>
|
|
<li><p><span class="lever">Keep the over-determination software (#63/#69).</span> No change — it earns its keep once step 1 lands.</p></li>
|
|
<li><p><span class="lever">Set exterior-client expectations honestly.</span> Outside the hull, multilateration can't be accurate. Ring the exterior with its own anchors, or declare it “presence, not precision.”</p></li>
|
|
<li><p><span class="lever">Consider a hardware-tier split.</span> Dedicated UWB anchors for fixed infrastructure (real antennas, CIR, range); phones as clients only — what every serious indoor RTLS does.</p></li>
|
|
</ol>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">06</span> Re-scope the acceptance criteria into tiers</h2>
|
|
<p class="lede">Today's criteria conflate asks that conflict: wide spacing vs indoor NLOS; exterior clients vs a
|
|
clustered hull; survey-free sub-cm vs a biased edge; phone-only vs range + NLOS rejection. Split the definition
|
|
of done.</p>
|
|
<div class="tiers">
|
|
<div class="tier a"><span class="badge">Tier A · now</span><h3>Locked interior mesh</h3><p>Static 4–6-anchor mesh, interior clients, solved-and-locked, <strong>decimetre</strong>, NLOS-mitigated, low client count. Essentially the convergence gate with a realistic tolerance and a 5th anchor. A real, demonstrable product.</p></div>
|
|
<div class="tier b"><span class="badge">Tier B · provision</span><h3>Multi-client + resilient</h3><p>Several clients, blockage-resilient, via 6–8 anchors + a ranging schedule. Needs the provisioning and scheduling levers (steps 1 & 4).</p></div>
|
|
<div class="tier c"><span class="badge">Tier C · renegotiate</span><h3>The maximalist ask</h3><p>Survey-free sub-cm <em>and</em> exterior clients <em>and</em> phone-only <em>and</em> wide spacing. Pick one or two to relax — all four together isn't supported by the physics on this hardware.</p></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">07</span> Revised constraints — courses of action, updated</h2>
|
|
<p class="lede">A later framing fixes four constraints and relaxes the rest. Freeing <strong>anchor count</strong>
|
|
and <strong>survey</strong> dissolves the hard limits above (L1/L2/L3/L7) and <em>activates</em> the #63/#69
|
|
over-determination code that was inert on 4 anchors — the geometry problem becomes a provisioning problem, and
|
|
provisioning is now allowed.</p>
|
|
<div class="constraints">
|
|
<div class="cgroup"><span class="clabel bind">Binding</span>
|
|
<span class="pill">human traffic</span><span class="pill">rapid clients</span>
|
|
<span class="pill">low-latency cm</span><span class="pill">commercial devices only</span></div>
|
|
<div class="cgroup"><span class="clabel relax">Relaxed</span>
|
|
<span class="pill off">anchor count</span><span class="pill off">survey</span>
|
|
<span class="pill off">spacing</span><span class="pill off">exterior</span></div>
|
|
</div>
|
|
<div class="verdict" style="border-left-color:var(--hard); margin-top:22px">
|
|
<p class="eyebrow" style="color:var(--hard)">The new binding tension</p>
|
|
<p><strong>Centimetre + rapid motion + consumer-only</strong> collide. Consumer per-range ≈ 8–12 cm; a dense
|
|
surveyed field lands position at <strong>≈5–10 cm</strong> — single-digit cm, <em>not</em> sub-cm. A moving tag
|
|
can't average ranges down; <strong>true ≤1 cm needs carrier-phase, which phone APIs don't expose</strong>; and
|
|
consumer clocks can't sync to the sub-ns TDoA needs (1 ns ≈ 30 cm), so ranging stays two-way. Human traffic is
|
|
now beaten by <strong>anchor density</strong> + NLOS rejection + IMU coasting.</p>
|
|
</div>
|
|
<div class="tiers" style="margin-top:22px">
|
|
<div class="tier a"><span class="badge">CoA A · recommended</span><h3>Dense surveyed lattice + TWR + IMU</h3>
|
|
<p>8–16 surveyed, height-diverse consumer anchors (≥6–8 in LoS everywhere) · robust redundant multilateration (#63/#69, now active) · NLOS rejection (#62) · ES-EKF IMU fusion (predict 100–200 Hz → low latency + smooth fast motion) · TDMA scheduling. <strong>≈5–10 cm, low-latency, traffic-robust</strong> — built on the existing stack.</p></div>
|
|
<div class="tier b"><span class="badge">CoA B · bonus</span><h3>Client AoA / PDoA refinement</h3>
|
|
<p>Where a client exposes direction (iPhone U1/U2; some Samsung), fuse the angle for a tighter fix. Real but coarse and device-specific — a refinement on A, not a foundation.</p></div>
|
|
<div class="tier c"><span class="badge">CoA C · the fork</span><h3>Relax one constraint for true ≤1 cm</h3>
|
|
<p>Sub-cm on fast movers isn't reachable consumer-only. Relax exactly one: <strong>(i)</strong> a dedicated commercial UWB anchor tier (CIR + carrier-phase + sync → TDoA RTLS; phones stay clients), or <strong>(ii)</strong> cm → few-cm and take A's ≈5–10 cm. A product decision.</p></div>
|
|
</div>
|
|
<p style="margin-top:18px"><strong>Recommendation.</strong> Build <strong>CoA A</strong> now (consumer-only optimum,
|
|
mostly wiring the existing engine), <strong>instrument the achieved σ</strong>, and let that number drive the CoA C
|
|
decision — the walk-capture in progress measures exactly it. Net-new engine work: a <span class="k">TDMA ranging
|
|
scheduler</span>, <span class="k">dense-anchor auto-survey / calibration</span>, an <span class="k">IMU-forward
|
|
low-latency output</span>, and <span class="k">live NLOS rejection</span> (mandatory at cm budget).</p>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">08</span> Relaxing sub-cm — the triggers survive</h2>
|
|
<p class="lede">Sub-cm is relaxed to CoA-A's ≈5–10 cm on one condition: the geometric-predicate triggers stay
|
|
accurate and low-latency. They do — because of one reframe.</p>
|
|
<div class="verdict" style="margin-top:6px">
|
|
<p class="eyebrow">The reframe</p>
|
|
<p><strong>Predicate reliability ≠ position accuracy.</strong> Evaluate a predicate against the position <em>and
|
|
its covariance</em> (the EKF already emits per-axis σ), and coarser position costs <strong>granularity — the
|
|
smallest resolvable zone / object / gap, not reliability.</strong> Margins are spatial, so <strong>latency is
|
|
untouched</strong> — crossings can even fire predictively off the fused velocity. The only real cost: at σ ≈
|
|
5–10 cm, features closer than ~0.5 m can't be cleanly separated.</p>
|
|
</div>
|
|
<ul class="facts" style="margin-top:18px">
|
|
<li><span class="idx">▢</span><p><strong>Enter / leave a zone.</strong> Two-threshold <strong>hysteresis</strong> (enter when confidently inside by ~2–3σ; leave when confidently outside) + a <strong>covariance gate</strong>. No boundary chatter; correct within a defined band.</p></li>
|
|
<li><span class="idx">→</span><p><strong>Point at an object.</strong> Angular, and <strong>dominated by orientation error, not position</strong> (10 cm at 3 m ≈ 1.9°) — so relaxing position sub-cm barely touches it; the real lever is the heading reference (#64). A <strong>σ-driven pointing cone</strong>, evaluated in the shared frame so common-mode error cancels.</p></li>
|
|
<li><span class="idx">⌇</span><p><strong>Cross a lane / plane.</strong> <strong>Velocity-gated</strong> crossing (a genuine directional transit from the IMU-fused velocity) + directional hysteresis. Separates a real crossing from jitter in one–two fixes — reliable <em>and</em> low-latency, even predictive.</p></li>
|
|
</ul>
|
|
<div class="verdict" style="border-left-color:var(--soft); margin-top:18px">
|
|
<p class="eyebrow" style="color:var(--soft)">Forward-compatible by design</p>
|
|
<p>Make every margin <strong>σ-driven</strong> and reintroducing sub-cm is <strong>automatic</strong>: feed
|
|
lower-variance measurements (better radios, a dedicated-anchor tier, or carrier-phase) → the covariance drops →
|
|
every predicate margin <strong>shrinks on its own</strong> and the triggers sharpen, with no predicate change.
|
|
So better tech is a <strong>recalibration</strong> (anchor positions + delays) at most; a new modality
|
|
(carrier-phase / TDoA) enters as <strong>one added EKF factor</strong>; the predicate logic never moves.
|
|
<strong>Design mandate: never hardcode a spatial tolerance — derive it from the live covariance.</strong> The
|
|
accuracy tier becomes a dial, not a rebuild.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">09</span> Below the floor — huddle-scale predicates (<1 m)</h2>
|
|
<p class="lede">Real predicates put entities <1 m apart (a huddle is ~0.3–0.5 m) — below §08's ~0.5 m
|
|
granularity floor, so it needs better than 5–10 cm. Does more hardware get there?</p>
|
|
<div class="verdict" style="border-left-color:var(--hard); margin-top:6px">
|
|
<p class="eyebrow" style="color:var(--hard)">More anchors ≠ sub-cm</p>
|
|
<p>Range error is <strong>random</strong> (averages ~1/√(N·M)) ⊕ <strong>systematic</strong> (antenna delay,
|
|
multipath, NLOS bias, timestamp quantization — persistent, not zero-mean). ToF resolution is set by
|
|
<strong>bandwidth</strong> (UWB 0.5–1 GHz → ~15–30 cm raw, few-cm refined), not anchor count. So anchors
|
|
asymptote at the <strong>systematic floor (~2–5 cm)</strong> and never reach sub-cm — and in a huddle the
|
|
<strong>bodies NLOS the anchor links</strong>, degrading it further. Crossing the floor needs a different
|
|
<em>measurement modality</em>, not more boxes.</p>
|
|
</div>
|
|
<p style="margin-top:18px"><strong>The unlock — relative, not absolute.</strong> The huddle is a
|
|
<em>tell-them-apart</em> question, and relative accuracy is cheaper: <strong>direct peer-to-peer ranging</strong>
|
|
measures a separation with no anchors, and <strong>common-mode anchor error cancels</strong> between co-located
|
|
devices. Match need to rung:</p>
|
|
<div class="tablescroll" style="margin-top:12px">
|
|
<table>
|
|
<thead><tr><th>Resolve</th><th>Needs error</th><th>Reachable by</th></tr></thead>
|
|
<tbody>
|
|
<tr><td>~1.0 m</td><td>~0.50 m</td><td>CoA A (5–10 cm) — already fine</td></tr>
|
|
<tr><td>~0.5 m loose huddle</td><td>~0.25 m</td><td>CoA A + dense anchors</td></tr>
|
|
<tr><td>~0.3 m huddle</td><td>~0.15 m</td><td><strong>CoA D</strong> — P2P relative ~5–10 cm</td></tr>
|
|
<tr><td>~0.1 m</td><td>~0.05 m</td><td><strong>CoA E / G</strong> — carrier-phase / optical</td></tr>
|
|
<tr><td>~0.02 m sub-cm</td><td>~0.01 m</td><td><strong>CoA E / F</strong> — carrier-phase, RTLS</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul class="coa" style="margin-top:18px">
|
|
<li><span class="cb soft">CoA D</span><p><strong>Peer-to-peer relative ranging + joint solver.</strong>
|
|
<em>Achieves</em> relative ~5–10 cm (resolves 0.3–0.5 m huddles; identities never confused). <em>Needs</em>
|
|
client↔client ranging + a P2P scheduler + a joint factor-graph solver. <em>Trade-off</em> air-time/capacity;
|
|
still ToF-limited (not sub-cm); solver cost grows with cluster size. <strong>Consumer-safe.</strong></p></li>
|
|
<li><span class="cb accent">CoA E</span><p><strong>Carrier-phase / PDoA ranging.</strong> <em>Achieves</em>
|
|
mm–cm → true sub-cm; the only path below ~2 cm. <em>Needs</em> phase/CIR-exposing radios (dedicated modules,
|
|
not phones) + integer-ambiguity resolution + CIR multipath exclusion. <em>Trade-off</em> new hardware tier;
|
|
multipath-fragile (huddle bodies can break phase lock → falls back to cm); highest complexity.</p></li>
|
|
<li><span class="cb caution">CoA F</span><p><strong>Synced dedicated-anchor TDoA + phase (industrial RTLS).</strong>
|
|
<em>Achieves</em> sub-cm–mm. <em>Needs</em> wired/RF-synced dedicated anchors + pro survey; dedicated tags for
|
|
sub-cm. <em>Trade-off</em> cost, cabling, fixed + not portable, not consumer — opposite of the vision.</p></li>
|
|
<li><span class="cb accent">CoA G</span><p><strong>Multi-modal fusion (UWB + optical / acoustic).</strong>
|
|
<em>Achieves</em> relative cm at short range (camera photogrammetry, or phone acoustic chirp) fused with UWB.
|
|
<em>Needs</em> a fusion layer + camera/mic. <em>Trade-off</em> light/quiet/LoS dependence, privacy, new
|
|
failure modes.</p></li>
|
|
<li><span class="cb soft">CoA H</span><p><strong>Predicate redesign to identity + relative.</strong>
|
|
<em>Achieves</em> the intent of many huddle predicates for free — UWB identity (never confuses people) +
|
|
direct P2P range/bearing + §08's uncertainty logic. <em>Trade-off</em> no <10 cm discrimination; the rest
|
|
need E/F/G. <strong>Free.</strong></p></li>
|
|
</ul>
|
|
<div class="verdict" style="border-left-color:var(--soft); margin-top:18px">
|
|
<p class="eyebrow" style="color:var(--soft)">Layer them — accuracy becomes per-zone</p>
|
|
<p>Because the engine is σ-driven, these aren't rival tiers — each is a measurement factor you add. Default to
|
|
<strong>A + H + D</strong> (all consumer-safe; resolves the huddle, keeps identities); add <strong>E or G only in
|
|
the zones that truly need <5 cm</strong>; reserve <strong>F</strong> for guaranteed-mm fixed installs. You
|
|
never need one global tier — a huddle zone runs P2P + optical while the rest runs anchor-only, and every
|
|
predicate consumes whatever covariance its region delivers.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">10</span> Interlacing meshes for sub-cm — consumer-only</h2>
|
|
<p class="lede">Constraint restored to consumer devices only. Can layering multiple meshes over a shared band
|
|
reach sub-cm? Yes — but not by stacking UWB.</p>
|
|
<div class="verdict" style="border-left-color:var(--hard); margin-top:6px">
|
|
<p class="eyebrow" style="color:var(--hard)">Stacking UWB doesn't cross the floor</p>
|
|
<p>More UWB — spatial, frequency-diverse, or differential (RTK-style) — all shares the same
|
|
ToF/bandwidth/multipath floor, so it clusters at <strong>low-cm (~2–3 cm), never sub-cm on a mover.</strong>
|
|
Consumer APIs give a distance per channel, not raw phase, so you can average channels but not <em>coherently
|
|
synthesize bandwidth</em>; and UWB multipath decorrelates within ~one wavelength (~4 cm), so a differential
|
|
reference can't cancel the rover's local multipath. Same physics floor, N times.</p>
|
|
</div>
|
|
<p style="margin-top:18px"><strong>The crossing needs a different-physics layer — and one is pure consumer:
|
|
acoustic.</strong> Sound is ~10⁶× slower than RF, so the sub-ns timing that's brutal for UWB is trivial for sound:
|
|
a 48 kHz mic samples every ~7 mm, cross-correlated to <strong>cm — sub-cm at short range.</strong> Speaker + mic
|
|
are on every phone; ultrasonic (18–24 kHz) keeps it inaudible. Its weaknesses (short range, noise, bodies) are
|
|
exactly UWB's strengths — which is why you <em>layer</em> them.</p>
|
|
<div class="stack">
|
|
<div class="layer uwb"><span class="lname">UWB</span><span class="lrole">absolute frame · identity · coverage · cm range + peer-to-peer</span></div>
|
|
<div class="layer aco"><span class="lname">ACOUSTIC</span><span class="lrole">short-range cm–sub-cm <strong>relative</strong> in the huddle (ultrasonic chirp ToF)</span></div>
|
|
<div class="layer imu"><span class="lname">IMU</span><span class="lrole">dynamics · low latency · coasting through dropouts</span></div>
|
|
<div class="layer opt"><span class="lname">OPTICAL</span><span class="lrole">optional — camera photogrammetry, mm relative (light / LoS / privacy)</span></div>
|
|
</div>
|
|
<ul class="coa">
|
|
<li><span class="cb accent">CoA I</span><p><strong>Heterogeneous layered mesh over the shared band.</strong>
|
|
<em>Achieves</em> sub-cm <strong>relative</strong> in the huddle (acoustic) + cm absolute (UWB) + low-latency
|
|
(IMU), <strong>consumer-only</strong>. <em>Needs</em> an acoustic-ranging subsystem, shared-band time-sync +
|
|
a cross-mesh schedule (extend the netcode), mesh-to-mesh association (via UWB IDs), and a joint multi-modal
|
|
factor-graph solver. <em>Trade-off</em> acoustic is short-range + noise/NLOS/temperature-sensitive → a
|
|
huddle-zone layer, not global; sub-cm <em>relative</em>, not absolute (true absolute sub-cm still needs the
|
|
non-consumer E/F).</p></li>
|
|
</ul>
|
|
<div class="verdict" style="border-left-color:var(--accent); margin-top:18px">
|
|
<p class="eyebrow">Why it fits Aether</p>
|
|
<p>The shared band <strong>already exists</strong> — BroadcastBand + the Raft fabric is the cross-mesh sync +
|
|
measurement-exchange channel the question posits. The ES-EKF becomes a <strong>σ-weighted joint factor
|
|
graph</strong> ingesting heterogeneous edges (UWB range, P2P, acoustic, IMU, optical). Accuracy is then
|
|
<strong>per-edge and per-zone</strong>: a huddle lights its acoustic layer for sub-cm relative; open areas run
|
|
UWB-only. You beat the UWB floor not by stacking UWB, but by <strong>interlacing a slower-wave mesh over the
|
|
same band.</strong></p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="col">
|
|
<h2><span class="num">11</span> Reliable mesh solving — the dependable precursor to aiming</h2>
|
|
<p class="lede">Accept cm (not sub-cm) accuracy for now and make the mesh solve <em>reliably</em> first — because
|
|
accurate client aiming can't sit on a frame that isn't dependable. Can 4 anchors do it, at what cost, and what do
|
|
more anchors measurably buy?</p>
|
|
|
|
<div class="verdict" style="border-left-color:var(--caution); margin-top:6px">
|
|
<p class="eyebrow" style="color:var(--caution)">4 anchors: reliable only if you trade away four freedoms</p>
|
|
<p>With <strong>zero spare constraints</strong> (masthead), a 4-mesh can't detect its own bad edge — so to be
|
|
dependable it must <strong>surrender survey-free operation</strong> (pin the frame to the survey),
|
|
<strong>arbitrary placement</strong> (non-coplanar, clean LoS on all 6 edges), <strong>continuous re-solve</strong>
|
|
(solve-once-and-<b>lock</b>), and <strong>self-healing</strong> (manual re-commission if bumped). It reliably
|
|
solves a <em>static, surveyed, locked, lightly-trafficked</em> mesh — not a <em>survey-free, mobile, trafficked,
|
|
self-healing</em> one.</p>
|
|
</div>
|
|
|
|
<figure class="figure" style="margin-top:26px">
|
|
<p class="cap">What more anchors buy · (1) survives human traffic</p>
|
|
<div class="chartscroll">
|
|
<svg class="chart" viewBox="0 0 640 250" role="img" aria-label="Probability of at least four clean anchor line-of-sight paths versus anchor count, at 30 percent per-anchor blockage: 24 percent at four anchors, 53 at five, 74 at six, 87 at seven, 94 at eight.">
|
|
<line x1="60" y1="200" x2="620" y2="200" style="stroke:var(--border);stroke-width:1.5"/>
|
|
<line x1="60" y1="122" x2="620" y2="122" style="stroke:var(--ink-muted);stroke-width:1;stroke-dasharray:3 5;opacity:.5"/>
|
|
<text class="axis" x="64" y="118" text-anchor="start" style="opacity:.7">50% — coin-flip</text>
|
|
<text class="axis" x="618" y="224" text-anchor="end">anchors →</text>
|
|
<text class="axis" x="18" y="112" text-anchor="middle" transform="rotate(-90 18 112)">P(≥4 clean LoS)</text>
|
|
<!-- n=4 : 24% -->
|
|
<rect x="92" y="163" width="72" height="37" rx="2" style="fill:var(--hard)"/>
|
|
<text class="bar-v" x="128" y="154" text-anchor="middle" style="fill:var(--hard)">24%</text>
|
|
<text class="bar-n" x="128" y="220" text-anchor="middle" style="fill:var(--hard)">4</text>
|
|
<text class="axis" x="128" y="240" text-anchor="middle" style="fill:var(--hard)">drops ¾</text>
|
|
<!-- n=5 : 53% -->
|
|
<rect x="196" y="118" width="72" height="82" rx="2" style="fill:var(--caution)"/>
|
|
<text class="bar-v" x="232" y="109" text-anchor="middle" style="fill:var(--caution)">53%</text>
|
|
<text class="bar-n" x="232" y="220" text-anchor="middle" style="fill:var(--caution)">5</text>
|
|
<!-- n=6 : 74% (target) -->
|
|
<rect x="300" y="85" width="72" height="115" rx="2" style="fill:var(--soft)"/>
|
|
<text class="bar-v" x="336" y="76" text-anchor="middle" style="fill:var(--soft)">74%</text>
|
|
<text class="bar-n" x="336" y="220" text-anchor="middle" style="fill:var(--soft)">6</text>
|
|
<text class="axis" x="336" y="240" text-anchor="middle" style="fill:var(--soft)">◄ recommended</text>
|
|
<!-- n=7 : 87% -->
|
|
<rect x="404" y="65" width="72" height="135" rx="2" style="fill:var(--soft)"/>
|
|
<text class="bar-v" x="440" y="56" text-anchor="middle" style="fill:var(--soft)">87%</text>
|
|
<text class="bar-n" x="440" y="220" text-anchor="middle" style="fill:var(--soft)">7</text>
|
|
<!-- n=8 : 94% -->
|
|
<rect x="508" y="54" width="72" height="146" rx="2" style="fill:var(--soft)"/>
|
|
<text class="bar-v" x="544" y="45" text-anchor="middle" style="fill:var(--soft)">94%</text>
|
|
<text class="bar-n" x="544" y="220" text-anchor="middle" style="fill:var(--soft)">8</text>
|
|
</svg>
|
|
</div>
|
|
<p class="sub">Each anchor independently body-blockable at <span class="k">p=0.7</span>; a good 3-D fix needs
|
|
<b>≥4 clean anchors</b>. Going <b>4 → 6</b> takes a mesh from <b>dying when a person walks through it (24%)</b> to
|
|
<b>solving 3 of 4 moments (74%)</b>. This is the resilience metric that matters under real traffic.</p>
|
|
</figure>
|
|
|
|
<figure class="figure" style="margin-top:20px">
|
|
<p class="cap">What more anchors buy · (2) accuracy — but only down to the floor</p>
|
|
<div class="chartscroll">
|
|
<svg class="chart" viewBox="0 0 640 250" role="img" aria-label="Position error versus anchor count falls from about twelve centimetres at four anchors toward a systematic floor near four centimetres, asymptoting and never reaching sub-centimetre.">
|
|
<line x1="70" y1="200" x2="620" y2="200" style="stroke:var(--border);stroke-width:1.5"/>
|
|
<text class="axis" x="618" y="224" text-anchor="end">anchors →</text>
|
|
<text class="axis" x="20" y="120" text-anchor="middle" transform="rotate(-90 20 120)">position σ (cm)</text>
|
|
<!-- systematic floor -->
|
|
<line x1="70" y1="154" x2="620" y2="154" style="stroke:var(--hard);stroke-width:1.5;stroke-dasharray:6 5"/>
|
|
<text class="axis" x="614" y="149" text-anchor="end" style="fill:var(--hard)">systematic floor ~4 cm — anchors can't cross</text>
|
|
<!-- diminishing-returns curve -->
|
|
<polyline points="110,63 230,109 350,123 470,131 590,136" fill="none" style="stroke:var(--accent);stroke-width:2.5"/>
|
|
<g style="fill:var(--accent)">
|
|
<circle cx="110" cy="63" r="5"/><circle cx="230" cy="109" r="5"/><circle cx="350" cy="123" r="5"/>
|
|
<circle cx="470" cy="131" r="5"/><circle cx="590" cy="136" r="5"/>
|
|
</g>
|
|
<text class="bar-v" x="110" y="52" text-anchor="middle" style="fill:var(--hard)">~12</text>
|
|
<text class="bar-v" x="230" y="99" text-anchor="middle">~8</text>
|
|
<text class="bar-v" x="350" y="113" text-anchor="middle">6.7</text>
|
|
<text class="bar-v" x="470" y="121" text-anchor="middle">6.0</text>
|
|
<text class="bar-v" x="590" y="126" text-anchor="middle">5.6</text>
|
|
<text class="bar-n" x="110" y="220" text-anchor="middle">4</text>
|
|
<text class="bar-n" x="230" y="220" text-anchor="middle">5</text>
|
|
<text class="bar-n" x="350" y="220" text-anchor="middle">6</text>
|
|
<text class="bar-n" x="470" y="220" text-anchor="middle">7</text>
|
|
<text class="bar-n" x="590" y="220" text-anchor="middle">8</text>
|
|
</svg>
|
|
</div>
|
|
<p class="sub">Illustrative <span class="k">σ ≈ floor + A/(N−3)</span>. More anchors shrink the geometric/GDOP error
|
|
and <b>asymptote at the ToF systematic floor</b> — real gains, but <b>never sub-cm</b>. The takeaway divides
|
|
cleanly: <b>add anchors for reliability & traffic-resilience (charts above), not to change the accuracy
|
|
class</b> (that needs §09–§10's different-physics layers).</p>
|
|
</figure>
|
|
|
|
<p style="margin-top:22px"><strong>Courses of action for a dependable solve — the R-series</strong>, ordered from
|
|
zero-hardware-today to the robust target:</p>
|
|
<ul class="coa">
|
|
<li><span class="cb accent">R1</span><p><strong>Surveyed & frame-locked 4-anchor.</strong> <em>now · 0 hw</em>
|
|
Pin to the recorded survey, solve once, <strong>lock</strong>. <em>Sacrifice</em> survey-dependent · manual
|
|
re-commission · 24% traffic coverage. Dependable for a <b>static, light-traffic</b> solve today.</p></li>
|
|
<li><span class="cb accent">R2</span><p><strong>Observer-walk self-survey + lock.</strong> <em>near-term</em>
|
|
The #69b-i walk over-determines the frame → <strong>self-solve then lock</strong>, dropping the tape-measure.
|
|
<em>Sacrifice</em> a commissioning walk · still static-lock · still 24% traffic. Fixes <em>how you get</em> the
|
|
frame, not 4-anchor fragility.</p></li>
|
|
<li><span class="cb soft">R3</span><p><strong>Provision to 6 anchors.</strong> <em>target</em> 3 spare constraints
|
|
→ detect & drop a bad edge, <b>74% coverage</b>, survey-free (self-checks), continuous re-solve,
|
|
self-diagnosis, mobility-tolerant. <em>Sacrifice</em> two more devices — the only real cost. Software is already
|
|
over-determined-ready (#69).</p></li>
|
|
<li><span class="cb caution">R4</span><p><strong>Static solve-and-LOCK + NLOS/σ gate.</strong> <em>cross-cutting</em>
|
|
Freeze the frame while clean; gate client range updates by an NLOS/σ test so a body-blocked spike can't corrupt
|
|
a position. <b>Mandatory at N=4</b>, belt-and-suspenders at N≥6. Makes <em>any</em> N dependable.</p></li>
|
|
</ul>
|
|
|
|
<div class="verdict" style="border-left-color:var(--accent); margin-top:18px">
|
|
<p class="eyebrow">Recommendation — lock now, provision to six for traffic</p>
|
|
<p><strong>NOW (0 hardware): R1 + R4</strong> — pin to survey, solve-once-and-lock, add the NLOS/σ gate → today's
|
|
mesh is dependable for a static, light-traffic solve, enough to start validating aiming against a frame that won't
|
|
move under you. <strong>NEAR-TERM: R2</strong> drops the tape-measure (validated by the walk capture).
|
|
<strong>TARGET: R3 — provision to 6 anchors</strong>, the honest precursor to reliable aiming under real traffic:
|
|
4 can be <em>made</em> reliable only by giving up mobility, blockage-tolerance and self-healing —
|
|
<b>6 buys all three back for the price of two devices.</b> Keep R4's lock-and-gate as the invariant.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="bottomline">
|
|
<p class="eyebrow">The mission, honestly</p>
|
|
<p>The premise is right and the software built so far is largely correct and necessary — it is simply operating
|
|
under a geometry that gives it nothing to work with. Spend the next effort on <b>anchors, placement, NLOS
|
|
signal, and a scheduler</b>, tier the acceptance criteria, and the achievable version is close at hand. The
|
|
walk-capture in progress will quantify exactly how much of the 4-anchor gap the observer lever can close — which
|
|
tells us whether a 5th anchor is <b>optional or mandatory</b> for the target tier.</p>
|
|
</div>
|
|
|
|
<div class="sources col">
|
|
<p class="eyebrow">Sources</p>
|
|
<ul>
|
|
<li><span class="lbl">RTLS</span>Sewio — <a href="https://www.sewio.net/accuracy-considerations-for-uwb-indoor-tracking-in-an-industrial-environment/">Accuracy considerations for UWB indoor tracking</a> · Cisco Spaces — <a href="https://spaces.cisco.com/uwb-rtls-success-begins-with-network-design-validation/">Network design & site surveys</a></li>
|
|
<li><span class="lbl">Geometry</span><a href="https://www.sciencedirect.com/science/article/pii/S0957417424016750">Optimal layout of four anchors for UWB indoor positioning</a> (Expert Systems with Applications)</li>
|
|
<li><span class="lbl">Phones</span><a href="https://www.mdpi.com/2673-8732/4/4/27">UWB & Wi-Fi RTT positioning survey</a> (MDPI) · <em>Smartphones with UWB: accuracy & reliability</em> (arXiv 2303.11220)</li>
|
|
<li><span class="lbl">NLOS</span><a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC10934496/">CIR features + two-step NLOS identification</a> · <em>First-path-power NLOS mitigation</em> (arXiv 2403.19706)</li>
|
|
<li><span class="lbl">Scale</span><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6022048/">Scalability of UWB localization for high user densities</a> (PMC)</li>
|
|
</ul>
|
|
<p class="foot">Full analysis + citations: <span class="k">design/MISSION_AND_FEASIBILITY.md</span> · basis: MOFE engine, roadmap, capture4 NDJSON, aether_mesh_survey.mp4</p>
|
|
</div>
|
|
</div>
|