Skip to the lesson
FixTheRobot Explore Robotics / Guidance, Navigation and Control / M12 GNC Systems Engineering and Capstone / M12-T2

Guidance, Navigation and Control · Theory · M12

M12-T2 — Monte Carlo Dispersion Analysis

A simulation campaign does not prove a requirement. It gives a number with a confidence, and the number of runs sets how sharp that confidence can be.

  • Lesson 2 of 6
  • Advanced
  • Module 12: GNC Systems Engineering and Capstone
  • Theory
  • About 14 minutes to read

The algebra of the previous lesson holds for a linear loop with Gaussian sources. A real Hopper saturates its gimbal, loses a beacon, and meets a wind that is not Gaussian. For those the tool is a Monte Carlo campaign: fly the simulation many times with the uncertain things drawn at random, and count how many flights land. This lesson answers the three questions every campaign must settle in advance: how many runs a requirement of 99% inside 3 m needs (299 without a single failure, 2995 for 99.9%), what the count of failures proves (an exact binomial bound, not the observed fraction), and what goes wrong when the result is read as the campaign runs, which raised a false acceptance from 1.2% to 6.3% in the example.

Learning objectives

After this lesson, you should be able to:

  • Compute the number of failure-free runs that demonstrates a probability at a stated confidence.
  • Compute an exact lower confidence bound on a success probability from a count of failures.
  • Say why the observed fraction of successes is not the demonstrated probability, and how many runs separate them.
  • Explain the effect of stopping a campaign as soon as it passes, and read the tail of a result rather than a Gaussian fit.

The intuition

Probability M1-T3: Simulating Randomness: Sampling and Monte Carlo shows how to draw random numbers and estimate an average. A GNC campaign uses the same idea for a different purpose. The thing estimated is not an average miss but the probability of meeting a requirement, which is a count: of 1000 flights, 990 landed on the pad. The requirement for Hopper reads "within 3 m in at least 99% of flights", so the campaign must produce a statement of the form "with 95% confidence, the probability exceeds 99%". That sentence has three numbers, and each of them costs runs.

What to disperse

Every quantity that differs between two real flights is drawn at random in each simulated flight: the wind speed and direction, the initial position error, the sensor biases and noise, the mass and its distribution, the engine thrust scale, the actuator lag. The distribution of each comes from a measurement, a datasheet or a stated assumption, and the assumption is written down, because a campaign gives an answer about those distributions and no others. Dispersed together, they produce the combinations that nobody thought to test by hand, such as a high headwind, a low engine thrust and a late navigation fix on the same flight.

Faults are not dispersed in the same draw. A beacon failure with probability 0.4% per flight is a separate event with its own probability, and the campaign needs a stated rule for how it counts toward the requirement. In the example it counts as an ordinary flight with a rare cause.

Why the count matters more than the fraction

Suppose 1000 flights all land. The observed fraction is 100%, but the data are equally consistent with a true probability of 99.7%, because at that probability the chance of seeing no failure in 1000 flights is still 5%. So the honest statement is the bound, 99.70%, and it is the bound that is compared with the requirement. If five flights fail, the observed fraction is 99.5% (above the requirement), but the bound is 98.95% (below it): the campaign has not demonstrated the requirement, and it is not evidence that the requirement fails either. It says that more runs are needed.

How the confidence bound tightens with the number of runsThe 95 percent lower bound on the success probability against the number of runs from 30 to 10000, for observed failure fractions of 0, 0.3, 0.6 and 0.8 percent. All curves rise as runs increase. A horizontal line marks the required 99 percent. The curve with no failures crosses it at about 300 runs, the 0.3 percent curve at about 650, the 0.6 percent curve at about 1700 and the 0.8 percent curve at about 6500.1.522.533.540.950.960.970.980.991log10 of the number of runs95% lower bound on the success probabilityrequired 99%0%0.3%0.6%0.8%
The 95% lower bound on the success probability against the number of runs, for observed failure fractions of 0%, 0.3%, 0.6% and 0.8% (labels at the right). The requirement is demonstrated where a curve crosses 99%.

The figure carries the practical consequence. A vehicle that never fails demonstrates 99% after 299 runs. A vehicle whose failure fraction is 0.3% needs about 650 runs to be shown to comply, at 0.6% about 1700, and at 0.8% about 6500. Each step toward the line multiplies the size of the campaign, and at 0.99% (on the line) no number of runs is enough. The smaller the margin, the larger the campaign.

