Pathfinder method: what is physics and what is a weight
This page answers the owner's question "what is physics and what is weights" and fixes one vocabulary for the team. Each part is described in plain words first, then under its standard name, then as the equation the code runs, with every constant, its value, the file:line that holds it and the decision (D-entry in docs/01-decisions.md) that set it.
Every number carries a tag: measured (sim) came from ArduPilot SITL flights and names its source; estimate is reasoned or computed by hand, not measured; configured is a value someone chose and typed in. Nothing on this page is measured on a real drone. Paths are relative to Pathfinder/; core files are under crates/pathfinder-core/src/.
0. Standard terms DECIDED (D-NAME-1)
Decided 11 Oct 2026 (D-NAME-1 "Domain names for the six parts"): Position Estimator (mode Pathfinder without ML), Velocity Predictor, Predictor Adapter, GPS Integrity Monitor, Navigator (mode Pathfinder with ML), GPS Fix. The table below is the earlier proposal, kept as the record of what was weighed; the rest of this page uses the decided names.
The owner's feedback: the plain words used so far (physics, weight, uncertainty, fixed weight) are not precise enough. Each row below gives the word in use today, what is wrong with it, two candidate replacements (recommended first), a plain definition, and the textbook term it maps to. Every proposed term is PROPOSED until the owner picks one. The rest of this page still uses today's words, so it reads against the code and the findings page; it switches over once the owner has picked.
| Word today | Problem | Proposed (1 = recommended) | Plain definition | Standard engineering term |
|---|---|---|---|---|
| Pathfinder-Physics | Learned is trained on physics too; the name hides that this is a navigation filter and that drag, compass and barometer feed it | 1. Pathfinder-Inertial PROPOSED 2. Pathfinder-Model | Works out position by adding up what the motion sensors feel, corrected by drag, compass and barometer | model-aided strapdown INS, error-state Kalman filter (ESKF) |
| Pathfinder-Learned | the per-drone adapter also learns; "learned" does not say what it outputs | 1. Pathfinder-Neural PROPOSED 2. Pathfinder-NetVelocity | A neural network that guesses airspeed and direction from the last second of sensors and motor commands | learned inertial odometry (TLIO-style velocity regression) |
| Pathfinder-Fused | Physics already fuses four sensors, so "fused" does not set the two apart | 1. Pathfinder-Hybrid PROPOSED 2. Pathfinder-Full (matches run type full) | Pathfinder-Physics with the network's velocity added as one more sensor | ESKF with a learned pseudo-measurement |
| ArduPilot alone | does not say which ArduPilot setup; "alone" is also used for "Learned alone" | 1. ArduPilot baseline PROPOSED 2. EKF3-only baseline | The autopilot's own navigation with no Pathfinder, failsafes off, flown through the same jam | unaided EKF3 dead-reckoning baseline (run type b1) |
| weight | three meanings: Kalman gain, network parameters, adapter layer (section 1) | 1. trust share PROPOSED 2. fusion gain | How much of a sensor's disagreement the estimate accepts, from 0 (ignore) to 1 (take it whole) | Kalman gain K |
| fixed weight | the gain is not fixed; the sensor-noise setting is | 1. constant noise setting PROPOSED 2. static R | The Learned sensor is always declared equally unreliable, whatever the flight is doing | time-invariant measurement noise covariance R |
| uncertainty (of the estimate) | used for both the filter's doubt and a sensor's doubt | 1. estimate uncertainty PROPOSED 2. self-doubt | How wrong the filter thinks its own position, speed and heading might be | state error covariance P |
| uncertainty (of a sensor) | same word as above | 1. sensor noise setting PROPOSED 2. sensor trust setting | How unreliable we declare each sensor to be; the one number we choose per sensor | measurement noise covariance R |
| process noise | "noise" suggests a sensor; it is an allowance for an imperfect motion model | 1. model slack PROPOSED 2. drift allowance | How much doubt the filter adds each second because its motion equations are not perfect | process noise covariance Q (densities σ, random walks) |
| drift | used for position error growth and for slow bias change | 1. error at t+N s (e.g. "error at t+120 s") PROPOSED 2. position drift | Distance between estimated and true position, N seconds after GPS was lost | unaided position error growth (horizontal error vs time) |
| error radius, honest radius, r95 | three names for one number; "honest" is the AC-3 test, not the radius | 1. 95% radius (r95) PROPOSED 2. confidence radius | Circle the filter claims holds the true position 95% of the time | 95% bound of the horizontal covariance ellipse, √(5.991·λmax); not CEP (CEP is 50%) |
| innovation | jargon to an owner reader | 1. sensor surprise PROPOSED 2. disagreement | What the sensor says minus what the filter expected | innovation y = z − h(x) |
| NIS gate, gate | no distribution or degrees of freedom named | 1. surprise gate (χ²ₖ p%) PROPOSED 2. outlier gate | Throw away a sensor reading that is too surprising given both uncertainties | chi-square NIS gate |
| divergence (GPS guard) | sounds like a rate; it is a distance | 1. GPS surprise distance PROPOSED 2. GPS Mahalanobis distance | How many sigmas the GPS fix is from where the filter expected it | Mahalanobis distance of the GPS innovation |
| drag model | "model" collides with the neural model | 1. drag aiding PROPOSED 2. air-drag law | The formula for how hard the air slows the drone, used as a sensor of airspeed | aerodynamic model aiding (drag-force pseudo-measurement) |
| adapter, drone tuner | two names; AC-7 calls it "in-flight calibration" | 1. in-flight calibration PROPOSED 2. per-drone tuning | While GPS is good, re-fit the network's last layer to this drone, then freeze it | online recursive least squares (RLS) last-layer adaptation |
| GPS guard | clear; code calls it "integrity" | 1. GPS guard (keep) PROPOSED 2. GPS integrity monitor | Decides on every fix whether GPS is honest, and cuts it off when jammed or spoofed | innovation-based integrity monitoring with fault detection and exclusion (FDE) |
| hand-off "odometry" | names the message, not what the autopilot does with it | 1. Mode A: external-nav feed PROPOSED 2. odometry feed | Pathfinder sends position and velocity; ArduPilot's own filter switches to it as a second source | MAVLink ODOMETRY into EKF3 external navigation (source set 2) |
| hand-off "gps-input" | names the flag, not the behaviour | 1. Mode B: GPS replacement PROPOSED 2. virtual GPS receiver | Pathfinder pretends to be a second GPS receiver; the autopilot switches to it when real GPS is bad | MAVLink GPS_INPUT as GPS2 (GPS_TYPE 14), D-65 |
1. The short answer
Physics is the part that predicts: the equations of motion that turn gyro and accelerometer readings into attitude, velocity and position, plus the drag formula that says how hard the air pushes back at a given airspeed. It is written by hand and runs 200 times a second.
A weight is how much one measurement is allowed to move that prediction. In Kalman-filter terms the weight is the Kalman gain K. Nobody types K in; it is computed every update from two numbers: how unsure the filter is of itself (P, the covariance) and how unsure we say the measurement is (R, the measurement noise). Large P, small R: big weight. Small P, large R: small weight.
The word "weights" has three meanings in this project, and the team keeps them apart from now on:
| Say this | Means | Where | Changes when |
|---|---|---|---|
| Kalman gain (the fusion weight) | how much a measurement moves the state | eskf.rs:188 | every update, from P and R |
| network parameters | the trained numbers inside the Velocity Predictor network | models/velocity-long.onnx | only when we retrain |
| adapter layer | the last layer [W|b] of the network, re-fitted per drone while GPS is good | adapter.rs:101-123 | first 30-180 s of a flight, then frozen |
"Fixed weight" means a constant R. Today every Velocity Predictor velocity sample enters with the same R = 22.9 × 294 = 6,733 (m/s)² per axis, a one-sigma of about 82 m/s estimate, whatever the flight phase, whatever the network says about its own confidence, however long GPS has been gone. The gain K still moves a little, because P grows as Position Estimator drifts, but nothing in the code chooses to trust Velocity Predictor more or less. Section 5 shows the arithmetic.
2. How the parts connect
Sensors on the left. Position Estimator is the filter in the middle; every arrow into it is a measurement with its own R. Velocity Predictor is one more arrow. The GPS Integrity Monitor decides whether the GPS arrow is open. The hand-off sends the result to the autopilot.
Rates: IMU 200.1 Hz over MAVLink measured (sim) D-61; GPS 4.75 Hz measured (sim) models/integrity.json gps_rate_hz; compass gated to 10 Hz in crates/pathfinderd/src/daemon.rs D-61; drag every 0.1 s configured config.rs:44 D-58; Velocity Predictor every 0.1 s configured config.rs:50 D-53.
3. Position Estimator
It adds up what the motion sensors feel, 200 times a second, to know where the drone is pointing, how fast it moves and where it is. Small sensor errors pile up, so it also keeps a running estimate of how wrong it might be. A drag formula, compass and barometer pull it back toward reality without GPS.
Standard term: error-state Kalman filter (ESKF, D-38 "Fusion filter", interface D-47). Run type b2, harness name B2_FILTER_DRAG.
3.1 State
The nominal state is what the filter believes. The error state is the small correction it is unsure about; the covariance P is defined over the error state.
| Index | Symbol | Meaning | Unit | Code |
|---|---|---|---|---|
| 0-2 | p | position, NED, from the first good fix | m | IP eskf.rs:6 |
| 3-5 | v | ground velocity, NED | m/s | IV eskf.rs:7 |
| 6-8 | δθ | attitude error (small rotation, body) | rad | ITH eskf.rs:8 |
| 9-11 | b_g | gyro bias | rad/s | IBG eskf.rs:9 |
| 12-14 | b_a | accelerometer bias | m/s² | IBA eskf.rs:10 |
| 15-16 | w | horizontal wind, NE | m/s | IW eskf.rs:11 |
17 states, N at eskf.rs:5 configured. Accelerometer scale and drag coefficient states were deliberately not added (D-53).
3.2 Prediction (propagation)
Plain: turn the gyro reading into a rotation, the accelerometer reading into an acceleration in the world frame, and integrate. Standard: strapdown inertial propagation with a state-transition Jacobian F and process noise Q.
ω = gyro − b_g a = accel − b_a a_ned = R(q)·a + [0, 0, g] g = 9.80665 m/s² (eskf.rs:12, 140) p ← p + v·dt + ½·a_ned·dt² v ← v + a_ned·dt q ← q ⊗ exp(ω·dt) (eskf.rs:141-143) P ← F·P·Fᵀ + Q then P ← ½(P + Pᵀ) (eskf.rs:166-167)
Non-zero blocks of F (eskf.rs:145-153): ∂p/∂v = I·dt, ∂v/∂δθ = −R·[a]×·dt, ∂v/∂b_a = −R·dt, ∂δθ/∂δθ = I − [ω]×·dt, ∂δθ/∂b_g = −I·dt. An IMU gap longer than max_imu_dt_s = 0.05 s configured (config.rs:45) is propagated in substeps with the newest sample (navigator.rs:102-107, D-58 item 2).
Process noise is how much the filter assumes it loses certainty every second without a measurement. Each term is a density σ and enters as σ²·dt on the diagonal (eskf.rs:157-165). Bias and wind terms are random walks: the filter assumes they wander slowly and without direction.
| Name | Value | Unit | Acts on | Where · set by | Tag |
|---|---|---|---|---|---|
accel_noise | 0.35 | m/s/√s | v | eskf.rs:32 · M0/M1 plan default, EKF3-style start value (eskf.rs:15) | configured |
gyro_noise | 0.015 | rad/√s | δθ | eskf.rs:33 · plan default | configured |
accel_bias_walk | 0.003 | m/s²/√s | b_a | eskf.rs:34 · plan default | configured |
gyro_bias_walk | 0.001 | rad/s/√s | b_g | eskf.rs:35 · plan default | configured |
wind_walk | 0.05 | m/s/√s | w, GPS trusted | eskf.rs:36 · D-58 (was 0.2; 98.3% replay coverage at 0.05), D-63 (99.5%) | measured (sim) |
wind_walk_denied | 0.05 | m/s/√s | w, GPS not trusted | eskf.rs:37, switch navigator.rs:93-97 · D-63 (smaller values tested and refuted) | measured (sim) |
"Plan default" = the starting value written in docs/plans/2026-10-07-pathfinder-m0-m1.md:2047; no D-entry has tuned it. D-63 names accel_noise and the drag R as the next things to measure.
3.3 Initial uncertainty
What P starts at, as one-sigma per block (eskf.rs:57-63; navigator.rs:203-224 overrides two).
| Block | σ | Where | Tag |
|---|---|---|---|
| position | max(GPS h_acc, 1.0) m (default 3.0 unused at start) | navigator.rs:13, 219 | configured |
| velocity | 0.5 m/s | eskf.rs:58 | configured |
| roll, pitch | 0.05 rad | eskf.rs:59 | configured |
| yaw | 0.2 rad with compass, π without | navigator.rs:14, 213-217 | configured |
| gyro bias | 0.01 rad/s | eskf.rs:61 | configured |
| accel bias | 0.2 m/s² | eskf.rs:62 | configured |
| wind | 5.0 m/s | eskf.rs:63 | configured |
3.4 Measurement update: the one formula every sensor goes through
Plain: compare what the sensor says with what the filter expected; move the state part of the way toward the sensor; shrink the uncertainty. Standard: Kalman update, Joseph form (eskf.rs:183-197).
y = z − h(x) innovation: sensor minus prediction S = H·P·Hᵀ + R innovation covariance K = P·Hᵀ·S⁻¹ Kalman gain = the weight (eskf.rs:188) δx = K·y correction, injected into x (eskf.rs:189, 200-207) P ← (I − K·H)·P·(I − K·H)ᵀ + K·R·Kᵀ (eskf.rs:194) NIS = yᵀ·S⁻¹·y normalised innovation squared (eskf.rs:177-181)
For one scalar measurement this is K = P/(P + R): the share of the disagreement the filter accepts. R is the only input we choose per sensor.
3.5 Position Estimator measurements and their R
| Measurement | z, H | R (one-sigma) | Where · set by | Tag |
|---|---|---|---|---|
| Drag: the air slows the drone in proportion to airspeed | mean body x,y accel over 0.1 s; predicted −k·u − k_q·u|u| + b_a, u = body air velocity = Rᵀ(v − w) | 0.5 m/s² per axis | drag.rs:21, law drag.rs:32-43, H drag.rs:45-66 · no D-entry; fit residual is 0.083 m/s² (drag.json), so R is about 6x the fit error estimate | configured |
| Drag coefficient k | 0.2541 /s (quad); hexa 0.2527, octa 0.2401 | drag.rs:19, models/drag.json · D-58 item 1, n = 4,851 samples, rms 0.083 m/s² | measured (sim) | |
| Drag coefficient k_quad | 0.0341 /m (quad); hexa 0.0345, octa 0.0363 | drag.rs:20, models/drag.json · D-58 | measured (sim) | |
| Barometer | down position, offset fixed at first sample (navigator.rs:129) | 1.0 m | config.rs:42, measurements.rs:37-45 · plan default | configured |
| Compass | tilt-compensated yaw + declination (measurements.rs:48-52) | 0.08 rad (4.6°) | config.rs:41, measurements.rs:55-66 · plan default; rate 10 Hz D-61; declination from COMPASS_DEC D-58 item 3 | configured |
| GPS position (only when the guard says TRUSTED) | NED position, H = I on p | receiver's own h_acc (horizontal), v_acc (vertical) | measurements.rs:11-24, navigator.rs:184-187 | reported by receiver |
| GPS velocity | N, E velocity | 0.3 m/s | config.rs:43, measurements.rs:26-35 · plan default | configured |
GPS position is the only measurement whose R changes during a flight, because the receiver reports its own accuracy with every fix. Every other R on this page is a constant.
4. Velocity Predictor
A small neural network looks at the last second of motion sensors, tilt and motor commands and guesses how fast the drone is moving through the air. Each guess is a few m/s off, but the errors go up and down instead of piling up. It never flies alone: on its own it is about 580 m off two minutes after GPS loss.
Standard term: learned inertial odometry (TLIO-style velocity regression) with a heteroscedastic variance head (D-35 "Model uncertainty") and an online last-layer adapter fitted by recursive least squares (D-37 "Per-drone adapter parameters").
4.1 Input and output
| Item | Value | Where · set by | Tag |
|---|---|---|---|
| Input channels (spec v2) | 13: gyro 3, specific force 3 (heading frame), baro rate, baro present, AHRS roll, pitch, motor mean, spread, present | learned.rs:13-27 · D-57 "Data spec v2: every model input exists onboard" | configured |
| Heading frame | body rotated by roll and pitch, yaw removed | learned.rs:112-114 · D-53 | configured |
| Motor normalisation | u = clamp((pwm − 1000)/1000, 0, 1) | learned.rs:31-32 · D-57 | configured |
| Window, rate, stride | 1 s, 50 Hz (50 samples), one guess every 0.1 s | meta file; stride config.rs:50 · D-53 | configured |
| Network | causal TCN, 4 residual blocks, dilation 1/2/4/8, kernel 3, 64 channels | D-53 | configured |
| Output | velocity mean (3) + log-variance (3), clamped to [−8, 6] | learned.rs:241-247 · D-53 | configured |
| Output frame | rotated to NED by the filter yaw | learned.rs:250-255 · D-53, gap noted in D-60 | |
| Held-out error, model alone, t+120 s | 580 m median (quad+octa, n = 8); 204 m (hexa, n = 4) | D-60, docs/measurements/2026-10-learned-v2-heldout.md | measured (sim) |
| Velocity error vs air velocity | 4.8 m/s RMS (vs ground velocity 5.9 m/s) | models/velocity-long.calib.json · D-62 | measured (sim) |
| Residual correlation time τ | 14.7 s | calib.json · D-62 | measured (sim) |
| Factor needed to make the model's own variance honest (95% inside χ²₂ 5.991) | about 2,000 (1,963 air) | calib.json q95_scale · D-62 | measured (sim) |
That last row is why the network's own confidence is switched off today: its variance would need to be multiplied by about 2,000 to be honest, so it carries no usable signal (D-62).
4.2 Predictor Adapter (per-drone tuning while GPS is good)
Plain: during the first minutes, while GPS is still trusted, the last layer of the network is nudged so its guesses match the filter's velocity on this particular drone. Standard: recursive least squares with a forgetting factor on θ = [W|b] (3 x 65).
φ = [h; 1] h = 64-wide hidden vector k = P_a·φ / (λ + φᵀ·P_a·φ) adapter gain (not the Kalman gain) (adapter.rs:112) θ ← θ + (target − θ·φ)·kᵀ target = filter air velocity, heading frame P_a ← (P_a − k·(P_a·φ)ᵀ) / λ (adapter.rs:110-115) if ‖θ − θ₀‖_F > max_delta: pull back onto the limit (adapter.rs:116-120)
| Name | Value | Where · set by | Tag |
|---|---|---|---|
forgetting λ | 0.999 | adapter.rs:25 · D-53 | configured |
prior_var | 0.01 | adapter.rs:26 · D-53 | configured |
max_delta | 2.0 (Frobenius) | adapter.rs:27 · D-53 | configured |
window | 300 steps = 30 s | adapter.rs:28 · D-53 | configured |
converge_rel | 0.02 (freeze when error falls under 2% per 30 s) | adapter.rs:29 · D-53 | configured |
min_steps, max_steps | 300, 1,800 (180 s cap) | adapter.rs:30-31 · D-53, D-24 | configured |
The adapted layer is used only while its error over the last 30 s is lower than the base layer's (adapter.rs:81-85). The adapter steps only while GPS is TRUSTED; its target is the air velocity v − w (D-60, D-62).
5. Navigator, and how a weight is computed today
The complete product: Position Estimator runs all the time, and every Velocity Predictor guess nudges it. How hard each guess nudges is the weight.
Standard term: Velocity Predictor velocity fused as a measurement in the same ESKF. Run type full, harness name PATHFINDER_FULL. Navigator on every stride whether GPS is trusted or not (navigator.rs:276-286, D-60).
5.1 The measurement
z = R_yaw · v̂_heading network output rotated to NED (learned.rs:250-255) h(x) = v − [w_n, w_e, 0] air velocity, because the network learned air velocity (D-62) H = [ I on v , −I on w ] (learned.rs:296-301) y = z − h(x) R = (s · Σ_model + f · I) · c (learned.rs:305) c = max(2·τ / Δt, 1) correlation inflation (navigator.rs:299)
| Symbol | Config name | Value | Where · set by | Tag |
|---|---|---|---|---|
s variance scale | learned_var_scale | 0 (model's own variance ignored) | config.rs:48 · D-62 | configured from a measured (sim) finding |
f variance floor | learned_var_floor | 22.9 (m/s)² = 4.8² (was 1.0 in D-60) | config.rs:47 · D-62 | measured (sim) |
τ correlation time | learned_corr_time_s | 14.7 s | config.rs:49 · D-62 | measured (sim) |
Δt stride | learned_stride_s | 0.1 s | config.rs:50 · D-53 | configured |
| NIS gate | learned_gate_nis | 11.34 (χ²₃ at 99%) | config.rs:51, applied learned.rs:328-335 · D-62 | configured |
| air-relative | learned_air_relative | true | config.rs:52 · D-62 | configured |
5.2 The arithmetic, step by step
c = 2 × 14.7 / 0.1 = 294. Errors 0.1 s apart are almost the same error (they stay correlated for about 15 s), so 294 consecutive samples are treated as carrying the information of one independent sample. D-62 writes "295x"; the code gives 294 estimate.R = (0 + 22.9) × 294 = 6,733 (m/s)²per axis, one-sigma about 82 m/s, the same for every sample estimate.- The gain per sample, per axis, is roughly
K ≈ P_air / (P_air + 6,733), whereP_airis the filter's variance of its own air velocity. WithP_air= 0.25 (m/s)² that is K ≈ 0.00004; with 4 (m/s)² it is 0.0006 estimate, illustrativeP_airvalues, not logged ones. - Summed over 29.4 s (= 2τ) of samples, that is about the pull of one 4.8 m/s-accurate velocity reading. D-62 describes it as "one sample every 15 s"; by the code's formula it is one per 29.4 s estimate.
- The gate rejects a sample only when
NIS > 11.34. WithS ≈ R= 6,733 per axis, an innovation would need to be around √(11.34 × 6,733) ≈ 276 m/s to be rejected, so the gate does not fire in normal flight estimate.
5.3 What "fixed weight" means, exactly
- Fixed:
R. It does not depend on time since GPS loss, flight phase, airspeed, or the network's own variance (scale 0). - Not fixed:
K, becausePchanges. As Position Estimator drifts, itsP_airgrows and Velocity Predictor gets a larger share. That growth is set byQand the dragR, not by a choice about Velocity Predictor. - Measured effect on one flight (heldout-jam-1000, findings page): Position Estimator 4 / 6 / 127 m at 1 / 2 / 5 min after the jam; Navigator 47 / 66 / 37 m measured (sim), n = 1. The constant
Rlets Velocity Predictor pull Position Estimator off early and pull it back late. - Option A on the findings page ("trust shifts over time") would replace the constant with an
Rthat starts large and shrinks as Position Estimator'sPgrows. Not built; its numbers are estimate.
6. GPS Integrity Monitor
Decides, on every GPS fix, whether GPS is honest. If the fix is far from where Position Estimator says the drone is, or jumps too fast, or its position and velocity disagree, GPS is cut off and Pathfinder takes over. It lets GPS back in only after 10 s of consistent fixes.
Standard term: innovation-based integrity monitor (fault detection on the GPS innovation, a Mahalanobis distance test) driving a three-state machine TRUSTED / SUSPECT / REJECTED (integrity.rs:69-218, D-21).
d = √( Δpᵀ · (P_pp + h_acc²·I)⁻¹ · Δp ) "divergence" in code; horizontal, before the update
(measurements.rs:69-76)
rate = (d − d_prev) / Δt (integrity.rs:130-133)
posvel = EMA of |Δp_gps/Δt − v_gps|, α = min(Δt/2.0, 1) (navigator.rs:190-201)
r95 = √(5.991 · λ_max(P_ne)) 95% horizontal radius (navigator.rs:11, 17-20)
Thresholds in flight come from models/integrity.json, which the harness passes as --config (tests/harness/runner.py:38, 64-65). The code defaults are the plan's pre-fit values and apply only when no config is passed.
| Name | In flight | Code default | Where · set by | Tag |
|---|---|---|---|---|
suspect_divergence | 12.22 | 3.0 | integrity.json:4, integrity.rs:26 · D-55 | measured (sim) |
reject_divergence | 24.45 | 6.0 | integrity.json:3, integrity.rs:27 · D-55 | measured (sim) |
reject_rate_per_s | 57.4 /s | 4.0 | integrity.json:5, integrity.rs:28 · D-55 | measured (sim) |
posvel_mismatch_mps | 0.7 m/s | 0.7 | integrity.json:6, integrity.rs:29 · D-55 (fitted 0.44, kept at default) | measured (sim) |
suspect_timeout_us | 2 s | integrity.rs:30 · plan default | configured | |
dropout_timeout_us | 1 s | integrity.rs:31 · plan default | configured | |
min_sats, max_h_acc_m, fix | 6, 5.0 m, 3D | integrity.rs:32-33, 113-118 · plan default | configured | |
retrust_window_us | 10 s | integrity.rs:34 · plan default | configured | |
reanchor_r95_m | 200 m | integrity.rs:35 · plan default | configured | |
spoof_clear_fraction | 0.5 | integrity.rs:36 · D-58 | configured | |
posvel_tau_s | 2.0 s | config.rs:46 · plan default | configured | |
Fit: 22 logs, 0.52 h of healthy SITL; rule suspect = max(healthy ceiling × 1.25, default), reject = 2 × suspect; 0 false alarms per hour on the fit set (D-55). 0.52 h cannot show the 0.1/h target (needs about 30 alarm-free hours), and one live clean flight still left TRUSTED once at 34.9 s with no cause found (D-55).
The guard's d is the square root of a 2-DOF NIS. Thresholds of 12 and 24 are far above the χ²₂ 95% point (√5.991 = 2.45): they were set from SITL noise, not from a probability.
7. Hand-off to the autopilot
Pathfinder's answer is sent to ArduPilot, which keeps flying the mission with it.
| Mode | What is sent | Constants | Set by |
|---|---|---|---|
--output odometry (default) | MAVLink ODOMETRY, body-FRD velocity, pose covariance; EKF3 switches to source set 2 (external nav) | z variance 1 m², angle 0.01 rad² configured; set 2 acked 0.57 s after loss measured (sim) | D-52, D-55 |
--output gps-input | MAVLink GPS_INPUT as a second GPS receiver at 10 Hz; pathfinderd writes GPS_PRIMARY 1 when it stops trusting GPS | horiz_accuracy = r95 / 2.4477 (= √5.991, so one-sigma); vert 1 m, speed 1 m/s, 6 sats placeholder configured; switch 0.5 s after loss measured (sim) | D-65, R-3 |
8. ArduPilot alone
The drone's own autopilot with no Pathfinder: the baseline to beat. ArduPilot's EKF3 left to continue without GPS.
Run type b1, harness name B1_EKF3_FAILSAFES_OFF. On heldout-jam-1000: 865 / 1,233 / 2,365 m at 1 / 2 / 5 min measured (sim), n = 1 (findings page).
9. Every constant, one table
Sorted by what it changes. "Weight input" marks the numbers that feed K through R or Q.
| Constant | Value | Unit | Kind | file:line | D-entry | Tag |
|---|---|---|---|---|---|---|
| gravity | 9.80665 | m/s² | physics | eskf.rs:12 | standard | configured |
| drag k (quad) | 0.2541 | 1/s | physics | drag.rs:19 | D-58 | measured (sim) |
| drag k_quad (quad) | 0.0341 | 1/m | physics | drag.rs:20 | D-58 | measured (sim) |
| accel_noise | 0.35 | m/s/√s | weight input (Q) | eskf.rs:32 | none (plan) | configured |
| gyro_noise | 0.015 | rad/√s | weight input (Q) | eskf.rs:33 | none (plan) | configured |
| accel_bias_walk | 0.003 | m/s²/√s | weight input (Q) | eskf.rs:34 | none (plan) | configured |
| gyro_bias_walk | 0.001 | rad/s/√s | weight input (Q) | eskf.rs:35 | none (plan) | configured |
| wind_walk | 0.05 | m/s/√s | weight input (Q) | eskf.rs:36 | D-58, D-63 | measured (sim) |
| wind_walk_denied | 0.05 | m/s/√s | weight input (Q) | eskf.rs:37 | D-63 | measured (sim) |
| drag sigma_mss | 0.5 | m/s² | weight input (R) | drag.rs:21 | none | configured |
| baro_sigma_m | 1.0 | m | weight input (R) | config.rs:42 | none (plan) | configured |
| mag_sigma_rad | 0.08 | rad | weight input (R) | config.rs:41 | none (plan) | configured |
| gps_vel_sigma_mps | 0.3 | m/s | weight input (R) | config.rs:43 | none (plan) | configured |
| learned_var_floor | 22.9 | (m/s)² | weight input (R) | config.rs:47 | D-62 (D-60 had 1.0) | measured (sim) |
| learned_var_scale | 0 | – | weight input (R) | config.rs:48 | D-62 | configured |
| learned_corr_time_s | 14.7 | s | weight input (R) | config.rs:49 | D-62 | measured (sim) |
| learned_stride_s | 0.1 | s | rate | config.rs:50 | D-53 | configured |
| learned_gate_nis | 11.34 | χ²₃ | gate | config.rs:51 | D-62 | configured |
| drag_period_s | 0.1 | s | rate | config.rs:44 | D-58 | configured |
| max_imu_dt_s | 0.05 | s | integration step | config.rs:45 | D-58 | configured |
| χ²₂ 95% | 5.991 | – | r95 radius | navigator.rs:11 | standard | configured |
| guard thresholds | see section 6 | |||||
| initial sigmas | see section 3.3 | |||||
| adapter constants | see section 4.2 | |||||
Count: of the 15 weight inputs above, 4 are measured (sim) and 11 are typed-in starting values that no D-entry has tuned estimate, by this table. Those 11 are where "standardize the weights" has real work to do.
10. Standard naming and units (use from now on)
10.1 System names
| Say | Never say | Run type · harness |
|---|---|---|
| Position Estimator | "the filter", "B2" in prose for owners | b2 · B2_FILTER_DRAG |
| Velocity Predictor | "the model", "ML", "the head" without the name | models/velocity-long.onnx · learned.rs |
| Navigator | "full", "Pathfinder" alone | full · PATHFINDER_FULL |
| ArduPilot alone | "stock", "EKF3" in prose for owners | b1 · B1_EKF3_FAILSAFES_OFF |
| GPS Integrity Monitor | "integrity", "the checker" | integrity.rs · GpsIntegrity |
| hand-off | "output", "feed" alone | --output odometry | gps-input |
10.2 Filter vocabulary
| Concept | Symbol | Name in docs | Code today | Unit |
|---|---|---|---|---|
| what the filter believes | x | state | Eskf.{p,v,q,bg,ba,wind} | per state |
| how unsure it is | P | covariance | cov | unit² |
| uncertainty added per second | Q, σ | process noise (density) | NoiseConfig | unit/√s |
| how unsure a sensor is | R, σ | measurement noise | Meas.r, *_sigma_* | sensor unit (σ), unit² (R) |
| sensor minus prediction | y | innovation | Meas.y | sensor unit |
| the fusion weight | K | Kalman gain | k in apply | state unit / sensor unit |
| surprise of one sample | NIS | normalised innovation squared | nis, learned_gate_nis | χ², with its DOF |
| GPS surprise distance | d | GPS Mahalanobis distance | divergence | σ (dimensionless) |
| 95% error radius | r95 | r95 | r95_m | m |
| correlated-error factor | c | correlation inflation | inflation | – |
10.3 Rules
- SI units, unit in the name.
_m,_mps,_mss,_rad,_rads,_s,_us(integer microseconds for timestamps),_hz. A variance says so:_varwith unit² in the doc comment. - One-sigma by default. A number called sigma is one standard deviation. A 95% number is called
r95or carries95in its name. - Noise densities are written per √s and enter
Qasσ²·dt. Random walks (bias, wind) use the suffix_walk. - Frames are named: NED (world, north-east-down), body FRD (forward-right-down), heading (body with roll and pitch removed). Vectors carry the frame:
vel_ned,accel_body,mean_heading. - "Weight" without a qualifier is banned in docs. Write Kalman gain, network parameters, or adapter layer (section 1).
- Every new constant lands with a tag (measured (sim) / estimate / configured) in its doc comment and a D-entry, and this page's table gets a row.
- A gate names its distribution and DOF: "NIS gate χ²₃ 99% = 11.34", never a bare "gate 11".
Code renames are not part of this page (read-only on code). Two names to change when the files are next touched: divergence → gps_mahalanobis (it is a distance, not a rate), and learned_var_floor → learned_var_base (with scale 0 it is the whole R, not a floor).
11. Glossary, A-Z
Every term, acronym and code name used in docs/ (swept 11 Oct 2026 across the .md and .html files). Terms marked PROPOSED are candidates from section 0, not yet chosen.
- AC, acceptance test
- A locked pass/fail test the owner approved. AC-1 "Mission continues", AC-2 "Less drift" (Navigator beats B2), AC-3 "Honest radius", AC-4 "Spoofing rejected", AC-5 "GPS return", AC-6 "Vehicle profile", AC-7 "In-flight calibration helps", AC-8 cross-platform build on four targets, AC-9 "Deterministic".
- Predictor Adapter
- The per-drone re-fit of the network's last layer by RLS while GPS is trusted (D-37, D-53). Proposed: in-flight calibration PROPOSED.
- AHRS
- Attitude and heading reference system: the autopilot's own roll, pitch and yaw estimate, sent as MAVLink ATTITUDE. Velocity Predictor's input attitude (D-57).
- Air velocity
- Ground velocity minus wind. What Velocity Predictor predicts (D-62).
- ArduPilot, ArduCopter
- The open-source autopilot Pathfinder targets; version Copter-4.6.3 in SITL.
- ArduPilot alone
- Run type
b1: EKF3 continuing without GPS, failsafes off. Proposed: ArduPilot baseline PROPOSED. - AUTO, LAND, RTL, LOITER, GUIDED
- ArduCopter flight modes: fly the mission, land, return to launch, hold position, follow commands. "Stayed AUTO" means no failsafe interrupted the mission.
- B0
- Baseline run type
b0_raw_imu: raw IMU integration after loss with no corrections. - B1
- See ArduPilot alone (
B1_EKF3_FAILSAFES_OFF). - B2
- See Position Estimator (
B2_FILTER_DRAG). - Barometer (baro)
- Air-pressure altimeter; gives height, σ 1.0 m in the filter.
- Bias
- A slowly changing offset in a sensor reading (gyro bias, accelerometer bias), estimated as a state.
- BIN log, DataFlash
- ArduPilot's onboard binary log. Message names used here: IMU, BARO, MAG, GPS, GPA, SIM, SIM2, POS, MODE, PARM, ERR, CMD, ATT, RCOU, XKF1, ORGN.
- Canonical log
- A flight converted to the repo's parquet tables (imu, gps, truth, ekf, events, att, rcou); the input to replay, training and scoring.
- CEP
- Circular error probable, the 50% radius. Not used here; r95 is the 95% radius.
- χ² (chi-square)
- The distribution of NIS for an honest filter; its percentiles set gates. χ²₂ 95% = 5.991, χ²₃ 99% = 11.34.
- CNN, TCN
- Convolutional network; temporal convolutional network, the causal 1-D CNN that Velocity Predictor uses (D-27, D-53).
- COMMAND_ACK, HEARTBEAT, PARAM_VALUE, PARAM_SET, PARAM_REQUEST_READ
- MAVLink control messages: command acknowledgement, keep-alive, parameter read and write.
- Compass (mag)
- Magnetometer; gives heading after tilt compensation and declination, σ 0.08 rad, fused at 10 Hz (D-61).
- Correlation time (τ)
- How long an error persists. Velocity Predictor's: 14.7 s (D-62).
- Covariance (P)
- The filter's estimate of its own error. Proposed: estimate uncertainty PROPOSED.
- Coverage
- Share of samples whose true error was inside r95. Honest is about 95%; AC-3 checks it.
- D-entry
- A numbered decision in
docs/01-decisions.md, with what was asked, chosen and measured. - Dead reckoning
- Navigating from known speed, heading and time with no position fix.
- Declination
- Angle between magnetic and true north; from
COMPASS_DEC(D-58). - Divergence
- Code name for the GPS Mahalanobis distance. Proposed: GPS surprise distance PROPOSED.
- DNAV-n
- Task ids of this project: DNAV-1 "GPS-denied navigation", DNAV-4 "Team brief", DNAV-6 "Pitch deck", DNAV-8 "Production phases and future upgrades".
- DOF
- Degrees of freedom: the number of components in a measurement, which picks the χ² row.
- Domain randomisation
- Training on simulated flights with randomised drone, wind and sensor settings so the network does not overfit one simulator setup (D-36).
- Drag model
- Body-axis law −k·u − k_quad·u|u| fused as a measurement of airspeed (D-58). Proposed: drag aiding PROPOSED.
- Drift
- Growth of position error after GPS loss. Proposed: error at t+N s PROPOSED.
- EKF, EKF3
- Extended Kalman filter; EKF3 is ArduPilot's navigation filter, run as several cores ("lanes").
- Error state
- The small correction the ESKF estimates on top of its believed (nominal) state.
- ESC, RPM
- Electronic speed controller of each motor; its telemetry can report motor RPM (not a model input yet, D-57).
- ESKF
- Error-state Kalman filter; the engine of Position Estimator (D-38).
- EUDIS
- EUDIS Defence Hackathon 2026, Cyprus Edition, 15-17 Oct 2026, Nicosia: the event this work is built for.
- External nav (ExtNav), source set
- EKF3's input for an outside position source; source set 2 is switched to when GPS is lost in hand-off Mode A.
- Failsafe
- An autopilot reaction to a fault (e.g. "EKF variance" LAND). B1 runs with failsafes off so it keeps flying.
- FDE
- Fault detection and exclusion: spotting a bad sensor and cutting it out. What the GPS Integrity Monitor does.
- FRAME_CLASS
- ArduCopter parameter for quad, hexa or octa; read for the vehicle profile (D-64).
- FRD, NED
- Frames: body forward-right-down; world north-east-down.
- GCS
- Ground control station.
- GNSS, GPS
- Satellite positioning in general; GPS is the US system and the word used throughout.
- GPS Integrity Monitor
- TRUSTED / SUSPECT / REJECTED state machine on every GPS fix (
integrity.rs). Keep, or GPS integrity monitor PROPOSED. - GPS_INPUT, GPS2, GPS_PRIMARY, GPS_TYPE 14
- Hand-off Mode B: Pathfinder as a second GPS receiver, and the parameter that tells ArduPilot which receiver to use (D-65).
- GPS_RAW_INT
- MAVLink message with the autopilot's raw GPS fix; Pathfinder's GPS source.
- Hand-off
- How Pathfinder's estimate reaches the autopilot: Mode A ODOMETRY, Mode B GPS_INPUT PROPOSED names.
- Heading frame
- Body frame with roll and pitch removed, yaw kept as the world heading; the network's frame.
- Held-out flight
- A SITL flight never used for training or tuning (seeds 1000-1999, D-46), e.g. heldout-jam-1000.
- HIGHRES_IMU, SCALED_IMU, RAW_IMU
- MAVLink IMU messages; Pathfinder reads HIGHRES_IMU at 200 Hz.
- IMU
- Inertial measurement unit: gyroscope plus accelerometer.
- Innovation (y)
- Measurement minus prediction. Proposed: sensor surprise PROPOSED.
- INS
- Inertial navigation system: position from integrated IMU readings.
- Integrity
- Code name for the GPS Integrity Monitor.
- Jamming
- Drowning GPS signals so the receiver loses its fix (
SIM_GPS1_JAMin SITL). - Joseph form
- A numerically safe way of writing the covariance update (eskf.rs:194).
- Kalman gain (K)
- The share of a disagreement the filter accepts. Proposed: trust share PROPOSED.
- Lab, scenario lab
sim/lab.sh: flies one scenario with chosen run types and knobs (docs/LAB.md).- Last layer
- The final linear layer of the network,
[W|b]3 x 65, the only part the Predictor Adapter changes. - Locked test
- An AC committed red and protected; thresholds change only with the owner (D-39).
- M0-M4
- Original milestones in the MVP design spec, replaced by
PLAN.md. M-1 is the IMU-rate measurement (D-51). - Mahalanobis distance
- Distance in sigmas; √NIS.
- MAVLink
- The message protocol between autopilot, companion computer and ground station.
- Measurement
- Any reading compared against the filter's prediction.
- Measurement noise (R)
- How unreliable we declare a sensor. Proposed: sensor noise setting PROPOSED.
- ML, RL
- Machine learning; reinforcement learning (considered, not used: the Predictor Adapter is supervised).
- MVP
- Minimum viable product: the hackathon scope.
- Night mode, night wave
- Unattended overnight work in waves of agents; D-entries from those runs say "night wave n".
- NIS, NIS gate
- Normalised innovation squared yᵀS⁻¹y, and the rule that rejects readings above a χ² percentile. Proposed: surprise gate PROPOSED.
- ODOMETRY
- MAVLink message for an external position and velocity; hand-off Mode A (D-52, D-55).
- ONNX, tract
- The portable network file format; tract is the pure-Rust runtime that runs it onboard (D-53).
- Optical flow, VIO, SLAM, TRN
- Other aiding sources Pathfinder must accept later (R-2): camera ground motion, visual-inertial odometry, mapping and localisation, terrain-referenced navigation.
- Parked
- Work stopped on purpose with the reason written down, e.g. AC-01/03/04 parked in D-61.
- Particle filter, UKF
- Alternative fusion filters the estimator interface leaves room for (D-38).
- Position Estimator
- The ESKF with drag, compass and barometer; run type
b2. Proposed: Pathfinder-Inertial PROPOSED. - Velocity Predictor
- The velocity network
models/velocity-long.onnx. Proposed: Pathfinder-Neural PROPOSED. - Navigator
- Position Estimator plus the network's velocity; run type
full,PATHFINDER_FULL. Proposed: Pathfinder-Hybrid PROPOSED. - pathfinderd, companion computer
- The Pathfinder daemon, running on a computer next to the autopilot (Raspberry Pi 5 class).
- Process noise (Q)
- Doubt added per second for an imperfect motion model. Proposed: model slack PROPOSED.
- PX4
- The other major open-source autopilot; Mode B should work with it, untested (D-65).
- r95
- The 95% horizontal radius. Proposed: 95% radius PROPOSED.
- R-n
- Owner requirements: R-1 "Mission requirement, clarified by the owner", R-2 "Works with VIO, SLAM, optical flow and TRN", R-3 feed Pathfinder as a GPS replacement.
- Random walk
- A state assumed to drift without direction (biases, wind).
- Re-anchor, re-trust
- After GPS returns: re-trust = let GPS back in after 10 s of consistent fixes; re-anchor = snap position to GPS when r95 has grown past 200 m.
- RLS
- Recursive least squares; the Predictor Adapter's update rule.
- RMS, RMSE, P50, P90, P95
- Root mean square (error); the median and 90th/95th percentile of a set of errors.
- RTS smoother
- Rauch-Tung-Striebel smoother: corrects the past track once GPS returns (AC-5, D-64).
- Run type
- Which system a flight runs: b0, b1, b2, full, gps_ok, jam_no_pathfinder_stock.
- Sensor profile, vehicle profile
- Named sets of sensor noise for training (D-36); frame, motor count and IMU ids read from the autopilot (AC-6, D-64).
- SERVO_OUTPUT_RAW, RCOU
- Motor output commands (PWM), MAVLink and log names; Velocity Predictor's motor inputs.
- SITL
- Software in the loop: ArduPilot's simulator, the source of every "measured (sim)" number.
- Speedup
- SITL running faster than real time (e.g. 10x).
- Spoofing
- Fake GPS signals that move the reported position; the GPS Integrity Monitor rejects them (AC-4).
- State
- What the filter believes: 17 numbers (section 3.1).
- Stride, window
- Network timing: one guess every 0.1 s, from the last 1 s (50 samples).
- TLIO
- Tight learned inertial odometry, the published method Velocity Predictor follows.
- Truth
- SITL's true vehicle state, used only for scoring and labels, never onboard.
- TRUSTED, SUSPECT, REJECTED
- The GPS Integrity Monitor's three states.
- UNVERIFIED
- A fact in a plan not yet checked against source; later D-entries replace it with checked values.
- USRL
- The Systems Research Laboratory of the Cyprus Institute that runs the Orounda test site (full name as in 04-event-brief.md).
- Variance head
- The network's own error estimate (D-35); off today, about 2,000x overconfident (D-62).
- Wind state, wind walk
- The two wind states and their random-walk density, 0.05 m/s/√s (D-58, D-63).
- WSL
- Windows Subsystem for Linux, where SITL runs on the dev PC.
- XKF1, ORGN, POS
- DataFlash messages: EKF3 core position, its origin, and the autopilot's position; used to score B1.
12. Open points found while writing this
- D-62 says the inflation is 295x and Velocity Predictor gives "one sample every 15 s"; the code computes 294x (navigator.rs:299), which is one independent sample per 2τ = 29.4 s. Either the D-entry wording or the factor 2 should be corrected.
- The Velocity Predictor NIS gate (11.34) cannot fire while R = 6,733 (m/s)² (section 5.2, step 5). It protects nothing today.
- Drag R (0.5 m/s²) is about 6x the measured fit residual (0.083 m/s²) and has no D-entry. It sets how fast Position Estimator's
P_airgrows, and so how fast Velocity Predictor's share grows. D-63 already names it as the next lever. - Eleven weight inputs are plan defaults with no tuning record (section 9).
models/velocity-long.meta.jsonis 0 bytes in this checkout, thoughModelMeta::from_jsonneeds it to load the model (learned.rs:72-77). Check before the next Navigator run.- All Navigator numbers on this page come from one flight. AC-2 "Less drift" needs the full held-out set (20+ flights).