Test Data & Analytics

Limites de mesure depuis les données

Apprenez à dériver des limites de mesure statistiquement fiables à partir des données de production en utilisant la méthode 3-sigma, à détecter les.

JJulien Buteau
intermediate10 min de lecture14 mars 2026

Les limites des fiches techniques sont des points de départ, pas des limites de production. Les cartes réelles présentent des tolérances, des variations d'assemblage et des dérives environnementales que les fiches techniques ne peuvent pas capturer. Ce guide vous montre comment collecter des données de mesure depuis votre ligne de production, appliquer la méthode 3-sigma pour dériver des limites statistiquement fiables, et configurer ces limites dans OpenHTF avec le suivi TofuPilot.

Prérequis

  • Compte TofuPilot avec des données d'exécution de production
  • Python 3.8+
  • numpy et scipy installés
  • Au moins 30 échantillons de test (100+ recommandés)

Pourquoi les limites des fiches techniques ne suffisent pas

Source de variationExemple
Tolérance des composantsUne résistance à +/-5 % décale la tension de sortie
Impédance des pistes du PCBDifférences de routage selon les positions dans le panneau
Variation d'assemblageLa résistance des joints de soudure varie
Dérive environnementaleTempérature à la station de test vs. sur le terrain
Bruit de mesureContact de la sonde, longueur du câble

Un rail 3,3 V avec une plage de +/-5 % selon la fiche technique (3,135 V-3,465 V) peut montrer une distribution de production réelle centrée à 3,31 V avec un écart-type de 0,012 V. Définir les limites uniquement à partir de la fiche technique ne permet pas de voir que votre processus dérive vers le haut.

Étape 1 : Collecter les échantillons de référence

Vous avez besoin d'un minimum de 30 échantillons provenant de cartes déjà validées comme conformes. Utilisez 100+ pour des estimations de sigma stables.

collect_samples.py
import numpy as np

# Collecte simulée à partir de cartes validées conformes
# En pratique, exportez depuis TofuPilot ou accumulez à partir des exécutions en direct
vdd_samples = [
    3.312, 3.308, 3.315, 3.310, 3.307,
    3.319, 3.311, 3.314, 3.309, 3.316,
    3.313, 3.308, 3.312, 3.317, 3.310,
    3.306, 3.315, 3.311, 3.313, 3.309,
    3.318, 3.310, 3.312, 3.315, 3.308,
    3.311, 3.314, 3.307, 3.316, 3.313,
    3.310, 3.308, 3.315, 3.312, 3.311,
    3.309, 3.317, 3.314, 3.310, 3.313,
]

n = len(vdd_samples)
mean = np.mean(vdd_samples)
std = np.std(vdd_samples, ddof=1)  # écart-type d'échantillon, pas de population

print(f"N={n}  moyenne={mean:.4f}V  écart-type={std:.4f}V")
# N=40  moyenne=3.3119V  écart-type=0.0031V

Utilisez ddof=1 pour l'écart-type d'échantillon lorsque la taille de votre échantillon est inférieure à la population complète.

Étape 2 : Vérifier les valeurs aberrantes et les distributions bimodales

Avant de calculer les limites, inspectez la distribution. Une distribution bimodale signale deux populations distinctes.

check_distribution.py
import numpy as np
from scipy import stats

vdd_samples = [
    3.312, 3.308, 3.315, 3.310, 3.307,
    3.319, 3.311, 3.314, 3.309, 3.316,
    3.313, 3.308, 3.312, 3.317, 3.310,
    3.306, 3.315, 3.311, 3.313, 3.309,
    3.318, 3.310, 3.312, 3.315, 3.308,
    3.311, 3.314, 3.307, 3.316, 3.313,
    3.310, 3.308, 3.315, 3.312, 3.311,
    3.309, 3.317, 3.314, 3.310, 3.313,
]

# Détection des valeurs aberrantes par z-score
z_scores = np.abs(stats.zscore(vdd_samples))
outliers = [v for v, z in zip(vdd_samples, z_scores) if z > 3]
print(f"Valeurs aberrantes (|z| > 3) : {outliers}")

# Test de normalité de Shapiro-Wilk
stat, p = stats.shapiro(vdd_samples)
print(f"Shapiro-Wilk p={p:.4f} ({'normal' if p > 0.05 else 'NON normal'})")

Si Shapiro-Wilk renvoie p < 0.05, recherchez si vos échantillons proviennent de deux lots d'assemblage ou de deux bobines de composants.

Étape 3 : Calculer les limites 3-sigma

La règle des 3-sigma couvre 99,73 % d'une distribution normale (environ 2700 DPMO au bord de la limite).

compute_limits.py
import numpy as np

