Datasheet limits are starting points, not production limits. Real boards have tolerances, assembly variation, and environmental drift that datasheets cannot capture. This guide shows you how to collect measurement data from your production line, apply the 3-sigma method to derive statistically sound limits, and configure those limits in OpenHTF with TofuPilot tracking.
Prerequisites
- TofuPilot account with production run data
- Python 3.8+
numpyandscipyinstalled- At least 30 test samples (100+ recommended)
Why Datasheet Limits Are Not Enough
| Source of Variation | Example |
|---|---|
| Component tolerance | Resistor +/-5% shifts output voltage |
| PCB trace impedance | Layout differences across panel positions |
| Assembly variation | Solder joint resistance changes |
| Environmental drift | Temperature at test station vs. field |
| Measurement noise | Probe contact, cable length |
A 3.3V rail with a datasheet range of +/-5% (3.135V-3.465V) may show actual production distribution centered at 3.31V with a std of 0.012V. Setting limits from the datasheet alone misses that your process is drifting high.
Step 1: Collect Baseline Samples
You need a minimum of 30 samples from boards you have already validated as good. Use 100+ for stable sigma estimates.
import numpy as np# Simulated collection from known-good boards# In practice, export from TofuPilot or accumulate from live runsvdd_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) # sample std, not populationprint(f"N={n} mean={mean:.4f}V std={std:.4f}V")# N=40 mean=3.3119V std=0.0031VUse ddof=1 for sample standard deviation when your sample size is less than the full population.
Step 2: Check for Outliers and Bimodal Distributions
Before computing limits, inspect the distribution. A bimodal distribution signals two distinct populations.
import numpy as npfrom scipy import statsvdd_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,]# Z-score outlier detectionz_scores = np.abs(stats.zscore(vdd_samples))outliers = [v for v, z in zip(vdd_samples, z_scores) if z > 3]print(f"Outliers (|z| > 3): {outliers}")# Shapiro-Wilk normality teststat, p = stats.shapiro(vdd_samples)print(f"Shapiro-Wilk p={p:.4f} ({'normal' if p > 0.05 else 'NOT normal'})")If Shapiro-Wilk returns p < 0.05, investigate whether your samples came from two assembly batches or two component reels.
Step 3: Compute 3-Sigma Limits
The 3-sigma rule covers 99.73% of a normal distribution (roughly 2700 DPMO at the limit edge).
import numpy as npvdd_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"Mean: {mean:.4f} V")print(f"Std: {std:.4f} V")for label, k in sigma_levels.items(): lo = mean - k * std hi = mean + k * std print(f"{label:25s} low={lo:.4f}V high={hi:.4f}V")| Sigma Level | Coverage | Hard limits (VDD example) |
|---|---|---|
| 3-sigma | 99.73% | 3.3026V to 3.3212V |
| 4-sigma | 99.9937% | 3.2995V to 3.3243V |
| 6-sigma | 99.99966% | 3.2933V to 3.3305V |
Step 4: Add Marginal Limits (Warning Zone)
Marginal limits create a warning zone between the soft limit and the hard fail. A board in the marginal zone passes but gets flagged for monitoring.
| Zone | Range | Result |
|---|---|---|
| Pass | mean +/- 2-sigma | Normal pass |
| Marginal | mean +/- 2-sigma to mean +/- 3-sigma | Pass with warning |
| Fail | outside mean +/- 3-sigma | Hard fail |
Step 5: Configure Limits in OpenHTF with TofuPilot
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import TofuPilot# Derived from 40 production samples: mean=3.3119V, std=0.0031VVDD_HARD_LOW = 3.3026 # mean - 3-sigmaVDD_HARD_HIGH = 3.3212 # mean + 3-sigmaVDD_MARGINAL_LOW = 3.3057 # mean - 2-sigmaVDD_MARGINAL_HIGH = 3.3181 # mean + 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("3.3V rail with marginal zone [2-sigma, 3-sigma] for drift monitoring."))def measure_vdd(test): voltage = read_voltage_at_tp12() test.measurements.vdd_rail_voltage = voltagedef 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()OpenHTF marginal outcome maps to MARGINAL_PASS in TofuPilot. You can filter by this outcome in the dashboard to track drift trends without stopping the line.
Step 6: Track Limit Drift in TofuPilot
Re-run the sigma analysis monthly and compare:
import numpy as npfrom datetime import datetimedef 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(), }Compare new limits to current production limits before deploying. A shift in mean greater than 1-sigma warrants a process investigation.
| Review Trigger | Action |
|---|---|
| Mean shift > 1-sigma | Investigate root cause before updating |
| Std increase > 20% | Check component reel change or station calibration |
| Marginal rate > 5% | Tighten limits or improve process |
| New sample N > 500 | Re-evaluate sigma level (consider 4-sigma) |