Guidance, Navigation and Control · Theory · M12
M12-T4 — Modes, Redundancy and Fault Management in GNC
A GNC system is not one control law. It is a set of modes, the guards between them, and the rules for what happens when a sensor lies.
Every algorithm in the preceding modules assumes a healthy vehicle in a known phase. A flight is neither. Hopper is on the pad, ascending, hopping, descending and landing, and during any of these an altimeter may stick or a beacon may be lost. This lesson covers the two structures that make the algorithms usable: the mode logic that decides which law runs, and the redundancy that decides which sensor to believe. A noisy guard without hysteresis switched 509 times in 30 s, one with a 0.75 m band once; a mid-value select of three altimeters is blind to nothing with one fault and wrong with two; and an analytic check against the inertial model caught a 1 m bias in 0.09 s but never caught a slow drift of 0.2 m/s, which ended 6 m wrong.
Learning objectives
After this lesson, you should be able to:
- Describe a flight as a set of modes with guards and a safe mode, and use hysteresis to stop chatter.
- Compare mid-value voting with analytic redundancy, and state what faults each can and cannot detect.
- Size a detector threshold from a false-alarm count and read its detection delay.
- Say what a detection delay costs at a given height and why drift faults need an independent sensor.
The intuition
The general methods of fault detection, isolation and recovery are covered in UAV M8-T9: Fault detection, isolation and recovery; failure modes and effects analysis is in UAV M8-T7: FMEA. This lesson takes the GNC end of it: what a guidance, navigation and control system does when its inputs or its own phase change.
Modes
A mode is a set of laws with a purpose. On the pad, Hopper checks its sensors; in ascent it holds a vertical thrust profile; in the hop it follows the guidance of module 8; in the descent it follows the convex powered descent of module 9; below 10 m it flares; on the ground it shuts down. Each change of mode is a guard: a condition on the state, such as "height below 10 m", that must hold. Two things go wrong with guards. A guard on a noisy signal chatters, switching back and forth as the noise crosses the threshold. And a guard that is only half specified leaves a state in which no rule applies.
The cure for chatter is hysteresis: enter the mode below m and leave it only above m. With 0.25 m of altimeter noise and a vehicle sinking slowly through the threshold, a plain guard switched 509 times in 30 s, a band of 0.25 m still 143 times, and a band of 0.75 m once.
Two kinds of redundancy
Voting compares copies of the same measurement. With three altimeters the mid-value select takes the middle reading: one failed sensor, high or low, never becomes the middle, so a single fault is tolerated without being identified. With two failed sensors in the same direction the middle reading is wrong and nothing in the vote says so.
Analytic redundancy compares a measurement with what the rest of the system predicts. The inertial observer of module 7 predicts the height from the accelerometer; the altimeter innovation, the difference between the two, is small when both are healthy, and large when one is not. It needs no second altimeter, but it needs a model, and it can be blinded: if the altimeter drifts slowly, the observer follows it.
Voting finds a fault by disagreement between copies and fails when copies fail together. Analytic redundancy finds it by disagreement with a model and fails when the fault is slower than the observer. A design uses both, and a safe mode for what neither can catch.
Definitions
- Mode
- A configuration of guidance, navigation and control laws active together.
- Guard
- A condition on the state or on time that triggers a transition between modes.
- Hysteresis
- A band around a threshold: the mode is entered at and left at , so that noise smaller than cannot make it switch.
- Mid-value select
- The median of three redundant measurements.
- Innovation
- The difference between a measurement and its prediction by the observer.
- CUSUM
- A cumulative sum of the normalized innovation minus a drift allowance, reset at zero: an alarm when it exceeds a threshold.
- Safe mode
- A mode entered on a confirmed fault, with a simple action chosen by height and state.
The mid-value of three readings , of which at most one is faulty, lies between the healthy ones:
The detector sums a normalized innovation and raises an alarm when the sum leaves a band:
Derivation: why a plain guard chatters, and what the observer absorbs
The number of switches of a plain guard is a level-crossing count of noise, and the observer's blindness to a drift is a statement about its steady state.
Near the threshold, with the true height only a fraction of away, each reading falls on either side with a probability close to one half.
White noise at the sampling rate crosses any level within a few of it again and again: here a switch every 0.06 s on average, 509 in 30 s.
With a hysteresis band the mode is left only if the reading rises above after it has fallen below ; for that is a rare event.
Now the observer. Suppose the altimeter reads and the observer is a second-order filter with gains and on the innovation.
The height and velocity estimates are driven by the accelerometer and corrected by the innovation.
After a constant bias the observer settles on the biased measurement: the innovation returns to zero, so a detector sees only a transient, at the moment of the step.
For a ramp a second-order observer also settles: the innovation goes to a small constant set by the accelerometer bias , and the velocity estimate absorbs the rate. A slow drift therefore leaves no signature larger than the noise, and the estimate drifts with the sensor.
A noisy guard needs hysteresis wider than the noise. An observer-based check sees changes, not levels: it finds a jump quickly and a slow drift not at all.
A worked example
Hopper's descent from 100 m at 2 m/s, with 0.30 m altimeter noise, an accelerometer with a 0.02 m/s² bias and 0.05 m/s² noise, and a CUSUM with drift allowance 0.5 and threshold 12 on the normalized innovation.
- Hysteresis. A plain 10 m guard on an altimeter with 0.25 m noise switches 509 times in 30 s; with a 0.25 m band, 143 times; with 0.75 m (three sigma), once.
- Voting. Three altimeters of 0.30 m noise give 0.20 m rms from the mid-value select without a fault. With one 5 m bias the select is at 0.30 m rms against 5.01 m for the faulty sensor; with two 5 m biases it is wrong by 4.84 m rms.
- The healthy innovation. Standard deviation 0.307 m. The CUSUM raised no false alarm in 300 healthy 60 s descents; by the rule of three the false-alarm rate is at most 1% per flight at 95% confidence.
- Step biases. A bias appearing at 30 s is detected in 100 of 100 runs with a mean delay of 0.09 s at 1 m, 0.04 s at 2 m and no delay at 5 m. At 0.5 m, about 1.7 noise standard deviations, it is detected in 86 of 100 runs, in 0.35 s on average and up to 0.90 s.
- Slow drifts. A drift of 0.05 m/s from 30 s is never detected: the estimate follows it to an error of 1.5 m at 60 s. At 0.20 m/s there is no alarm, and the estimate is 6.0 m wrong. At 0.50 m/s the alarm comes after 1.7 s.
- What delay costs. Free fall from hover at 10, 20 and 50 m takes 1.43, 2.02 and 3.19 s; a detection delay of 0.4 s uses 28%, 20% and 13% of that.
import math
import random
# ---- 1. hysteresis in the mode logic: the descent-to-landing switch at 10 m height, with a noisy altimeter
rng = random.Random(5)
def switches(hyst, sigma=0.25, T=30.0, dt=0.01):
"""Count mode switches between DESCENT and LANDING while the true height sinks slowly through 10 m (0.05 m/s)."""
mode = 'DESCENT'; n = 0
for k in range(int(T / dt)):
h_true = 10.4 - 0.05 * k * dt * 1.0
h = h_true + rng.gauss(0, sigma)
if mode == 'DESCENT' and h < 10.0 - hyst: mode = 'LANDING'; n += 1
elif mode == 'LANDING' and h > 10.0 + hyst: mode = 'DESCENT'; n += 1
return n
for hyst in (0.0, 0.25, 0.75):
print(f"switch at 10 m with a {hyst:.2f} m hysteresis band and 0.25 m altimeter noise: {switches(hyst)} mode switches in 30 s")
# ---- 2. three altimeters: mid-value select against a fault
def mid(a, b, c): return sorted((a, b, c))[1]
rng = random.Random(11)
SIG = 0.3
def trial(fault, n=20000):
worst_single = 0.0; worst_mid = 0.0; s_single = 0.0; s_mid = 0.0
for _ in range(n):
z = [rng.gauss(0, SIG) for _ in range(3)]
if fault == 'one bias 5 m': z[0] += 5.0
if fault == 'two biases 5 m': z[0] += 5.0; z[1] += 5.0
s_single += z[0] ** 2; s_mid += mid(*z) ** 2
worst_single = max(worst_single, abs(z[0])); worst_mid = max(worst_mid, abs(mid(*z)))
return math.sqrt(s_single / n), math.sqrt(s_mid / n), worst_mid
print("three altimeters, noise 0.30 m each; rms error of one sensor and of the mid-value select:")
for f in ('no fault', 'one bias 5 m', 'two biases 5 m'):
a, b, w = trial(f)
print(f" {f:15s}: sensor 1 {a:5.2f} m rms, mid-value select {b:5.2f} m rms (worst {w:.2f} m)")
# ---- 3. analytic redundancy: the altimeter checked against the inertial model
DT = 0.02
def run(bias, fault_t, seed, T=60.0, cusum=None):
"""Descent from 100 m. Observer: height and velocity from the accelerometer (bias 0.02 m/s2, noise 0.05) corrected by the altimeter.
The altimeter has a step bias at fault_t. Returns the CUSUM alarm time (or None) and the max |innovation|."""
r = random.Random(seed)
h = 100.0; v = -2.0; he, ve = 100.0, -2.0
L1, L2 = 1.2, 0.5
s_hi = s_lo = 0.0
sigma_i = 0.33 # innovation spread of the healthy filter, from the fault-free runs below
k = 0; alarm = None
maxi = 0.0
while k * DT < T:
t = k * DT
a_true = 0.0
h += v * DT; v += a_true * DT
a_meas = a_true + 0.02 + r.gauss(0, 0.05)
he += ve * DT; ve += a_meas * DT
z = h + r.gauss(0, 0.3) + (bias if t >= fault_t else 0.0)
inn = z - he
he += L1 * DT * inn; ve += L2 * DT * inn
maxi = max(maxi, abs(inn))
if cusum is not None:
drift, thr = cusum
s_hi = max(0.0, s_hi + inn / sigma_i - drift); s_lo = max(0.0, s_lo - inn / sigma_i - drift)
if alarm is None and (s_hi > thr or s_lo > thr): alarm = t
k += 1
return alarm, maxi
# innovation spread without a fault
vals = []
r = random.Random(3)
he = 100.0; ve = -2.0; h = 100.0; v = -2.0
for k in range(int(60 / DT)):
h += v * DT
he += ve * DT; ve += (0.02 + r.gauss(0, 0.05)) * DT
inn = h + r.gauss(0, 0.3) - he
he += 1.2 * DT * inn; ve += 0.5 * DT * inn
if k * DT > 10: vals.append(inn)
mean_i = sum(vals) / len(vals); sd = math.sqrt(sum((x - mean_i) ** 2 for x in vals) / len(vals))
print(f"healthy innovation of the altimeter against the inertial observer: mean {mean_i:.3f} m, standard deviation {sd:.3f} m")
DRIFT, THR = 0.5, 12.0
fa = 0
for seed in range(100, 400):
alarm, _ = run(0.0, 1e9, seed, cusum=(DRIFT, THR))
if alarm is not None: fa += 1
print(f"CUSUM (drift {DRIFT}, threshold {THR}) on the normalized innovation: false alarms in 300 healthy 60 s descents: {fa}")
print("detection of an altimeter bias that appears at 30 s (mean over 100 runs, and the largest delay):")
for bias in (0.5, 1.0, 2.0, 5.0):
delays = []; miss = 0
for seed in range(1000, 1100):
alarm, _ = run(bias, 30.0, seed, cusum=(DRIFT, THR))
if alarm is None: miss += 1
else: delays.append(alarm - 30.0)
if delays: print(f" bias {bias:3.1f} m: detected in {100 - miss} of 100 runs, mean delay {sum(delays) / len(delays):5.2f} s, largest {max(delays):5.2f} s")
else: print(f" bias {bias:3.1f} m: never detected in 100 runs")
# a slow drift is absorbed by the observer: the altimeter ramps away from the truth after 30 s
def run_ramp(rate, seed, T=60.0):
r = random.Random(seed)
h = 100.0; v = -2.0; he, ve = 100.0, -2.0
s_hi = s_lo = 0.0; alarm = None
for k in range(int(T / DT)):
t = k * DT
h += v * DT
he += ve * DT; ve += (0.02 + r.gauss(0, 0.05)) * DT
z = h + r.gauss(0, 0.3) + (rate * (t - 30.0) if t >= 30.0 else 0.0)
inn = z - he
he += 1.2 * DT * inn; ve += 0.5 * DT * inn
s_hi = max(0.0, s_hi + inn / 0.33 - DRIFT); s_lo = max(0.0, s_lo - inn / 0.33 - DRIFT)
if alarm is None and (s_hi > THR or s_lo > THR): alarm = t
return alarm, he - h
print("a slow drift of the altimeter from 30 s, seen by the same CUSUM (the error of the estimated height at 60 s is what the loop would use):")
for rate in (0.02, 0.05, 0.2, 0.5):
al, err = run_ramp(rate, 4242)
print(f" drift {rate:4.2f} m/s: " + (f"alarm after {al - 30.0:5.1f} s" if al is not None else "no alarm") + f", altimeter error at 60 s {rate * 30.0:5.1f} m, estimate error {err:5.2f} m")
# ---- 4. what a detection delay costs
g = 9.81
for h0 in (10.0, 20.0, 50.0):
t_fall = math.sqrt(2 * h0 / g)
print(f"free fall from hover at {h0:4.0f} m: {t_fall:.2f} s; a 0.4 s detection delay uses {100 * 0.4 / t_fall:.0f}% of that")switch at 10 m with a 0.00 m hysteresis band and 0.25 m altimeter noise: 509 mode switches in 30 s switch at 10 m with a 0.25 m hysteresis band and 0.25 m altimeter noise: 143 mode switches in 30 s switch at 10 m with a 0.75 m hysteresis band and 0.25 m altimeter noise: 1 mode switches in 30 s three altimeters, noise 0.30 m each; rms error of one sensor and of the mid-value select: no fault : sensor 1 0.30 m rms, mid-value select 0.20 m rms (worst 0.87 m) one bias 5 m : sensor 1 5.01 m rms, mid-value select 0.30 m rms (worst 1.15 m) two biases 5 m : sensor 1 5.01 m rms, mid-value select 4.84 m rms (worst 5.84 m) healthy innovation of the altimeter against the inertial observer: mean -0.039 m, standard deviation 0.307 m CUSUM (drift 0.5, threshold 12.0) on the normalized innovation: false alarms in 300 healthy 60 s descents: 0 detection of an altimeter bias that appears at 30 s (mean over 100 runs, and the largest delay): bias 0.5 m: detected in 86 of 100 runs, mean delay 0.35 s, largest 0.90 s bias 1.0 m: detected in 100 of 100 runs, mean delay 0.09 s, largest 0.14 s bias 2.0 m: detected in 100 of 100 runs, mean delay 0.04 s, largest 0.04 s bias 5.0 m: detected in 100 of 100 runs, mean delay 0.00 s, largest 0.00 s a slow drift of the altimeter from 30 s, seen by the same CUSUM (the error of the estimated height at 60 s is what the loop would use): drift 0.02 m/s: no alarm, altimeter error at 60 s 0.6 m, estimate error 0.61 m drift 0.05 m/s: no alarm, altimeter error at 60 s 1.5 m, estimate error 1.51 m drift 0.20 m/s: no alarm, altimeter error at 60 s 6.0 m, estimate error 6.01 m drift 0.50 m/s: alarm after 1.7 s, altimeter error at 60 s 15.0 m, estimate error 15.00 m free fall from hover at 10 m: 1.43 s; a 0.4 s detection delay uses 28% of that free fall from hover at 20 m: 2.02 s; a 0.4 s detection delay uses 20% of that free fall from hover at 50 m: 3.19 s; a 0.4 s detection delay uses 13% of that
In robotics
The structure is the same on every vehicle; the numbers and the safe action change.
- Mode logic as a table. A mode design is reviewed as a table of modes, guards and actions, with a check that every state has exactly one applicable rule and that there is a path to the safe mode from each. A model checker or a test over all pairs of mode and event does the same automatically.
- Dissimilar sensors. Voting fails against faults that affect copies together: a software error, a calibration shared by identical units, a common power supply. Using a different kind of sensor for the second copy (a radar altimeter next to a barometric one) turns a common-mode fault into one the vote can see.
- Drift needs an independent reference. The drift of 0.2 m/s that the observer absorbed ended 6 m wrong: the cure is a measurement the drift does not enter, such as the beacons of module 7, or a vote against a second altimeter. The detector is tuned to the faults it can see and a different layer covers the rest.
- The safe action depends on height. Near the ground the safe action is to cut the thrust (falling from 10 m takes 1.4 s and cannot be improved); at 100 m it is to hold attitude and descend on the last good estimate. The mode logic therefore reads the height, which is why it must not trust a single altimeter.
- Budgeting the delay. A detection delay of 0.4 s costs a fifth of the time to impact from 20 m; the detector, the vote and the mode change together are a latency that appears in the loop of the next lesson.
The margin policy of M12-T3: A Stability-Margin Policy treats the delay of a detector as one of the dispersed parameters, and the analysis of M12-T1: Error Budgets and Covariance Analysis treats an undetected fault as an error source with its own probability.
Common misconceptions
“A guard is just a threshold.”
On a noisy signal a plain threshold switched 509 times in 30 s. A guard needs a band wider than the noise, and a rule for what happens in the band.
“Three sensors tolerate any fault.”
They tolerate one. With two failed in the same direction the mid-value select was wrong by 4.84 m rms and nothing in the vote showed it.
“A model-based check catches everything the sensors do wrong.”
It sees changes the observer cannot follow. A step bias was found within 0.1 s, a drift of 0.2 m/s never, because the observer tracked the sensor.
“A lower detection threshold is always safer.”
It raises the false-alarm rate: every false alarm in the descent enters the safe mode. The threshold is set from a count of healthy runs (none in 300 here) and the delay it costs is stated.
“The safe mode is a single action.”
The right action depends on height and state: cutting thrust near the ground, holding attitude high up. A safe mode has a small table of its own.
Key takeaways
- A flight is modes and guards; a safe mode is reachable from every flight mode and is not left in flight.
- A guard on a noisy signal needs hysteresis wider than the noise: 509 switches in 30 s without, 1 with a band of three sigma.
- Mid-value select tolerates one fault in three sensors and fails with two; it needs dissimilar sensors for common-mode faults.
- Analytic redundancy finds a jump fast (0.09 s for 1 m) and a slow drift never; the observer follows the sensor.
- A detector is tuned from healthy data: none in 300 descents gives at most a 1% false-alarm rate per flight at 95% confidence.
- A detection delay of 0.4 s uses 20% of the 2 s that Hopper has in free fall from 20 m.
References and further reading
Each source is marked free or paid. Free to read does not mean free to reuse: the course resources page lists every source with its licence.
- R. Isermann, Fault-Diagnosis Systems: An Introduction from Fault Detection to Fault Tolerance, Springer, 2006, for analytic redundancy and residual generation. Paid.
- M. Basseville and I. V. Nikiforov, Detection of Abrupt Changes: Theory and Application, Prentice-Hall, 1993, for the CUSUM and its delay and false-alarm trade. Free PDF from the authors' archive.
- J. Gertler, Fault Detection and Diagnosis in Engineering Systems, Marcel Dekker, 1998, on parity relations and redundancy. Paid.
- MIT 16.851 Satellite Engineering (OpenCourseWare) , for fault management and redundancy at the system level. Free; licence CC BY-NC-SA 4.0.
Knowledge check
Three questions. Write an answer, then reveal the explanation. Your answers stay in your browser.
Question 1
A guard switches Hopper into the landing mode at 10 m of height. The altimeter noise is 0.3 m (one sigma). What hysteresis band would you choose, and what does it cost?
Explanation
A band of three sigma, 0.9 m on each side, makes a spurious switch rare: the reading must fall below 9.1 m to enter and rise above 10.9 m to leave. The cost is that the vehicle enters the landing mode up to 0.9 m lower than the nominal threshold, which matters if the flare law needs the height of 10 m to start; the choice of the nominal threshold takes the band into account (here by placing the nominal at 10.9 m).
Question 2
Three altimeters read 100.1, 99.8 and 108.0 m. What does the mid-value select give, and which situations would make it wrong?
Explanation
The sorted values are 99.8, 100.1, 108.0, so the select is 100.1 m: the high reading is isolated without being identified as the fault. It would be wrong if two sensors were wrong in the same direction (two at 108 m would give 108), or if all three shared a fault such as a common calibration or a common reflection from the same surface. The vote cannot tell either case from agreement.
Question 3
An altimeter drifts at 0.05 m/s and a CUSUM on the innovation never alarms. Why does the observer not show it, and what covers the fault?
Explanation
The observer tracks the altimeter: the innovation settles to a small constant, here inside the 0.3 m noise, so the CUSUM drift allowance absorbs it, and the height estimate carries the error: 1.5 m after 30 s of drift. A different layer must cover it: a second dissimilar altimeter voted against the first, an independent reference such as the range beacons, or a requirement that the descent end with the radar altimeter alone. The detector is for jumps; the drift is the voting layer's job.
What’s next
Related content
Nothing below is required to finish this lesson.
- BeforeM12-T3: A Stability-Margin Policy
Set margin requirements for nominal and dispersed cases, verify them across the envelope, and confirm them in the time domain.
Other courses on this site treat neighbouring topics from their own angle:
- Probability M1-T3: Simulating Randomness: Sampling and Monte Carlo
- Probability M4-T4: Propagating Uncertainty Through Transformations
- Linear Algebra M9-T4: Covariance Propagation
- UAV M8-T9: Fault detection, isolation and recovery
- UAV M8-T7: FMEA
- UAV M8-T3: Verification and validation
- UAV M8-T4: SIL, HIL and ground testing
- UAV M6-T14: Software-in-the-Loop simulation
- UAV M7-T7: Jitter and deadline monitoring
- UAV M8-T1: System requirements engineering
- UAV M8-T5: Flight-test planning
- Navigation M10-T2: Engineering Trade-offs and Safety Cases
- Robot Learning M11-T2: Seeds, Variance and Statistics
This course leaves the following to the pages that already teach them:
Get notified when the next lesson and new labs are released.
One email per new lesson or lab.