forked from RnD/rotatingMachine
changes to RUL
This commit is contained in:
@@ -677,34 +677,39 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
|||||||
|
|
||||||
_registerFailure(cause, runtimeOverride) {
|
_registerFailure(cause, runtimeOverride) {
|
||||||
const runtime = runtimeOverride ?? this.state.getRunTimeHours();
|
const runtime = runtimeOverride ?? this.state.getRunTimeHours();
|
||||||
const maintenance_time = this.state.getMaintenanceTimeHours();
|
const maintenanceTime = this.state.getMaintenanceTimeHours();
|
||||||
|
|
||||||
this.kpi.failures += 1;
|
this.kpi.failures += 1;
|
||||||
this.kpi.rulFailureTriggered = false;
|
|
||||||
this.kpi.lastFailureTime = Date.now();
|
this.kpi.lastFailureTime = Date.now();
|
||||||
this.kpi.lastFailureRuntime = runtime;
|
this.kpi.lastFailureRuntime = runtime;
|
||||||
this.kpi.lastFailureCause = cause;
|
this.kpi.lastFailureCause = cause;
|
||||||
|
|
||||||
const failures = this.kpi.failures;
|
this.kpi.cycleMTBF =
|
||||||
|
this.kpi.failures > 0
|
||||||
|
? runtime / this.kpi.failures
|
||||||
|
: runtime;
|
||||||
|
|
||||||
// If no failures yet: MTBF = total runtime & MTTR = 0
|
this.kpi.lastRUL = null;
|
||||||
this.kpi.MTBF = failures > 0 ? runtime / failures : runtime;
|
this.kpi.rulFailureTriggered = false;
|
||||||
this.kpi.MTTR = failures > 0 ? maintenance_time / failures : 0;
|
|
||||||
|
|
||||||
const mtbf = this.kpi.MTBF ?? 0;
|
this.kpi.MTTR =
|
||||||
|
this.kpi.failures > 0
|
||||||
|
? maintenanceTime / this.kpi.failures
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const mtbf = this.kpi.cycleMTBF ?? 0;
|
||||||
const mttr = this.kpi.MTTR ?? 0;
|
const mttr = this.kpi.MTTR ?? 0;
|
||||||
|
|
||||||
if (mtbf <= 0 && mttr <= 0) {
|
if (mtbf <= 0 && mttr <= 0) {
|
||||||
this.kpi.availability = 1;
|
this.kpi.availability = 1;
|
||||||
} else {
|
} else {
|
||||||
const availability = mtbf / (mtbf + mttr);
|
this.kpi.availability = Math.min(
|
||||||
this.kpi.availability = Math.min(1, Math.max(0, availability));
|
1,
|
||||||
}
|
Math.max(0, mtbf / (mtbf + mttr))
|
||||||
|
|
||||||
this.logger.warn(
|
|
||||||
`Failure registered (cause=${cause}). Total failures=${this.kpi.failures}, runtime=${runtime.toFixed(2)}h`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_handleStateChangeForKPI(newState) {
|
_handleStateChangeForKPI(newState) {
|
||||||
const runtime = this.state.getRunTimeHours();
|
const runtime = this.state.getRunTimeHours();
|
||||||
@@ -840,64 +845,50 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculateSimpleRUL() {
|
calculateSimpleRUL() {
|
||||||
const mtbf = this.kpi?.MTBF ?? 0;
|
const mtbf =
|
||||||
const healthIndex = typeof this.assetHealth?.index === "number"
|
this.kpi.cycleMTBF ??
|
||||||
? this.assetHealth.index
|
this.kpi.MTBF ??
|
||||||
: 0;
|
0;
|
||||||
|
|
||||||
if (this.kpi?.rulFailureTriggered) {
|
|
||||||
this.kpi.lastRUL = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mtbf <= 0) {
|
if (mtbf <= 0) {
|
||||||
this.logger.debug("No MTBF available, RUL cannot be estimated.");
|
|
||||||
this.kpi.lastRUL = 0;
|
this.kpi.lastRUL = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clampedHI = Math.min(5, Math.max(0, healthIndex));
|
|
||||||
const runtime = this.state?.getRunTimeHours?.() ?? 0;
|
const runtime = this.state?.getRunTimeHours?.() ?? 0;
|
||||||
const lastFailureRuntime = this.kpi?.lastFailureRuntime ?? 0;
|
const lastFailureRuntime = this.kpi?.lastFailureRuntime ?? 0;
|
||||||
const ageSinceLastFailure = Math.max(0, runtime - lastFailureRuntime);
|
const age = Math.max(0, runtime - lastFailureRuntime);
|
||||||
|
|
||||||
const fractionByHealth = (5 - clampedHI) / 5;
|
const baseFractionLeft = Math.max(0, 1 - age / mtbf);
|
||||||
const fractionByAge = Math.max(0, 1 - ageSinceLastFailure / mtbf);
|
let rul = mtbf * baseFractionLeft;
|
||||||
const fractionLeft = Math.min(fractionByHealth, fractionByAge);
|
|
||||||
|
|
||||||
let rul = mtbf * fractionLeft;
|
const healthIndex = Math.min(5, Math.max(0, this.assetHealth?.index ?? 0));
|
||||||
if (rul < 0) rul = 0;
|
|
||||||
|
const decayFactor = 1 + (healthIndex / 5) * 2;
|
||||||
|
const acceleratedAge = age * decayFactor;
|
||||||
|
const acceleratedFractionLeft = Math.max(0, 1 - acceleratedAge / mtbf);
|
||||||
|
rul = mtbf * acceleratedFractionLeft;
|
||||||
|
|
||||||
|
if (this.kpi.lastRUL != null) {
|
||||||
|
rul = Math.min(this.kpi.lastRUL, rul);
|
||||||
|
}
|
||||||
|
|
||||||
const prevRUL = this.kpi.lastRUL ?? null;
|
|
||||||
const EPS = 1e-3;
|
const EPS = 1e-3;
|
||||||
|
|
||||||
const state = this.state?.getCurrentState?.();
|
const state = this.state?.getCurrentState?.();
|
||||||
const isOperational = ["operational", "accelerating", "decelerating"].includes(state);
|
const isOperational = ["operational", "accelerating", "decelerating"].includes(state);
|
||||||
|
|
||||||
if (isOperational) {
|
if (isOperational && rul <= EPS && !this.kpi.rulFailureTriggered) {
|
||||||
const hadPrev = prevRUL !== null;
|
|
||||||
const wasPositive = hadPrev && prevRUL > EPS;
|
|
||||||
const isNowZeroish = rul <= EPS;
|
|
||||||
const isDecreasing = hadPrev && rul <= prevRUL + EPS;
|
|
||||||
|
|
||||||
if (wasPositive && isNowZeroish && isDecreasing) {
|
|
||||||
this.kpi.rulFailureTriggered = true;
|
this.kpi.rulFailureTriggered = true;
|
||||||
|
|
||||||
this.kpi.lastFailureTime = Date.now();
|
this.kpi.lastFailureTime = Date.now();
|
||||||
this.kpi.lastFailureRuntime = runtime;
|
this.kpi.lastFailureRuntime = runtime;
|
||||||
this.kpi.lastFailureCause = "RUL";
|
this.kpi.lastFailureCause = "RUL";
|
||||||
|
|
||||||
rul = 0;
|
rul = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.kpi.lastRUL = rul;
|
this.kpi.lastRUL = rul;
|
||||||
|
|
||||||
return rul;
|
return rul;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateCurve(newCurve) {
|
updateCurve(newCurve) {
|
||||||
this.logger.info(`Updating machine curve`);
|
this.logger.info(`Updating machine curve`);
|
||||||
const newConfig = { asset: { machineCurve: newCurve } };
|
const newConfig = { asset: { machineCurve: newCurve } };
|
||||||
@@ -968,9 +959,10 @@ calculateSimpleRUL() {
|
|||||||
output["asset_tag_number"] = 'L001'; // hardcoded for now
|
output["asset_tag_number"] = 'L001'; // hardcoded for now
|
||||||
output["maintenanceMode"] = this.kpi.maintenanceMode;
|
output["maintenanceMode"] = this.kpi.maintenanceMode;
|
||||||
output["maintenanceTime"] = this.state.getMaintenanceTimeHours();
|
output["maintenanceTime"] = this.state.getMaintenanceTimeHours();
|
||||||
output["rul_hours"] = this.calculateSimpleRUL();
|
|
||||||
this._calculateAssetHealthIndex();
|
this._calculateAssetHealthIndex();
|
||||||
output["assetHealthIndex"] = this.assetHealth.index;
|
output["assetHealthIndex"] = this.assetHealth.index;
|
||||||
|
output["rul_hours"] = this.calculateSimpleRUL();
|
||||||
const healthColors = ["#006400", "#008000", "#FFFF00", "#FFA500", "#FF0000", "#8B0000"]; // 0 = darkgreen, 1 = green, 2 = yellow, 3 = orange, 4 = red, 5 = darkred
|
const healthColors = ["#006400", "#008000", "#FFFF00", "#FFA500", "#FF0000", "#8B0000"]; // 0 = darkgreen, 1 = green, 2 = yellow, 3 = orange, 4 = red, 5 = darkred
|
||||||
output["assetHealthColor"] = healthColors[this.assetHealth.index] || "unknown";
|
output["assetHealthColor"] = healthColors[this.assetHealth.index] || "unknown";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user