TECHNICAL BLOG
Deep Dives for Engineers
Detailed technical articles covering the real problems we solve in embedded systems, AI, and robotics engineering.
Detailed technical articles covering the real problems we solve in embedded systems, AI, and robotics engineering.
Practical approaches to detecting anomalies in high-frequency IoT sensor streams — from statistical baselines to LSTM autoencoders — with deployment considerations for edge and cloud.
Industrial IoT deployments generate continuous streams of sensor data — temperature, vibration, current draw, pressure, flow rate — at frequencies from 1 Hz to 10 kHz. Anomalies in these streams often precede equipment failures by hours or days. Detecting them reliably requires algorithms that handle temporal correlations, non-stationary distributions, and heavily imbalanced datasets where normal data vastly outnumbers anomalous events.
Before reaching for deep learning, validate simpler statistical approaches. Z-score detection on a rolling window is often sufficient for sensors with near-Gaussian distributions:
import pandas as pd
import numpy as np
def rolling_zscore_anomaly(series: pd.Series, window: int = 60, threshold: float = 3.5) -> pd.Series:
rolling_mean = series.rolling(window, center=True).mean()
rolling_std = series.rolling(window, center=True).std()
z_scores = (series - rolling_mean) / (rolling_std + 1e-8)
return z_scores.abs() > threshold
df["anomaly"] = rolling_zscore_anomaly(df["temperature_c"], window=120, threshold=3.0)
For multivariate sensors, Isolation Forest provides strong unsupervised baseline performance with minimal tuning:
from sklearn.ensemble import IsolationForest
model = IsolationForest(n_estimators=200, contamination=0.01, random_state=42)
df["anomaly_score"] = model.fit_predict(df[["temp", "vibration", "current"]])
When anomalies manifest as pattern deviations over time — a motor that gradually increases vibration over 30 minutes before failure — LSTM autoencoders are effective. They learn to reconstruct normal sequences; reconstruction error spikes on anomalous inputs.
import torch
import torch.nn as nn
class LSTMAutoencoder(nn.Module):
def __init__(self, input_size: int, hidden_size: int, num_layers: int):
super().__init__()
self.encoder = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.decoder = nn.LSTM(hidden_size, input_size, num_layers, batch_first=True)
def forward(self, x):
_, (h, c) = self.encoder(x)
# Repeat context vector for each timestep
context = h[-1].unsqueeze(1).repeat(1, x.size(1), 1)
output, _ = self.decoder(context)
return output
def compute_anomaly_score(model, sequence, threshold):
with torch.no_grad():
reconstruction = model(sequence)
mse = nn.functional.mse_loss(reconstruction, sequence, reduction="none")
score = mse.mean(dim=[1, 2])
return score > threshold
Threshold selection is where most anomaly detection systems fail in production. Setting it too low floods on-call teams with false positives; too high misses real failures. Best practice:
For low-latency anomaly detection that must act before a cloud round-trip, deploy the model at the edge. Export the trained model to ONNX and run it on the Jetson Nano or Raspberry Pi:
import onnxruntime as ort
import numpy as np
session = ort.InferenceSession("autoencoder.onnx")
input_name = session.get_inputs()[0].name
def detect_anomaly_edge(window: np.ndarray) -> bool:
reconstruction = session.run(None, {input_name: window[np.newaxis, ...]})[0]
mse = np.mean((reconstruction - window) ** 2)
return mse > THRESHOLD
Use cloud models for deeper historical analysis and threshold calibration, edge models for real-time response.
Start with statistical methods and Isolation Forest — they provide strong baselines with minimal data requirements and are interpretable. Add LSTM autoencoders when temporal pattern learning is needed. Always invest heavily in threshold calibration and production monitoring. An anomaly detection system that cries wolf is worse than none — it trains operators to ignore it.
Continue reading — handpicked articles you might enjoy