MiravoMiravo

Lifecycle And faults

Model wear over operating hours and named failure modes that change runtime values, then see the health change in tags and protocol output.

Lifecycle models long-term wear across operating hours. Faults are named failures that fire from a lifecycle stage, a process condition, or manual injection.

Technical details

Lifecycle stages

lifecycle:
  stages:
    - name: healthy
      duration_hours: [4000, 7000]
      effects: {}
    - name: degraded
      duration_hours: [1000, 2000]
      effects:
        vibration_baseline: { multiplier: 1.4 }
        bearing_temperature: { offset: 8 }
    - name: critical
      duration_hours: [300, 700]
      effects:
        vibration_baseline: { multiplier: 2.0 }
        bearing_temperature: { offset: 18 }

Stages are an ordered list. The model author picks the names and the count. duration_hours is a [min, max] range, and each asset gets its own random length within it. Effects blend over 60 simulated seconds at each transition.

lifecycle.running_member is optional. It must name a Boolean member of the same model, and operating hours advance only while that member's previous-step process value is true. Without it, operating hours always accumulate. Every built-in model sets it except storage-tank, a passive vessel with no running state, so a machine on a production line stops wearing while its station is off shift, on break, down or starved. Assets created with starting_hours start at that age regardless.

Reset wear with maintenance

Operating hours never rewind, but wear can be reset. Maintenance restores a lifecycle stage, restarts the stage clock, keeps the asset's randomized stage durations, and ramps effects back over 60 simulated seconds. By default it also clears active faults and cancels pending precursors. Every maintenance action emits an asset:maintenance event (reason: manual or scheduled), which appears in the event log.

To schedule preventive maintenance in the model, set lifecycle.maintenance. The first service happens one interval after spawn, even for assets created with starting_hours.

lifecycle:
  maintenance:
    interval_hours: 2000      # operating hours between services
    restores_to: healthy      # optional, defaults to the first stage
  stages:
    # ...

To allow manual maintenance, expose it as a method with the reset-lifecycle runtime. Both fields are optional: stage (default: restores_to, else the first stage) and clear_faults (default true).

methods:
  Maintain:
    description: "Service the pump: restore the healthy stage."
    runtime:
      type: reset-lifecycle
    output_arguments:
      accepted: { data_type: Boolean }

OPC UA clients call it as a method. Over the admin API, send a command. The admin API needs credentials unless Miravo runs with --no-auth, so the examples below use the default admin:admin.

curl -s -u admin:admin http://127.0.0.1:8080/api/commands \
  -H 'content-type: application/json' \
  -d '{"type":"invokeMethod","assetId":"pump-001","method":"Maintain"}'

The built-in pump, motor, compressor, and conveyor models ship a Maintain method. There is no dedicated CLI command.

Faults

faults:
  - name: cavitation
    trigger:
      condition: "discharge_pressure < 2.5"
      rate_per_hour: 36
    effects:
      vibration_radial: { spike: 1.8, duration_s: 180 }
      flow_rate: { multiplier: 0.75, duration_s: 180 }

  - name: bearing_wear
    trigger:
      lifecycle_stage: degraded
      rate_per_hour: 14.4
    effects:
      bearing_temperature: { offset: 6, duration_s: 600 }

A fault condition reads previous-step process values, before observation effects. Substeps let faults cascade within an accelerated tick.

rate_per_hour is a Poisson rate. Each simulated step of dt seconds triggers the fault with p = 1 - exp(-rate_per_hour * dt / 3600).

trigger.lifecycle_stage is an exact match, not "this stage and later". The fault can trigger only while the asset is in that stage, and the check repeats on every step. A bearing_wear fault with lifecycle_stage: early_wear keeps firing through the whole early_wear stage and stops firing when the asset enters degraded or any later stage. An already active fault is not cancelled by a stage change: it runs out its own duration. To cover several stages, add one fault per stage, or drop lifecycle_stage and gate on a condition. For an end-of-life failure, set lifecycle_stage: critical, no duration_s (the fault holds until cleared), and a rate high enough to fire within the stage's minimum duration_hours. The built-in rotating models ship one.

duration_s, onset_s, and recovery_s are simulated seconds. The longest effect duration sets when the fault clears on its own. Leave out the duration for manual clearing, and leave out onset_s or recovery_s for an instant change. Ramps follow simulated time, not tick count.

On an object-form effect, quality: bad or quality: uncertain degrades the member's reported quality while the fault is active (the worse of this and the observation quality). The quality reaches the MQTT quality field and the OPC UA StatusCode. Modbus has no quality channel. For example, liquid_temperature: { multiplier: 0, quality: bad, duration_s: 900 } models an open-circuit RTD.

Add a precursor before the failure

Real degradation shows up before the failure event. A precursor ramps multiplier and offset effects linearly from 0 to 1 over duration_s after the trigger fires. The fault itself activates, and fault:triggered fires, only when the ramp ends.

faults:
  - name: bearing_wear
    trigger:
      lifecycle_stage: degraded
      rate_per_hour: 14.4
    precursor:
      duration_s: 1800
      effects:
        vibration_axial: { multiplier: 1.15 }
        bearing_temperature: { offset: 2 }
    effects:
      vibration_axial: { multiplier: 1.4, duration_s: 600 }
      bearing_temperature: { offset: 6, duration_s: 600 }

During the precursor there is no event, the fault-active and fault-count bindings do not change, and the drift shows up only in member values. Persisted state resumes the precursor after a restart. The precursor phase draws no random numbers.

List each precursor member in the fault's effects too. The precursor ends at activation, or fades out as that effect's onset_s ramps in. Keep precursor magnitudes below the fault's. miravo inject and triggerFault skip the precursor and activate the fault at once. A clear-faults method such as ResetFault, and maintenance, cancel it.

Inject or clear a fault

Inject a fault.

miravo inject pump-001 cavitation

Clear the same fault.

miravo inject pump-001 cavitation --clear

Reference

Field or bindingNotes
duration_hours[min, max] range for the stage length, randomized per asset
Lifecycle effect fieldsmultiplier, offset
Lifecycle stage extrasscrap_rate_add (see Production lines)
Fault trigger fieldslifecycle_stage, condition, rate_per_hour
Fault effect fieldsspike, multiplier, offset, quality, duration_s, onset_s, recovery_s
Fault precursor fieldsduration_s, effects (per member multiplier and offset)
Fault production effectproduction_effect: stop, { derate }, or { scrap }
Lifecycle maintenanceinterval_hours, restores_to
Maintenance methodruntime.type: reset-lifecycle, optional stage and clear_faults
Fault state bindingsfault-active, fault-count, active-fault-code, health-state
Lifecycle bindinglifecycle-stage

Was this page useful?

Last updated on