A campaign demonstrates a bound, not a fraction. The number of runs is chosen before it starts, from the probability, the confidence and the margin that the design is expected to have.

Definitions

Requirement probability p0p_0
The success probability to be demonstrated: 0.99 for Hopper.
Confidence 1−α1-\alpha
The probability that the method of calculation gives a bound that is correct. 0.95 here, so α=0.05\alpha = 0.05.
Failures kk of nn runs
A flight that lands farther than 3 m from the pad, or fails to land, is a failure.
Lower confidence bound pLp_L
A number such that, whatever the true probability, the bound exceeds it with probability at most α\alpha. The requirement is demonstrated when pL≥p0p_L \ge p_0.
Dispersion
Drawing each uncertain input from its distribution for each run.

The count of failures in nn independent runs, each failing with probability q=1−pq = 1 - p, follows the binomial law. The exact lower bound pL=1−qUp_L = 1 - q_U uses the largest failure probability that still makes the observed count likely:

The exact (Clopper-Pearson) lower bound
∑i=0k(ni) qU i (1−qU)n−i=α⟹pL=1−qU\sum_{i=0}^{k}\binom{n}{i}\,q_U^{\,i}\,(1-q_U)^{n-i} = \alpha \qquad\Longrightarrow\qquad p_L = 1 - q_U
The left side is the probability of seeing k or fewer failures when the failure probability is qU. The equation is solved for qU by bisection, as in the worked example.

With no failures the equation is a power and has a closed form. The number of failure-free runs that demonstrates p0p_0 at confidence 1−α1-\alpha is:

Failure-free runs (the rule of three)
n0=⌈ln⁡αln⁡p0⌉  ≈  −ln⁡α1−p0  =  31−p0 for α=0.05n_0 = \left\lceil \frac{\ln\alpha}{\ln p_0} \right\rceil \;\approx\; \frac{-\ln\alpha}{1-p_0} \;=\; \frac{3}{1-p_0}\ \text{for}\ \alpha = 0.05
The approximation holds because ln⁡p0≈−(1−p0)\ln p_0 \approx -(1-p_0) and −ln⁡0.05=3.0-\ln 0.05 = 3.0. For 99% it gives 300 runs, for 99.9% 3000.

Derivation: the failure-free count and the stopping problem

The failure-free count first.

  1. P(no failure in n runs)=p nP(\text{no failure in } n \text{ runs}) = p^{\,n}

    The runs are independent and each succeeds with probability pp.

  2. p n≤αfor every p≤p0  ⟺  p0 n≤αp^{\,n} \le \alpha \quad\text{for every } p \le p_0 \iff p_0^{\,n} \le \alpha

    To demonstrate p0p_0, a vehicle with any probability at or below p0p_0 must have a chance of at most α\alpha of passing. The worst case is p=p0p = p_0, since pnp^n grows with pp.

  3. n≥ln⁡αln⁡p0n \ge \frac{\ln\alpha}{\ln p_0}

    Take logarithms; ln⁡p0\ln p_0 is negative, which turns the inequality around. For p0=0.99p_0 = 0.99 and α=0.05\alpha = 0.05: 298.07, so 299 runs.

Now the effect of repeated looks. A test with a single look at nn runs accepts a non-compliant vehicle with probability at most α\alpha. A test that looks at n1<n2<⋯<nLn_1 < n_2 < \dots < n_L and accepts as soon as any look passes accepts if any of the looks accepts.

  1. Aj={look j passes},P(Aj)≤αA_j = \{\text{look } j \text{ passes}\},\qquad P(A_j) \le \alpha

    Each look on its own has a false-acceptance probability of at most α\alpha for a vehicle at the requirement.

  2. P(accepted)=P(⋃j=1LAj)  ≥  max⁡jP(Aj)P(\text{accepted}) = P\Bigl(\bigcup_{j=1}^{L} A_j\Bigr) \;\ge\; \max_j P(A_j)

    The union of events is at least as probable as the most probable of them, and at most the sum of probabilities. The looks are strongly dependent (they share runs), so the union lies between α\alpha and LαL\alpha.

  3. so the true confidence is below 1−α\text{so the true confidence is below } 1-\alpha

    A campaign stopped at the first pass has a false-acceptance rate above the stated 5%. In the example the rate rises from 1.2% (one look) to 6.3% (15 looks).

