MOVEdot

Building a Steer-by-Wire System · Chapter 4 · Part 4 of 5

2 msWorst-case margin left
Steer-by-Wire

The noise filter fix

Girish Radhakrishnan
Girish RadhakrishnanJuly 13, 2026 · 7 min read
Steer-by-WireMargin AnalysisSeries

One change from v5 to v6: a noise filter on the drift monitor. All 11 acceptance metrics pass and the golden-run false alarms are gone — but the per-run margin shows slow-drift detection sitting 2 ms from the gate.

Paired diff of 384 runs (1:1 by run_id). Data sources: operator_log.xlsx + _internal/ground_truth_per_run.parquet for v5 and v6. Scored against the 11-metric acceptance_spec_sheet.csv.

  • 11 / 11 acceptance metrics PASS (v6)
  • 4 → 0 golden hs false alarms (of 4 hs runs; 4/12 pooled → 0/12 pooled)
  • 34–67 → 2–17 ms mild-drift-at-hs margin to the 150 ms gate
  • 2 ms worst-case margin remaining (inj_145 / inj_147)

The one change

Chapter 4 (v6) applies a single modification to the Chapter 3 (v5) system: a causal moving-average noise filter (35–45 ms window, per-run manufacturing scatter) on the torque_sensor_drift monitor residual. Its purpose is to remove the false alarms observed in v5 on golden (fault-free) high-speed runs, where road/tire noise in the 5–70 Hz band exceeded the 0.06 N·m drift threshold. No other monitor, plant model, or handover logic changes between v5 and v6. This was verified directly: road-wheel-angle telemetry (RWA_cmd_deg, RWA_achieved_deg) for a sampled handover run (hov_001) is byte-identical between the v5 and v6 raw MF4 files (max abs difference = 0.0 across 6501 samples), confirming the filter touches only the drift detection path.

The paired diff — 384 runs

Each of the 384 runs was scored PASS/FAIL independently for v5 and v6 against its governing gate (self-steer FTTI by operating point, 150 ms commission/handover-omission class, or zero false positives for golden runs), then classified into four buckets.

Paired diff — 384 runsv5 → v6 · 1:1 by run_id
4
Fixed
Failed v5, passes v6
380
Unchanged
Same result both
0
New break
Passed v5, fails v6
0
Still broken
Failed both
All 4 fixed runs are the golden high-speed runs (gld_001–gld_004). No new breaks, no still-broken runs. The diff table is clean across every bucket.

All 4 Fixed runs are the golden high-speed runs (gld_001gld_004). No new breaks, no still-broken runs. The diff table is clean across every bucket.

Full 11-metric verdict (v6)11 pass · 0 fail
MetricEvidence (v6, independently computed)
Diagnostic coverage — pooled (≥ 99%)100.00%pass
Diagnostic coverage — per fault type (≥ 99%)min 100.0%pass
Detection time vs governing FTTI (< gate)all within gatepass
FTTI self-steer — high speed (< 100 ms)max 81 ms vs 100 mspass
FTTI self-steer — urban (< 200 ms)max 15 ms vs 200 mspass
FTTI self-steer — park (< 500 ms)max 15 ms vs 500 mspass
FTTI incorrect steer / assist (< 150 ms)max 148 ms (2 ms margin — see margin analysis)pass
Handover omission (< 150 ms)max 104 mspass
RWA handover deviation (≤ 1.0 deg)unchanged from v5 (telemetry identical, confirmed)pass
False-positive rate (= 0)0/12pass
EOTTI bounded window (≤ 5 s)max 164 ms (gate 5000 ms)pass
RWA handover deviation carries forward unchanged from the v5 result (0/48 fail) because the handover/plant telemetry is byte-identical between versions. Binary verdict: 11 PASS / 0 FAIL.

Binary verdict: 11 PASS / 0 FAIL. Every acceptance gate is met. This is the number that appears in a pass/fail sign-off sheet.

False-alarm confirmation

The false-positive-rate metric is the one that failed in v5 (4/12 golden runs, all high-speed). In v6, all 4 previously-failing golden hs runs now report zero DTC trips.

False-alarm confirmation4/12 → 0/12
Checkv5v6
Golden hs false positives4 / 4 hs runs (4/12 pooled)0 / 4 hs runs (0/12 pooled)
DTC that firedtorque_sensor_driftsilent
Filter addedMoving-average, 35–45 ms window
Golden-run false positives, pooled across all 12 golden runs (4 park + 4 urban + 4 hs). All 4 hits were high-speed in v5; urban and park were already clean in both versions.

Margin analysis — the real story

