Twelve weeks on locating phones, tags and people indoors from radio signals: received signal strength, ranging, geometry, fingerprints, filters, maps and fusion. The course is built so that the student can move every parameter of every method on the projector and watch it succeed and then fail.
The throughline is one question asked every week: which part of this error can the method reach? A position error has a noise part, which averages away, and a bias part, which is fixed to the room and does not. Filters and averaging act on the first. Maps, better propagation models and other modalities act on the second. A student who measures the split before choosing a method will not spend a semester tuning a Kalman filter against a bias it cannot see.
Every lecture is self-contained. Each scenario is introduced on its own terms (for example: ten Bluetooth receivers around one open hall, a phone carried at chest height). No lecture depends on another course, on a lab register, or on knowing which measurement campaign a number came from.
The 12-week arc
2 of 12 lectures published — each a self-contained read with a slide deck and runnable workbook. Start at the first published week and work forward.
| Wk | Theme & focus | Read |
|---|---|---|
| 01 | RF ranging fundamentals start here RSSI, time of flight and angle of arrival: what each radio measurement costs and buys. Widgets: `RangingModalities` (shadowing sigma 0-10 dB, path-loss exponent n 1.5-4, bandwidth B 1-160 MHz, antenna spacing d/lambda 0.1-1.5; readouts: RSSI range factor 10^(sigma/10n), ToF resolution c/2B, AoA from the phase difference; break it: spacing above lambda/2 aliases the angle), `ErrorCdf` (seeded ranging errors, the CDF beside a single RMSE) | read → slides · workbook |
| 02 | Log-normal path loss Fitting P(d0), n and sigma by least squares, the exact price of a decibel, why one model drifts across rooms, and an exponent below free space in a hall that guides the signal. Widgets: `PathLossFit` (P0 -80 to -40 dBm, n 1-5, sigma 0-10 dB, readings 5-200, obstructed share 0-60 %, extra loss 0-15 dB; readouts: fitted P0, n, sigma and the distance multiplier; break it: pool obstructed readings and watch sigma inflate), `AveragingFloor` (packets per estimate 1-256; the fading part falls as 1/sqrt(N), the shadowing floor does not) | read → slides · workbook |
| 03 | Trilateration & geometry From ranges to a fix by Gauss-Newton least squares; dilution of precision as the matrix that turns range error into position error; the RSS Cramér-Rao bound, proportional to sigma squared over n squared; why a ring of anchors around one open hall pulls a weighted centroid to the middle. Widgets: `TrilaterationBench` (drag 3-10 anchors and the target on a 30 x 15 m floor, sigma 0-10 dB, n 1-4; draws range annuli, solver iterations and the 1-sigma error ellipse; readouts: GDOP, CRB in m, miss in m; break it: make the anchors collinear, move the target outside their hull, bias one anchor by +6 dB), `DopMap` (GDOP or CRB heat map for preset layouts: ring, four corners, one wall; centroid against least squares) | planned |
| 04 | Bluetooth as a measurement What a scanner actually receives: three advertising channels (2402, 2426, 2480 MHz) with different gains and noise, advertising interval against readings per fix, public addresses as a static background, random addresses that rotate every 10 to 15 minutes, so an address is neither a device nor a person. Widgets: `AdvertisingChannels` (per-channel offset 0-8 dB and sigma 0-4 dB, channel label known or hidden; readout: pooled against per-channel sigma and the range multiplier each implies; break it: pool the channels), `AdvertisingCadence` (interval 20-10240 ms, scan duty 10-100 %; readings per 2 s bin and the fix variance), `AddressRotation` (rotation period 1-30 min, dwell 1-240 min, public share 0-100 %; addresses counted per device, what a linker's precision and recall do to the count) | planned |
| 05 | Unknown transmit power: proximity and sectors When the phone's power is unknown only RSSI differences constrain it: a difference fixes the ratio d_i/d_j, whose level sets are Apollonius circles; nearest-receiver Voronoi and order-2 Voronoi sectors; hit rate against sector size, scored against a constant-answer baseline and Cohen's kappa. Widgets: `ApolloniusField` (two to four receivers, P0 known or profiled out, n 1-4, sigma 0-8 dB; draws the circle family and the posterior), `SectorScorer` (sector kind square 1-6 m, node Voronoi or order-2 Voronoi, fix error 0.5-4 m, visit skew; readouts: hit rate, constant-answer rate, kappa; break it: rank the two strongest receivers directly instead of from a fix, and score room accuracy on a walk that stays in one room) | planned |
| 06 | Fingerprinting and radio maps k-NN and Gaussian-likelihood fingerprints, survey cost against accuracy, spatially correlated shadowing as what a map captures and a two-parameter model cannot, and map ageing. Widgets: `RadioMapBuilder` (survey spacing 0.5-5 m, readings per point 1-50, k 1-15, shadowing correlation length 0.5-8 m; readouts: median and p90 error, survey minutes), `MapAging` (elapsed time 0-60 days, a shelf-sized scatterer moved 0-3 m, drift 0-6 dB; break it: localise with a stale map and watch the tail grow) | planned |
| 07 | Noise or bias: smoothing and outlier rejection The two tests that split an error: average the fixes of one dwell (white noise falls as sigma/sqrt(N), bias does not move) and decompose error variance into within-cell and between-cell parts; error autocorrelation; Hampel, median and EMA filters in the RSSI domain, and why they do nothing after a per-bin median. Widgets: `BiasNoiseSplitter` (white noise 0-4 m, bias field amplitude 0-6 m, bias correlation length 1-10 m, fixes per dwell 1-64; readouts: error after averaging against the sqrt(N) prediction, between-cell share, lag-1 autocorrelation; break it: set white noise to zero and watch averaging stall), `RssiCleaner` (Hampel window 3-31 samples, threshold 1-5 MAD, EMA alpha 0-1, bin 0.5-5 s; readout: change in fix error) | planned |
| 08 | The Kalman filter State-space tracking derived from Bayes' rule: random-walk against constant-velocity models, process noise q and measurement noise R, the chi-square innovation gate, the Rauch-Tung-Striebel smoother, and the normalised innovation squared as a consistency check that fails when measurement errors are correlated. What the filter buys: the tail and plausibility, not the median. Widgets: `KalmanTrack` (model RW or CV, q 0.01-5 m^2/s, R scale 0.25-4, gate p 0.001-0.1, causal or smoothed; readouts: median, p90, path ratio, share of steps above 1.5 m/s, mean NIS; break it: raise the measurement-error autocorrelation 0-0.95 and follow NIS to an oversmoothed track), `GainBetweenAnchors` (fix interval 1-60 s, q/R; the gain just after and just before a fix) | planned |
| 09 | Particle filters and map constraints Sequential importance resampling, effective sample size, walls as zero-likelihood moves, doors and a room graph as the prior for map matching. Widgets: `ParticleFloor` (particles 50-5000, resample below ESS 10-100 %, motion sigma 0.1-1.5 m/s, walls on or off, one door open or closed; readouts: ESS, error, particles that crossed a wall; break it: too few particles, or close the door the walker uses), `RoomGraph` (rooms as nodes, maximum walking speed 0.5-2 m/s; which room sequences survive) | planned |
| 10 | Calibration as maintenance A radio map drifts; recalibration costs a survey. Calendar schedules against condition-based triggers, a drift statistic that compares the estimate with an independent cheap measurement rather than with the filter's own innovation, and the evaluation arm with feature shift and zero error that every drift detector needs. Parity at lower spend is the honest target, not lower error. Widgets: `DriftMonitor` (drift 0-3 dB per week, survey interval 1-90 days, trigger threshold, cost per survey; error over time and total spend for both policies), `DetectorArms` (true drift on or off, benign feature shift on or off; readouts: false alarms of a self-monitoring test against a cross-modal disagreement; break it: evaluate without the shift-without-error arm) | planned |
| 11 | Sensor fusion: BLE, CSI and inertial Combining modalities as one estimate: an intermittent absolute fix against a continuous relative signal that drifts, a staleness switch w = exp(-s/tau) against a fixed blend, inertial dead reckoning between fixes, and scale: at 5 GHz one Fresnel zone is about 3 cm, so a metre-level Bluetooth fix can gate a Wi-Fi link's neighbourhood but not a zone. Widgets: `StalenessSwitch` (BLE cadence 1-80 s, tau 1-60 s, CSI drift rate, blend weight 0-1; error curves of held BLE, CSI alone, fixed blend and switch; break it: fix the blend and watch it lose at both ends of the cadence range), `FresnelGate` (band 2.4, 5 or 6 GHz, BLE error 0.5-4 m, link length 2-20 m; zones inside the BLE uncertainty) | planned |
| 12 | Ground truth, error CDFs and the capstone Scoring honestly: paired differences, percentile intervals from a moving-block bootstrap sized to the error correlation time, p50 and p90 side by side, constant-answer baselines; auditing the reference itself (a rigid fit from two known points, a handedness flip between coordinate frames, a printed marker whose size the solver must share). Capstone review. Widgets: `ErrorCdfLab` (two estimators, error autocorrelation 0-0.95, block length 1-120 fixes; readouts: p50 and p90 with intervals; break it: an iid bootstrap on correlated errors and its too-narrow interval), `ReferenceAudit` (anchor error 0-0.5 m, handedness flip on or off, printed marker size against declared size; readout: registration residual and the scale error it hides) | planned |
Capstone
Across weeks 9 to 12, each student builds a Bluetooth localisation pipeline for a floor plan with at least two rooms and a stated anchor layout, simulated with a seeded, spatially correlated shadowing field plus white noise. The pipeline must:
- fit and state its propagation model, with the residual sigma;
- report GDOP or the CRB over the floor before any estimator runs;
- split its own error into noise and bias with the dwell test and the cell decomposition, and say which method the split justifies;
- add one tracker (Kalman or particle) and report what it changed at p50 and p90, each with a paired block-bootstrap interval;
- document a calibration procedure with its cost, and one drift test with a shift-without-error arm;
- show where and why it fails, with a constant-answer baseline beside every accuracy number.
Week 12 is the review: each pipeline is scored on a held-out seed the student has not seen.