The remedy is to fix the number of runs before the campaign, or to use a sequential test designed for repeated looks with a stricter bound at each.

For zero failures, n≥ln⁡α/ln⁡p0n \ge \ln\alpha/\ln p_0 runs. For any count, the bound comes from the binomial law, not from the observed fraction. And the number of looks is part of the test.

A worked example

A dispersed Hopper campaign: the linear-loop landing miss has a spread of 0.95 m per axis (inside 3 m with probability 99.32% when Gaussian), and a beacon fault in 0.4% of flights adds a 2.5 m offset in a random direction.

  1. Failure-free runs. To demonstrate 95%, 99%, 99.9% at a confidence of 95%: 59, 299 and 2995 runs; the rule of three gives 60, 300 and 3000.
  2. The count against the fraction. After 1000 runs with 0, 5 and 10 failures the bound on the success probability is 99.70%, 98.95% and 98.31%.
  3. The campaign. The simulated campaign reaches 98.00% after 100 runs, 98.33% after 300, 99.00% after 1000, 99.30% after 3000 and 99.06% after 10 000, with lower bounds of 93.8%, 96.5%, 98.3%, 99.0% and 98.9%: at none of these sizes does it demonstrate 99%.
  4. Why. Integrating the model gives a true success probability of 99.17%, 0.17 points above the requirement; the 10 000-run estimate (94 failures against 82.6 expected) was a little unlucky. At that margin a campaign of 10 000 runs demonstrates the requirement only 55% of the time, and one of 30 000 runs 93%.
  5. The tail. The radius containing 99% of the 10 000 flights is 2.97 m (2.88 m without faults); for 99.9% it is 3.90 m against 3.53 m. A Gaussian fit to the bulk underestimates the far tail by 10%.
  6. Failures allowed. At 95% confidence the requirement is demonstrated by at most 0 failures in 300 runs, 4 in 1000, 20 in 3000 and 83 in 10 000.
  7. Repeated looks. A vehicle at 98.9% in 2000 simulated campaigns of up to 3000 runs: accepted by a single look at 3000 runs in 1.2% of them; by stopping at the first of 15 looks that passes, in 6.3%.
import math
import random

R = 3.0                          # requirement: land within 3 m ...
P_REQ = 0.99                     # ... in at least 99% of flights
CONF = 0.95                      # the confidence the campaign must reach

def binom_cdf(k, n, p):
    """P(X <= k) for X ~ Binomial(n, p), summed in logs so that large n is safe."""
    if p <= 0: return 1.0
    if p >= 1: return 1.0 if k >= n else 0.0
    s = 0.0
    for i in range(k + 1):
        s += math.exp(math.lgamma(n + 1) - math.lgamma(i + 1) - math.lgamma(n - i + 1) + i * math.log(p) + (n - i) * math.log1p(-p))
    return min(1.0, s)

def bisect(f, lo, hi):
    for _ in range(80):
        mid = 0.5 * (lo + hi)
        if f(mid) > 0: lo = mid
        else: hi = mid
    return 0.5 * (lo + hi)

def success_lower(k_fail, n, conf=CONF):
    """One-sided Clopper-Pearson lower bound on the success probability, given k_fail failures in n runs."""
    # the largest failure probability q for which seeing k_fail or fewer failures still has probability >= 1 - conf
    q = bisect(lambda q: binom_cdf(k_fail, n, q) - (1 - conf), 0.0, 1.0)
    return 1 - q

# how many failure-free runs demonstrate a probability at a confidence
print("failure-free runs needed to demonstrate a probability with 95% confidence:")
for p in (0.95, 0.99, 0.999):
    n = math.ceil(math.log(1 - CONF) / math.log(p))
    print(f"  {p:.3f}: {n} runs  (rule of three: 3/(1-p) = {3 / (1 - p):.0f})")

# the lower bound after zero, one and two failures in 1000 runs
print("lower bound on the success probability after 1000 runs:")
for k in (0, 5, 10):
    print(f"  {k:2d} failures: estimate {1 - k / 1000:.3f}, lower bound {success_lower(k, 1000):.4f}")

