Skip to content
Test Data & Analytics

How to Detect Measurement Drift with TofuPilot

Learn how TofuPilot grades measurement drift against each series' own baseline, and how to write tests that make a real shift visible early.

JJulien Buteau
intermediate8 min readMarch 14, 2026

Measurement drift is a gradual shift in your test data over time. Parts still pass today, but the distribution is creeping toward a spec limit. TofuPilot grades every numeric measurement series for drift automatically, so the question is no longer whether someone remembered to look at the chart. This guide explains what triggers a drift alert, and how to write tests that make a real shift visible early.

What Causes Drift

Drift has real physical causes. Knowing them helps you investigate when an alert fires.

Instrument aging is the most common. A DMM's calibration drifts over months. A current sense resistor changes value with thermal cycling. A force gauge spring weakens with use.

Fixture wear matters too. Pogo pins lose spring force after thousands of contacts. Test sockets develop intermittent connections. Alignment features wear down, changing DUT positioning.

Environmental changes are subtler. Seasonal temperature shifts affect analog measurements. Humidity changes impact high-impedance readings. Facility voltage fluctuations add noise.

Component lot variation comes from your supply chain. A new reel of resistors from a different lot shifts your circuit's behavior slightly. The parts are all in spec, but the distribution center moved.

How TofuPilot Detects Drift

There is no threshold to configure. Each measurement series is judged against its own history, not against an absolute limit.

TofuPilot maintains a smoothed average of the series and replays that same statistic at many points across the measurement's past. That replay answers the only question that matters: how much does this measurement normally move? The current gap between the smoothed average and that baseline is then expressed in σ (sigma) — multiples of the series' own normal variation.

SeverityFires at
Info≥ 3σ
Warning≥ 4σ
Critical≥ 5σ

Because the scale is relative, a 2 mV shift on a rock-steady reference and a 200 mV shift on a noisy rail can both be the same severity. That is the point: a threshold that is right for one measurement is wrong for the next one.

Two properties are worth knowing when you read an alert:

  • Each part is its own series. Two product variants tested by one procedure are two physical populations, so they never share a baseline. The alert names the part it fired on.
  • Stations are pooled. Two benches running the same procedure share one baseline, which maximizes coverage but dilutes a problem confined to a single bench. If one station's volume justifies its own baseline, scope a custom rule to it.

A series needs at least 70 values before it is graded at all, and 100 before the full severity ladder unlocks. If a new line produces no drift alerts, this is usually why. The full method, including the noise guards that deliberately suppress alerts, is documented in automatic detection.

One Alert per Event, Not per Measurement

A single physical cause rarely moves a single measurement. A degrading fixture or a warm afternoon moves everything downstream of it at once.

TofuPilot groups automatic drift into one alert per procedure and part. Every drifting measurement attaches to that alert with its own entry in the timeline, and the alert names the strongest one. It resolves only once every attached measurement has recovered. So a bad night on one line reads as one incident with six measurements listed inside it, not six separate notifications.

Writing Tests That Reveal Drift

Drift detection needs consistent, repeatable measurements with enough resolution to see small shifts. Use physical units, set limits with margin, and avoid rounding.

Rounding deserves emphasis: a value quantized to a coarse grid carries no information below one step of that grid, and TofuPilot will not report a shift finer than the step it detects in your data. Recording 2.4988 V rather than 2.5 V is what makes early drift visible at all.

drift_sensitive_test.py
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import TofuPilot@htf.measures(    htf.Measurement("ref_voltage")    .with_units(units.VOLT)    .in_range(minimum=2.495, maximum=2.505),    htf.Measurement("temp_sensor")    .in_range(minimum=23.0, maximum=27.0),    htf.Measurement("adc_offset")    .in_range(minimum=-3, maximum=3),)def calibration_check(test):    """Measure reference points that are sensitive to drift."""    test.measurements.ref_voltage = 2.4988    test.measurements.temp_sensor = 24.6    test.measurements.adc_offset = 1@htf.measures(    htf.Measurement("contact_resistance")    .in_range(maximum=0.100)    .with_units(units.OHM),    htf.Measurement("leakage_current")    .in_range(maximum=0.000001)    .with_units(units.AMPERE),)def fixture_health_check(test):    """Track fixture-related measurements that degrade over time."""    test.measurements.contact_resistance = 0.0423    test.measurements.leakage_current = 0.00000012@htf.measures(    htf.Measurement("gain")    .in_range(minimum=19.5, maximum=20.5),    htf.Measurement("phase_margin")    .in_range(minimum=45.0),    htf.Measurement("output_impedance")    .in_range(maximum=2.0)    .with_units(units.OHM),)def analog_performance_test(test):    """Measure analog parameters prone to component lot variation."""    test.measurements.gain = 20.05    test.measurements.phase_margin = 52.3    test.measurements.output_impedance = 1.1def main():    test = htf.Test(        calibration_check,        fixture_health_check,        analog_performance_test,    )    with TofuPilot(test):        test.execute(test_start=lambda: "UNIT-1001")if __name__ == "__main__":    main()

The fixture_health_check phase is particularly useful. Contact resistance that climbs from 40 to 80 mohm over a few weeks tells you the fixture needs maintenance, even though every reading still passes.

Splitting measurements by channel rather than collapsing them into one pass/fail is the other habit that pays. A drift confined to channel 3 is actionable; a generic "the LED test is failing more" is not.

Investigating a Drift Alert

The alert tells you a series moved. The measurement data tells you why.

Open the series in TofuPilot and read the trend chart first: drift shows up as a consistent slope. The control chart adds the statistical view, flagging the classic Western Electric patterns — one point beyond 3σ, two of three consecutive points beyond 2σ on the same side, four of five beyond 1σ on the same side, and eight consecutive points on one side of the center line.

Then narrow the scope before you touch any hardware. Filter by station and by time range. Because stations share one baseline, a drift caused by a single worn fixture shows up as a pooled shift, and the station filter is what separates "the process moved" from "bench 2 moved".

Responding to Drift

When you confirm drift, the response depends on the cause.

For instrument drift, recalibrate and verify with a known reference, then check whether your calibration interval is too long.

For fixture wear, inspect and replace the worn components. Track the fixture's cycle count and set preventive maintenance from the drift data you have collected.

For environmental drift, correlate with facility logs. If temperature is the driver, improve environmental control around the station or add temperature compensation to the measurement.

For component lot variation, compare the distributions before and after the lot change. If the shift is significant but still in spec, the new baseline will establish itself as the series accumulates values. If it is borderline, work with your supplier on tighter incoming specs.

Once the cause is fixed, the alert closes on its own: the series has to measure recovered on three consecutive values before TofuPilot resolves it, which is what stops an alert from closing on a single lucky reading.

More Guides

Put this guide into practice