Test Types & Methods

Tests HIL, SIL et MIL comparés

Comparez les tests Model-in-the-Loop (MIL), Software-in-the-Loop (SIL) et Hardware-in-the-Loop (HIL) avec leurs compromis en coût, vitesse et fidélité, et.

JJulien Buteau
intermediate8 min de lecture14 mars 2026

MIL, SIL et HIL sont trois niveaux de test hardware-in-the-loop qui échangent coût et vitesse contre fidélité. Utilisez le MIL pendant le développement d'algorithmes, le SIL pour valider le code compilé, et le HIL pour vérifier le comportement sur du matériel réel avant la production.

Ce que signifient MIL, SIL et HIL

Model-in-the-Loop (MIL) exécute votre algorithme de contrôle sous forme de modèle de simulation contre une plante simulée. Aucun matériel impliqué. Itération rapide, faible coût, mais fidélité la plus basse.

Software-in-the-Loop (SIL) compile votre code de production et l'exécute sur une machine hôte contre un environnement simulé. Même binaire, pas de matériel. Détecte les bugs de génération de code que le MIL manque.

Hardware-in-the-Loop (HIL) exécute votre code de production sur l'ECU ou le microcontrôleur cible, connecté à un simulateur temps réel qui émule l'environnement physique. Fidélité la plus élevée, coût le plus élevé.

Matrice de comparaison

DimensionMILSILHIL
CoûtFaibleFaible à moyenÉlevé
VitesseRapide (secondes)Moyenne (minutes)Lente (minutes à heures)
FidélitéFaibleMoyenneÉlevée
Matériel requisAucunAucunECU cible + rack simulateur
Usage typiqueConception d'algorithmesVérification du codeValidation système
Compatible CIOuiOuiNon (banc dédié)
Découverte de bugsErreurs de conceptionErreurs de codegenIntégration, timing

Quand utiliser chaque approche

MIL : développement précoce d'algorithmes

Utilisez le MIL quand l'algorithme change encore, que vous avez besoin d'itérations rapides, que le matériel n'est pas encore disponible, ou que vous effectuez des balayages paramétriques. Le MIL n'est pas adapté quand vous devez valider le comportement temporel, la latence d'interruption ou la communication sur bus.

SIL : vérification du code avant le matériel

Utilisez le SIL quand la génération de code est terminée, que vous voulez détecter les régressions en CI, que vous validez l'équivalence numérique entre le modèle et le code généré, ou que les créneaux sur le banc matériel sont rares. Le SIL manque les défauts de timing temps réel et le comportement des périphériques spécifiques au matériel.

HIL : validation système pré-production

Utilisez le HIL quand le firmware de l'ECU est figé, que vous devez valider le timing et le comportement du bus, que la certification exige des preuves matérielles, ou que vous exécutez des suites de régression de nuit. Le HIL est coûteux à mettre en place et lent à itérer.

Exemple : test de limite de tension à chaque niveau

La même logique de test s'exécute aux trois niveaux. Seul le plug change.

MIL : capteur simulé

tests/mil/test_voltage_limit.py
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot


class SimulatedVoltageSensor(htf.plugs.BasePlug):
    """Retourne une valeur déterministe depuis un modèle de simulation."""

    def setUp(self):
        pass

    def read_voltage(self) -> float:
        return 11.8

    def tearDown(self):
        pass


@htf.plug(sensor=SimulatedVoltageSensor)
@htf.measures(
    htf.Measurement("battery_voltage")
    .in_range(minimum=10.0, maximum=14.5)
    .with_units(units.VOLT),
)
def measure_battery_voltage(test, sensor):
    test.measurements.battery_voltage = sensor.read_voltage()


def main():
    test = htf.Test(measure_battery_voltage, test_name="battery-voltage-mil")
    with TofuPilot(test):
        test.execute(test_start=lambda: "UNIT-MIL-001")

if __name__ == "__main__":
    main()

SIL : code compilé contre un bus simulé

tests/sil/test_voltage_limit.py
import ctypes
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot


class SILVoltageSensor(htf.plugs.BasePlug):
    """Appelle la bibliothèque C de production compilée via ctypes."""

    LIB_PATH = "./build/battery_monitor.so"

    def setUp(self):
        self._lib = ctypes.CDLL(self.LIB_PATH)
        self._lib.get_battery_voltage.restype = ctypes.c_float

    def read_voltage(self) -> float:
        return float(self._lib.get_battery_voltage())

    def tearDown(self):
        pass


@htf.plug(sensor=SILVoltageSensor)
@htf.measures(
    htf.Measurement("battery_voltage")
    .in_range(minimum=10.0, maximum=14.5)
    .with_units(units.VOLT),
)
def measure_battery_voltage(test, sensor):
    test.measurements.battery_voltage = sensor.read_voltage()


def main():
    test = htf.Test(measure_battery_voltage, test_name="battery-voltage-sil")
    with TofuPilot(test):
        test.execute(test_start=lambda: "UNIT-SIL-001")

if __name__ == "__main__":
    main()

HIL : ECU réel sur banc matériel

tests/hil/test_voltage_limit.py
import can
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot


class HILVoltageSensor(htf.plugs.BasePlug):
    """Lit la tension depuis l'ECU réel via le bus CAN."""

    CHANNEL = "can0"
    BUSTYPE = "socketcan"

    def setUp(self):
        self._bus = can.interface.Bus(channel=self.CHANNEL, bustype=self.BUSTYPE)

    def read_voltage(self) -> float:
        msg = self._bus.recv(timeout=1.0)
        raw = msg.data[2]
        return raw * 0.1

    def tearDown(self):
        self._bus.shutdown()


@htf.plug(sensor=HILVoltageSensor)
@htf.measures(
    htf.Measurement("battery_voltage")
    .in_range(minimum=10.0, maximum=14.5)
    .with_units(units.VOLT),
)
def measure_battery_voltage(test, sensor):
    test.measurements.battery_voltage = sensor.read_voltage()


def main():
    test = htf.Test(measure_battery_voltage, test_name="battery-voltage-hil")
    with TofuPilot(test):
        test.execute(test_start=lambda: "UNIT-HIL-001")

if __name__ == "__main__":
    main()

Comment TofuPilot suit les résultats à tous les niveaux

Chaque exécution de test est envoyée à TofuPilot avec le même nom de mesure (battery_voltage) quel que soit le niveau. Le champ test_name distingue l'environnement.

test_nameNiveauTraçabilité
battery-voltage-milMILRéférence algorithme
battery-voltage-silSILRégression codegen
battery-voltage-hilHILValidation matérielle

Une unité qui passe le MIL mais échoue au SIL indique un problème de génération de code. Une unité qui passe le SIL mais échoue au HIL indique un problème d'intégration matérielle.

Cadre de décision

ActivitéNiveau recommandé
Réglage des gains de contrôleMIL
Tests de régression en CISIL
Vérification de la sortie de génération de codeSIL
Validation du comportement bus CAN/LINHIL
Vérification des interruptions et du timingHIL
Suite d'injection de fautes de nuitHIL
Balayage paramétrique (100+ cas)MIL ou SIL
Validation pré-releaseHIL
Analyse de cause racine d'un problème terrainHIL

Plus de guides

Mettez ce guide en pratique