VFD-0004 — VFD process-loop hunting
| Status | verified — engine e2ff2f8, cxf:fnv1a128:2589d83e4938cac060cbe7919a919495, 2026-08-20 |
| Severity | 3 |
| Method | rule |
| Phase | 2 |
| Category | EFFICIENCY_LOSS |
| Confidence | MEDIUM |
| Estimation | QUALITATIVE_ONLY |
| G36 | — |
| Clusters | — |
| Suppresses | — |
| Suppressed by | VFD-0001, VFD-0005 |
| Related | VFD-0002, VFD-0003 |
| Playbooks | vfd-pump-faults |
| Source | NIST, Automatically Detecting Faulty Regulation in HVAC Controls (2013), pp. 412 and 416-419 — setpoint allowance bands, oscillatory regulation, regulating-variable hunting, reset exclusions, and field-tuned alarm parameters; Library precedent VAV-0005 — verified rolling-mean crossing count plus rolling MAD hunting topology and its sampling/count-scale contract; Library precedent AHU-0022 — moving-average/MAD implementation and warm-up treatment; its short/long onset ratio is not reused because it self-clears sustained hunting; PNNL Variable Speed Drives O&M Best Practice — trend drive output speed/frequency with the controlled process variable |
| Operating states | drive and one identified process loop in settled remote automatic operation |
Preconditions (host-enforced): The drive must be enabled and accepting remote automatic control; VFD-0005 suppresses the rule during local/hand or bypass operation, and VFD-0001 suppresses it while speed feedback cannot establish actual drive motion. Exclude startup, shutdown, smoke/purge, lead/lag changeover, commissioning, manual tuning tests, safety/current/torque/demand limits, and real load or setpoint-reset transitions until the loop is settled. vfd_process_value and vfd_process_sp must be the same loop in the same units, and pv_allowance_band must be configured in those units. The host must report NO_EVAL for the first evaluation_window after valid operation begins. Use a fixed tick in [14.3 s, 150 s) at the defaults, 60 s recommended, with count_scale = evaluation_window / tick; irregular timing and change-of-value deadbands invalidate the counts. When any gate is unmet the verdict is NO_EVAL, not healthy.
Points: vfd_speed, vfd_process_value, vfd_process_sp
Outputs:
yFault— True after both the material speed-hunting and unstable-process subconditions remain active continuously for alarm_persistenceySpeedHunting— Immediate diagnostic; true when rolling speed mean-crossing count and rolling speed MAD both exceed their strict limitsyProcessUnstable— Immediate diagnostic; true when process-error mean crossings exceed the count limit and rolling mean absolute error from setpoint exceeds pv_allowance_band
Parameters:
| Name | Default | Unit | CXF path | Description |
|---|---|---|---|---|
evaluation_window | 900.0 | s | muSpeed.delta, crossRate.delta, speedMad.delta, muProcess.delta, processCrossRate.delta, pvMae.delta | ADOPTED_TUNABLE informed by AHU-0022’s 15-minute scatter window. Drives all six rolling means and must be changed on every listed path together. |
max_crossings_per_window | 6.0 | 1 | crossHigh.t, processCrossHigh.t | ADOPTED_TUNABLE: maximum allowed rolling mean crossings for each lane. The strict comparisons mean six clears and seven faults; one physical cycle normally yields two crossings. |
min_speed_mad | 5.0 | % | amplitudeHigh.t | ADOPTED_TUNABLE: rolling mean absolute speed deviation above which motion is material. Five MAD points equal a 10-point peak-to-peak square wave; waveform conversion differs for a sine. |
pv_allowance_band | 10.0 | 1 | pvBandHigh.t | NO_PORTABLE_DEFAULT: rolling mean absolute process error in the bound loop’s own units. The executable 10.0 is an adoption-blocking placeholder. |
count_scale | 15.0 | 1 | crossCount.k, processCrossCount.k | DERIVED: evaluation_window / fixed host tick = 900/60. Both event-count lanes must be retuned together whenever the window or tick changes. |
alarm_persistence | 300.0 | s | persist.delayTime | ADOPTED_TUNABLE: continuous overlap of both instability diagnostics required before alarm (5 min). |
Description
The drive and its process are moving together, but not settling. A poorly tuned loop, noisy process signal, conflicting reset sequence, mechanical backlash, or an application limit can make speed repeatedly overshoot its own center while the controlled quantity repeatedly moves and remains materially away from setpoint. The rule requires evidence in both places. Speed oscillation with a stable process is useful tuning evidence but not this combined fault; process oscillation behind a steady drive points somewhere else.
Detection Logic
speed_mean = MovingAverage(vfd_speed, evaluation_window)
speed_count = MovingAverage(Change(vfd_speed > speed_mean), window)
* count_scale
speed_mad = MovingAverage(abs(vfd_speed - speed_mean), window)
ySpeedHunting = speed_count > max_crossings_per_window
AND speed_mad > min_speed_mad
process_err = vfd_process_value - vfd_process_sp
process_mean = MovingAverage(process_err, evaluation_window)
process_count = MovingAverage(Change(process_err > process_mean), window)
* count_scale
process_mae = MovingAverage(abs(process_err), evaluation_window)
yProcessUnstable = process_count > max_crossings_per_window
AND process_mae > pv_allowance_band
yFault = TrueDelay(ySpeedHunting AND yProcessUnstable, alarm_persistence)
Each Boolean Change pulse is converted to integer and then real before its
rolling average, as shown in the CXF graph.
Block graph (rule.cxf.jsonld):
Both diagnostics are immediate rolling subconditions; only their overlap is delayed. Stable operation clears them by aging old pulses and deviations out of the trailing windows. A fresh engine instance resets the rings, edge histories, and persistence timer.
Possible Diagnoses
- PID gain too high or integral time too short for the driven system.
- Noisy, quantized, or intermittently connected process sensor.
- Conflicting control loops or reset sequences acting on the same drive.
- Mechanical backlash, sticking damper/valve, unstable pump system, or rapidly changing system resistance.
- A real load disturbance, staging event, or setpoint reset that the host did not exclude.
- Drive current/torque/application limits interacting with the BAS loop.
Energy Impact
EFFICIENCY_LOSS, MEDIUM confidence, QUALITATIVE_ONLY. The loss is application dependent: extra cube-law fan/pump work on high excursions, process energy that overshoots and is corrected, and wear from continuous speed changes. The rule has no power point or application model, so it reports hunting duration rather than an invented savings percentage.
Emissions Impact
Scope 2, qualitative. Any avoidable motor and process energy is purchased electricity. Convert measured incremental energy after diagnosis; the rolling statistics themselves have no emissions factor.
Deviations
- Mean crossings substitute for literal direction reversals. This is the
verified VAV-0005 implementation: a periodic cycle produces two of either,
while drift with ripple can differ. The parameter is therefore named
max_crossings_per_window, notminimum_reversals. - The roadmap’s 10% speed excursion becomes 5% MAD. For a square wave, 10 points peak-to-peak is +/-5 and has MAD 5. A 10-point peak-to-peak sine has MAD about 3.2, so waveform shape matters. Computed-statistic boundaries are bracketed in vectors rather than asserted on exact equality ticks.
- The process lane is an adaptation, not NIST’s two-sided CUSUM. It counts crossings of process error around its rolling mean and independently requires mean absolute error from the true setpoint. This rejects stable offset but intentionally admits a one-sided oscillatory offset; the dedicated vector pins that broader behavior.
- The same crossing limit is applied to both lanes. NIST publishes no
VFD-specific value of six. It is one adopted, jointly tuned concept and both
strict comparisons use
> 6. pv_allowance_bandhas no portable default. The executable 10.0 must be replaced in the loop’s own units before deployment.- Event counts are tick-coupled. A one-tick pulse has area equal to the
preceding tick interval;
count_scale = evaluation_window / dtconverts its moving average back to a count. Irregular ticks bias individual events. - The legal sampling interval is narrow. The 64-checkpoint ring requires
dt >= 900/63 = 14.3 s, while strictcount > 6requiresdt < 900/6 = 150 s. At the current replay harness’s 300-second cadence this rule can never alarm. Sixty seconds is the only cadence exercised here. - Warm-up is host-gated. Partial-window divisors extrapolate the observed
event pace, so a startup burst can raise raw diagnostics despite
delayOnInit=true; the first 900 seconds are NO_EVAL. - Moving averages are continuous-time integrals, not sample statistics, and event history is half-open: an event exactly one window old has aged out.
- Change-of-value and sub-tick blindness remain. A wide COV deadband hides crossings; an even number of reversals between samples can return to the same observed value and disappear entirely.
- Suppressions are instance-scoped. VFD-0001 and VFD-0005 invalidate this drive’s speed/automatic-loop premise. Their raw states should gate evaluation immediately; waiting for another rule’s delayed alarm creates a race.
- No simulation FPR is claimed. The harness has neither a genuine VFD speed/PV/ setpoint triplet nor a legal hunting cadence.
Notes
The diagnostic split is the investigation order. If only ySpeedHunting is
true, inspect speed command, feedback, limits, and mechanical response before
retuning the process loop. If only yProcessUnstable is true, the disturbance
or sensor is not being driven by measured VFD motion. When both are true, first
exclude a legitimate reset/load step, then compare their phase: process motion
leading speed suggests real load or noise; speed leading process suggests
tuning or actuator behavior.
Test Vectors
18 scenarios, clock step 60 s over 7200 s.
| Scenario | Description |
|---|---|
constant_speed_first_sample_artifact | Constant speed and satisfied PV remain clear. The speed-mean crossing branch has a zero-area initialization pulse and one harmless fill artifact, neither of which can satisfy both speed criteria. |
load_step_monotonic_recovery | After a settled baseline, speed moves once from 50% to 60% while PV carries a 20-unit error for only five minutes. The error area is below pv_allowance_band times the window and the speed never repeatedly crosses its center. |
fast_shallow_dither | A four-minute speed cycle crosses often but stays at +/-4%; its settled speed MAD is below the strict 5-point materiality threshold. PV is satisfied. |
speed_mad_just_below_threshold | A +/-4.9% square speed wave brackets the computed materiality boundary from the nonfaulting side. Rolling MAD is not asserted at an exact equality edge; the process branch is independently active. |
speed_mad_just_above_threshold | A +/-5.1% square wave brackets the materiality boundary from the active side. Fast crossings and unstable process error allow the combined fault to mature. |
speed_hunting_process_stable | Material fast speed motion is present, but PV stays on setpoint; the speed diagnostic can guide tuning without producing the combined fault. |
slow_deep_speed_motion | A deep ten-minute speed cycle has large MAD but only three mean crossings per 900-second window, below the strict count limit. PV remains unsatisfied, isolating the speed-frequency rejection. |
process_unstable_speed_stable | PV alternates 12 units around setpoint while speed is fixed. The process diagnostic is active after warm-up, but the rule refuses to call it VFD hunting without material speed crossings. |
count_exactly_allowed | A 900-second repeating speed pattern produces six mean crossings per full window with material MAD. The strict count > 6 comparison keeps ySpeedHunting and the combined fault clear while the process branch is active. |
one_crossing_over_limit | A repeating seven-crossing pattern is one event above the allowed six, with material speed MAD and unstable process error; all raw criteria and the delayed fault remain active after warm-up. |
pv_mae_exactly_threshold | With established speed hunting, a constant absolute PV error of exactly 10.0 loop units leaves the strict process-MAE comparison false and blocks the fault. |
pv_mae_just_over_threshold | A 10.1-unit mean absolute PV error brackets the process boundary from the active side while the speed branch is materially hunting. |
persistent_both_error_directions | Material speed hunting paired with PV alternating above and below setpoint proves the process statistic is symmetric and the combined fault persists. |
one_sided_oscillatory_process_offset | PV oscillates between 20 and 30 units above setpoint while speed hunts. Crossings around the rolling process-error mean plus MAE from the real setpoint intentionally classify this one-sided oscillatory offset as unstable; this is broader than NIST’s two-sided allowance-band CUSUM. |
window_aging_clears | The loop hunts through t=3600 s and then speed settles while PV remains 11 units off setpoint. The process diagnostic stays active; speed crossings and MAD must age out before the fault clears. |
warmup_burst_raw_behavior | Eight tick-rate speed changes during the partial-window fill can be extrapolated above the rolling count threshold while PV is off setpoint. The raw result is pinned; hosts must report NO_EVAL during the first evaluation window. |
setpoint_step_excluded_raw_behavior | A setpoint step at t=1800 followed by sustained materially reversing speed raises the raw diagnostics and fault. Deployment must instead report NO_EVAL until reset and disturbance response are settled. |
subtick_hunting_aliases_clear | A host sampling once per minute cannot see an even number of reversals that occur and return between samples; the staged trace is therefore constant and every output stays clear. This pins the Nyquist limitation, not healthy plant behavior. |
vectors.json
{
"schema": "cxf-library/vectors/v1",
"clock": {
"step_s": 60,
"horizon_s": 7200
},
"scenarios": [
{
"name": "constant_speed_first_sample_artifact",
"description": "Constant speed and satisfied PV remain clear. The speed-mean crossing branch has a zero-area initialization pulse and one harmless fill artifact, neither of which can satisfy both speed criteria.",
"inputs": {
"vfd_speed": 50.0,
"vfd_process_value": 100.0,
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 0,
"to_s": 7200,
"equals": false
}
]
},
{
"name": "load_step_monotonic_recovery",
"description": "After a settled baseline, speed moves once from 50% to 60% while PV carries a 20-unit error for only five minutes. The error area is below pv_allowance_band times the window and the speed never repeatedly crosses its center.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 50.0
},
{
"t": 1800,
"value": 60.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 100.0
},
{
"t": 1800,
"value": 120.0
},
{
"t": 2100,
"value": 100.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 0,
"to_s": 7200,
"equals": false
}
]
},
{
"name": "fast_shallow_dither",
"description": "A four-minute speed cycle crosses often but stays at +/-4%; its settled speed MAD is below the strict 5-point materiality threshold. PV is satisfied.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 54.0
},
{
"t": 120,
"value": 46.0
},
{
"t": 240,
"value": 54.0
},
{
"t": 360,
"value": 46.0
},
{
"t": 480,
"value": 54.0
},
{
"t": 600,
"value": 46.0
},
{
"t": 720,
"value": 54.0
},
{
"t": 840,
"value": 46.0
},
{
"t": 960,
"value": 54.0
},
{
"t": 1080,
"value": 46.0
},
{
"t": 1200,
"value": 54.0
},
{
"t": 1320,
"value": 46.0
},
{
"t": 1440,
"value": 54.0
},
{
"t": 1560,
"value": 46.0
},
{
"t": 1680,
"value": 54.0
},
{
"t": 1800,
"value": 46.0
},
{
"t": 1920,
"value": 54.0
},
{
"t": 2040,
"value": 46.0
},
{
"t": 2160,
"value": 54.0
},
{
"t": 2280,
"value": 46.0
},
{
"t": 2400,
"value": 54.0
},
{
"t": 2520,
"value": 46.0
},
{
"t": 2640,
"value": 54.0
},
{
"t": 2760,
"value": 46.0
},
{
"t": 2880,
"value": 54.0
},
{
"t": 3000,
"value": 46.0
},
{
"t": 3120,
"value": 54.0
},
{
"t": 3240,
"value": 46.0
},
{
"t": 3360,
"value": 54.0
},
{
"t": 3480,
"value": 46.0
},
{
"t": 3600,
"value": 54.0
},
{
"t": 3720,
"value": 46.0
},
{
"t": 3840,
"value": 54.0
},
{
"t": 3960,
"value": 46.0
},
{
"t": 4080,
"value": 54.0
},
{
"t": 4200,
"value": 46.0
},
{
"t": 4320,
"value": 54.0
},
{
"t": 4440,
"value": 46.0
},
{
"t": 4560,
"value": 54.0
},
{
"t": 4680,
"value": 46.0
},
{
"t": 4800,
"value": 54.0
},
{
"t": 4920,
"value": 46.0
},
{
"t": 5040,
"value": 54.0
},
{
"t": 5160,
"value": 46.0
},
{
"t": 5280,
"value": 54.0
},
{
"t": 5400,
"value": 46.0
},
{
"t": 5520,
"value": 54.0
},
{
"t": 5640,
"value": 46.0
},
{
"t": 5760,
"value": 54.0
},
{
"t": 5880,
"value": 46.0
},
{
"t": 6000,
"value": 54.0
},
{
"t": 6120,
"value": 46.0
},
{
"t": 6240,
"value": 54.0
},
{
"t": 6360,
"value": 46.0
},
{
"t": 6480,
"value": 54.0
},
{
"t": 6600,
"value": 46.0
},
{
"t": 6720,
"value": 54.0
},
{
"t": 6840,
"value": 46.0
},
{
"t": 6960,
"value": 54.0
},
{
"t": 7080,
"value": 46.0
}
],
"vfd_process_value": 100.0,
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 0,
"to_s": 7200,
"equals": false
}
]
},
{
"name": "speed_mad_just_below_threshold",
"description": "A +/-4.9% square speed wave brackets the computed materiality boundary from the nonfaulting side. Rolling MAD is not asserted at an exact equality edge; the process branch is independently active.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 54.9
},
{
"t": 120,
"value": 45.1
},
{
"t": 240,
"value": 54.9
},
{
"t": 360,
"value": 45.1
},
{
"t": 480,
"value": 54.9
},
{
"t": 600,
"value": 45.1
},
{
"t": 720,
"value": 54.9
},
{
"t": 840,
"value": 45.1
},
{
"t": 960,
"value": 54.9
},
{
"t": 1080,
"value": 45.1
},
{
"t": 1200,
"value": 54.9
},
{
"t": 1320,
"value": 45.1
},
{
"t": 1440,
"value": 54.9
},
{
"t": 1560,
"value": 45.1
},
{
"t": 1680,
"value": 54.9
},
{
"t": 1800,
"value": 45.1
},
{
"t": 1920,
"value": 54.9
},
{
"t": 2040,
"value": 45.1
},
{
"t": 2160,
"value": 54.9
},
{
"t": 2280,
"value": 45.1
},
{
"t": 2400,
"value": 54.9
},
{
"t": 2520,
"value": 45.1
},
{
"t": 2640,
"value": 54.9
},
{
"t": 2760,
"value": 45.1
},
{
"t": 2880,
"value": 54.9
},
{
"t": 3000,
"value": 45.1
},
{
"t": 3120,
"value": 54.9
},
{
"t": 3240,
"value": 45.1
},
{
"t": 3360,
"value": 54.9
},
{
"t": 3480,
"value": 45.1
},
{
"t": 3600,
"value": 54.9
},
{
"t": 3720,
"value": 45.1
},
{
"t": 3840,
"value": 54.9
},
{
"t": 3960,
"value": 45.1
},
{
"t": 4080,
"value": 54.9
},
{
"t": 4200,
"value": 45.1
},
{
"t": 4320,
"value": 54.9
},
{
"t": 4440,
"value": 45.1
},
{
"t": 4560,
"value": 54.9
},
{
"t": 4680,
"value": 45.1
},
{
"t": 4800,
"value": 54.9
},
{
"t": 4920,
"value": 45.1
},
{
"t": 5040,
"value": 54.9
},
{
"t": 5160,
"value": 45.1
},
{
"t": 5280,
"value": 54.9
},
{
"t": 5400,
"value": 45.1
},
{
"t": 5520,
"value": 54.9
},
{
"t": 5640,
"value": 45.1
},
{
"t": 5760,
"value": 54.9
},
{
"t": 5880,
"value": 45.1
},
{
"t": 6000,
"value": 54.9
},
{
"t": 6120,
"value": 45.1
},
{
"t": 6240,
"value": 54.9
},
{
"t": 6360,
"value": 45.1
},
{
"t": 6480,
"value": 54.9
},
{
"t": 6600,
"value": 45.1
},
{
"t": 6720,
"value": 54.9
},
{
"t": 6840,
"value": 45.1
},
{
"t": 6960,
"value": 54.9
},
{
"t": 7080,
"value": 45.1
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "speed_mad_just_above_threshold",
"description": "A +/-5.1% square wave brackets the materiality boundary from the active side. Fast crossings and unstable process error allow the combined fault to mature.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 55.1
},
{
"t": 120,
"value": 44.9
},
{
"t": 240,
"value": 55.1
},
{
"t": 360,
"value": 44.9
},
{
"t": 480,
"value": 55.1
},
{
"t": 600,
"value": 44.9
},
{
"t": 720,
"value": 55.1
},
{
"t": 840,
"value": 44.9
},
{
"t": 960,
"value": 55.1
},
{
"t": 1080,
"value": 44.9
},
{
"t": 1200,
"value": 55.1
},
{
"t": 1320,
"value": 44.9
},
{
"t": 1440,
"value": 55.1
},
{
"t": 1560,
"value": 44.9
},
{
"t": 1680,
"value": 55.1
},
{
"t": 1800,
"value": 44.9
},
{
"t": 1920,
"value": 55.1
},
{
"t": 2040,
"value": 44.9
},
{
"t": 2160,
"value": 55.1
},
{
"t": 2280,
"value": 44.9
},
{
"t": 2400,
"value": 55.1
},
{
"t": 2520,
"value": 44.9
},
{
"t": 2640,
"value": 55.1
},
{
"t": 2760,
"value": 44.9
},
{
"t": 2880,
"value": 55.1
},
{
"t": 3000,
"value": 44.9
},
{
"t": 3120,
"value": 55.1
},
{
"t": 3240,
"value": 44.9
},
{
"t": 3360,
"value": 55.1
},
{
"t": 3480,
"value": 44.9
},
{
"t": 3600,
"value": 55.1
},
{
"t": 3720,
"value": 44.9
},
{
"t": 3840,
"value": 55.1
},
{
"t": 3960,
"value": 44.9
},
{
"t": 4080,
"value": 55.1
},
{
"t": 4200,
"value": 44.9
},
{
"t": 4320,
"value": 55.1
},
{
"t": 4440,
"value": 44.9
},
{
"t": 4560,
"value": 55.1
},
{
"t": 4680,
"value": 44.9
},
{
"t": 4800,
"value": 55.1
},
{
"t": 4920,
"value": 44.9
},
{
"t": 5040,
"value": 55.1
},
{
"t": 5160,
"value": 44.9
},
{
"t": 5280,
"value": 55.1
},
{
"t": 5400,
"value": 44.9
},
{
"t": 5520,
"value": 55.1
},
{
"t": 5640,
"value": 44.9
},
{
"t": 5760,
"value": 55.1
},
{
"t": 5880,
"value": 44.9
},
{
"t": 6000,
"value": 55.1
},
{
"t": 6120,
"value": 44.9
},
{
"t": 6240,
"value": 55.1
},
{
"t": 6360,
"value": 44.9
},
{
"t": 6480,
"value": 55.1
},
{
"t": 6600,
"value": 44.9
},
{
"t": 6720,
"value": 55.1
},
{
"t": 6840,
"value": 44.9
},
{
"t": 6960,
"value": 55.1
},
{
"t": 7080,
"value": 44.9
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 7200,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "speed_hunting_process_stable",
"description": "Material fast speed motion is present, but PV stays on setpoint; the speed diagnostic can guide tuning without producing the combined fault.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4440,
"value": 40.0
},
{
"t": 4560,
"value": 60.0
},
{
"t": 4680,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4920,
"value": 40.0
},
{
"t": 5040,
"value": 60.0
},
{
"t": 5160,
"value": 40.0
},
{
"t": 5280,
"value": 60.0
},
{
"t": 5400,
"value": 40.0
},
{
"t": 5520,
"value": 60.0
},
{
"t": 5640,
"value": 40.0
},
{
"t": 5760,
"value": 60.0
},
{
"t": 5880,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6120,
"value": 40.0
},
{
"t": 6240,
"value": 60.0
},
{
"t": 6360,
"value": 40.0
},
{
"t": 6480,
"value": 60.0
},
{
"t": 6600,
"value": 40.0
},
{
"t": 6720,
"value": 60.0
},
{
"t": 6840,
"value": 40.0
},
{
"t": 6960,
"value": 60.0
},
{
"t": 7080,
"value": 40.0
}
],
"vfd_process_value": 100.0,
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 0,
"to_s": 7200,
"equals": false
}
]
},
{
"name": "slow_deep_speed_motion",
"description": "A deep ten-minute speed cycle has large MAD but only three mean crossings per 900-second window, below the strict count limit. PV remains unsatisfied, isolating the speed-frequency rejection.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 65.0
},
{
"t": 300,
"value": 35.0
},
{
"t": 600,
"value": 65.0
},
{
"t": 900,
"value": 35.0
},
{
"t": 1200,
"value": 65.0
},
{
"t": 1500,
"value": 35.0
},
{
"t": 1800,
"value": 65.0
},
{
"t": 2100,
"value": 35.0
},
{
"t": 2400,
"value": 65.0
},
{
"t": 2700,
"value": 35.0
},
{
"t": 3000,
"value": 65.0
},
{
"t": 3300,
"value": 35.0
},
{
"t": 3600,
"value": 65.0
},
{
"t": 3900,
"value": 35.0
},
{
"t": 4200,
"value": 65.0
},
{
"t": 4500,
"value": 35.0
},
{
"t": 4800,
"value": 65.0
},
{
"t": 5100,
"value": 35.0
},
{
"t": 5400,
"value": 65.0
},
{
"t": 5700,
"value": 35.0
},
{
"t": 6000,
"value": 65.0
},
{
"t": 6300,
"value": 35.0
},
{
"t": 6600,
"value": 65.0
},
{
"t": 6900,
"value": 35.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "process_unstable_speed_stable",
"description": "PV alternates 12 units around setpoint while speed is fixed. The process diagnostic is active after warm-up, but the rule refuses to call it VFD hunting without material speed crossings.",
"inputs": {
"vfd_speed": 50.0,
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "count_exactly_allowed",
"description": "A 900-second repeating speed pattern produces six mean crossings per full window with material MAD. The strict count > 6 comparison keeps ySpeedHunting and the combined fault clear while the process branch is active.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 150,
"value": 40.0
},
{
"t": 300,
"value": 60.0
},
{
"t": 450,
"value": 40.0
},
{
"t": 600,
"value": 60.0
},
{
"t": 750,
"value": 40.0
},
{
"t": 900,
"value": 60.0
},
{
"t": 1050,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1350,
"value": 40.0
},
{
"t": 1500,
"value": 60.0
},
{
"t": 1650,
"value": 40.0
},
{
"t": 1800,
"value": 60.0
},
{
"t": 1950,
"value": 40.0
},
{
"t": 2100,
"value": 60.0
},
{
"t": 2250,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2550,
"value": 40.0
},
{
"t": 2700,
"value": 60.0
},
{
"t": 2850,
"value": 40.0
},
{
"t": 3000,
"value": 60.0
},
{
"t": 3150,
"value": 40.0
},
{
"t": 3300,
"value": 60.0
},
{
"t": 3450,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3750,
"value": 40.0
},
{
"t": 3900,
"value": 60.0
},
{
"t": 4050,
"value": 40.0
},
{
"t": 4200,
"value": 60.0
},
{
"t": 4350,
"value": 40.0
},
{
"t": 4500,
"value": 60.0
},
{
"t": 4650,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4950,
"value": 40.0
},
{
"t": 5100,
"value": 60.0
},
{
"t": 5250,
"value": 40.0
},
{
"t": 5400,
"value": 60.0
},
{
"t": 5550,
"value": 40.0
},
{
"t": 5700,
"value": 60.0
},
{
"t": 5850,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6150,
"value": 40.0
},
{
"t": 6300,
"value": 60.0
},
{
"t": 6450,
"value": 40.0
},
{
"t": 6600,
"value": 60.0
},
{
"t": 6750,
"value": 40.0
},
{
"t": 6900,
"value": 60.0
},
{
"t": 7050,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "one_crossing_over_limit",
"description": "A repeating seven-crossing pattern is one event above the allowed six, with material speed MAD and unstable process error; all raw criteria and the delayed fault remain active after warm-up.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 900,
"value": 40.0
},
{
"t": 1020,
"value": 60.0
},
{
"t": 1140,
"value": 40.0
},
{
"t": 1260,
"value": 60.0
},
{
"t": 1380,
"value": 40.0
},
{
"t": 1500,
"value": 60.0
},
{
"t": 1620,
"value": 40.0
},
{
"t": 1800,
"value": 60.0
},
{
"t": 1920,
"value": 40.0
},
{
"t": 2040,
"value": 60.0
},
{
"t": 2160,
"value": 40.0
},
{
"t": 2280,
"value": 60.0
},
{
"t": 2400,
"value": 40.0
},
{
"t": 2520,
"value": 60.0
},
{
"t": 2700,
"value": 40.0
},
{
"t": 2820,
"value": 60.0
},
{
"t": 2940,
"value": 40.0
},
{
"t": 3060,
"value": 60.0
},
{
"t": 3180,
"value": 40.0
},
{
"t": 3300,
"value": 60.0
},
{
"t": 3420,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4500,
"value": 40.0
},
{
"t": 4620,
"value": 60.0
},
{
"t": 4740,
"value": 40.0
},
{
"t": 4860,
"value": 60.0
},
{
"t": 4980,
"value": 40.0
},
{
"t": 5100,
"value": 60.0
},
{
"t": 5220,
"value": 40.0
},
{
"t": 5400,
"value": 60.0
},
{
"t": 5520,
"value": 40.0
},
{
"t": 5640,
"value": 60.0
},
{
"t": 5760,
"value": 40.0
},
{
"t": 5880,
"value": 60.0
},
{
"t": 6000,
"value": 40.0
},
{
"t": 6120,
"value": 60.0
},
{
"t": 6300,
"value": 40.0
},
{
"t": 6420,
"value": 60.0
},
{
"t": 6540,
"value": 40.0
},
{
"t": 6660,
"value": 60.0
},
{
"t": 6780,
"value": 40.0
},
{
"t": 6900,
"value": 60.0
},
{
"t": 7020,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 6900,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 6900,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 6900,
"equals": true
}
]
},
{
"name": "pv_mae_exactly_threshold",
"description": "With established speed hunting, a constant absolute PV error of exactly 10.0 loop units leaves the strict process-MAE comparison false and blocks the fault.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4440,
"value": 40.0
},
{
"t": 4560,
"value": 60.0
},
{
"t": 4680,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4920,
"value": 40.0
},
{
"t": 5040,
"value": 60.0
},
{
"t": 5160,
"value": 40.0
},
{
"t": 5280,
"value": 60.0
},
{
"t": 5400,
"value": 40.0
},
{
"t": 5520,
"value": 60.0
},
{
"t": 5640,
"value": 40.0
},
{
"t": 5760,
"value": 60.0
},
{
"t": 5880,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6120,
"value": 40.0
},
{
"t": 6240,
"value": 60.0
},
{
"t": 6360,
"value": 40.0
},
{
"t": 6480,
"value": 60.0
},
{
"t": 6600,
"value": 40.0
},
{
"t": 6720,
"value": 60.0
},
{
"t": 6840,
"value": 40.0
},
{
"t": 6960,
"value": 60.0
},
{
"t": 7080,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 110.0
},
{
"t": 120,
"value": 90.0
},
{
"t": 240,
"value": 110.0
},
{
"t": 360,
"value": 90.0
},
{
"t": 480,
"value": 110.0
},
{
"t": 600,
"value": 90.0
},
{
"t": 720,
"value": 110.0
},
{
"t": 840,
"value": 90.0
},
{
"t": 960,
"value": 110.0
},
{
"t": 1080,
"value": 90.0
},
{
"t": 1200,
"value": 110.0
},
{
"t": 1320,
"value": 90.0
},
{
"t": 1440,
"value": 110.0
},
{
"t": 1560,
"value": 90.0
},
{
"t": 1680,
"value": 110.0
},
{
"t": 1800,
"value": 90.0
},
{
"t": 1920,
"value": 110.0
},
{
"t": 2040,
"value": 90.0
},
{
"t": 2160,
"value": 110.0
},
{
"t": 2280,
"value": 90.0
},
{
"t": 2400,
"value": 110.0
},
{
"t": 2520,
"value": 90.0
},
{
"t": 2640,
"value": 110.0
},
{
"t": 2760,
"value": 90.0
},
{
"t": 2880,
"value": 110.0
},
{
"t": 3000,
"value": 90.0
},
{
"t": 3120,
"value": 110.0
},
{
"t": 3240,
"value": 90.0
},
{
"t": 3360,
"value": 110.0
},
{
"t": 3480,
"value": 90.0
},
{
"t": 3600,
"value": 110.0
},
{
"t": 3720,
"value": 90.0
},
{
"t": 3840,
"value": 110.0
},
{
"t": 3960,
"value": 90.0
},
{
"t": 4080,
"value": 110.0
},
{
"t": 4200,
"value": 90.0
},
{
"t": 4320,
"value": 110.0
},
{
"t": 4440,
"value": 90.0
},
{
"t": 4560,
"value": 110.0
},
{
"t": 4680,
"value": 90.0
},
{
"t": 4800,
"value": 110.0
},
{
"t": 4920,
"value": 90.0
},
{
"t": 5040,
"value": 110.0
},
{
"t": 5160,
"value": 90.0
},
{
"t": 5280,
"value": 110.0
},
{
"t": 5400,
"value": 90.0
},
{
"t": 5520,
"value": 110.0
},
{
"t": 5640,
"value": 90.0
},
{
"t": 5760,
"value": 110.0
},
{
"t": 5880,
"value": 90.0
},
{
"t": 6000,
"value": 110.0
},
{
"t": 6120,
"value": 90.0
},
{
"t": 6240,
"value": 110.0
},
{
"t": 6360,
"value": 90.0
},
{
"t": 6480,
"value": 110.0
},
{
"t": 6600,
"value": 90.0
},
{
"t": 6720,
"value": 110.0
},
{
"t": 6840,
"value": 90.0
},
{
"t": 6960,
"value": 110.0
},
{
"t": 7080,
"value": 90.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": false
}
]
},
{
"name": "pv_mae_just_over_threshold",
"description": "A 10.1-unit mean absolute PV error brackets the process boundary from the active side while the speed branch is materially hunting.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4440,
"value": 40.0
},
{
"t": 4560,
"value": 60.0
},
{
"t": 4680,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4920,
"value": 40.0
},
{
"t": 5040,
"value": 60.0
},
{
"t": 5160,
"value": 40.0
},
{
"t": 5280,
"value": 60.0
},
{
"t": 5400,
"value": 40.0
},
{
"t": 5520,
"value": 60.0
},
{
"t": 5640,
"value": 40.0
},
{
"t": 5760,
"value": 60.0
},
{
"t": 5880,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6120,
"value": 40.0
},
{
"t": 6240,
"value": 60.0
},
{
"t": 6360,
"value": 40.0
},
{
"t": 6480,
"value": 60.0
},
{
"t": 6600,
"value": 40.0
},
{
"t": 6720,
"value": 60.0
},
{
"t": 6840,
"value": 40.0
},
{
"t": 6960,
"value": 60.0
},
{
"t": 7080,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 110.1
},
{
"t": 120,
"value": 89.9
},
{
"t": 240,
"value": 110.1
},
{
"t": 360,
"value": 89.9
},
{
"t": 480,
"value": 110.1
},
{
"t": 600,
"value": 89.9
},
{
"t": 720,
"value": 110.1
},
{
"t": 840,
"value": 89.9
},
{
"t": 960,
"value": 110.1
},
{
"t": 1080,
"value": 89.9
},
{
"t": 1200,
"value": 110.1
},
{
"t": 1320,
"value": 89.9
},
{
"t": 1440,
"value": 110.1
},
{
"t": 1560,
"value": 89.9
},
{
"t": 1680,
"value": 110.1
},
{
"t": 1800,
"value": 89.9
},
{
"t": 1920,
"value": 110.1
},
{
"t": 2040,
"value": 89.9
},
{
"t": 2160,
"value": 110.1
},
{
"t": 2280,
"value": 89.9
},
{
"t": 2400,
"value": 110.1
},
{
"t": 2520,
"value": 89.9
},
{
"t": 2640,
"value": 110.1
},
{
"t": 2760,
"value": 89.9
},
{
"t": 2880,
"value": 110.1
},
{
"t": 3000,
"value": 89.9
},
{
"t": 3120,
"value": 110.1
},
{
"t": 3240,
"value": 89.9
},
{
"t": 3360,
"value": 110.1
},
{
"t": 3480,
"value": 89.9
},
{
"t": 3600,
"value": 110.1
},
{
"t": 3720,
"value": 89.9
},
{
"t": 3840,
"value": 110.1
},
{
"t": 3960,
"value": 89.9
},
{
"t": 4080,
"value": 110.1
},
{
"t": 4200,
"value": 89.9
},
{
"t": 4320,
"value": 110.1
},
{
"t": 4440,
"value": 89.9
},
{
"t": 4560,
"value": 110.1
},
{
"t": 4680,
"value": 89.9
},
{
"t": 4800,
"value": 110.1
},
{
"t": 4920,
"value": 89.9
},
{
"t": 5040,
"value": 110.1
},
{
"t": 5160,
"value": 89.9
},
{
"t": 5280,
"value": 110.1
},
{
"t": 5400,
"value": 89.9
},
{
"t": 5520,
"value": 110.1
},
{
"t": 5640,
"value": 89.9
},
{
"t": 5760,
"value": 110.1
},
{
"t": 5880,
"value": 89.9
},
{
"t": 6000,
"value": 110.1
},
{
"t": 6120,
"value": 89.9
},
{
"t": 6240,
"value": 110.1
},
{
"t": 6360,
"value": 89.9
},
{
"t": 6480,
"value": 110.1
},
{
"t": 6600,
"value": 89.9
},
{
"t": 6720,
"value": 110.1
},
{
"t": 6840,
"value": 89.9
},
{
"t": 6960,
"value": 110.1
},
{
"t": 7080,
"value": 89.9
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 7200,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "persistent_both_error_directions",
"description": "Material speed hunting paired with PV alternating above and below setpoint proves the process statistic is symmetric and the combined fault persists.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4440,
"value": 40.0
},
{
"t": 4560,
"value": 60.0
},
{
"t": 4680,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4920,
"value": 40.0
},
{
"t": 5040,
"value": 60.0
},
{
"t": 5160,
"value": 40.0
},
{
"t": 5280,
"value": 60.0
},
{
"t": 5400,
"value": 40.0
},
{
"t": 5520,
"value": 60.0
},
{
"t": 5640,
"value": 40.0
},
{
"t": 5760,
"value": 60.0
},
{
"t": 5880,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6120,
"value": 40.0
},
{
"t": 6240,
"value": 60.0
},
{
"t": 6360,
"value": 40.0
},
{
"t": 6480,
"value": 60.0
},
{
"t": 6600,
"value": 40.0
},
{
"t": 6720,
"value": 60.0
},
{
"t": 6840,
"value": 40.0
},
{
"t": 6960,
"value": 60.0
},
{
"t": 7080,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 7200,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "one_sided_oscillatory_process_offset",
"description": "PV oscillates between 20 and 30 units above setpoint while speed hunts. Crossings around the rolling process-error mean plus MAE from the real setpoint intentionally classify this one-sided oscillatory offset as unstable; this is broader than NIST's two-sided allowance-band CUSUM.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 60.0
},
{
"t": 3720,
"value": 40.0
},
{
"t": 3840,
"value": 60.0
},
{
"t": 3960,
"value": 40.0
},
{
"t": 4080,
"value": 60.0
},
{
"t": 4200,
"value": 40.0
},
{
"t": 4320,
"value": 60.0
},
{
"t": 4440,
"value": 40.0
},
{
"t": 4560,
"value": 60.0
},
{
"t": 4680,
"value": 40.0
},
{
"t": 4800,
"value": 60.0
},
{
"t": 4920,
"value": 40.0
},
{
"t": 5040,
"value": 60.0
},
{
"t": 5160,
"value": 40.0
},
{
"t": 5280,
"value": 60.0
},
{
"t": 5400,
"value": 40.0
},
{
"t": 5520,
"value": 60.0
},
{
"t": 5640,
"value": 40.0
},
{
"t": 5760,
"value": 60.0
},
{
"t": 5880,
"value": 40.0
},
{
"t": 6000,
"value": 60.0
},
{
"t": 6120,
"value": 40.0
},
{
"t": 6240,
"value": 60.0
},
{
"t": 6360,
"value": 40.0
},
{
"t": 6480,
"value": 60.0
},
{
"t": 6600,
"value": 40.0
},
{
"t": 6720,
"value": 60.0
},
{
"t": 6840,
"value": 40.0
},
{
"t": 6960,
"value": 60.0
},
{
"t": 7080,
"value": 40.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 130.0
},
{
"t": 120,
"value": 120.0
},
{
"t": 240,
"value": 130.0
},
{
"t": 360,
"value": 120.0
},
{
"t": 480,
"value": 130.0
},
{
"t": 600,
"value": 120.0
},
{
"t": 720,
"value": 130.0
},
{
"t": 840,
"value": 120.0
},
{
"t": 960,
"value": 130.0
},
{
"t": 1080,
"value": 120.0
},
{
"t": 1200,
"value": 130.0
},
{
"t": 1320,
"value": 120.0
},
{
"t": 1440,
"value": 130.0
},
{
"t": 1560,
"value": 120.0
},
{
"t": 1680,
"value": 130.0
},
{
"t": 1800,
"value": 120.0
},
{
"t": 1920,
"value": 130.0
},
{
"t": 2040,
"value": 120.0
},
{
"t": 2160,
"value": 130.0
},
{
"t": 2280,
"value": 120.0
},
{
"t": 2400,
"value": 130.0
},
{
"t": 2520,
"value": 120.0
},
{
"t": 2640,
"value": 130.0
},
{
"t": 2760,
"value": 120.0
},
{
"t": 2880,
"value": 130.0
},
{
"t": 3000,
"value": 120.0
},
{
"t": 3120,
"value": 130.0
},
{
"t": 3240,
"value": 120.0
},
{
"t": 3360,
"value": 130.0
},
{
"t": 3480,
"value": 120.0
},
{
"t": 3600,
"value": 130.0
},
{
"t": 3720,
"value": 120.0
},
{
"t": 3840,
"value": 130.0
},
{
"t": 3960,
"value": 120.0
},
{
"t": 4080,
"value": 130.0
},
{
"t": 4200,
"value": 120.0
},
{
"t": 4320,
"value": 130.0
},
{
"t": 4440,
"value": 120.0
},
{
"t": 4560,
"value": 130.0
},
{
"t": 4680,
"value": 120.0
},
{
"t": 4800,
"value": 130.0
},
{
"t": 4920,
"value": 120.0
},
{
"t": 5040,
"value": 130.0
},
{
"t": 5160,
"value": 120.0
},
{
"t": 5280,
"value": 130.0
},
{
"t": 5400,
"value": 120.0
},
{
"t": 5520,
"value": 130.0
},
{
"t": 5640,
"value": 120.0
},
{
"t": 5760,
"value": 130.0
},
{
"t": 5880,
"value": 120.0
},
{
"t": 6000,
"value": 130.0
},
{
"t": 6120,
"value": 120.0
},
{
"t": 6240,
"value": 130.0
},
{
"t": 6360,
"value": 120.0
},
{
"t": 6480,
"value": 130.0
},
{
"t": 6600,
"value": 120.0
},
{
"t": 6720,
"value": 130.0
},
{
"t": 6840,
"value": 120.0
},
{
"t": 6960,
"value": 130.0
},
{
"t": 7080,
"value": 120.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 7200,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "window_aging_clears",
"description": "The loop hunts through t=3600 s and then speed settles while PV remains 11 units off setpoint. The process diagnostic stays active; speed crossings and MAD must age out before the fault clears.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 60.0
},
{
"t": 120,
"value": 40.0
},
{
"t": 240,
"value": 60.0
},
{
"t": 360,
"value": 40.0
},
{
"t": 480,
"value": 60.0
},
{
"t": 600,
"value": 40.0
},
{
"t": 720,
"value": 60.0
},
{
"t": 840,
"value": 40.0
},
{
"t": 960,
"value": 60.0
},
{
"t": 1080,
"value": 40.0
},
{
"t": 1200,
"value": 60.0
},
{
"t": 1320,
"value": 40.0
},
{
"t": 1440,
"value": 60.0
},
{
"t": 1560,
"value": 40.0
},
{
"t": 1680,
"value": 60.0
},
{
"t": 1800,
"value": 40.0
},
{
"t": 1920,
"value": 60.0
},
{
"t": 2040,
"value": 40.0
},
{
"t": 2160,
"value": 60.0
},
{
"t": 2280,
"value": 40.0
},
{
"t": 2400,
"value": 60.0
},
{
"t": 2520,
"value": 40.0
},
{
"t": 2640,
"value": 60.0
},
{
"t": 2760,
"value": 40.0
},
{
"t": 2880,
"value": 60.0
},
{
"t": 3000,
"value": 40.0
},
{
"t": 3120,
"value": 60.0
},
{
"t": 3240,
"value": 40.0
},
{
"t": 3360,
"value": 60.0
},
{
"t": 3480,
"value": 40.0
},
{
"t": 3600,
"value": 50.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 2400,
"to_s": 3480,
"equals": true
},
{
"output": "yFault",
"from_s": 5400,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 1800,
"to_s": 3480,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 5400,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "warmup_burst_raw_behavior",
"description": "Eight tick-rate speed changes during the partial-window fill can be extrapolated above the rolling count threshold while PV is off setpoint. The raw result is pinned; hosts must report NO_EVAL during the first evaluation window.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 70.0
},
{
"t": 60,
"value": 30.0
},
{
"t": 120,
"value": 70.0
},
{
"t": 180,
"value": 30.0
},
{
"t": 240,
"value": 70.0
},
{
"t": 300,
"value": 30.0
},
{
"t": 360,
"value": 70.0
},
{
"t": 420,
"value": 30.0
},
{
"t": 480,
"value": 50.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 112.0
},
{
"t": 120,
"value": 88.0
},
{
"t": 240,
"value": 112.0
},
{
"t": 360,
"value": 88.0
},
{
"t": 480,
"value": 112.0
},
{
"t": 600,
"value": 88.0
},
{
"t": 720,
"value": 112.0
},
{
"t": 840,
"value": 88.0
},
{
"t": 960,
"value": 112.0
},
{
"t": 1080,
"value": 88.0
},
{
"t": 1200,
"value": 112.0
},
{
"t": 1320,
"value": 88.0
},
{
"t": 1440,
"value": 112.0
},
{
"t": 1560,
"value": 88.0
},
{
"t": 1680,
"value": 112.0
},
{
"t": 1800,
"value": 88.0
},
{
"t": 1920,
"value": 112.0
},
{
"t": 2040,
"value": 88.0
},
{
"t": 2160,
"value": 112.0
},
{
"t": 2280,
"value": 88.0
},
{
"t": 2400,
"value": 112.0
},
{
"t": 2520,
"value": 88.0
},
{
"t": 2640,
"value": 112.0
},
{
"t": 2760,
"value": 88.0
},
{
"t": 2880,
"value": 112.0
},
{
"t": 3000,
"value": 88.0
},
{
"t": 3120,
"value": 112.0
},
{
"t": 3240,
"value": 88.0
},
{
"t": 3360,
"value": 112.0
},
{
"t": 3480,
"value": 88.0
},
{
"t": 3600,
"value": 112.0
},
{
"t": 3720,
"value": 88.0
},
{
"t": 3840,
"value": 112.0
},
{
"t": 3960,
"value": 88.0
},
{
"t": 4080,
"value": 112.0
},
{
"t": 4200,
"value": 88.0
},
{
"t": 4320,
"value": 112.0
},
{
"t": 4440,
"value": 88.0
},
{
"t": 4560,
"value": 112.0
},
{
"t": 4680,
"value": 88.0
},
{
"t": 4800,
"value": 112.0
},
{
"t": 4920,
"value": 88.0
},
{
"t": 5040,
"value": 112.0
},
{
"t": 5160,
"value": 88.0
},
{
"t": 5280,
"value": 112.0
},
{
"t": 5400,
"value": 88.0
},
{
"t": 5520,
"value": 112.0
},
{
"t": 5640,
"value": 88.0
},
{
"t": 5760,
"value": 112.0
},
{
"t": 5880,
"value": 88.0
},
{
"t": 6000,
"value": 112.0
},
{
"t": 6120,
"value": 88.0
},
{
"t": 6240,
"value": 112.0
},
{
"t": 6360,
"value": 88.0
},
{
"t": 6480,
"value": 112.0
},
{
"t": 6600,
"value": 88.0
},
{
"t": 6720,
"value": 112.0
},
{
"t": 6840,
"value": 88.0
},
{
"t": 6960,
"value": 112.0
},
{
"t": 7080,
"value": 88.0
}
],
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 600,
"equals": false
},
{
"output": "yFault",
"from_s": 720,
"to_s": 840,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 300,
"to_s": 840,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 420,
"to_s": 840,
"equals": true
},
{
"output": "yFault",
"from_s": 3000,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 3000,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 1800,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "setpoint_step_excluded_raw_behavior",
"description": "A setpoint step at t=1800 followed by sustained materially reversing speed raises the raw diagnostics and fault. Deployment must instead report NO_EVAL until reset and disturbance response are settled.",
"inputs": {
"vfd_speed": [
{
"t": 0,
"value": 50.0
},
{
"t": 1800,
"value": 60.0
},
{
"t": 1920,
"value": 40.0
},
{
"t": 2040,
"value": 60.0
},
{
"t": 2160,
"value": 40.0
},
{
"t": 2280,
"value": 60.0
},
{
"t": 2400,
"value": 40.0
},
{
"t": 2520,
"value": 60.0
},
{
"t": 2640,
"value": 40.0
},
{
"t": 2760,
"value": 60.0
},
{
"t": 2880,
"value": 40.0
},
{
"t": 3000,
"value": 60.0
},
{
"t": 3120,
"value": 40.0
},
{
"t": 3240,
"value": 60.0
},
{
"t": 3360,
"value": 40.0
},
{
"t": 3480,
"value": 60.0
},
{
"t": 3600,
"value": 40.0
},
{
"t": 3720,
"value": 60.0
},
{
"t": 3840,
"value": 40.0
},
{
"t": 3960,
"value": 60.0
},
{
"t": 4080,
"value": 40.0
},
{
"t": 4200,
"value": 60.0
},
{
"t": 4320,
"value": 40.0
},
{
"t": 4440,
"value": 60.0
},
{
"t": 4560,
"value": 40.0
},
{
"t": 4680,
"value": 60.0
},
{
"t": 4800,
"value": 40.0
},
{
"t": 4920,
"value": 60.0
},
{
"t": 5040,
"value": 40.0
},
{
"t": 5160,
"value": 60.0
},
{
"t": 5280,
"value": 40.0
},
{
"t": 5400,
"value": 60.0
},
{
"t": 5520,
"value": 40.0
},
{
"t": 5640,
"value": 60.0
},
{
"t": 5760,
"value": 40.0
},
{
"t": 5880,
"value": 60.0
},
{
"t": 6000,
"value": 40.0
},
{
"t": 6120,
"value": 60.0
},
{
"t": 6240,
"value": 40.0
},
{
"t": 6360,
"value": 60.0
},
{
"t": 6480,
"value": 40.0
},
{
"t": 6600,
"value": 60.0
},
{
"t": 6720,
"value": 40.0
},
{
"t": 6840,
"value": 60.0
},
{
"t": 6960,
"value": 40.0
},
{
"t": 7080,
"value": 60.0
}
],
"vfd_process_value": [
{
"t": 0,
"value": 100.0
},
{
"t": 1800,
"value": 124.0
},
{
"t": 1920,
"value": 100.0
},
{
"t": 2040,
"value": 124.0
},
{
"t": 2160,
"value": 100.0
},
{
"t": 2280,
"value": 124.0
},
{
"t": 2400,
"value": 100.0
},
{
"t": 2520,
"value": 124.0
},
{
"t": 2640,
"value": 100.0
},
{
"t": 2760,
"value": 124.0
},
{
"t": 2880,
"value": 100.0
},
{
"t": 3000,
"value": 124.0
},
{
"t": 3120,
"value": 100.0
},
{
"t": 3240,
"value": 124.0
},
{
"t": 3360,
"value": 100.0
},
{
"t": 3480,
"value": 124.0
},
{
"t": 3600,
"value": 100.0
},
{
"t": 3720,
"value": 124.0
},
{
"t": 3840,
"value": 100.0
},
{
"t": 3960,
"value": 124.0
},
{
"t": 4080,
"value": 100.0
},
{
"t": 4200,
"value": 124.0
},
{
"t": 4320,
"value": 100.0
},
{
"t": 4440,
"value": 124.0
},
{
"t": 4560,
"value": 100.0
},
{
"t": 4680,
"value": 124.0
},
{
"t": 4800,
"value": 100.0
},
{
"t": 4920,
"value": 124.0
},
{
"t": 5040,
"value": 100.0
},
{
"t": 5160,
"value": 124.0
},
{
"t": 5280,
"value": 100.0
},
{
"t": 5400,
"value": 124.0
},
{
"t": 5520,
"value": 100.0
},
{
"t": 5640,
"value": 124.0
},
{
"t": 5760,
"value": 100.0
},
{
"t": 5880,
"value": 124.0
},
{
"t": 6000,
"value": 100.0
},
{
"t": 6120,
"value": 124.0
},
{
"t": 6240,
"value": 100.0
},
{
"t": 6360,
"value": 124.0
},
{
"t": 6480,
"value": 100.0
},
{
"t": 6600,
"value": 124.0
},
{
"t": 6720,
"value": 100.0
},
{
"t": 6840,
"value": 124.0
},
{
"t": 6960,
"value": 100.0
},
{
"t": 7080,
"value": 124.0
}
],
"vfd_process_sp": [
{
"t": 0,
"value": 100.0
},
{
"t": 1800,
"value": 112.0
}
]
},
"expect": [
{
"output": "yFault",
"from_s": 4200,
"to_s": 7200,
"equals": true
},
{
"output": "ySpeedHunting",
"from_s": 3600,
"to_s": 7200,
"equals": true
},
{
"output": "yProcessUnstable",
"from_s": 3600,
"to_s": 7200,
"equals": true
}
]
},
{
"name": "subtick_hunting_aliases_clear",
"description": "A host sampling once per minute cannot see an even number of reversals that occur and return between samples; the staged trace is therefore constant and every output stays clear. This pins the Nyquist limitation, not healthy plant behavior.",
"inputs": {
"vfd_speed": 50.0,
"vfd_process_value": 100.0,
"vfd_process_sp": 100.0
},
"expect": [
{
"output": "yFault",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "ySpeedHunting",
"from_s": 0,
"to_s": 7200,
"equals": false
},
{
"output": "yProcessUnstable",
"from_s": 0,
"to_s": 7200,
"equals": false
}
]
}
]
}