Manufacturing and Predictive Maintenance
Industrial sensor and historian data
A factory's sensors report on different schedules and occasionally freeze or drift, so the raw data has to be aligned and checked before any model can trust it.
- 10 min read
- 3 reading levels
- Published
Read these first
On this page 5
One lesson, three depths. Pick the one that fits you today — you can switch any time.
Beginner — No maths. Plain English.
A factory's sensors do not all report at the same time, or always tell the truth.
Think about a hospital ICU, where machines beep and blink around a patient's bed. One monitor tracks heart rate every second. Another checks blood pressure every few minutes. A nurse does not expect all these readings to arrive at the same moment. She learns to read each one on its own schedule. She also learns to notice immediately if a monitor looks stuck.
A factory runs the same way, except the patients are machines, and there can be hundreds of them.
Why it exists
Every meaningful sensor on a factory floor — temperature, pressure, vibration, current draw — writes its readings into a system called a historian. A historian is a database built specifically to store huge streams of timestamped sensor values, often called tags.
Two things make this data harder to work with than a typical business dataset. First, different sensors report at different speeds. A vibration sensor on a spinning motor might report thousands of times a second. A tank's temperature might only need checking every few minutes. Nothing lines up on its own.
Second, sensors fail in quiet, easy-to-miss ways. A pressure gauge can jam and report the exact same number for hours, looking like a perfectly stable reading instead of a broken one. A model trained on that frozen data would learn a plainly false idea: that nothing changes.
How it works
Temperature sensor: reports every 1 second
Pressure sensor: reports every 5 seconds
|
v
[ line both up on one shared time grid ]
|
v
one clean table, both readings at every timestamp
Meanwhile, check: did any sensor freeze on one value for too long?
4.31, 4.14, 4.18, 4.18, 4.23 <- the repeated 4.18 is worth investigatingOnly once the data is aligned and checked does it become something a model — or a human engineer — can actually trust.
Where you have already seen it
- Your car's dashboard, quietly tracking engine temperature, RPM and fuel level continuously, even though you only glance at it occasionally.
- A smartwatch's heart-rate graph, which samples faster during exercise and slower at rest — the same "different sensors, different speeds" idea, on your wrist.
- A weather station's readings, where rainfall might be logged once an hour while wind speed updates every few seconds.
Remember this
- Different sensors on the same machine often report on completely different schedules, and need to be aligned before use.
- A sensor reporting the exact same value for too long is a warning sign, not a sign of stability.
- Clean, trustworthy sensor data is the foundation every other lesson in this section depends on.
What to learn next
- Predictive maintenance — what this cleaned-up sensor data is used to predict.
- Vibration analysis for rotating machines — one specific, especially rich kind of sensor data.
- What is time series data? — the general ideas this lesson applies to a factory floor.
Developer — Code and libraries.
Setup
pip install numpy pandasMinimal runnable code
A temperature sensor reports every second, a pressure sensor every five seconds — realistic and mismatched. We align them onto one shared time grid, then check for a sensor that got stuck.
import numpy as np
import pandas as pd
rng = np.random.default_rng(1)
# A temperature sensor reports every second. A pressure sensor on the
# same machine reports only every 5 seconds -- a very common real setup,
# since not every measurement needs the same update speed.
n_temp = 30
temp_times = pd.date_range("2026-08-20 09:00:00", periods=n_temp, freq="1s")
temperature = 70 + np.cumsum(rng.normal(0, 0.3, n_temp))
n_pressure = 6
pressure_times = pd.date_range("2026-08-20 09:00:00", periods=n_pressure, freq="5s")
pressure = 4.2 + rng.normal(0, 0.05, n_pressure)
# Simulate a stuck sensor: readings 3 and 4 freeze at the exact same value,
# a classic sign of a jammed or disconnected pressure transmitter.
pressure[3] = pressure[2]
temp_series = pd.Series(temperature, index=temp_times, name="temperature_C")
pressure_series = pd.Series(pressure, index=pressure_times, name="pressure_bar")
print("raw temperature readings (first 6):")
print(temp_series.head(6))
print()
print("raw pressure readings (all 6):")
print(pressure_series)
print()
# A historian question every model needs answered first: put both tags on
# one shared time grid, since they were never sampled at the same moments.
aligned = pd.DataFrame({"temperature_C": temp_series}).asfreq("1s")
aligned["pressure_bar"] = pressure_series.reindex(aligned.index).ffill()
print("aligned onto a common 1-second grid (first 8 rows):")
print(aligned.head(8))
print()
# Detect a frozen sensor: the same exact reading repeated for too long.
repeated = pressure_series.diff().eq(0)
print("pressure readings that exactly repeat the previous one (possible stuck sensor):")
print(repeated[repeated].index.tolist())raw temperature readings (first 6):
2026-08-20 09:00:00 70.103675
2026-08-20 09:00:01 70.350161
2026-08-20 09:00:02 70.449292
2026-08-20 09:00:03 70.058345
2026-08-20 09:00:04 70.329951
2026-08-20 09:00:05 70.463864
Freq: s, Name: temperature_C, dtype: float64
raw pressure readings (all 6):
2026-08-20 09:00:00 4.305892
2026-08-20 09:00:05 4.144399
2026-08-20 09:00:10 4.181120
2026-08-20 09:00:15 4.181120
2026-08-20 09:00:20 4.232335
2026-08-20 09:00:25 4.233153
Freq: 5s, Name: pressure_bar, dtype: float64
aligned onto a common 1-second grid (first 8 rows):
temperature_C pressure_bar
2026-08-20 09:00:00 70.103675 4.305892
2026-08-20 09:00:01 70.350161 4.305892
2026-08-20 09:00:02 70.449292 4.305892
2026-08-20 09:00:03 70.058345 4.305892
2026-08-20 09:00:04 70.329951 4.305892
2026-08-20 09:00:05 70.463864 4.144399
2026-08-20 09:00:06 70.302778 4.144399
2026-08-20 09:00:07 70.477113 4.144399
pressure readings that exactly repeat the previous one (possible stuck sensor):
[Timestamp('2026-08-20 09:00:15')]What actually happened
asfreq("1s") creates an evenly spaced 1-second time grid from the temperature sensor's own timestamps. reindex(...).ffill() places the pressure readings onto that same grid, forward-filling — carrying the last known pressure reading forward until a new one arrives. This is the standard way to combine tags recorded at different rates, and it is why every row from 09:00:00 to 09:00:04 shows the exact same pressure value: no new pressure reading arrived during that stretch.
The last check finds 09:00:15 — the one timestamp where pressure repeated its previous value exactly. In this small example that repeat was deliberately injected. In real historian data, a repeat lasting a few seconds is often nothing. A repeat lasting hours, on a sensor that should be constantly fluctuating, usually means the sensor itself has failed.
Common mistakes
Assuming every sensor updates at the same rate. Joining tables of differently sampled sensors with a plain merge, instead of an explicit forward-fill onto a shared grid, silently drops or misaligns most of the data.
Treating forward-filled values as if they were real new measurements. The pressure value at 09:00:03 in the table above is not a new reading — it is the last known one, carried forward. A model should ideally know the difference, which is why production pipelines often keep a separate "how stale is this reading" feature.
Flagging every repeated value as a broken sensor. A genuinely stable process can legitimately report the same rounded value more than once. The right threshold for "too long to be real" depends on how fast that specific sensor should be changing under normal operation.
Ignoring sensor drift, which is quieter than a frozen sensor. A sensor that slowly reports numbers a little too high, month after month, as it ages, will not show up as repeated values at all — it needs periodic calibration checks against a known reference, not only a repeat-detector like the one above.
Try it yourself
Change the stuck-sensor line to pressure[2:5] = pressure[2], freezing three consecutive readings instead of one. Re-run, and check how the list of flagged timestamps grows — that is what a genuinely failed sensor looks like, rather than one coincidental repeat.
What to learn next
Researcher — Mathematics and papers.
Historian architecture and the data model
Industrial historians (OSIsoft PI, Wonderware, Honeywell PHD, and open alternatives built on time-series databases) store data as sparse, irregularly sampled tag streams rather than dense regular time series, using exception-based reporting: a new value is written only when it changes by more than a configured deadband, or after a maximum time interval elapses, whichever comes first. This compresses storage dramatically for slowly changing signals, but means the raw stream itself already encodes an implicit, sensor-specific sampling policy that a naive asfreq + forward-fill, as used above, only partially reconstructs.
Aligning multi-rate signals rigorously
The developer example uses simple forward-fill, adequate for slowly varying tags like pressure or tank level. For fast-changing signals sampled at genuinely different native rates — a common case pairing a 10 kHz vibration accelerometer with a 1 Hz process temperature — naive forward-fill of the slow signal onto the fast grid, or downsampling the fast signal onto the slow grid by simple decimation, both discard information. Two standard alternatives:
- Windowed feature aggregation. Compute summary statistics (mean, RMS, peak) of the fast signal over each interval between slow-signal readings, rather than picking one point.
- Resampling with an explicit interpolation model. Linear or spline interpolation for physically smooth signals (temperature, pressure); never for signals with discrete state changes (a digital on/off tag), where interpolation would fabricate physically meaningless intermediate values.
Sensor fault taxonomy
Industrial condition-monitoring literature (Isermann, 2006, Fault-Diagnosis Systems) distinguishes several sensor fault modes that need different detection logic:
- Stuck-at fault — the repeated-value pattern detected above; detectable from a single tag's own history.
- Drift — a slow, monotonic bias growing over time; requires either a redundant reference sensor or a physical model of expected behaviour to detect, since the drifted signal still looks locally smooth and plausible.
- Spike/outlier noise — transient, physically implausible values; addressed with the methods in Z-scores, IQR fences and MAD or a domain-specific rate-of-change limit.
- Dropout — missing data entirely, distinct from a stuck value; needs explicit gap detection in the timestamp index itself, not only a check on the value column.
Why this groundwork disproportionately determines downstream model quality
Predictive-maintenance and process-monitoring models, covered in the rest of this section, are trained on engineered features built from exactly this kind of aligned, validated sensor history. A stuck or drifted sensor that goes undetected does not produce a model that fails outright — it produces a model that learned a subtly wrong relationship, and that failure mode is far more expensive to catch after deployment than before it. Industrial data-quality audits typically budget more engineering time for this alignment-and-validation stage than for the modelling stage that follows it.
Key references
- Isermann, R. (2006). Fault-Diagnosis Systems: An Introduction from Fault Detection to Fault Tolerance. Springer.
- Qin, S. J. (2012). Survey on Data-Driven Industrial Process Monitoring and Diagnosis. Annual Reviews in Control 36(2).