Initial commit with Dockerfile and demo code
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Injectable fault profiles.
|
||||
*
|
||||
* Each profile turns "time since injection" into a set of physics modifiers that
|
||||
* stations.js and line.js consume. Faults are progressive where a real fault
|
||||
* would be progressive - the bearing does not fail the instant you press the
|
||||
* button, it degrades, which is the whole point of showing trend extrapolation.
|
||||
*/
|
||||
|
||||
export const FAULT_PROFILES = [
|
||||
{
|
||||
id: 'bearing-degradation',
|
||||
station: 'CNC-02',
|
||||
label: 'CNC-02 bearing degradation',
|
||||
short: 'Bearing wear',
|
||||
severity: 'major',
|
||||
headline: true,
|
||||
description:
|
||||
'Spindle bearing begins to spall. Vibration rises exponentially, spindle load creeps up, and out-of-tolerance parts start reaching inspection.',
|
||||
},
|
||||
{
|
||||
id: 'oven-burner',
|
||||
station: 'OVN-03',
|
||||
label: 'OVN-03 zone 2 burner fault',
|
||||
short: 'Burner fault',
|
||||
severity: 'major',
|
||||
description:
|
||||
'Zone 2 loses roughly 40% of its heating capacity. The controller saturates trying to hold setpoint, the cure runs cold, and quality falls downstream.',
|
||||
},
|
||||
{
|
||||
id: 'packer-jam',
|
||||
station: 'PKG-05',
|
||||
label: 'PKG-05 film jam',
|
||||
short: 'Film jam',
|
||||
severity: 'critical',
|
||||
description:
|
||||
'Film binds then tears, stopping the packer. Work in progress backs up through the line and upstream stations block.',
|
||||
},
|
||||
{
|
||||
id: 'sensor-dropout',
|
||||
station: 'INS-04',
|
||||
label: 'INS-04 sensor dropout',
|
||||
short: 'Sensor dropout',
|
||||
severity: 'minor',
|
||||
description:
|
||||
'The inspection station stops reporting. Values go stale rather than to zero, which is what a real dropout looks like and what a twin has to handle honestly.',
|
||||
},
|
||||
];
|
||||
|
||||
export function faultProfile(id) {
|
||||
return FAULT_PROFILES.find((f) => f.id === id);
|
||||
}
|
||||
|
||||
/** Time constant for the bearing ramp, in simulated seconds. */
|
||||
const BEARING_TAU = 420;
|
||||
const BEARING_GAIN = 0.35;
|
||||
const BEARING_CAP = 3.2;
|
||||
|
||||
/**
|
||||
* Collapse the set of active faults into physics modifiers.
|
||||
*
|
||||
* active: Map of faultId -> { injectedAt } in simulated seconds.
|
||||
*/
|
||||
export function computeModifiers(active, simTime) {
|
||||
const mods = {
|
||||
bearingVibration: 0,
|
||||
ovenZone2Capacity: 1,
|
||||
packerJamPhase: null,
|
||||
faultedStations: new Set(),
|
||||
offlineStations: new Set(),
|
||||
};
|
||||
|
||||
for (const [id, info] of active) {
|
||||
const t = Math.max(0, simTime - info.injectedAt);
|
||||
|
||||
switch (id) {
|
||||
case 'bearing-degradation':
|
||||
// Exponential ramp: slow to start, unmistakable once it moves. Crosses
|
||||
// the 3.5 mm/s warn band around 13 simulated minutes.
|
||||
mods.bearingVibration = Math.min(
|
||||
BEARING_CAP,
|
||||
BEARING_GAIN * (Math.exp(t / BEARING_TAU) - 1),
|
||||
);
|
||||
break;
|
||||
|
||||
case 'oven-burner': {
|
||||
// Capacity degrades over the first minute rather than cliff-edging.
|
||||
const frac = Math.min(1, t / 60);
|
||||
mods.ovenZone2Capacity = 1 - 0.38 * frac;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'packer-jam':
|
||||
mods.faultedStations.add('PKG-05');
|
||||
mods.packerJamPhase = t < 8 ? 'bind' : 'tear';
|
||||
break;
|
||||
|
||||
case 'sensor-dropout':
|
||||
mods.offlineStations.add('INS-04');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mods;
|
||||
}
|
||||
Reference in New Issue
Block a user