188 lines
5.2 KiB
JavaScript
188 lines
5.2 KiB
JavaScript
// 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;
|