AIOps for Industrial IoT: Multivariate Anomaly Detection & Root-Cause
A modern plant emits a relentless stream of telemetry — thousands of OT sensors (temperatures, pressures, vibration, flow) alongside IT signals from the systems that run alongside them. Threshold alarms on each tag individually produce thousands of alerts a day, most of them noise, and bury the few that matter. AIOps replaces per-tag thresholds with models that understand the system as a whole: detecting multivariate anomalies, correlating related alerts, and pointing at the likely root cause. This article covers the streaming architecture that does it.
Why single-tag thresholds fail
A bearing temperature of 70°C may be normal at full load and alarming at idle. Static thresholds can't encode that context, so operators either set them loose (and miss real events) or tight (and drown in false alarms). The fix is to model the joint behaviour of related sensors and flag deviations from the learned normal operating envelope — which depends on load, ambient conditions, and the relationships between tags.
Fusing IT and OT on one bus
OT data arrives over OPC-UA/Modbus from PLCs and historians; IT data arrives as logs and metrics. An edge gateway normalises both into a common schema (tag, timestamp, value, quality, asset-id) and publishes to Kafka. Co-locating IT and OT on one bus is what lets a single model reason across, say, a controller error log and the vibration spike it preceded — the correlation that single-domain tools miss.
Windowing and alignment
Sensors sample at different rates and drift out of sync. A stream processor aligns tags onto a common cadence, resamples, and emits fixed sliding windows per asset. Robust scaling (median/IQR) is fit offline and applied online so a single stuck sensor doesn't distort the whole window.
The anomaly model: an LSTM autoencoder
We train an LSTM autoencoder on windows of healthy operation. It learns to reconstruct normal multivariate dynamics; at inference, a high reconstruction error means the current behaviour doesn't match anything healthy — without needing labelled failures. The per-sensor error vector also tells you which tags drove the anomaly, which seeds root-cause analysis.
Streaming scoring with an LSTM autoencoder
import torch, numpy as np
model = torch.jit.load("lstm_ae.ts").eval().cuda() # trained on healthy windows
thr = load_thresholds() # per-asset, from val set
def score_window(win): # win: [T, n_sensors] aligned + scaled
x = torch.tensor(win, dtype=torch.float32).cuda().unsqueeze(0)
with torch.no_grad():
recon = model(x)
err = ((recon - x) ** 2).mean(dim=1).squeeze(0).cpu().numpy() # per-sensor
score = float(err.mean())
drivers = np.argsort(err)[::-1][:5] # top contributing sensors
return score, drivers
score, drivers = score_window(window)
if score > thr[asset_id]:
emit_anomaly(asset_id, score, sensors=[tag_names[i] for i in drivers])
From anomalies to incidents: correlation over topology
A single fault ripples across connected assets and raises many simultaneous anomalies. Treating each as its own ticket recreates the noise problem. We attach a topology graph — how assets connect physically and in process flow — and correlate anomalies that are close in time and adjacent in the graph into one incident. Root-cause analysis then walks the graph and the per-sensor drivers to nominate the most likely originating asset.
Graph-based alert correlation and root-cause nomination
def correlate(anomalies, topology, window="5min"):
incidents = []
for group in cluster_by_time(anomalies, window):
sub = topology.subgraph([a.asset_id for a in group])
# the upstream-most node with earliest onset is the likely cause
root = min(sub.nodes, key=lambda n: (onset_time(n, group),
sub.in_degree(n)))
incidents.append(Incident(root_cause=root,
members=group,
impact=business_impact(group)))
return rank_by_impact(incidents)
Operations and the learning loop
Operators confirm or dismiss incidents and tag the true root cause; that feedback retrains thresholds and the model, and false-alarm sources get suppressed. Windows of confirmed-healthy operation continually refresh the autoencoder so "normal" tracks seasonal and load changes. As with our other systems, the cold-path feedback loop is what keeps the hot path honest over time.
What this delivers
Thousands of daily alerts become a handful of actionable incidents with root-cause nominations, IT and OT are reasoned about together, and emerging failures are caught before they cascade into downtime. The architecture is domain-agnostic across the asset-heavy industries — power, cement, steel — wherever the cost of a missed event dwarfs the cost of watching everything at once.
All insights