5.5.25Embedded Systems & Real-Time Software

Redundancy — TMR (triple modular redundancy), voting logic

2,783 words13 min readdifficulty · medium

Overview

Triple Modular Redundancy (TMR) is a fault-tolerance technique where three identical modules execute the same computation in parallel, and a voter selects the majority output. This masks single-point failures in safety-critical systems like aerospace, medical devices, and autonomous vehicles.

Why TMR matters: A single bit-flip from cosmic radiation or hardware aging can crash a spacecraft computer. TMR ensures that one faulty module cannot compromise the system output.


[!intuition] The Core Idea

Imagine three clocks showing time. If one breaks and shows the wrong time, you can still trust the other two that agree. TMR does the same with computations:

  • Redundancy: Run the same task on 3 independent hardware/software modules
  • Voting: Compare outputs; the majority (2-out-of-3) wins
  • Masking: Hide the faulty module's error from the system

Key insight: TMR trades space (3× hardware) and power (3× computation) for reliability (masks 1 fault). It cannot detect which module failed, only that one disagrees.


[!definition] Formal Definition

A TMR system consists of:

  1. Three identical modules M1,M2,M3M_1, M_2, M_3 computing function f(x)f(x)
  2. A voter VV that applies a majority function: V(y1,y2,y3)=majority(y1,y2,y3)V(y_1, y_2, y_3) = \text{majority}(y_1, y_2, y_3) where yi=Mi(x)y_i = M_i(x) is module ii's output

Assumptions:

  • Modules fail independently (no common-cause failure)
  • Voter is ultra-reliable (often hardened or redundant itself)
  • Failures are fail-silent (a faulty component stops producing output or signals an error rather than emitting wrong data; contrast with a fail-incorrect module that keeps outputting plausible but wrong values, which is harder for a voter to handle)

[!formula] Reliability Derivation

Setup: Each module has reliability RR (probability of correct operation over time tt). Assume exponential failure: R(t)=eλtR(t) = e^{-\lambda t} where λ\lambda is failure rate.

Single Module System

Rsingle(t)=R(t)=eλtR_{\text{single}}(t) = R(t) = e^{-\lambda t}

Why? Only one module; if it fails, system fails. RR is R(t)=eλtR(t)=e^{-\lambda t}—there is no extra factor.

TMR System

The system works if at least 2 of 3 modules work (voter picks majority).

Step 1: Probability all 3 work: P(all 3 work)=R3P(\text{all 3 work}) = R^3

Why? Independent failures multiply: R×R×RR \times R \times R.

Step 2: Probability exactly 2 work (one fails):

  • Choose which 2 work: (32)=3\binom{3}{2} = 3 ways
  • Each scenario: R2(1R)R^2 (1-R) (two work, one fails) P(exactly 2 work)=3R2(1R)P(\text{exactly 2 work}) = 3R^2(1-R)

Why this step? Binomial probability: pick 2 successes from 3 trials.

Step 3: Total TMR reliability: RTMR(t)=R3+3R2(1R)=3R22R3R_{\text{TMR}}(t) = R^3 + 3R^2(1-R) = 3R^2 - 2R^3

Simplify: RTMR(t)=R2(32R)R_{\text{TMR}}(t) = R^2(3 - 2R)

Interpretation:

  • If R=0.9R = 0.9: Single module Rsingle=0.9R_{\text{single}} = 0.9, TMR RTMR=0.81×1.2=0.972R_{\text{TMR}} = 0.81 \times 1.2 = 0.972 ✅ Better!
  • If R<0.5R < 0.5: TMR is worse than single module (unreliable modules outvote the good one)

Critical threshold: TMR only helps if R>0.5R > 0.5 (modules are more reliable than not).


[!example] Example 1: Sensor Reading Voter

Scenario: Three temperature sensors reading a furnace. Outputs: 850°C, 850°C, 920°C.

Voter logic (software):

def majority_vote(vals):
    """Returns majority value if 2+ agree, else None"""
    if vals[0] == vals[1] or vals[0] == vals[2]:
        return vals[0]
    elif vals[1] == vals[2]:
        return vals[1]
    else:
        return None  # All disagree - catastrophic failure
 
sensors = [850, 850, 920]
output = majority_vote(sensors)  # Returns 850

Why this step?

  • Compare pair-wise: if any two agree, that's the majority
  • If all three disagree, TMR cannot decide (requires higher redundancy like 5-modular)

Real-world: The 920°C sensor likely has a bias fault (calibration drift). The voter masks it; system proceeds with 850°C.


[!example] Example 2: Critical Computation in Flight Control

