Skip to content

routedQErrArm: per-edge chi2 router for the TICC arm (flag, default off)#79

Open
bobvan wants to merge 1 commit into
mainfrom
bravo/routed-qerr-arm
Open

routedQErrArm: per-edge chi2 router for the TICC arm (flag, default off)#79
bobvan wants to merge 1 commit into
mainfrom
bravo/routed-qerr-arm

Conversation

@bobvan
Copy link
Copy Markdown
Owner

@bobvan bobvan commented May 29, 2026

Summary

Implements the agreed routedQErrArm design. Each TICC edge routes (priority-ordered) to one of three candidates based on chi²; first to pass the gate wins:

Candidate model H R
external z = ticc_diff + ext_qerr, h = −x[2] [0,0,−1,0] R_base
internal h = −x[2] − qerr(x[0]) (today) [−1,0,−1,0] R_base + R_lin
raw h = −x[2] [0,0,−1,0] R_base + tick²/12

chi² is the correlation-quality detector: a mis-correlated external qErr is wrong by ~a tick = conspicuous outlier vs the small external R → falls through to raw. An F10T's uncorrelated qErr always fails → routes to raw, no per-receiver flag.

Design points (from the dayplan review)

  • Priority-ordered, not argmin-chi²: raw has the largest R so it would always win a min-chi² contest. External is tried first (most informative) and accepted only if consistent.
  • Raw R = sawtooth variance (tick²/12 = 5.33 ns²), not the worst-case half-tick (impl-flag-1).
  • Reuses the existing recv_mono matching (qVIR=165x) — qerr_for_ticc_pps_ns is already computed at the servo epoch; this just delivers it to Arm 4 (impl-flag-2).
  • External uses H=[0,0,−1,0] — clean x[2]-only update, no x[0] coupling (matters on --no-ppp-arm where x[0] is loose).

Coupling note

Tick discrimination needs the honest small Q from qFromCharPerActuator. With the 0.92 ns default, Q re-inflates P[2,2] to σ≈0.93 ns each predict, where a full-tick (8 ns) mismatch is only ~8.6σ (χ²≈74 < 100) and would be wrongly accepted. The router operates in the char-Q regime — documented in the tests.

Test coverage (7 new, 1245 total)

  • well-correlated external fires; mis-correlated (tick-off) falls through; no-external → internal/raw; F10T random qErr → mostly raw; disabled → always internal; raw R = sawtooth variance; external doesn't couple x[0].

Test plan

  • 1245/1245 pass; default-off byte-identical
  • Closed-loop A/B in Charlie's closedLoopServoSim (PiFace clean-correlation + MadHat F10T auto-reject)
  • Lab A/B on PiFace + MadHat after the sim validates

🤖 Generated with Claude Code

Each TICC edge routes (priority-ordered) to ONE of three candidates,
first to pass the chi2 gate wins:

  external — z = ticc_diff + ext_qerr, h = -x[2], H=[0,0,-1,0],
             R = R_base.  Most informative: clean x[2]-only update,
             no x[0] coupling.  The receiver's TIM-TP sub-tick report
             replaces the filter's qerr(x[0]) estimate.
  internal — today's behavior: h = -x[2] - qerr(x[0]), coupled
             H=[-1,0,-1,0], R = R_base + R_lin.
  raw      — h = -x[2], H=[0,0,-1,0], R = R_base + tick^2/12
             (sawtooth variance, NOT the worst-case half-tick).
             The always-accepted robust floor.

chi2 is the correlation-quality detector: a mis-correlated external
qErr is wrong by ~a tick = a conspicuous chi2 outlier vs the small
external R, so it falls through to raw.  An F10T's uncorrelated qErr
always fails -> routes to raw, with no per-receiver flag.

Priority-ordered (not argmin-chi2): raw has the largest R so it would
always win a min-chi2 contest; instead external is tried first (most
informative) and accepted only if consistent.

The per-edge external qErr (qerr_for_ticc_pps_ns from the existing
recv_mono matching, qVIR=165x) is already computed at the servo
epoch; this just delivers it to Arm 4 behind --routed-qerr-arm.

COUPLING NOTE: tick discrimination needs the honest small Q (from
qFromCharPerActuator).  With the 0.92 ns default, Q re-inflates
P[2,2] to sigma~0.93 ns each predict, where a full-tick (8 ns)
mismatch is only ~8.6sigma (chi2~74 < 100) and would be wrongly
accepted.  The router operates in the char-Q regime.

last_ticc_route ('ext'/'int'/'raw') exposed for observability.
7 new tests, 1245 total pass.  Default off — byte-identical when
--routed-qerr-arm absent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant