// Add unit conversion support const convertModule = require('../../../convert/dependencies/index'); class Measurement { constructor(type, variant, position, windowSize) { this.type = type; // e.g. 'pressure', 'flow', etc. this.variant = variant; // e.g. 'predicted' or 'measured', etc.. this.position = position; // Downstream or upstream of parent object this.windowSize = windowSize; // Rolling window size // Place all data inside an array this.values = []; // Array to store all values this.timestamps = []; // Array to store all timestamps // Unit tracking this.unit = null; // Current unit of measurement // For tracking differences if this is a calculated difference measurement this.isDifference = false; this.sourcePositions = []; } // -- Updater methods -- setType(type) { this.type = type; return this; } setVariant(variant) { this.variant = variant; return this; } setPosition(position) { this.position = position; return this; } setValue(value, timestamp = Date.now()) { /* if (value === undefined || value === null) { value = null ; //throw new Error('Value cannot be null or undefined'); } */ //shift the oldest value if(this.values.length >= this.windowSize){ this.values.shift(); this.timestamps.shift(); } //push the new value this.values.push(value); this.timestamps.push(timestamp); return this; } setUnit(unit) { this.unit = unit; return this; } // -- Getter methods -- getCurrentValue() { if (this.values.length === 0) return null; return this.values[this.values.length - 1]; } getAverage() { if (this.values.length === 0) return null; const sum = this.values.reduce((acc, val) => acc + val, 0); return sum / this.values.length; } getMin() { if (this.values.length === 0) return null; return Math.min(...this.values); } getMax() { if (this.values.length === 0) return null; return Math.max(...this.values); } getAllValues() { return { values: [...this.values], timestamps: [...this.timestamps], unit: this.unit }; } // -- Position-based methods -- // Create a new measurement that is the difference between two positions static createDifference(upstreamMeasurement, downstreamMeasurement) { console.log('hello:'); if (upstreamMeasurement.type !== downstreamMeasurement.type || upstreamMeasurement.variant !== downstreamMeasurement.variant) { throw new Error('Cannot calculate difference between different measurement types or variants'); } // Ensure units match let downstream = downstreamMeasurement; if (upstreamMeasurement.unit && downstream.unit && upstreamMeasurement.unit !== downstream.unit) { downstream = downstream.convertTo(upstreamMeasurement.unit); } // Create a new difference measurement const diffMeasurement = new Measurement( upstreamMeasurement.type, upstreamMeasurement.variant, 'difference', Math.min(upstreamMeasurement.windowSize, downstream.windowSize) ); // Mark as a difference measurement and keep track of sources diffMeasurement.isDifference = true; diffMeasurement.sourcePositions = ['upstream', 'downstream']; // Calculate all differences where timestamps match const upValues = upstreamMeasurement.getAllValues(); const downValues = downstream.getAllValues(); // Match timestamps and calculate differences for (let i = 0; i < upValues.timestamps.length; i++) { const upTimestamp = upValues.timestamps[i]; const downIndex = downValues.timestamps.indexOf(upTimestamp); if (downIndex !== -1) { const diff = upValues.values[i] - downValues.values[downIndex]; diffMeasurement.setValue(diff, upTimestamp); } } diffMeasurement.setUnit(upstreamMeasurement.unit); return diffMeasurement; } // -- Additional getter methods -- getLatestTimestamp() { if (this.timestamps.length === 0) return null; return this.timestamps[this.timestamps.length - 1]; } getValueAtTimestamp(timestamp) { const index = this.timestamps.indexOf(timestamp); if (index === -1) return null; return this.values[index]; } // -- Unit conversion methods -- convertTo(targetUnit) { if (!this.unit) { throw new Error('Current unit not set, cannot convert'); } try { const convertedValues = this.values.map(value => convertModule.convert(value).from(this.unit).to(targetUnit) ); const newMeasurement = new Measurement( this.type, this.variant, this.position, this.windowSize ); // Copy values and timestamps newMeasurement.values = convertedValues; newMeasurement.timestamps = [...this.timestamps]; newMeasurement.unit = targetUnit; return newMeasurement; } catch (error) { throw new Error(`Unit conversion failed: ${error.message}`); } } } module.exports = Measurement;