10 · Project — HIL Test Plan for an ECU Feature¶
This project pulls together every Level 3 module into one deliverable: a real, structured HIL test plan for a single ECU feature, written the way a test lead would actually hand it to a team before rig time is booked. You'll produce the plan, not just talk about what one should contain.
About this module
No physical HIL rig was used to produce or validate this project. The plan template, CAPL sketches, and fault matrix below follow documented HIL/ISO 26262/SOTIF practice from Modules 1–9 — treat the whole deliverable as a template to adapt, not a captured real test campaign.
The feature: Automatic Emergency Braking (AEB), scoped down¶
To keep the project concrete, scope it to one feature and one clear boundary: an AEB ECU that receives a simulated forward-object distance and closing-speed signal (from a radar-simulation HIL plant model) and commands autonomous braking when a collision is imminent and the driver hasn't reacted.
Section 1 — Scope and test levels¶
In scope:
- AEB activation logic under nominal, boundary, and fault conditions
- Closed-loop HIL validation of braking command reaching simulated
vehicle deceleration
- Functional-safety mechanism testing for the two identified safety
goals (see Section 3)
- Known-unsafe (SOTIF Area 2) scenario regression
Out of scope (explicitly, and why):
- Radar perception algorithm accuracy itself (owned by perception
validation team, not signal-level HIL — see Level 3 Module 9)
- Electrical-level fault injection on radar wiring (requires a
breakout box not assumed available for this project — flagged as
a gap, see Section 6)
Stating out-of-scope items explicitly, with reasons, is itself part of professional test-plan writing — it prevents a stakeholder from assuming a gap was an oversight rather than a deliberate, documented boundary.
Section 2 — Requirements traced¶
| Requirement ID | Summary | ASIL |
|---|---|---|
| SW-REQ-201 | AEB shall command full braking within 150ms of a validated imminent-collision condition | ASIL D |
| SW-REQ-202 | AEB shall not activate on implausible or out-of-range distance/speed signals | ASIL D |
| SW-REQ-203 | AEB shall disengage cleanly if the driver applies throttle above a defined threshold (override) | ASIL C |
Every testcase in Section 4 carries one of these IDs in its title, per the Level 3 Module 8 tagging convention.
Section 3 — Safety goals and mechanisms under test¶
| Safety goal | Safety mechanism | Fault(s) to inject |
|---|---|---|
| Avoid failing to brake when collision is imminent | Plausibility check on distance/speed signal pair; redundant timing computation | Signal timeout (Module 6), implausible value jump |
| Avoid unintended/false braking | Confidence threshold on radar-simulated object; driver-override path | Simulated low-confidence noisy object, throttle-override signal |
Section 4 — Representative CAPL testcases¶
testcase tc_AebActivatesWithinSpec()
{
testCaseTitle("[SW-REQ-201] AEB commands full braking within 150ms of imminent collision");
dword t0, t1;
HilSetParameter("ClosingSpeed_kph", 60.0);
HilSetParameter("ForwardDistance_m", 15.0); // set up an imminent-collision geometry
t0 = timeNowNS() / 1000000;
testWaitForSignal(AEB_BrakeCommand, 1, 150);
t1 = timeNowNS() / 1000000;
testStepCheck("brake command issued within 150ms", (t1 - t0) <= 150);
}
testcase tc_AebIgnoresImplausibleDistance()
{
testCaseTitle("[SW-REQ-202] AEB does not activate on an implausible negative distance reading");
HilSetParameter("ForwardDistance_m", -5.0); // physically impossible
testWaitForTimeout(300);
testStepCheck("no brake command on implausible input", getSignal(AEB_BrakeCommand) == 0);
}
testcase tc_AebDisengagesOnDriverOverride()
{
testCaseTitle("[SW-REQ-203] AEB disengages cleanly on driver throttle override above threshold");
HilSetParameter("ClosingSpeed_kph", 60.0);
HilSetParameter("ForwardDistance_m", 15.0);
testWaitForSignal(AEB_BrakeCommand, 1, 150);
setSignal(ThrottlePosition_pct, 40.0); // above the defined override threshold
testWaitForSignal(AEB_BrakeCommand, 0, 500);
testStepCheck("AEB cleanly released control, no residual brake command", getSignal(AEB_BrakeCommand) == 0);
}
Section 5 — Fault injection matrix (Module 6 practice applied)¶
| Signal | Implausible value | Frame timeout | Electrical (needs breakout box) |
|---|---|---|---|
| ForwardDistance_m | Covered — tc_AebIgnoresImplausibleDistance |
Planned, not yet written | Gap — see Section 6 |
| ClosingSpeed_kph | Planned, not yet written | Planned, not yet written | Gap — see Section 6 |
Section 6 — Known gaps and risk acceptance¶
Gap: No breakout-box hardware assumed available for this project, so
electrical-level fault injection (open/short on radar signal lines)
for both ForwardDistance_m and ClosingSpeed_kph is NOT covered by this
plan's test suite.
Risk: For ASIL D requirement SW-REQ-201/202, this is a real coverage
gap against the safety case, not a cosmetic one — electrical faults on
these lines are a plausible real-world failure mode. This must be
explicitly flagged to the safety assessor as an open item, with a
target date for hardware acquisition, rather than silently left out of
the plan.
Naming the gap explicitly — rather than a plan that looks complete because it simply never mentions what it doesn't cover — is the single most professionally important habit this project is meant to practice.
Section 7 — Exit criteria¶
This test plan is considered executed and closeable when:
1. All testcases in Section 4 (and remaining planned ones from
Section 5) have a recorded verdict.
2. Every ASIL D requirement's test cases show a Passed verdict, or
a filed, tracked defect for each Failed one.
3. The Section 6 gap has a documented risk acceptance signed off by
the safety assessor, or the breakout-box testing has been
completed and the gap closed.
Cheat sheet¶
| Section | What it forces you to make explicit |
|---|---|
| Scope / out-of-scope | What this plan does NOT claim to cover, and why |
| Requirements traced | Every testcase ties to a requirement ID and ASIL |
| Safety goals/mechanisms | What specifically each fault-injection testcase is proving |
| Fault matrix | Coverage gaps are visible as empty cells, not silently absent |
| Known gaps | Honest, dated, risk-accepted — never hidden |
| Exit criteria | An unambiguous definition of "done" for the plan itself |
How It Actually Works¶
HilSetParameter doesn't write a CAN frame — it writes a plant-model input.
On a real rig, ForwardDistance_m and ClosingSpeed_kph are not CAN
signals you inject directly; they're inputs to a real-time plant model
(often a Simulink/dSPACE or NI VeriStand model running on the HIL's
real-time target) that itself computes and transmits the radar-object
CAN/Ethernet frames the ECU actually receives. HilSetParameter writes
into that model's parameter memory over the HIL vendor's own backplane
(e.g. XCP-on-Ethernet from the CANoe/CANape PC to the real-time target),
and the model integrates the new value on its next fixed-step tick —
typically 1ms or 5ms. That step time is why testWaitForSignal's 150ms
budget in tc_AebActivatesWithinSpec has to be generous relative to the
ECU's own logic latency: it must absorb at least one plant-model tick of
parameter-propagation delay plus the CAN frame's own transmission and
the ECU's input-debounce/plausibility filtering, none of which is "AEB
decision time" but all of which the wall-clock measurement includes.
testWaitForSignal is a polling primitive, not an interrupt. Under
the hood CAPL's test module runtime re-evaluates the signal's current
value against the target on every CAN/bus event and on a background
timer tick (commonly every 1ms in CANoe's test scheduler), returning as
soon as a match occurs or the ms timeout elapses. This means the
measured t1 - t0 in tc_AebActivatesWithinSpec has an inherent
sampling jitter bounded by that tick rate — a 150ms spec measured this
way effectively has a resolution floor of a few milliseconds, not
true edge-triggered nanosecond precision. A test plan that needs
tighter timing accuracy (e.g. proving 150ms with 5ms margin) needs to
say explicitly which oscilloscope- or logic-analyzer-based measurement
backs it up, because the CAPL-level stopwatch alone can't prove a bound
that tight — this is exactly the kind of measurement-method gap that
belongs in Section 6 next to the electrical fault-injection gap.
Why "implausible negative distance" is a real class of bug, not a
contrived one. ForwardDistance_m = -5.0 in tc_AebIgnoresImplausibleDistance
is testing the ECU's own input plausibility check — a required
mechanism under ISO 26262 for any ASIL D input, because a physical
radar sensor's raw output is an unsigned range-bin measurement; a
negative value can only reach the ECU through a corrupted CAN payload,
a signal encoding/scaling bug in the DBC (e.g. a signed vs. unsigned
mismatch, or a wrong offset in the linear scaling physical =
raw * factor + offset), or the HIL plant model itself being
misconfigured. The safety mechanism this test proves isn't "does AEB
ignore an obviously wrong number" — it's "does the ECU's range/rate
plausibility filter reject a value outside physically possible bounds
before it ever reaches the AEB decision logic," which is the actual
ISO 26262 Table-referenced technique (range checks / plausibility
checks on safety-related inputs) the requirement SW-REQ-202 traces to.
Why the driver-override test checks release, not just activation.
tc_AebDisengagesOnDriverOverride is exercising a specific failure
mode class: safety mechanisms that latch. A naive AEB implementation
that sets a brake-request flag and never re-evaluates the override
condition on every control loop tick will pass an activation-only test
but fail this one, because setSignal(ThrottlePosition_pct, 40.0)
only changes the input — it's the ECU's control loop cycle (typically
10–20ms for a braking-relevant loop) that must re-read the override
signal and clear its own latched brake-request state. A HIL test plan
that stops at "does it activate" and never tests "does it also
correctly de-activate under a competing input" systematically misses
this entire class of stuck-actuator defects, which is why Section 2
explicitly gives override its own ASIL C requirement rather than
folding it into SW-REQ-201.
Exercise¶
- Write the two "Planned, not yet written" testcases from Section 5
(frame timeout on
ClosingSpeed_kph, implausible value on the same signal), following the pattern of Section 4's testcases. tc_AebDisengagesOnDriverOverridedoesn't check how quickly the brake command clears once override begins. Add a timing assertion, propose a reasonable spec value, and add it to Section 2's requirements table with a new requirement ID.- Section 6 names one gap. Identify a second plausible gap in this plan (consider SOTIF Area 3, Level 3 Module 9) that isn't already listed, and write its Section 6 entry in the same style.