# a dispersed Hopper campaign: linear-loop miss per axis (sigma 0.95 m), plus a beacon fault in 0.4% of flights that adds a 2.5 m offset
SIG, P_FAULT, OFFSET = 0.95, 0.004, 2.5
rng = random.Random(2024)
def flight():
    x, y = rng.gauss(0, SIG), rng.gauss(0, SIG)
    if rng.random() < P_FAULT:
        a = rng.uniform(0, 2 * math.pi)
        x += OFFSET * math.cos(a); y += OFFSET * math.sin(a)
    return math.hypot(x, y)

p_gauss = 1 - math.exp(-R * R / (2 * SIG * SIG))
print(f"the Gaussian linear-loop prediction without faults: {p_gauss:.4f} inside {R:.0f} m")
misses = []
print("   runs  failures  estimate  95% lower bound  decision")
marks = (100, 300, 1000, 3000, 10000)
for n in range(1, 10001):
    misses.append(flight())
    if n in marks:
        k = sum(1 for d in misses if d > R)
        lb = success_lower(k, n)
        print(f"{n:7d}  {k:8d}  {1 - k / n:8.4f}  {lb:15.4f}  {'requirement demonstrated' if lb >= P_REQ else 'not demonstrated'}")

def inside(cx, cy, N=300):
    """Probability that a 2-D Gaussian of spread SIG centred at (cx, cy) falls within R of the origin, by midpoint integration."""
    h = 2 * R / N; tot = 0.0
    for i in range(N):
        x = -R + (i + 0.5) * h
        for j in range(N):
            y = -R + (j + 0.5) * h
            if x * x + y * y <= R * R:
                tot += math.exp(-((x - cx) ** 2 + (y - cy) ** 2) / (2 * SIG * SIG)) * h * h / (2 * math.pi * SIG * SIG)
    return tot
p_true = (1 - P_FAULT) * inside(0, 0) + P_FAULT * inside(OFFSET, 0)
print(f"the true success probability with the faults, by integration: {p_true:.4f}; expected failures in 10000 runs {10000 * (1 - p_true):.1f}, observed {sum(1 for d in misses if d > R)}")
srt = sorted(misses)
r99 = srt[int(0.99 * len(srt))]
r999 = srt[int(0.999 * len(srt))]
print(f"radius containing 99% of 10000 flights: {r99:.2f} m (Gaussian without faults {SIG * math.sqrt(-2 * math.log(0.01)):.2f} m)")
print(f"radius containing 99.9%: {r999:.2f} m (Gaussian without faults {SIG * math.sqrt(-2 * math.log(0.001)):.2f} m)")

# the largest number of failures that still demonstrates the requirement, for a campaign of n runs
def k_allowed(n):
    k = -1
    while binom_cdf(k + 1, n, 1 - P_REQ) <= 1 - CONF: k += 1
    return k
print("failures allowed for the requirement to be demonstrated at 95% confidence:")
for n in (300, 1000, 3000, 10000):
    print(f"  {n:6d} runs: at most {k_allowed(n)} failures ({k_allowed(n) / n:.4f} of the runs)")

# looking again and again and stopping at the first success is not the same test: a vehicle that truly succeeds 98.9% of the time
looks = list(range(200, 3001, 200))
allowed = {n: k_allowed(n) for n in looks}
rng = random.Random(99)
trials, accepted_once, accepted_final = 2000, 0, 0
for _ in range(trials):
    fails = 0; n = 0; hit = False
    for nl in looks:
        while n < nl:
            n += 1
            if rng.random() < 0.011: fails += 1
        if fails <= allowed[nl]: hit = True
        last = fails <= allowed[nl]
    accepted_once += hit; accepted_final += last
print(f"a vehicle that truly meets only 98.9%, {trials} campaigns of up to 3000 runs: accepted by a single look at 3000 runs {accepted_final / trials:.1%}, by stopping at the first of {len(looks)} looks that passes {accepted_once / trials:.1%} (the confidence promises 5% at most)")

for n in (10000, 30000):
    kk = k_allowed(n)
    print(f"a campaign of {n} runs of the true {p_true:.4f} vehicle demonstrates the requirement with probability {binom_cdf(kk, n, 1 - p_true):.2f}")
