Project · Powertrain MBD · Diagnostics

Sensor Diagnostic
Monitor

An OBD-style diagnostic monitor for a safety-relevant redundant sensor pair, built the full MBD way: requirements → Simulink/Stateflow model → generated C → MIL/SIL with structural coverage. Three rationality tests (electrical range, signal rate, and cross-channel correlation) feed a debounced fault-confirmation machine — NO_FAULT → PENDING → CONFIRMED → HEALING — that sets a DTC, captures a freeze-frame, drives the MIL, and heals only after a sustained clean run. The panel below is a live, in-browser run of the same logic — inject a fault and watch it confirm, store, and heal.

StateflowOBD / ISO 14229 Embedded CoderMISRA-C MIL / SILMCDC Coverage AUTOSAR SWCIn Progress
Live · Try It

Diagnostic Console

New here? Move the pedal — the two redundant sensors track together and the monitor stays green. Then hit a fault button: a sustained fault walks PENDING → CONFIRMED after a debounce, lights the MIL, and freezes the conditions. A single glitch never trips it. Cold engine? Diagnostics are disabled.

Sensor A · APP1 NORMAL
0 V5 V
Sensor B · APP2 NORMAL
0 V2.5 V
Sensor A (primary) Sensor B (redundant) Fault confirm counter

What you're watching: both sensors read the same pedal in %, so they sit on top of each other when healthy. The orange counter fills as a fault persists; at the confirm threshold the trace turns red — the DTC is stored and the MIL comes on. It stays on until a sustained clean run heals it.

No fault injected

Inject Fault clamps Sensor A to 4.90 V (OOR) — a sustained fault that walks PENDINGCONFIRMED and lights the MIL. Remove enters HEALING.

Inject Spike fires a single-sample +3 V burst — Rate (and Corr) LEDs flash, the counter ticks up by 2 then decays straight back to zero. A glitch never confirms. That is the debounce protection working exactly as designed.

Reset starts fresh.

Range
Rate
Corr
Malfunction Indicator
OFF
Debounce Counter
0 / 20
NO_FAULT
PENDING
CONFIRMED
HEALING
State
NO_FAULT
DTC
Freeze-Frame — not captured
No confirmed fault. The freeze-frame snapshots the operating point at the moment a DTC is confirmed.

A browser run of the diagnostic logic (range / rate / correlation rationality, a shared debounced fail counter, and the NO_FAULT→PENDING→CONFIRMED→HEALING machine) — the same logic and parameters as the Simulink/Stateflow model in the repo, and as verify_diag_logic.js. Not the Simulink artifact itself.

Theory

How It Works

Three rationality tests, one debounced counter, and a four-state machine. The same logic runs in the console above.

Sensor A · B redundant pair Range electrical OOR Rate implausible step Correlation A vs B mismatch Debounce shared fail counter Fault State Machine NO_FAULT · PENDING CONFIRMED · HEALING DTC · freeze-frame · MIL Enable warm-up gate gates counting
Monitor software (code-generated) Sensors & enable inputs

Read it left-to-right: a redundant sensor pair feeds three rationality tests. Any failing test increments one shared debounced counter (but only while the enable gate is open — a warm engine). When the counter reaches the confirm threshold, the state machine latches a CONFIRMED DTC, captures a freeze-frame, and lights the MIL; a sustained clean run then heals it. A single-sample glitch raises the counter by one and it ages straight back to zero — so it never confirms.

range_bad = v1 < v_oor_lo || v1 > v_oor_hi

Range: the primary sensor is electrically out of range (short to ground / battery, open circuit) — outside the band the real pedal travel never reaches.

rate_bad = |v1 − v1_prev| > dv_max

Rate: the signal jumps more than is physically possible in one 10 ms sample — a spike, dropout, or EMI burst.

corr_bad = |pct1 − pct2| > corr_tol

Correlation: the two redundant channels disagree by more than tolerance — catches single-channel drift / stuck where one sensor is still in-range.

failCnt = clamp(failCnt ± 1, 0, confirm_cnt) // only if enabled

Debounce: one shared counter rises on any failing test and decays on clean samples; confirmation needs persistence, so noise ages out.

NO_FAULT →(cnt>0) PENDING →(cnt≥confirm) CONFIRMED →(clean) HEALING →(heal_cnt clean) NO_FAULT

State machine: PENDING is an unconfirmed DTC (MIL off); CONFIRMED stores the DTC + freeze-frame and lights the MIL; HEALING keeps the MIL on until a full clean run clears it (like OBD warm-up cycles).

Design

Architecture

SIGNAL SOURCE · SENSORS & OPERATING POINT APP1 / APP2redundant volts rpm · loadoperating point coolant tempenable gate v1·v2·rpm·load·ect DIAGNOSTIC MONITOR · CODE-GENERATED · EMBEDDED CODER · 100 Hz Rationalityrange · rate · corr Debounceshared fail counter SupervisorStateflow · 4 states DTC + Freezestore · MIL state·dtc·mil·ff_valid CONSUMERS · DTC MEMORY & OBD DTC memory MIL / cluster Scan tool (CDT / OBD)