Scenario: Compute aileron deflection angle δ=K(θdesiredθactual)\delta = K \cdot (\theta_{\text{desired}} - \theta_{\text{actual}}).

Modules:

  • Module 1: δ1=5.2°\delta_1 = 5.2°
  • Module 2: δ2=5.2°\delta_2 = 5.2°
  • Module 3: δ3=1.8°\delta_3 = -1.8° (hardware glitch flipped sign bit)

Voter (hardware comparator):

  • Checks bit-by-bit equality
  • δ1=δ2δ3\delta_1 = \delta_2 \neq \delta_3 → Output 5.2°5.2°

Why this step? Hardware voters use bit-level comparison (faster than floating-point equality). If any two outputs match exactly, send that value to actuators.

Consequence: Aircraft maintains stable roll; the faulty module is masked. Ground diagnostics later identify Module 3 for replacement.


[!example] Example 3: Voter Failure Modes

Scenario: All three modules output different values: 100, 105, 110 (within sensor noise).

Problem: Strict equality voting fails. Need approximate voting:

def approximate_vote(vals, tolerance=5):
    """Majority within tolerance"""
    for i in range(len(vals)):
        matches = sum(1 for v in vals if abs(v - vals[i]) <= tolerance)
        if matches >= 2:
            return vals[i]
    return None  # No consensus
 
sensors = [100, 105, 110]
output = approximate_vote(sensors, tolerance=10)  # Returns 100 (first in majority)

Why this step? Analog sensors have noise. Exact matching is too strict; we vote on "close enough" values using a tolerance window.

Trade-off: Tolerance too large → mask real faults. Tolerance too small → false disagreements.


[!mistake] Common Mistakes

Mistake 1: "TMR always improves reliability"

Why it feels right: More redundancy = more safety, right?

Why it's wrong: If module reliability R<0.5R < 0.5 (more likely to fail than work), TMR is worse than a single module.

The math:

  • Single: R=0.4R = 0.4
  • TMR: RTMR=3(0.4)22(0.4)3=0.480.128=0.352R_{\text{TMR}} = 3(0.4)^2 - 2(0.4)^3 = 0.48 - 0.128 = 0.352 ❌ Worse!

Why? Two unreliable modules outvote the one good module more often than all three work.

Fix: Only use TMR when R>0.5R > 0.5. For unreliable components, fix the base reliability first (better hardware, screening) before adding redundancy.


Mistake 2: "The voter is just an OR gate"

Why it feels right: OR gates are simple; if any module works, output is good.

Why it's wrong: OR would pass through a faulty output. We need majority, not any:

M1M_1 M2M_2 M3M_3 OR Majority
0 1 0 1 0
1 0 0 1 0
1 1 0 1 1 ✅

Why this step? OR gate outputs 1 if any input is 1 (useless for fault tolerance). Majority outputs 1 only if most inputs are 1 (2 or more).

Fix: Use a majority gate (2-out-of-3 logic): V=(M1M2)+(M2M3)+(M1M3)V = (M_1 \cdot M_2) + (M_2 \cdot M_3) + (M_1 \cdot M_3).


Mistake 3: "TMR detects which module failed"

Why it feels right: Three modules vote; we know two agreed, so the third must be faulty.

Why it's wrong: TMR only masks faults, it doesn't diagnose them. You know someone is wrong, but not who (unless you add comparison logic).

Example:

  • Outputs: 50, 50, 75
  • Voter: picks 50 (majority)
  • Question: Is Module 3 broken, or are Modules 1 & 2 both broken identically (common-cause)?

Fix: Add self-checking pairs or watchdog timers to identify faulty modules for maintenance. TMR + diagnostics = robust system.


[!formula] Voter Logic Design

Boolean Majority Function (Digital)

For binary outputs M1,M2,M3{0,1}M_1, M_2, M_3 \in \{0,1\}:

V=M1M2+M2M3+M1M3V = M_1 M_2 + M_2 M_3 + M_1 M_3

Derivation:

  • Output is 1 if at least two inputs are 1
  • Truth table approach:
    • (M1=1,M2=1,M3=?)(M_1=1, M_2=1, M_3=?): Always 1 → M1M2M_1 M_2
    • (M1=1,M2=?,M3=1)(M_1=1, M_2=?, M_3=1): Always 1 → M1M3M_1 M_3
    • (M1=?,M2=1,M3=1)(M_1=?, M_2=1, M_3=1): Always 1 → M2M3M_2 M_3
  • OR these terms together (if any pair is true, output is true)

Why this step? Each product term represents one pair agreeing. OR-ing them captures "any two agree".