failure-free runs needed to demonstrate a probability with 95% confidence:
  0.950: 59 runs  (rule of three: 3/(1-p) = 60)
  0.990: 299 runs  (rule of three: 3/(1-p) = 300)
  0.999: 2995 runs  (rule of three: 3/(1-p) = 3000)
lower bound on the success probability after 1000 runs:
   0 failures: estimate 1.000, lower bound 0.9970
   5 failures: estimate 0.995, lower bound 0.9895
  10 failures: estimate 0.990, lower bound 0.9831
the Gaussian linear-loop prediction without faults: 0.9932 inside 3 m
   runs  failures  estimate  95% lower bound  decision
    100         2    0.9800           0.9384  not demonstrated
    300         5    0.9833           0.9653  not demonstrated
   1000        10    0.9900           0.9831  not demonstrated
   3000        21    0.9930           0.9899  not demonstrated
  10000        94    0.9906           0.9889  not demonstrated
the true success probability with the faults, by integration: 0.9917; expected failures in 10000 runs 82.6, observed 94
radius containing 99% of 10000 flights: 2.97 m (Gaussian without faults 2.88 m)
radius containing 99.9%: 3.90 m (Gaussian without faults 3.53 m)
failures allowed for the requirement to be demonstrated at 95% confidence:
     300 runs: at most 0 failures (0.0000 of the runs)
    1000 runs: at most 4 failures (0.0040 of the runs)
    3000 runs: at most 20 failures (0.0067 of the runs)
   10000 runs: at most 83 failures (0.0083 of the runs)
a vehicle that truly meets only 98.9%, 2000 campaigns of up to 3000 runs: accepted by a single look at 3000 runs 1.2%, by stopping at the first of 15 looks that passes 6.3% (the confidence promises 5% at most)
a campaign of 10000 runs of the true 0.9917 vehicle demonstrates the requirement with probability 0.55
a campaign of 30000 runs of the true 0.9917 vehicle demonstrates the requirement with probability 0.93
The bound is solved by bisection on the exact binomial sum; the random number generator is seeded so that the campaign is reproducible. The numbers of runs and failures that matter are in the printed tables.

In robotics

These rules decide what a campaign report may claim.

  • Acceptance campaigns. An acceptance criterion is written as a bound ("99% at 95% confidence"), the number of runs is fixed in advance, and the table of allowed failures is part of the plan. The same table serves as a go or no-go for a new software version: 4 failures in 1000 runs passes, 5 does not.
  • Margin determines cost. A design with 99.9% true success is demonstrated with a few thousand runs; one at 99.17% needs tens of thousands. Improving the design is cheaper than extending the campaign.
  • Reading the tail. The fault flights make the far tail heavier than the Gaussian prediction: a Gaussian fit to 10 000 flights predicts 3.53 m for 99.9%, the run shows 3.90 m. A requirement stated on a tail, such as 99.9% containment, must be read from the runs and not from a fitted curve, and needs many more of them.
  • Seeds and reproducibility. Each run is made reproducible by its seed, so a failing flight can be replayed with logging and examined: the first use of a campaign is the list of failures, and the second the number. The seeds of the failures are archived with the report.
  • Combining with the analysis. The covariance analysis of M12-T1: Error Budgets and Covariance Analysis predicts which inputs to disperse widely (those with the largest variance share) and gives an expected result for the linear case to check the simulation against.

The statistics of seeds and runs for learned policies are in Robot Learning M11-T2: Seeds, Variance and Statistics, and the planning of the flight tests that follow in UAV M8-T5: Flight-test planning.

Common misconceptions

“1000 successful runs proves 99.9%.”

It proves 99.70% at 95% confidence. At a true probability of 99.7% the chance of a clean run of 1000 flights is still 5%. To demonstrate 99.9% needs 2995 failure-free runs.

“The observed fraction is the probability.”

It is an estimate with a spread. 99.5% observed in 1000 runs has a lower bound of 98.95%, below 99%: the campaign has not demonstrated the requirement, although the observed fraction exceeds it.

“Run until it passes, then stop.”

Stopping at the first passing look raises the false-acceptance rate above the stated 5%: 6.3% in the example against 1.2% for one look. The run count and the number of looks belong in the plan.

“A Gaussian fit to the miss is enough.”

