An ISO 26262 functional-safety monitor for an electronic throttle / torque path — the classic ASIL-D unintended-acceleration safety case — built the full MBD way: requirements → Simulink/Stateflow → generated C → MIL/SIL with structural coverage. It implements the E-Gas three-level concept: Level 2 recomputes a permissible torque independently and limits torque if the actual exceeds it; Level 3 runs a question/answer watchdog that forces a safe state if the computer misbehaves — both reacting inside the FTTI. The console below is a live run of the same logic — inject an over-torque or fail the watchdog and watch it react.
New here? Move the pedal — the teal torque tracks the driver demand and stays under the dashed permissible ceiling. Then inject an over-torque (a stuck/runaway fault): Level 2 limits the torque within the FTTI. Or fail the watchdog: Level 3 cuts to a safe state. Reactions latch — hit Reset (a key-cycle) to recover.
What you're watching: teal is the torque the function path is producing; the dashed line is the independent L2 ceiling. While healthy, the orange command equals the actual. Cross the ceiling and the command is limited; a watchdog timeout drops it to zero — the safe state.
A browser run of the monitor logic (independent permissible-torque L2 with debounce, question/answer watchdog L3, and the latched OK→L2_LIMIT→L3_SAFE supervisor) — the same logic and parameters as the Simulink/Stateflow model in the repo, and as verify_safety_monitor.js. Not the Simulink artifact itself.
Three independent layers guarding one safety goal — no unintended torque. The same logic runs in the console above.
The function (L1) produces a torque request the normal way. The monitor (L2) recomputes the maximum torque the pedal could justify on an independent path and limits torque if the actual exceeds it. The computer check (L3) proves the controller is actually executing via a question/answer watchdog; if it fails, L3 forces the safe state regardless of L1/L2. Both reactions complete inside the fault-tolerant time interval (FTTI).
permissible = pedal/100 · t_max + t_marginL2 ceiling: the most torque the driver could be asking for, recomputed independently of L1, plus a margin for normal transients.
l2_bad = torque_actual > permissible (for l2_cnt samples)L2 test: a debounced comparison — sustained excess beyond the ceiling means unintended torque and triggers limitation.
l3_trip = (missed Q/A answers ≥ wd_cnt)L3 watchdog: the controller must answer the watchdog's question each cycle; too many misses prove the computer is unhealthy.
reaction ≤ FTTI (L2 = 30 ms, L3 = 50 ms ≤ 50 ms)Timing: debounce counts are sized so detection + reaction always complete within the fault-tolerant time interval.
OK →(l2_confirmed) L2_LIMIT →(l3_trip) L3_SAFE · L3 has priority, reactions latchSupervisor: torque limitation handles over-torque; the safe state (zero torque) handles computer faults and overrides L2. Reactions latch until a key-cycle / reset.
Three layers. The inputs (grey, top) are the pedal (an independent acquisition for L2), the L1 function-path torque, and the watchdog answer. The monitor (teal, inside the dashed boundary) is the code-generated unit running at 100 Hz: the L2 permissible-torque check, the L3 watchdog, and the latched Stateflow supervisor. The actuation (grey, bottom) applies the torque limit or fuel cut. The interface is small and explicit: pedal·torque_actual·wd_ok in, state·tq_cmd·safe_state out — the same contract as autosar/SafetyMonitor.arxml.
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_safety_monitor.js — independent of Simulink — and exercised live in the console above.
Latest headless run · verify_safety_monitor.js — REQ-SAF-001…010 all pass.
Interface · 100 Hz (Ts = 10 ms)
| Signal | Dir | Type · Range |
|---|---|---|
pedal | in | single, % · 0 … 100 (L2 independent path) |
torque_actual | in | single, Nm · 0 … 400 (L1 output) |
wd_ok | in | boolean · watchdog answered correctly |
state | out | uint8 · 0 … 2 (OK / L2_LIMIT / L3_SAFE) |
tq_cmd | out | single, Nm · ≤ permissible when limiting |
safe_state | out | boolean · a safety reaction is active |
| ID | Requirement | Verification |
|---|---|---|
| REQ-SAF-001 Functional | L2 computes a permissible torque independently from the pedal; monotonic and bounded. | Analysis · JS |
| REQ-SAF-002 Safety | L2 detects a torque fault when actual exceeds the permissible torque. | MIL · tc_l2 |
| REQ-SAF-003 Safety | On a confirmed L2 fault, limit torque (≤ t_limp) within the FTTI. | MIL · tc_l2 |
| REQ-SAF-004 Robustness | A torque excess shorter than the L2 debounce shall not trigger a reaction. | MIL · tc_l2_glitch |
| REQ-SAF-005 Safety | L3 maintains a question/answer watchdog; a correct answer resets the fail counter. | Analysis |
| REQ-SAF-006 Safety | On watchdog timeout, force the safe state (tq_cmd = 0) within the FTTI, independent of L1/L2. | MIL · tc_l3 |
| REQ-SAF-007 Safety | Safety reactions are latched; recovery requires a reset / key cycle. | MIL · tc_latch |
| REQ-SAF-008 Safety | The L3 safe state has priority over the L2 torque limit (escalation). | MIL · tc_priority |
| REQ-SAF-009 Robustness | Nominal torque ripple within the L2 margin shall not trigger any reaction. | MIL · tc_nominal |
| REQ-SAF-010 Interface | Conform to the interface; outputs in range and tq_cmd ≤ permissible when limiting. | Analysis + all MIL tests |
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.
/* safety_params.h — one parameter set (mirrors matlab/safety_params.m). * Monitor executes at Ts = 0.01 s (100 Hz). */ #define TS 0.01F /* sample time [s] */ #define FTTI 0.05F /* fault-tolerant time interval [s] */ /* Level 2 torque model */ #define T_MAX 300.0F /* max engine torque [Nm] */ #define T_MARGIN 30.0F /* allowance above requested [Nm] */ #define T_LIMP 60.0F /* limited torque in L2 reaction [Nm] */ /* debounce / watchdog (sized so reaction <= FTTI) */ #define L2_CNT 3U /* samples to confirm L2 fault (=30 ms) */ #define WD_CNT 5U /* missed answers to trip L3 (=50 ms) */ /* safety goal: no unintended torque — ASIL D (illustrative) */
/* safety_monitor_step — Level 2 permissible-torque check + Level 3 * question/answer watchdog. Both feed the safe-state supervisor. */ void safety_monitor_step(const SafIn *const in, SafWork *const w) { /* L2 — independent permissible torque (REQ-SAF-001/002) */ const real32_T requested = in->pedal / 100.0F * T_MAX; w->permissible = requested + T_MARGIN; boolean_T l2_bad = in->torque_actual > w->permissible; if (l2_bad) { if (w->l2Cnt < L2_CNT) w->l2Cnt++; } else { w->l2Cnt = 0U; } w->l2_confirmed = (w->l2Cnt >= L2_CNT); /* debounced (REQ-SAF-004) */ /* L3 — question/answer watchdog (REQ-SAF-005/006) */ if (!in->wd_ok) { if (w->wdFail < WD_CNT) w->wdFail++; } else { w->wdFail = 0U; } w->l3_trip = (w->wdFail >= WD_CNT); }
/* safety_supervisor_step — OK->L2_LIMIT->L3_SAFE (Stateflow). * L3 has priority; reactions latch until reset (REQ-SAF-007/008). */ void safety_supervisor_step(const SafIn *const in, SafWork *const w, SafOut *const out) { if (w->l3_trip) { /* highest priority */ w->state = SAF_L3_SAFE; } else if (w->state == SAF_OK && w->l2_confirmed) { w->state = SAF_L2_LIMIT; } /* (no automatic exit — latched until a key-cycle reset) */ switch (w->state) { case SAF_OK: out->tq_cmd = fminf(in->torque_actual, w->permissible); break; case SAF_L2_LIMIT: out->tq_cmd = fminf(in->torque_actual, T_LIMP); break; default: out->tq_cmd = 0.0F; break; } out->state = w->state; out->safe_state = (w->state != SAF_OK); }
/* safety_monitor_types.h — I/O contract (REQ-SAF-010). */ typedef enum { SAF_OK = 0, SAF_L2_LIMIT, SAF_L3_SAFE } SafState; /* 0 … 2 */ typedef struct { real32_T pedal; /* accelerator [%] — independent L2 path */ real32_T torque_actual; /* L1 function-path torque [Nm] */ boolean_T wd_ok; /* watchdog answered correctly */ } SafIn; typedef struct { SafState state; /* OK / L2_LIMIT / L3_SAFE */ real32_T tq_cmd; /* allowed torque [Nm] (<= permissible) */ boolean_T safe_state; /* a safety reaction is active */ } SafOut;
The Simulink model and Stateflow safe-state 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 L2/L3 logic, FTTI budget, and supervisor shown above.
Exercised live above and checked against requirement thresholds in test/test_safety_monitor.m and verify_safety_monitor.js — REQ-SAF-001…010 all pass, including reaction-time vs FTTI, independent of Simulink.
A hand-authored, schema-valid autosar/SafetyMonitor.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.
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.