Hardware: Implement with 3 AND gates + 1 OR gate. Propagation delay: 2 gate delays.


Analog Voter (Median Filter)

For continuous outputs y1,y2,y3Ry_1, y_2, y_3 \in \mathbb{R}:

V=median(y1,y2,y3)V = \text{median}(y_1, y_2, y_3)

Why median, not average?

  • Average: (100+100+1000)/3=400(100 + 100 + 1000)/3 = 400 → faulty outlier skews result
  • Median: median(100,100,1000)=100\text{median}(100, 100, 1000) = 100 → outlier ignored ✅

Algorithm:

  1. Sort values: ysortedy_{\text{sorted}}
  2. Pick middle: ysorted[1]y_{\text{sorted}}[1]

Hardware: Use analog comparator circuits to find min/max, then compute median = max(min(y1,y2),min(y2,y3),min(y1,y3))\max(\min(y_1,y_2), \min(y_2,y_3), \min(y_1,y_3)).


[!example] Example 4: Real-Time Voter Timing

Scenario: Flight control running at 100 Hz (10 ms period). TMR modules must complete + vote within deadline.

Timing breakdown:

  • Module computation: 3 ms each (parallel)
  • Voter comparison: 0.5 ms
  • Total: max(3,3,3)+0.5=3.5\max(3, 3, 3) + 0.5 = 3.5 ms ✅ (within 10 ms)

Why this step? Parallel execution means we wait for the slowest module, not the sum. Voter adds serial delay.

Failure case: If one module hangs (infinite loop), we need a timeout:

import multiprocessing
 
def compute_with_timeout(func, args, timeout_ms):
    # Shared queue lets the child return its actual result
    q = multiprocessing.Queue()
 
    def worker(q, args):
        q.put(func(*args))
 
    p = multiprocessing.Process(target=worker, args=(q, args))
    p.start()
    p.join(timeout_ms / 1000.0)
    if p.is_alive():
        p.terminate()      # Kill the hung module
        p.join()
        return None        # Fail-silent: no output within deadline
    return q.get()         # Retrieve the module's real computed result

Why? If a module doesn't respond in time, treat it as failed (returns None). The result must be pulled back from the child process via a shared Queue—a plain function call in another process cannot return a value directly. The voter then uses the other two outputs.


[!mnemonic] TMR Memory Hook

"Two Trusty, reject the Rogue"

  • Two modules agree? Trust them.
  • Reject the Rogue outlier.

Visual: Picture three guards voting on "friend or foe". Two say "friend" → majority wins, even if third guard is confused.


[!recall]- Feynman Explanation (ELI12)

Imagine you're doing a math test, and you're not sure if you got the right answer. So you ask three friends to solve the same problem. If two friends get the same answer, you trust that one. If one friend got something totally different, maybe they made a mistake—but you're safe because the other two agree!

That's how computers stay safe in rockets or hospital machines. They run the same calculation three times on three different "mini-computers." If one mini-computer breaks (maybe a tiny wire got zapped by space radiation!), the other two still work and tell the correct answer. The "voter" is like a referee who picks the answer that two computers agree on.

Why three, not two? With two computers, if they disagree, you don't know who's right! With three, the majority (two) is almost always correct—unless you're really unlucky and two break at the exact same time (very rare if they're independent).


Connections

  • Fault Tolerance Fundamentals — TMR is one pattern; compare to N-version programming
  • Watchdog Timers — Detect hung modules that don't output in time
  • Error Detection Codes — Hamming/CRC detect errors; TMR corrects them
  • Safety-Critical Systems Standards — DO-178C, IEC 61508 mandate redundancy for certain SIL levels
  • Common-Cause Failures — TMR assumes independence; diverse implementations reduce common-mode risk
  • Byzantine Fault Tolerance — When modules can lie maliciously (not just fail-silent); requires 4+ modules
  • Redundancy vs. Diversity — TMR uses identical modules; N-version uses different algorithms/languages

Key Takeaways

  1. TMR masks single faults by voting on three parallel computations (2-out-of-3 majority)
  2. Reliability improves only if R>0.5R > 0.5 (module reliability threshold)
  3. Voter must be ultra-reliable (often the weakest link; use hardened hardware or voter redundancy)
  4. TMR doesn't diagnose which module failed—only masks it; add self-checking for maintenance
  5. Analog systems need median voting (average is vulnerable to outliers)
  6. Real-time systems must budget voter delay and handle timeouts (fail-silent assumption)

#flashcards/coding

