Diverse Monitor Techniques in Functional Safety

31 August 2025 · Dr. Michel Houtermans · 7 min read

A diverse monitor is an independently specified and implemented supervisory function that checks a main controller against simple safety invariants — on the same computer. It can block unsafe commands and force a safe state, providing a credible independent safeguard for SIL 2–4 applications under IEC 61508.

What is a diverse monitor?

A diverse monitor continuously checks a main (monitored) function against simple, safety-oriented rules — invariants. Unlike the main controller, it derives from a distinct specification and is realised using a different language, toolchain, and runtime partition.

The monitor does not prove full correctness. Instead, it ensures the system does not enter or remain in an unsafe state and, when needed, actively enforces a safe reaction.

How it supports functional safety

The technique targets systematic failures in requirements, design, and implementation by adding an independently specified checker that validates outputs, timing, and key assumptions.

Because it observes real data and time, it can also detect manifestations of random or common-cause hardware faults (e.g. stuck outputs, clock drift) and prevent unsafe propagation. The monitor must have authority to inhibit or override the main function so the safety function never silently acts on unsafe or corrupted information.

The key question is: what makes this monitor diverse — and does it have the authority to enforce a safe state independently?

When to use

  • SIL 2–4 software where residual specification or implementation faults in the controller are credible and consequences are severe
  • Complex or novel control algorithms that are hard to verify exhaustively, where independence is required but a second computer is impractical
  • When timing integrity matters (e.g. rate limits, watchdog windows) and you need an independent time base plus a decisive safe reaction path

Inputs and outputs

Inputs

  • Candidate setpoints or key internal states from the main function (one-way, integrity-protected interface)
  • Independent references: timer/clock domain, select sensors (read-only), configuration limits

Outputs

  • Permission gate for actuation (opened per cycle upon successful checks)
  • Safe-state commands (e.g. de-energise, force pump off) and diagnostic flags/events

Procedure

  1. Define safety invariants. Translate hazards into bounds, temporal guards (rates, timeouts), and plausibility checks that are distinct from the control law.
  2. Engineer independence. Separate specification. Different implementation approach (e.g. C monitor vs. C++ controller). Diverse toolchains. Memory/MPU partitioning. Independent timer/clock.
  3. Design the authority path. Give the monitor exclusive control of a permission gate and/or the final safety output so it can enforce a safe state regardless of main behaviour.
  4. Harden the interface. One-way main→monitor data with sequence counters and CRC. Avoid callbacks and shared mutable state.
  5. Supervise timing. The monitor owns the windowed watchdog. Loss of monitor activity must drop the system to a safe state.
  6. Verify and validate. Fault-inject specification and timing errors. Demonstrate independence (build/report evidence). Prove deterministic safe reactions.
Be ready to answer "What makes this monitor diverse?" — show distinct spec, language/toolchain, memory/timing isolation, one-way interface integrity, and exclusive authority over the safe output.

Worked example — chemical dosing controller

A chemical dosing controller computes a pump flow setpoint. A diverse monitor (independent spec) checks: (1) absolute flow bound, (2) ramp rate per 10 ms, (3) commanded vs measured plausibility, and (4) interface integrity. The monitor alone can open a per-cycle gate to actuate; otherwise it forces the pump off.

Code-level example

// --- pump_controller.cpp (C++, Toolchain A) ---
// Publishes candidate setpoints only; does not actuate without a gate.
struct Candidate { uint32_t seq; float cmd; uint32_t crc32; };

void PumpControllerTask() {
    static uint32_t seq = 0;
    for (;;) {
        float demand = IO::readDemand();
        float temp   = IO::readTemperature();
        float cmd    = compute_command(demand, temp);  // complex control law

        Candidate f{ ++seq, cmd, 0 };
        f.crc32 = crc32(&f, sizeof(f) - sizeof(f.crc32));
        MonitorIF::publish(f);                // one-way to monitor
        if (MonitorIF::gate_open_once()) {
            IO::setPumpFlow(cmd);             // actuate only if gate opened
        }
        rtos::delay_ms(10);
    }
}

// --- safety_monitor.c (C, Toolchain B) ---
// Independent spec: invariants + temporal guards; owns watchdog & safety output.
typedef struct { uint32_t seq; float cmd; uint32_t crc32; } candidate_t;
#define MAX_SAFE_FLOW   100.0f
#define MAX_RAMP_PER10   10.0f   // mg/s per 10 ms window
static float    last_cmd = 0.0f;
static uint32_t last_seq = 0;

