UAV Systems Engineering · Module 8
M8-T4: SIL, HIL and ground testing
Find each defect at the cheapest level that can expose it, and gate the move upward on evidence.
Flight tests are expensive, risky and slow; SIL runs are free. A good test strategy puts each class of defect where it is cheapest to find, and uses entry criteria so that a vehicle only leaves the bench when the bench has nothing more to say. The matrix of defects against levels also shows what only flight can reveal.
Learning objectives
After this lesson, you should be able to:
- Describe the purpose and limits of each test level.
- Define entry criteria for moving from one level to the next.
- Design fault-injection tests per level and know where each fault can be injected.
- Build a defect-class by test-level coverage matrix and find what only flight can test.
Conceptual explanation
Established The staged approach is standard in aerospace and robotics testing. Details (which levels exist, which gates apply) depend on the programme; the table is a typical pattern, not a prescription.
| Level | What runs for real | Good at finding | Cannot find |
|---|---|---|---|
| Unit / component | One function or module | Logic errors, numerical bugs, edge cases | Integration and timing issues |
| SIL (software-in-the-loop) | Full software stack, simulated world | System logic, failsafe sequences, regressions, statistics over many runs | Hardware, timing on target, sensor realism not modelled |
| HIL (hardware-in-the-loop) | Flight controller and companion hardware, simulated world | Timing and load, drivers, wiring, boot, integration | Real sensors, vibration, aerodynamics |
| Ground test | Whole vehicle, props off or restrained | Calibration, sensor health, power, thermal, link range, kill switch, vibration spectra | Flight dynamics, real navigation performance |
| Tethered / constrained flight | Whole vehicle, mechanically limited | Controller stability, first estimator behaviour, thrust margin | Large excursions, failsafe outcomes |
| Free flight | Everything in the real environment | Real performance, environment-specific failures | Nothing is hidden, but failures are costly |
Fault injection belongs at every level: at SIL and HIL by altering the simulated sensor stream or the message flow (dropouts, freezes, biases, noise bursts); on the ground by disconnecting sensors or links; in flight only for faults whose consequences are bounded by the safety design (a pilot ready to take over, a geofence).

