Measurement drift is a gradual shift in your test data over time. Parts still pass today, but the distribution is drifting 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.
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. The current gap between the smoothed average and that baseline is expressed in σ, multiples of the series' own normal variation.
| Severity | Fires 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, add a dedicated custom rule in the "Configure rules" tab.
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. Why this self-calibrating design was chosen over a fixed threshold, and how it was calibrated on real production data, is covered in Setting Alert Thresholds That Actually Work.
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.
drift_sensitive_test.py58 lines
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import upload@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, ) test.add_output_callbacks(upload()) 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.
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. You can also filter by stations, parts, revisions with this view.
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 you accept this new baseline as the new "normal", you can manually resolve the alert in the alerts page. 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.