void SafetyMonitorTask(void) {
    lptim_start();                    // independent clock domain
    wdt_config_windowed();            // only the monitor services the watchdog

    for (;;) {
        candidate_t f;
        if (MonitorIF_try_read(&f)) {
            // Integrity: sequence & CRC
            if (!crc_ok(&f, sizeof(f)) || f.seq <= last_seq) {
                MonitorIF_close_gate();
                IO_forcePumpOff();    // SAFE REACTION: invalid frame
                Log_warn("SM: integrity fail");
                continue;
            }

            uint32_t dt = lptim_elapsed_ms();
            float max_step = (MAX_RAMP_PER10 * (dt / 10.0f));

            // Invariant 1: absolute bound
            if (f.cmd > MAX_SAFE_FLOW) {
                MonitorIF_close_gate();
                IO_forcePumpOff();    // SAFE REACTION: bound violated
                Log_warn("SM: abs bound");
                continue;
            }

            // Invariant 2: rate limit
            if ((f.cmd - last_cmd) > max_step) {
                MonitorIF_close_gate();
                IO_forcePumpOff();    // SAFE REACTION: ramp exceeded
                Log_warn("SM: ramp");
                continue;
            }

            // Invariant 3: plausibility vs. measured flow (read-only)
            float pv = IO_readMeasuredFlow();
            if (f.cmd > 0 && pv <= 0) {
                MonitorIF_close_gate();
                IO_forcePumpOff();    // SAFE REACTION: cmd/pv mismatch
                Log_warn("SM: plausibility");
                continue;
            }

            // All checks passed: open gate for this cycle only
            MonitorIF_pulse_gate();
            last_cmd = f.cmd;
            last_seq = f.seq;
            wdt_kick();              // only the monitor kicks the watchdog
        }

        lptim_delay_ms(10);
    }
}

// --- boot_platform.c (conceptual) ---
// MPU/ownership: monitor has exclusive write access to safety output.
mpu_allow_write(SAFETY_DO_BASE, SAFETY_DO_SIZE, TASK_SAFETY_MONITOR);
mpu_deny_write (SAFETY_DO_BASE, SAFETY_DO_SIZE, TASK_MAIN_CTRL);
// Hardware wiring: SAFE_OFF line is driven only by monitor context.
// If monitor stalls and WDT expires -> hardware drops to safe.

Result: Even if the main controller has a systematic fault, unsafe commands are blocked. Timing anomalies or interface corruption trigger a deterministic safe reaction (pump de-energised).

Quality criteria

  • Independence evidence: Distinct specification; different language/toolchain; separate memory, stacks, and RTOS tasking; independent time base.
  • Authority: Monitor controls a permission gate and/or exclusive safety output path that the main function cannot override.
  • Simplicity: Monitor logic limited to clear invariants and temporal guards; easy to test and justify.
  • Interface integrity: One-way data flow with sequence counters and CRC; no shared mutable state.
  • Deterministic reactions: Safe reaction defined, implemented, and verified — including watchdog ownership by the monitor.

Common pitfalls

Hidden coupling

Shared libraries, callbacks, or global variables silently undermine the independence claim.

Mitigation: Enforce one-way interface. Static linking separation. Code reviews specifically for coupling.

Monitor without authority

The monitor detects problems but has no path to enforce a safe state — the main controller can override it.

Mitigation: Give exclusive ownership of the safety output. Prove it via MPU configuration and wiring diagrams.

Over-complex monitor

The monitor re-implements parts of the controller, defeating the purpose of diversity and simplicity.

Mitigation: Keep to bounds, plausibility, and timing checks. Avoid re-implementing the control law.

No independent time base

The monitor shares the same clock as the main function, so timing faults affect both equally.

Mitigation: Use a separate timer/clock domain and a windowed watchdog serviced only by the monitor.

Frequently asked questions

Does the monitor prove the controller is correct?

No. It ensures the system does not become unsafe. The controller may still be sub-optimal; the monitor's role is to block hazardous behaviour.

Can both functions share an OS?

Yes, if you can prove independence: separate tasks, MPU partitions, one-way interface, and a monitor-owned watchdog and output authority.

Related techniques

  • Diverse monitor on a separate computer — stronger physical independence via separate processor and safety fieldbus
  • Watchdog timer — complements the monitor by enforcing timing integrity and fail-safe recovery

References

  • IEC 61508-3:2010 — Annex A & C.3.4
  • Peters & Parnas (2002) — "Requirements-Based Monitors for Real-Time Systems," IEEE TSE
  • ISO 26262 — Road Vehicles — Functional Safety, Part 6 & Part 10

Go deeper — IEC 61508 Certification Course

Our IEC 61508 course covers software safety techniques, diverse redundancy, fault tolerance design, and safety case preparation — for engineers building safety-related systems.

Explore the course → Ask us a question
We use cookies
Cookie preferences
Below you may find information about the purposes for which we and our partners use cookies and process data. You can exercise your preferences for processing, and/or see details on our partners' websites.
Analytical cookies Disable all
Functional cookies
Other cookies
We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. Learn more about our cookie policy.
Accept all Decline all Change preferences
Cookies