Engineering intuition
The cost of finding a defect rises by about an order of magnitude per level. A sign error found in a unit test costs minutes; the same error found in HIL costs hours; on the ground days; in flight, possibly the vehicle. So the discipline is to ask, for every flight test: could this have been found lower? If yes, add the missing lower-level test before flying.
The reverse is also true: some things only flight reveals (vibration coupling into the IMU at specific throttle, wind gust response, lighting changes). The matrix tells you which defect classes have no cheaper level, so you plan flight time for them deliberately instead of hoping to meet them.
Mathematical formulation
A simple expected-cost model chooses how much to test at each level. If a defect class has occurrence probability , and test level detects it with probability at cost (incurred whether or not it is found), and an escape to the next level costs more by a factor of , then the expected cost of finding and fixing at the first detecting level is
With typically high at lower levels for logic defects and zero for environment-specific ones. The cumulative detection probability after levels 1… is ; with independent detection probabilities of 0.9, 0.6 and 0.5 it is 1 − 0.1·0.4·0.5 = 0.98. Escapes that reach flight are the product of the non-detections, which is why raising the lowest-cost level’s detection rate has the biggest effect on the total. Treat the probabilities as engineering judgement informed by history; they are prioritisation aids, not measurements.
- probability that level detects the defect class.
- cost of executing level .
- cost of fixing a defect found at level .
Architecture and data flow
Code change → unit tests in CI → SIL regression (many seeded scenarios) in CI → HIL bench test on a rig (nightly or per release) → ground test checklist on the vehicle → tethered flight → free flight per test card. At each level the result is stored with the baseline ID; the entry criteria for the next level read those results automatically (all required tests pass on this baseline, no open critical defects, traceability coverage complete).
Real-world UAV applications
- Planning the test campaign for a new navigation algorithm.
- Deciding what must be verified before the first outdoor flight.
- Defining the SIL regression suite that gates merges.
- Organising fault-injection tests across levels.
Implementation example
This runs as shown. A defect-class by level matrix with detection probabilities (illustrative judgement values), the cumulative detection, the classes that only flight can find, and a gate checker for entry criteria.
import numpy as np
levels = ['unit', 'SIL', 'HIL', 'ground', 'tether', 'flight']
detect = { # defect class -> probability of detection at each level (illustrative engineering judgement)
'frame / unit error': [0.50, 0.90, 0.60, 0.50, 0.80, 0.90],
'failsafe logic error': [0.20, 0.85, 0.80, 0.60, 0.30, 0.80],
'timing / overload on target': [0.00, 0.00, 0.90, 0.40, 0.50, 0.70],
'sensor driver / wiring fault': [0.00, 0.00, 0.70, 0.90, 0.80, 0.80],
'vibration coupling into IMU': [0.00, 0.00, 0.00, 0.60, 0.70, 0.90],
'wind / aerodynamic limit': [0.00, 0.10, 0.00, 0.00, 0.30, 0.90]}
for k, d in detect.items():
cum = 1 - np.cumprod(1 - np.array(d)); first_cheap = next((levels[i] for i, c in enumerate(d) if c >= 0.5), 'never')
print(f"{k:>28}: first level with detection >= 0.5: {first_cheap:>6}; cumulative before flight {cum[-2]:.2f}, after flight {cum[-1]:.2f}")
flight_only = [k for k, d in detect.items() if max(d[:-1]) < 0.5]
print("classes with no pre-flight level at >= 0.5 (plan flight time for these):", flight_only)
assert flight_only == ['wind / aerodynamic limit']
results = {'unit': 'pass', 'SIL': 'pass', 'HIL': 'pass', 'ground': 'fail', 'tether': 'not run'}
def gate(next_level):
need = levels[:levels.index(next_level)]; blockers = [l for l in need if results.get(l) != 'pass']
return ('OPEN', []) if not blockers else ('CLOSED', blockers)
print("gate to tether:", gate('tether'), "| gate to HIL:", gate('HIL'))
assert gate('HIL')[0] == 'OPEN' and gate('tether') == ('CLOSED', ['ground'])Common engineering mistakes
Skipping levels under schedule pressure
A defect SIL would have found now costs a vehicle.
SIL with ideal sensors only
Inject noise, bias, dropouts and latency that match real data.
Treating HIL as a flight rehearsal
It tests the target and integration, not sensors and dynamics.
Entry criteria as dates
Gate on evidence: tests passed on this baseline, defects closed.
No fault injection on the ground
Pull the sensor connector in a safe test and see what happens before it happens in the air.
Failure modes
| Failure mode | How it shows up | Likely cause |
|---|---|---|
| First flight crashes from a logic error | A defect that SIL could expose | No SIL scenario for the failure case |
| Timing overruns only appear in flight | Load differs from the bench | HIL load unrepresentative; test with full sensors and logging |
| Calibration surprises outdoors | Compass or camera mismatch | Ground test not done in representative conditions |
| Regression after a minor change | Previously working behaviour broke | No automated SIL regression suite |
Debugging approach
- For every flight defect, ask which level should have caught it and add the test there.
- Keep a defect log with the level of discovery and the level it should have been found.
- Check HIL timing with the full flight load.
- Review the gate results before each move up.
Practical exercises
- Fill the defect-by-level matrix for your project with probabilities and justify two entries.
- Define the entry criteria list for the first free flight of your navigation system.
- Design five SIL fault-injection scenarios for GNSS loss and VO failure.
- Compute the cumulative detection before flight for a defect class with detection probabilities 0.7, 0.5, 0.4 at SIL, HIL and ground.
Interview questions
Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.
Question 1
Why test at several levels?
Model answer
Cost to find a defect rises steeply with each level; lower levels find logic and integration defects cheaply, while only flight reveals some environment-dependent ones. The staging puts each defect class where it is cheapest to find.
Question 2
What is the purpose of an entry criterion?
Model answer
To require evidence that the lower level has nothing more to find (tests passed on this baseline, defects closed) before taking the risk and cost of the next level.
Question 3
What can HIL not find?
Model answer
Real sensor performance, vibration, magnetic and optical environment effects and flight dynamics: those need ground and flight tests.
References and further reading
Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.