A fit to the bulk misses the tail made by faults and saturations: here 3.53 m predicted for the 99.9% radius, 3.90 m observed.

“If the campaign fails to show compliance, the design fails.”

A result "not demonstrated" means the data cannot separate the design from the requirement. With a true 99.17% the choice is between a much longer campaign (30 000 runs) and more margin in the design.

Key takeaways

  1. A campaign demonstrates a lower confidence bound on the success probability, not the observed fraction.
  2. Failure-free runs needed: ln⁡α/ln⁡p0\ln\alpha/\ln p_0, about 3/(1−p₀) at 95%: 299 for 99%, 2995 for 99.9%.
  3. The bound for any failure count comes from the exact binomial sum; 5 failures in 1000 runs gives 98.95%, below 99%.
  4. The smaller the margin between the true probability and the requirement, the more runs; at a margin of 0.17 points, 10 000 runs decide only about half the time.
  5. Fix the number of runs and looks in advance: stopping at the first pass took the false-acceptance rate from 1.2% to 6.3%.
  6. Read the tail from the runs, not from a Gaussian fit, and archive the seeds of the failures.

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.

  • C. J. Clopper and E. S. Pearson, "The use of confidence or fiducial limits illustrated in the case of the binomial", Biometrika 26(4), 1934, the source of the exact bound. Paid (Oxford University Press).
  • L. D. Brown, T. T. Cai and A. DasGupta, "Interval estimation for a binomial proportion", Statistical Science 16(2), 2001, a comparison of the bounds. Free to read from Project Euclid.
  • W. Feller, An Introduction to Probability Theory and Its Applications, vol. 1, Wiley, 1968, for the binomial law. Paid.
  • MIT 18.05 Introduction to Probability and Statistics (OpenCourseWare) , for confidence intervals and the binomial. 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 new Hopper software release is to be accepted if it demonstrates 99.5% at 95% confidence with no failures allowed. How many runs are needed, and what happens if one run in the campaign fails?

Explanation

The count is ln 0.05/ln 0.995 = 2.996/0.005013 = 597.6, so 598 runs with no failure. A single failure ends the plan: with one failure allowed the exact bound needs 947 runs in all. A rule that allows no failures is the cheapest but also the most brittle; a plan with an allowed-failures table states in advance what a failure costs.

Question 2

A campaign of 1000 runs ends with 6 failures. Observed 99.4%. Is the 99% requirement demonstrated at 95% confidence? Use the table of allowed failures.

Explanation

No. The table allows at most 4 failures in 1000 runs for a lower bound of 99%; 6 failures give a bound of 98.82%. The observed 99.4% is above the requirement, but the data are consistent with a true probability below 99%. The next step is either more runs (the margin is 0.4 points, which needs several thousand) or a design change that gives more margin; it is not to report the 99.4%.

Question 3

Why can a campaign run until its bound first reaches the requirement, and be stopped there, give a wrong answer more often than the 5% that the confidence promises?

Explanation

Each look is a separate test with a false-acceptance probability of up to 5% for a vehicle at the requirement, and the campaign accepts if any look passes, so the probability that some look passes is larger than for one. The looks share runs and are dependent, so the total lies between 5% and the number of looks times 5%: 6.3% in the example with 15 looks for a vehicle at 98.9%. Fixing the run count beforehand, or using a sequential test whose bounds account for the looks, keeps the stated confidence.

What’s next

Practice this lesson

How Many Runs Are Enough?

A requirement says 99% of landings within 3 m. Build the error budget, run a dispersion campaign, and state with what confidence the requirement is met.

Next lesson

M12-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.

Nothing below is required to finish this lesson.

  • Before
    M12-T1: Error Budgets and Covariance Analysis

    Allocate a requirement over error sources, propagate their covariance through a linearized loop, and find the source that dominates.

  • Lab
    M12-L1: How Many Runs Are Enough?

    A requirement says 99% of landings within 3 m. Build the error budget, run a dispersion campaign, and state with what confidence the requirement is met.

  • Lab
    M12-L2: Capstone: Land Hopper

    Write the navigation filter, the guidance law and the controller of Hopper, and pass an acceptance campaign of dispersed flights with wind, sensor errors, mass uncertainty and one beacon fault.

Other courses on this site treat neighbouring topics from their own angle:

This course leaves the following to the pages that already teach them: