Skip to content

Predictive Maintenance Connector

The Predictive connector enriches an incoming Meddle payload with predictive maintenance metrics for one or more configured signals. For each signal it computes a trend (rate of change), a Remaining Useful Life (RUL) estimate in cycles, and a health score between 0 and 100. It also raises an optional alert flag when RUL falls below a user-defined threshold.

Connector Types:

  • Predictive - Stateful processor that maintains a rolling buffer per signal and emits enriched payloads

Although it’s a processor, the connector is categorized under industrial/ because its primary use case is condition monitoring of machines, motors, pumps, and other industrial assets.

  • ✅ Three trend computation methods: linear regression, moving average, EWMA
  • ✅ Per-signal upper and lower limits
  • ✅ RUL estimation in cycles toward the configured limits
  • ✅ Health score derived from distance to configured limits (0-100)
  • ✅ Optional RUL alert flag below a threshold
  • ✅ Lenient numeric coercion (handles ints, floats, strings)
  • ✅ Original payload preserved — predictive fields are merged in
{
"type": "Predictive",
"config": {
"signals": [
{
"key": "vibration_rms",
"upperLimit": 0.8,
"degradationRate": 0.001
}
],
"windowSize": 30,
"method": "linear_regression",
"alertOnRul": 168
}
}
{
"type": "Predictive",
"config": {
"signals": [
{
"key": "bearing_temperature",
"upperLimit": 95.0,
"lowerLimit": 20.0
}
],
"windowSize": 50,
"method": "ewma"
}
}
{
"type": "Predictive",
"config": {
"signals": [
{
"key": "motor_current",
"upperLimit": 25.0
},
{
"key": "vibration_rms",
"upperLimit": 0.8
},
{
"key": "oil_pressure",
"lowerLimit": 2.0
}
],
"windowSize": 30,
"method": "linear_regression",
"alertOnRul": 48
}
}

Required, non-empty list of signals to monitor.

{
"signals": [
{
"key": "vibration_rms",
"upperLimit": 0.8,
"lowerLimit": 0.0,
"degradationRate": 0.001
}
]
}

The payload key to read each cycle. Must match the incoming payload exactly.

{ "key": "vibration_rms" }

The configured operational bounds for this signal.

{
"upperLimit": 0.8,
"lowerLimit": 0.0
}
  • upperLimit - The “alarm high” value. When the trend is positive, RUL is computed as the distance to this limit divided by trend
  • lowerLimit - The “alarm low” value. When the trend is negative, RUL is computed as the distance below current value divided by |trend|

At least one of the two should be set for a meaningful RUL; otherwise RUL is reported as +Inf.

Reserved for future use (per-signal expected degradation slope). Optional.

{ "degradationRate": 0.001 }

Required. The number of recent samples to retain in the per-signal ring buffer.

{ "windowSize": 30 }

Recommended values:

  • Fast/clean signals: 10-30
  • Noisy industrial sensors: 50-200
  • Slow degradation signals: 500+

The window size also drives the EWMA smoothing factor: alpha = 2 / (windowSize + 1).

Required. One of:

  • linear_regression - Least-squares slope over the entire window (needs ≥ 3 samples)
  • moving_average - Difference between successive moving averages (needs ≥ 1 sample)
  • ewma - Exponentially weighted moving average; trend is delta between successive EWMA values (needs ≥ 1 sample)
{ "method": "linear_regression" }

Choosing a method:

  • Linear regression: best when you trust the recent past as a predictor of degradation slope (motor bearings, gradual wear)
  • Moving average: best when you want noise rejection but minimal lag
  • EWMA: best when recent samples should weigh more than old ones (rapidly changing systems)

Optional. When the RUL falls below this threshold (in cycles), the output payload is tagged with <key>_rul_alert: true.

{ "alertOnRul": 168 }

The unit is “cycles” — i.e. the number of samples until the signal is projected to hit its limit. To translate to wall-clock time, multiply by the sampling interval upstream.

Each signal produces three new keys (and optionally a fourth):

{
"vibration_rms": 0.62,
"vibration_rms_trend": 0.005,
"vibration_rms_rul": 36,
"vibration_rms_health_score": 22.5,
"vibration_rms_rul_alert": true
}
KeyMeaning
<key>_trendRate of change per cycle
<key>_rulRemaining Useful Life in cycles (or +Inf when not predictable)
<key>_health_score0-100 score (100 = healthy, 0 = at/beyond a limit)
<key>_rul_alertSet to true only when alertOnRul is configured and RUL is below it

The original keys from the incoming payload are passed through unchanged.

  • linear_regression: slope m = (n·Σxy − Σx·Σy) / (n·Σx² − (Σx)²) over the window
  • moving_average: mean(window_t) − mean(window_{t−1})
  • ewma: EWMA_t − EWMA_{t−1}, with alpha = 2 / (windowSize + 1)
  • If trend > 0 and upperLimit set: RUL = (upperLimit − currentVal) / trend
  • If trend < 0 and lowerLimit set: RUL = (currentVal − lowerLimit) / |trend|
  • Otherwise: RUL = +Inf (no meaningful estimate)

If the current value is already past the relevant limit, RUL = 0.

  • If both limits set: 100 means at the midpoint; 0 at either limit (linear)
  • If only upper: 100 at 0, 0 at upperLimit (linear)
  • If only lower: 100 at high values, 0 at lowerLimit
  • If neither: 100 (no constraints, signal informational)

All scores are clamped to [0, 100].

DataPayload → Predictive → DataPayload + (<key>_trend, _rul, _health_score, _rul_alert?)

Example (linear_regression, windowSize=10, upperLimit=0.8):

Last 10 samples of vibration_rms:

[0.42, 0.45, 0.47, 0.51, 0.55, 0.58, 0.60, 0.63, 0.65, 0.68]
  • Trend (slope): ≈ +0.029 per cycle
  • Current value: 0.68
  • RUL: (0.8 − 0.68) / 0.029 ≈ 4.1 cycles
  • Health score: ((0.8 − 0.68) / 0.8) × 100 = 15.0
  • If alertOnRul: 10 is set → _rul_alert: true

Monitor vibration RMS and predict failure 7 days out (assuming 1-minute sampling, 168 cycles/week × 60 ≈ 10080 cycles/week):

{
"type": "Predictive",
"config": {
"signals": [
{
"key": "vibration_rms",
"upperLimit": 0.8
}
],
"windowSize": 60,
"method": "linear_regression",
"alertOnRul": 10080
}
}
{
"type": "Predictive",
"config": {
"signals": [
{
"key": "oil_pressure_bar",
"lowerLimit": 2.0
}
],
"windowSize": 30,
"method": "ewma",
"alertOnRul": 240
}
}
{
"type": "Predictive",
"config": {
"signals": [
{ "key": "motor_current", "upperLimit": 25 },
{ "key": "discharge_pressure", "lowerLimit": 5, "upperLimit": 12 },
{ "key": "vibration_rms", "upperLimit": 0.7 },
{ "key": "bearing_temp", "upperLimit": 90 }
],
"windowSize": 50,
"method": "moving_average"
}
}

The downstream pipeline can compute an overall pump health score by aggregating <signal>_health_score keys.

Problem: Error reported for the first few samples

Solutions:

  1. Expected behavior — linear_regression needs at least 3 samples before it can emit a trend
  2. EWMA and moving average need at least 1 sample
  3. Use a Filter connector downstream to swallow the warning if desired

Problem: A signal value can’t be coerced to a number

Solutions:

  1. Confirm the upstream connector is delivering numeric values for the configured key
  2. Booleans, structs, and arrays cannot be processed — use a Transform upstream to extract a scalar
  3. Strings are accepted by upstream connectors that pass through OEE-style numeric parsing, but Predictive requires connector.ToFloat64-compatible types

Problem: Trend appears to be 0 or no limit is set

Solutions:

  1. The signal must have a non-zero trend AND a limit aligned with the trend direction
  2. If the signal isn’t changing, RUL is not meaningfully defined — this is correct behavior
  3. For a flat-but-degraded signal, prefer the health score over RUL

Problem: Spurious _rul_alert: true across many cycles

Solutions:

  1. Increase windowSize to smooth the trend estimate
  2. Switch from linear_regression to ewma for less-jittery trends
  3. Raise the alertOnRul threshold to align with your real lead time

Problem: Score sticks at 0

Solutions:

  1. Verify the current value is not already past the configured limit — if so, the score is correctly 0
  2. If only lowerLimit is set and the value equals 0, the formula value / lowerLimit is also 0
  3. Configure both upperLimit and lowerLimit for a midpoint-based score

1. Calibrate Limits Against Real Operating Data

Section titled “1. Calibrate Limits Against Real Operating Data”

Don’t lift upperLimit from a vendor datasheet. Profile the asset for a few weeks and pick a limit that’s 10-20% inside the catastrophic threshold.

For 1Hz data and weekly degradation, a window of ~1 hour (3600 samples) may be overkill — most degradation signals don’t need that much history. Start with ~30 samples and tune.

Section titled “3. Use Linear Regression for Diagnostic Trending”

Linear regression’s slope is the most interpretable trend output and is the right default for slow industrial degradation.

The first ≤ 3 samples produce trends of zero or RUL of +Inf. Use a Trigger or Filter downstream so alerts don’t fire spuriously at startup.

Feed the _rul_alert flag into an Isa182 block to apply standardized acknowledgement workflow on top of the raw prediction.

ModbusReader → Predictive → Isa182 → Alert (email)
  1. ModbusReader: Pulls vibration_rms and bearing_temp from a vibration sensor
  2. Predictive: Computes trend, RUL, and health score for both signals
  3. Isa182: Triggers an alarm when vibration_rms_rul_alert == true or bearing_temp_health_score < 30
  4. Alert: Emails the maintenance team
OpcuaReader → Predictive → Reshape → Chart (gauge per signal)
└→ InfluxDb2Writer
  1. OpcuaReader: Reads all relevant signals from the asset’s OPC UA server
  2. Predictive: Enriches each signal with _trend, _rul, _health_score
  3. Reshape: Restructures the payload for chart consumption
  4. Chart: Renders one gauge per signal’s health score
  5. InfluxDb2Writer: Persists for long-term trend analysis