Skip to main content

Asset health scoring

At a glance

Effort: ~20–30 minutes · You'll build: a composite 0–100 health index from several signals, with a healthy/watch/critical classification · Stack: the SDK plus a little arithmetic — no model training.

A machine rarely fails on one signal. Vibration is creeping up, the bearing runs a little hot, oil pressure sags at load — each is fine alone, but together they tell a story. A health score rolls those signals into one comparable number so an operator can rank a whole fleet at a glance and a dashboard can show green/amber/red. It's the lightweight cousin of predictive maintenance: no model to train, just a transparent, tunable index.

New to machine learning?

No background needed. Skim the gentle primer for the ideas in plain language — model, feature, training, and the algorithm itself — and use Generate sample data for a sandbox to run this against.

Need data to run this?

This reads several pump signals. Generate a sandbox first — section A ingests pump_07_bearing_temp_c, pump_07_oil_pressure_kpa and a stand-in pump_07_vibration_anomaly (or run predictive maintenance to produce the real one).

1. Pull the latest value of each signal

Take the most recent reading (or short average) of each contributing series for the asset.

import datahub_sdk, pandas as pd

client = datahub_sdk.DataHubClient.from_env()

def latest(external_id):
rf = datahub_sdk.RetrieveFilter(
ts=external_id,
start=pd.Timestamp.now(tz="UTC") - pd.Timedelta(minutes=15),
end=pd.Timestamp.now(tz="UTC"),
aggregates=["avg"], granularity="15m")
pts = client.timeseries.retrieve_datapoints(rf)[0].get_datapoints()
return float(pts[-1].average)

signals = {
"vibration": latest("pump_07_vibration_anomaly"), # 0..~1, from the anomaly model
"bearing_temp": latest("pump_07_bearing_temp_c"),
"oil_pressure": latest("pump_07_oil_pressure_kpa"),
}

2. Normalise each signal to a "badness" in 0–1

Every signal lives on its own scale, so map each to a common 0 (fine) → 1 (alarm) range against its healthy and limit values. A reading at or below healthy scores 0; at or above the limit scores 1; in between, it ramps linearly.

def badness(value, healthy, limit):
if limit == healthy:
return 0.0
return max(0.0, min(1.0, (value - healthy) / (limit - healthy)))

LIMITS = { # (healthy, limit) per signal
"vibration": (0.05, 0.30),
"bearing_temp": (60.0, 90.0),
"oil_pressure": (350.0, 250.0), # inverted: lower is worse
}
parts = {k: badness(v, *LIMITS[k]) for k, v in signals.items()}

3. Weight, combine, and classify

Weight the signals by how much each matters for this asset class, combine into a 0–100 score (100 = perfect health), and bucket it.

WEIGHTS = {"vibration": 0.5, "bearing_temp": 0.3, "oil_pressure": 0.2}

badness_total = sum(parts[k] * WEIGHTS[k] for k in parts)
score = round(100 * (1 - badness_total), 1)

band = "healthy" if score >= 80 else "watch" if score >= 60 else "critical"

4. Publish the score and flag the bad ones

Write the score back as its own series — now you can chart, rank and subscribe to asset health like any other signal — and raise an event when an asset drops to critical.

client.timeseries.create([datahub_sdk.TimeSeries(
external_id="pump_07_health_score", name="Pump 07 health score", unit="score", value_type="float")])
client.timeseries.insert_from_lists(
timestamps=[pd.Timestamp.now(tz="UTC")], values=[score], ts="pump_07_health_score")

if band == "critical":
client.events.create([datahub_sdk.Event(
external_id=f"health_critical_pump_07_{int(pd.Timestamp.now().timestamp())}",
type="health_critical", status="open",
event_time=pd.Timestamp.now(tz="UTC"),
metadata={"asset": "pump_07", "score": str(score),
"worst_signal": max(parts, key=parts.get)})])

Run it across the fleet on a schedule and you have a single ranked health view — worst_signal in the metadata tells maintenance why each asset is red.

Where to take it further

  • Feed it the model. Swap the hand-set vibration limits for the anomaly score as a direct input.
  • Trend the score. A falling health score over days is itself a predictor — forecast it like any other series.
  • Roll up the graph. Average child scores up a site graph for a line- or plant-level health number.

Further reading

See also