Three layers. The signal source (grey, top) is the redundant sensor pair plus the operating point and the coolant-temperature enable gate. The monitor (teal, inside the dashed boundary) is the code-generated unit running at 100 Hz: rationality tests, the debounced counter, the Stateflow supervisor, and DTC/freeze-frame storage. The consumers (grey, bottom) are DTC memory, the MIL/cluster, and the off-board scan tool. The interface is small and explicit: v1·v2·rpm·load·ect in, state·dtc·mil·ff_valid out — the same contract as autosar/DiagMonitor.arxml.

Traceability

Requirements

The Verification column lists the planned MIL/SIL methods (run on a personal MATLAB). The monitor logic itself is re-proven headlessly today by verify_diag_logic.js — independent of Simulink — and exercised live in the console above.

200 ms
Confirmation
debounced · 20 samples
0
False trips
on 1-sample glitch
3
Heal cycles
to MIL-off
3
Monitors
range · rate · corr

Latest headless run · verify_diag_logic.js — REQ-DIAG-001…010 all pass.

Interface · 100 Hz (Ts = 10 ms)

SignalDirType · Range
v1insingle, V · 0 … 5 (APP1 primary)
v2insingle, V · 0 … 5 (APP2 redundant)
rpminsingle, rpm · 0 … 7000
loadinsingle, % · 0 … 100
ectinsingle, °C · −40 … 130 (enable)
stateoutuint8 · 0 … 3 (NO_FAULT…HEALING)
dtcoutuint8 · bit0 range, bit1 rate, bit2 corr
miloutboolean · 0 / 1
ff_validoutboolean · freeze-frame captured
IDRequirementVerification
REQ-DIAG-001
Functional
Flag a range fault when the primary sensor is electrically out of range.MIL · tc_range · JS
REQ-DIAG-002
Functional
Flag a rate fault on an implausible step (> dv_max) between samples.MIL · tc_rate · JS
REQ-DIAG-003
Functional
Flag a correlation fault when the redundant channels disagree by > corr_tol.MIL · tc_corr · JS
REQ-DIAG-004
Safety
Confirm a DTC only after confirm_cnt debounced samples; a single-sample glitch never confirms.MIL · tc_confirm, tc_glitch
REQ-DIAG-005
Functional
Report PENDING for an unconfirmed detected fault; MIL stays off.MIL · tc_confirm
REQ-DIAG-006
Functional
Capture a freeze-frame of the operating point and tripping test at confirmation.MIL · tc_confirm
REQ-DIAG-007
Functional
MIL on iff ≥ 1 DTC is confirmed (remains on through HEALING until cleared).MIL · tc_confirm, tc_heal
REQ-DIAG-008
Functional
Heal a confirmed DTC only after heal_cnt consecutive clean samples; archive the DTC and clear the MIL; re-fail re-confirms.MIL · tc_heal
REQ-DIAG-009
Functional
Run tests / accumulate failures only when enable conditions are met; counter frozen otherwise.MIL · tc_enable
REQ-DIAG-010
Interface
Conform to the interface above; outputs stay within declared ranges (state ∈ [0,3], dtc ∈ [0,255]).Analysis + all MIL tests
Production C

Monitor Setup

The deployed monitor and its setup, in MISRA-aligned C — the same logic running in the console above. Embedded Coder produces this from the Simulink/Stateflow model in the repo; shown here in equivalent hand form.

/* diag_params.h — one parameter set (mirrors matlab/diag_params.m).
 * Monitor executes at Ts = 0.01 s (100 Hz). */
#define TS           0.01F   /* sample time [s] */

/* sensor scaling: APP1 0.5..4.5V, APP2 0.25..2.25V over 0..100% */
#define V1_LO        0.5F
#define V1_HI        4.5F
#define V2_LO        0.25F
#define V2_HI        2.25F

/* rationality thresholds */
#define V_OOR_LO     0.20F   /* electrical out-of-range low  [V] */
#define V_OOR_HI     4.80F   /* electrical out-of-range high [V] */
#define DV_MAX       1.50F   /* max plausible step / sample [V] */
#define CORR_TOL     10.0F   /* max |pct1-pct2| mismatch [%] */

/* confirmation / healing / enable */
#define CONFIRM_CNT  20U     /* failing samples to confirm (=200 ms) */
#define HEAL_CNT     300U    /* clean samples to heal (~3 cycles) */
#define WARM_MIN     60.0F   /* coolant temp enabling diagnostics [C] */

/* DTC bitfield: bit0 range, bit1 rate, bit2 correlation */
MBD Artifacts

Build & Verification

Done

Monitor defined as code

The Simulink model and Stateflow fault machine are constructed via the Simulink API in build_model.m — reviewable and diffable in git. Requirements, design, and test plan are in the repo and track the same rationality tests, debounce, and state machine shown above.

Done

Logic verified (browser + reference tests)

Exercised live above and checked against requirement thresholds in test/test_diag_monitor.m and verify_diag_logic.js — REQ-DIAG-001…010 all pass, independent of Simulink.

Done

AUTOSAR Classic SWC description

A hand-authored, schema-valid autosar/DiagMonitor.arxml — ports, sender/receiver interfaces, a 10 ms periodic runnable, and the I/O contract for integrating the monitor as an AUTOSAR Classic software component.

Pending

Simulink/Stateflow diagram + MCDC coverage

The rendered .slx diagram and the decision/condition/MCDC coverage report — produced by running build_model.m / collect_coverage.m on a personal MATLAB. Screenshots will be embedded here.

View Repository → Back to Projects