Data
Scoring
Calibration
Binning & Tags
Export
function synthesizeTelemetryRow(){ const sim = state.integration.simulation; sim.wear = clamp(sim.wear + 0.003, 0, 1); const machines = ["SIM-EXC-1","SIM-EXC-2","SIM-LOAD-7","SIM-CRANE-4","SIM-TRUCK-2"]; const sites = ["Yard-A","Yard-B","Quarry","Bridge","Depot"]; const baseRow = state.rawRows[0] || {}; const machine = (baseRow.MachineID || baseRow.machineId || machines[Math.floor(Math.random()*machines.length)]); const site = (baseRow.JobSite || baseRow.jobsite || sites[Math.floor(Math.random()*sites.length)]); const rpmBase = parseNumeric(baseRow.RPM || baseRow.rpm) || 680; const torqueBase = parseNumeric(baseRow.Torque || baseRow.torque) || 120; const vibBase = parseNumeric(baseRow.Vibration || baseRow.vibration) || 1.2; const tempBase = parseNumeric(baseRow.Temperature || baseRow.temperature) || 68; const fuelBase = parseNumeric(baseRow.FuelLevel || baseRow.fuel) || 0.55; const signalBase = parseNumeric(baseRow.SignalQuality || baseRow.signalQuality) || 0.82; const greaseBase = parseNumeric(baseRow.GreasePressure || baseRow.greasePressure) || 2800; const bearingBase = parseNumeric(baseRow.BearingTemp || baseRow.bearingTemp) || 60; const engLoadBase = parseNumeric(baseRow.EngineLoad || baseRow.engineLoad) || 58; const hydBase = parseNumeric(baseRow.HydraulicPressure || baseRow.hydraulicPressure) || 2100; const movementBase = parseNumeric(baseRow.MovementRate || baseRow.movementRate) || 40; const wearHeat = tempBase + 8*sim.wear + (Math.random()*6 - 2); const wearVib = vibBase + 1.6*sim.wear + (Math.random()*0.6 - 0.2); const wearLoad = engLoadBase + 12*sim.wear + (Math.random()*4 - 2); return { MachineID: machine, JobSite: site, Timestamp: new Date().toISOString(), RPM: round(rpmBase + (Math.random()*160 - 80),0), Torque: round(torqueBase + (Math.random()*36 - 18),2), Temperature: round(wearHeat,2), Vibration: round(Math.max(0.1, wearVib),3), FuelLevel: round(Math.max(0.04, fuelBase - sim.wear*0.03 + (Math.random()*0.02 - 0.01)),3), SignalQuality: round(Math.max(0.3, signalBase + (Math.random()*0.08 - 0.04)),3), MovementRate: round(Math.max(0, movementBase + (Math.random()*14 - 7)),2), GreasePressure: round(Math.max(800, greaseBase - sim.wear*120 + (Math.random()*60 - 30)),1), BearingTemp: round(Math.max(40, bearingBase + sim.wear*6 + (Math.random()*4 - 2)),2), EngineHours: round((parseNumeric(baseRow.EngineHours || baseRow.engineHours) || 1500) + 0.1,1), EngineLoad: round(Math.min(100, wearLoad),2), HydraulicPressure: round(Math.max(1200, hydBase - sim.wear*40 + (Math.random()*40 - 20)),1), Operator: baseRow.Operator || baseRow.operator || "sim-op", SequenceID: "SIM_" + String(Date.now()).slice(-6) }; } /** ------------------------- * Helpers * ------------------------- */ function clamp(x,a,b){ return Math.min(b, Math.max(a, x)); } function clampInt(x,a,b){ return Math.min(b, Math.max(a, x|0)); } function sum(xs){ return xs.reduce((a,b)=>a+b,0); } function sigmoid(z){ return 1/(1+Math.exp(-z)); } function round(x,n){ const p = Math.pow(10,n); return Math.round(x*p)/p; } function unique(arr){ const s = new Set(); for(const x of arr){ const v = String(x ?? ""); if(!s.has(v)) s.add(v); } return Array.from(s); } function deepClone(o){ return JSON.parse(JSON.stringify(o)); } function parseNumeric(v){ if(v == null) return NaN; if(typeof v === "number") return v; const s = String(v).trim(); if(!s) return NaN; const cleaned = s.replaceAll(",",""); const x = parseFloat(cleaned); return isFinite(x) ? x : NaN; } function defaultIfNaN(x, d){ return isFinite(x) ? x : d; } function pearsonCorr(X, Y){ const n = Math.min(X.length, Y.length); if(n<2) return NaN; const mx = X.reduce((a,b)=>a+b,0)/n; const my = Y.reduce((a,b)=>a+b,0)/n; let num=0, dx=0, dy=0; for(let i=0;ii); idx.sort((a,b)=>arr[a]-arr[b]); const ranks = new Array(n); let i=0; while(i{ t.onclick = ()=>setTab(t.dataset.tab); }); } function init(){ // MOBILE FIX: mount controls stack correctly before wiring/reading refs setupResponsiveMounts(); window.addEventListener("resize", debounce(setupResponsiveMounts, 120)); wireTabs(); syncGatesUIFromState(); initIntegrationHooks(); log("RedNode Dashboard ready. Upload telemetry or connect to RedNode."); render(); } // expose init return { init }; })(); App.init();