Binary pass/fail treats every run the same whether it clears its gate by 100 ms or by 2 ms. For every torque_sensor_drift run, margin is computed directly as:

margin = FTTI gate (150 ms) − detection time

Why the added lag scales with speed, not magnitude. A 40 ms moving-average has a fixed group delay of roughly 20 ms. The larger shifts seen here — about 45 ms at high speed versus about 5 ms at park — are not the filter's group delay alone. In v5, high-speed detection was partly noise-assisted: road/tire noise rode on top of the true drift residual and pushed it over the 0.06 N·m threshold earlier than the drift alone would have. The filter removes that noise contribution. Detection therefore reverts to the true drift-only crossing, which occurs later. This is the same mechanism that produced the golden-run false alarms — noise inflating the residual — seen here on real-fault runs. The effect is driven by how much noise is present (operating point), not by fault size, which is why severe, moderate, and mild drift all shift by a similar ~45 ms at high speed while all barely move at park.

Evidence: mean detection-time shift (v6 − v5) by magnitude × op point, recomputed from ch4_drift_margin_table.csv — hs: mild +47.5 ms (range 30–65), moderate +42.5 ms (35–50), severe +47.5 ms (45–50); park: mild +3.75 ms (0–5), moderate +5.0 ms, severe +5.0 ms. The hs shift is essentially uniform across magnitude; the park shift is uniformly small.

Margin by magnitude × operating pointworst case per cell
MagnitudeOpnv5 detect (ms)v6 detect (ms)v5 margin (ms)v6 margin (ms)Mean margin lost
mildhs483–116133–14834–672–1788.5%
mildpark499–103103–10847–5142–477.7%
mildurban494–108109–11842–5632–4124.0%
moderatehs455–6899–11182–9539–5148.0%
moderatepark456–6461–6986–9481–895.6%
moderateurban455–6465–7486–9576–8511.3%
severehs442–4687–96104–10854–6344.6%
severepark439–4544–50105–111100–1064.6%
severeurban438–4248–55108–11295–10210.2%
Highlighted row: mild drift at high speed — the worst-case cell in the matrix. Margin to the 150 ms gate collapses from 34–67 ms to 2–17 ms.

Plotting detection time for every torque_sensor_drift run against the 150 ms gate, the same run connected across versions, the high-speed / mild-magnitude points in v6 sit right against the gate line.

Mild drift at high speed — per-run detail2 ms worst case
RunChannelv5 detect (ms)v6 detect (ms)v5 margin (ms)v6 margin (ms)Margin lost (ms)Margin lost (%)
inj_145ECUA831486726597.0%
inj_146ECUA1161463443088.2%
inj_147ECUB981485225096.2%
inj_148ECUB8813362174572.6%
All four runs still pass the 150 ms gate in v6. Two of them (inj_145, inj_147) do so with only 2 ms to spare — a group of runs sitting at roughly 1–11% of their original headroom.

What the margin analysis shows. All four mild-drift-at-high-speed runs pass the 150 ms gate in v6. Two of them (inj_145, inj_147) do so with only 2 ms to spare. Average margin loss across this cell is 88.5%, versus single-digit-percent margin loss at park and moderate loss at urban/moderate/severe cells.

Verdict

"All tests pass. But the fix that silenced the false alarms left slow-drift detection 2 ms from the limit. Pass/fail said ship. The margin said wait."

The filter delivers exactly what it was built for: false alarms on golden high-speed runs go from 4/12 to 0/12, and all 11 acceptance metrics report PASS. Independently of that binary result, the per-run margin computed here (150 ms gate minus measured detection time) shows that the same filter that removed the false alarms also added detection lag that is felt most by the slowest real fault (mild-magnitude drift) at the noisiest operating point (high speed) — the same condition the filter was tuned against. The worst-case margin for that cell fell from 34 ms in v5 to 2 ms in v6, a group of runs sitting at roughly 1–11% of their original headroom.

The lag is largest at high speed because the filter strips out the noise that had been assisting early detection in v5; mild drift shows the worst margin loss simply because it starts with the least headroom, so the same delay consumes the largest fraction of it.

Chapter 4 (v6) analysis. Data: sbw_ch4/dataset/ (v6) paired 1:1 with sbw_ch3/dataset/ (v5) by run_id. Scoring source: _internal/ground_truth_per_run.parquet + acceptance_spec_sheet.csv (independently recomputed, not read from generation-side manifests).

All data in this series is synthetic, generated to mirror a real steer-by-wire validation program. No customer data is used.


Next in the series: the safety case, where every one of these margins has to be defended in the sign-off. If a green pass/fail sheet is the only thing standing between a fix and a shipped ECU, we would like to talk: founders@movedot.com, or www.movedot.ai.