vdd_samples = [
    3.312, 3.308, 3.315, 3.310, 3.307,
    3.319, 3.311, 3.314, 3.309, 3.316,
    3.313, 3.308, 3.312, 3.317, 3.310,
    3.306, 3.315, 3.311, 3.313, 3.309,
    3.318, 3.310, 3.312, 3.315, 3.308,
    3.311, 3.314, 3.307, 3.316, 3.313,
    3.310, 3.308, 3.315, 3.312, 3.311,
    3.309, 3.317, 3.314, 3.310, 3.313,
]

mean = np.mean(vdd_samples)
std = np.std(vdd_samples, ddof=1)

sigma_levels = {
    "3s (99,73%)" : 3,
    "4s (99,9937%)" : 4,
    "6s (99,99966%)": 6,
}

print(f"Moyenne : {mean:.4f} V")
print(f"Écart-type : {std:.4f} V
")

for label, k in sigma_levels.items():
    lo = mean - k * std
    hi = mean + k * std
    print(f"{label:25s}  bas={lo:.4f}V  haut={hi:.4f}V")
Niveau sigmaCouvertureLimites dures (exemple VDD)
3-sigma99,73 %3,3026 V à 3,3212 V
4-sigma99,9937 %3,2995 V à 3,3243 V
6-sigma99,99966 %3,2933 V à 3,3305 V

Étape 4 : Ajouter des limites marginales (zone d'alerte)

Les limites marginales créent une zone d'alerte entre la limite souple et l'échec dur. Une carte dans la zone marginale passe mais est signalée pour surveillance.

ZonePlageRésultat
Passmoyenne +/- 2-sigmaPassage normal
Marginalmoyenne +/- 2-sigma à moyenne +/- 3-sigmaPassage avec avertissement
Failau-delà de moyenne +/- 3-sigmaÉchec dur

Étape 5 : Configurer les limites dans OpenHTF avec TofuPilot

vdd_test.py
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

# Dérivé de 40 échantillons de production : moyenne=3.3119V, écart-type=0.0031V
VDD_HARD_LOW      = 3.3026  # moyenne - 3-sigma
VDD_HARD_HIGH     = 3.3212  # moyenne + 3-sigma
VDD_MARGINAL_LOW  = 3.3057  # moyenne - 2-sigma
VDD_MARGINAL_HIGH = 3.3181  # moyenne + 2-sigma


@htf.measures(
    htf.Measurement("vdd_rail_voltage")
    .in_range(
        minimum=VDD_HARD_LOW,
        maximum=VDD_HARD_HIGH,
        marginal_minimum=VDD_MARGINAL_LOW,
        marginal_maximum=VDD_MARGINAL_HIGH,
    )
    .with_units(units.VOLT)
    .doc("Rail 3,3 V avec zone marginale [2-sigma, 3-sigma] pour la surveillance de dérive.")
)
def measure_vdd(test):
    voltage = read_voltage_at_tp12()
    test.measurements.vdd_rail_voltage = voltage


def main():
    test = htf.Test(
        measure_vdd,
        test_name="VDD Rail Validation",
    )
    with TofuPilot(test):
        test.execute(test_start=lambda: "SN-001")


if __name__ == "__main__":
    main()

Le résultat marginal d'OpenHTF correspond à MARGINAL_PASS dans TofuPilot. Vous pouvez filtrer par ce résultat dans le tableau de bord pour suivre les tendances de dérive sans arrêter la ligne.

Étape 6 : Suivre la dérive des limites dans TofuPilot

Relancez l'analyse sigma mensuellement et comparez :

refresh_limits.py
import numpy as np
from datetime import datetime


def compute_sigma_limits(samples: list[float], k: float = 3.0) -> dict:
    arr = np.array(samples)
    mean = np.mean(arr)
    std = np.std(arr, ddof=1)
    return {
        "n": len(arr),
        "mean": round(mean, 6),
        "std": round(std, 6),
        "low": round(mean - k * std, 6),
        "high": round(mean + k * std, 6),
        "sigma": k,
        "computed_at": datetime.utcnow().isoformat(),
    }

Comparez les nouvelles limites aux limites de production actuelles avant le déploiement. Un décalage de la moyenne supérieur à 1-sigma justifie une investigation du processus.

Déclencheur de revueAction
Décalage de la moyenne > 1-sigmaInvestiguer la cause racine avant de mettre à jour
Augmentation de l'écart-type > 20 %Vérifier le changement de bobine de composants ou la calibration de la station
Taux marginal > 5 %Resserrer les limites ou améliorer le processus
Nouvel échantillon N > 500Réévaluer le niveau sigma (envisager le 4-sigma)

Plus de guides

Mettez ce guide en pratique