Test Data & Analytics

Hardware Telemetry Analysis

Learn how to collect, store, and analyze hardware sensor telemetry data using TofuPilot's measurement arrays and dashboards.

JJulien Buteau
intermediate10 min readNovember 18, 2025

Sensor data from hardware tests is only useful if you can find patterns across thousands of runs. Storing telemetry as structured, indexed measurements is what lets you surface trends before they become production issues.

What Hardware Telemetry Looks Like in Practice

A single hardware test run can produce hundreds of sensor readings: temperature curves, voltage traces, vibration spectra, pressure waveforms. Without a structured system, this data ends up in CSV files on shared drives, impossible to query at scale.

Treat every sensor measurement as a first-class object. Each reading gets a name, unit, limits, and an optional array dimension for time-series or multi-axis data.

Ingesting Sensor Data

OpenHTF Users

OpenHTF measurements flow in automatically. Multi-dimensional arrays (1D waveforms, 2D matrices, ND tensors) are processed without code changes.

telemetry_test.py
27 lines
import openhtf as htffrom tofupilot.openhtf import upload@htf.measures(    htf.Measurement("temperature_curve").with_dimensions("time_s"),    htf.Measurement("vibration_spectrum").with_dimensions("freq_hz"),)def sensor_sweep(test):    for t in range(100):        test.measurements.temperature_curve[t] = read_thermocouple()    for f in range(500):        test.measurements.vibration_spectrum[f] = read_accelerometer_fft(f)def main():    test = htf.Test(        sensor_sweep,        procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",  # procedure UUID from the dashboard        part_number="DUT-100",    )    test.add_output_callbacks(upload())    test.execute(lambda: "DUT-001")if __name__ == "__main__":    main()

Install it with pip install "tofupilot[openhtf]". The upload() callback reads TOFUPILOT_API_KEY from the environment.

Python SDK Users

If you are not running OpenHTF, create the run directly. Dimensional data goes in as a series of measurements under a phase:

upload_telemetry.py
35 lines
import osfrom datetime import datetime, timedelta, timezoneimport numpy as npfrom tofupilot.v2 import TofuPilotstarted = datetime.now(timezone.utc) - timedelta(seconds=30)ended = datetime.now(timezone.utc)waveform = np.sin(np.linspace(0, 2 * np.pi, 1000))ripple_pk_pk = float(waveform.max() - waveform.min())with TofuPilot(api_key=os.getenv("TOFUPILOT_API_KEY")) as client:    client.runs.create(        procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",        serial_number="PSU-2025-0042",        part_number="PSU-100",        outcome="PASS",        started_at=started,        ended_at=ended,        phases=[{            "name": "Output Ripple",            "outcome": "PASS",            "started_at": started,            "ended_at": ended,            "measurements": [{                "name": "Ripple Peak to Peak",                "measured_value": ripple_pk_pk,                "units": "mV",                "validators": [                    {"operator": "<=", "expected_value": 50},                ],            }],        }],    )

Note what this example does with the waveform: it uploads the extracted scalar, not the thousand raw samples. That is deliberate, and it is the single most useful habit in telemetry work. Store the features you will actually query on (peak-to-peak, rise time, overshoot) as measurements with limits, and keep the full capture as an attachment on failures or a sample. A test record platform is for results; it is not a time-series acquisition store, and uploading every sample from every unit will outgrow its usefulness fast.

Querying Telemetry at Scale

Once ingested, every measurement is queryable. Filter by procedure, unit serial number, date range, or outcome.

QueryWhat it shows
All runs for a procedure over the last 7 daysRipple voltage trends across production
Failed runs with temperature_curve out of limitsUnits that exceeded thermal specs
Measurement distribution for vibration_spectrumHistogram of vibration amplitudes across the fleet

Catching Telemetry Drift

Measurement distributions are tracked over time. When a sensor reading starts drifting toward its limits, you can catch it before it causes failures.

The practical approach is to alert on the trend rather than the threshold. By the time a reading crosses its limit, the drift has usually been present for weeks. Watch the mean and the spread separately: a moving mean with a tight spread points to something that shifted, such as a recalibrated instrument or a new component lot, while a stable mean with a widening spread points to something that became inconsistent, such as a worn fixture or temperature variation across a shift.

This matters most for temperature sensors, where gradual calibration drift goes unnoticed until units start failing in the field.

Where This Pays Off

A thermal cycling test across 8 temperature zones produces 8 time-series measurements per run, one per zone. The manual version of this is downloading CSV files from each chamber controller, merging them in a spreadsheet, and checking limits by hand.

With the measurements uploaded per run, the limits are evaluated on ingest and the zone-by-zone history is queryable across the full production record. The gain is not that the analysis becomes possible; it is that it stops depending on someone remembering to do it.

More Guides

Put this guide into practice