What is Triple Modular Redundancy (TMR)?
A fault-tolerance technique using three identical modules computing in parallel, with a voter selecting the majority output to mask single-point failures.
Why does TMR require R > 0.5 for reliability improvement?
If module reliability R < 0.5, two faulty modules are more likely to outvote the one working module, making TMR worse than a single module. The formula RTMR=3R22R3R_{\text{TMR}} = 3R^2 - 2R^3 only exceeds RR when R>0.5R > 0.5.
What is the boolean logic for a TMR voter with binary inputs M1,M2,M3M_1, M_2, M_3?
V=M1M2+M2M3+M1M3V = M_1 M_2 + M_2 M_3 + M_1 M_3 (output is 1 if any two inputs are 1; OR of all pairwise ANDs).
Why use median instead of average for analog TMR voting?
Average is skewed by outliers (one faulty extreme value changes the result), while median ignores outliers by picking the middle value, correctly masking one faulty module.
What is the key assumption for TMR to work?
Modules fail independently (no common-cause failures like power surge affecting all three). If failures are correlated, multiple modules fail together and TMR breaks.
What does "fail-silent" mean vs "fail-incorrect"?
Fail-silent means a faulty component stops producing output or signals an error (easy for a voter to handle). Fail-incorrect means it keeps outputting plausible but wrong values (harder to mask).
Can TMR detect which module failed?
No, TMR only masks faults by majority vote. It knows one disagreed but not which one is faulty (could be the majority that's wrong in common-cause failure). Requires additional diagnostics for fault identification.
What happens if all three TMR modules output different values?
Strict equality voting fails (no majority). Need approximate voting with a tolerance window for analog systems, or declare a catastrophic failure and escalate to a backup system.
How does TMR affect real-time system timing?
Modules run in parallel (max delay = slowest module), then voter adds serial delay. Must budget both + timeout handling for hung modules to meet real-time deadlines.

Concept Map

threatens

masks

uses

feed outputs to

applies

selects

assume

assume

enables

assumed

R greater than 0.5

R less than 0.5

costs

Single-point failure

Safety-critical system

Triple Modular Redundancy

Three identical modules M1 M2 M3

Voter V

Majority function 2-of-3

System output

Independent failures

Fail-silent behavior

R_TMR = R^2 times 3-2R

Ultra-reliable voter

More reliable than single

Worse than single module

3x hardware and power

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho yaar, TMR ka core idea bilkul simple hai — imagine tumhare paas teen ghadiyan hain jo time dikha rahi hain. Agar ek ghadi kharab ho jaaye aur galat time dikhaye, toh bhi tum baaki do par bharosa kar sakte ho jo aapas mein agree kar rahi hain. Bas yehi cheez TMR karta hai computations ke saath — teen identical modules ek hi kaam parallel mein karte hain, aur ek "voter" majority output (2-out-of-3) choose kar leta hai. Iska matlab, agar ek module mein fault aa bhi gaya — jaise cosmic radiation se bit-flip ya hardware aging — toh woh faulty module poore system ko crash nahi kar sakta, kyunki baaki do usse outvote kar dete hain.

Ab why-it-matters wali baat samjho. Safety-critical systems mein — jaise spacecraft, medical devices, ya autonomous vehicles — ek chhoti si galti bhi disaster ban sakti hai. Yahan TMR ek trade-off deta hai: tum 3x hardware aur 3x power kharch karte ho, lekin badle mein reliability milti hai jo ek single fault ko completely mask kar deti hai. Formula bhi yaad rakhna — RTMR=R2(32R)R_{TMR} = R^2(3 - 2R). Agar single module ki reliability R=0.9R = 0.9 hai, toh TMR se 0.972 ho jaati hai, kaafi better! Lekin ek critical catch hai: TMR sirf tabhi help karta hai jab R>0.5R > 0.5 ho. Agar modules already zyada unreliable hain, toh do kharab module mil ke ek acche wale ko outvote kar denge, aur system aur bura ho jayega.

Ek important nuance yeh bhi hai ki TMR yeh nahi bata sakta ki kaunsa module fail hua — bas itna pata chalta hai ki koi ek disagree kar raha hai. Aur yeh best tab kaam karta hai jab failures "fail-silent" hon, matlab kharab component chup ho jaaye ya error signal de, bajaye galat-magar-plausible values dene ke. Isliye jab tum embedded ya real-time systems padho, toh yaad rakhna — redundancy sirf hardware duplicate karna nahi hai, balki voting logic aur reliability assumptions ko samajhna asli game hai.

Go deeper — visual, from zero

Test yourself — Embedded Systems & Real-Time Software

Connections