@sailboat-computer/validation
Version:
Validation framework for sailboat computer v3
205 lines • 7.68 kB
JavaScript
;
/**
* Extended validation types for Signal K
*
* This file extends the base validation types with Signal K specific types
* to enable more comprehensive validation of Signal K data.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSignalKPathMetadata = exports.calculateSignalKConfidence = exports.SignalKValueType = void 0;
/**
* Signal K value types
*/
var SignalKValueType;
(function (SignalKValueType) {
SignalKValueType["NUMBER"] = "number";
SignalKValueType["STRING"] = "string";
SignalKValueType["BOOLEAN"] = "boolean";
SignalKValueType["OBJECT"] = "object";
SignalKValueType["ARRAY"] = "array";
SignalKValueType["POSITION"] = "position";
SignalKValueType["ATTITUDE"] = "attitude";
SignalKValueType["DATETIME"] = "datetime";
})(SignalKValueType || (exports.SignalKValueType = SignalKValueType = {}));
/**
* Calculate confidence for Signal K data
*
* @param factors Confidence factors
* @returns Confidence score (0-1)
*/
function calculateSignalKConfidence(factors) {
// Weighted average of confidence factors
const weights = {
sourceReliability: 0.25,
pathConsistency: 0.15,
valueStability: 0.20,
updateFrequency: 0.15,
crossValidation: 0.15,
contextAppropriateness: 0.10
};
let confidence = 0;
let totalWeight = 0;
for (const [factor, weight] of Object.entries(weights)) {
if (factor in factors && typeof factors[factor] === 'number') {
confidence += factors[factor] * weight;
totalWeight += weight;
}
}
// Normalize by total weight
if (totalWeight > 0) {
confidence /= totalWeight;
}
return Math.max(0, Math.min(1, confidence));
}
exports.calculateSignalKConfidence = calculateSignalKConfidence;
/**
* Get Signal K path metadata for common paths
*
* @param path Signal K path
* @returns Path metadata if available
*/
function getSignalKPathMetadata(path) {
// Common path metadata
const pathMetadata = {
'navigation.position': {
path: 'navigation.position',
valueType: SignalKValueType.POSITION,
description: 'The vessel\'s current position',
displayName: 'Position'
},
'navigation.courseOverGroundTrue': {
path: 'navigation.courseOverGroundTrue',
valueType: SignalKValueType.NUMBER,
units: 'rad',
description: 'Course over ground (true)',
displayName: 'COG',
zones: [
{ lower: 0, upper: 6.28318, state: 'normal' }
]
},
'navigation.speedOverGround': {
path: 'navigation.speedOverGround',
valueType: SignalKValueType.NUMBER,
units: 'm/s',
description: 'Speed over ground',
displayName: 'SOG',
zones: [
{ lower: 0, upper: 30, state: 'normal' },
{ lower: 30, upper: 50, state: 'warn', message: 'High speed' },
{ lower: 50, state: 'alarm', message: 'Excessive speed' }
]
},
'navigation.headingTrue': {
path: 'navigation.headingTrue',
valueType: SignalKValueType.NUMBER,
units: 'rad',
description: 'Heading (true)',
displayName: 'Heading',
zones: [
{ lower: 0, upper: 6.28318, state: 'normal' }
]
},
'navigation.headingMagnetic': {
path: 'navigation.headingMagnetic',
valueType: SignalKValueType.NUMBER,
units: 'rad',
description: 'Heading (magnetic)',
displayName: 'Heading (M)',
zones: [
{ lower: 0, upper: 6.28318, state: 'normal' }
]
},
'environment.depth.belowKeel': {
path: 'environment.depth.belowKeel',
valueType: SignalKValueType.NUMBER,
units: 'm',
description: 'Depth below keel',
displayName: 'Depth',
zones: [
{ lower: 3, state: 'normal' },
{ lower: 1, upper: 3, state: 'warn', message: 'Shallow water' },
{ lower: 0, upper: 1, state: 'alarm', message: 'Very shallow water' },
{ upper: 0, state: 'emergency', message: 'Aground' }
]
},
'environment.wind.speedApparent': {
path: 'environment.wind.speedApparent',
valueType: SignalKValueType.NUMBER,
units: 'm/s',
description: 'Apparent wind speed',
displayName: 'AWS',
zones: [
{ lower: 0, upper: 15, state: 'normal' },
{ lower: 15, upper: 25, state: 'warn', message: 'Strong wind' },
{ lower: 25, state: 'alarm', message: 'Storm conditions' }
]
},
'environment.wind.angleApparent': {
path: 'environment.wind.angleApparent',
valueType: SignalKValueType.NUMBER,
units: 'rad',
description: 'Apparent wind angle',
displayName: 'AWA',
zones: [
{ lower: -3.14159, upper: 3.14159, state: 'normal' }
]
},
'electrical.batteries.*.voltage': {
path: 'electrical.batteries.*.voltage',
valueType: SignalKValueType.NUMBER,
units: 'V',
description: 'Battery voltage',
displayName: 'Voltage',
zones: [
{ lower: 12.5, upper: 14.8, state: 'normal' },
{ lower: 11.8, upper: 12.5, state: 'warn', message: 'Low voltage' },
{ lower: 0, upper: 11.8, state: 'alarm', message: 'Critical voltage' },
{ lower: 14.8, state: 'warn', message: 'High voltage' }
]
},
'propulsion.*.revolutions': {
path: 'propulsion.*.revolutions',
valueType: SignalKValueType.NUMBER,
units: 'Hz',
description: 'Engine revolutions',
displayName: 'RPM',
zones: [
{ lower: 0, upper: 2500, state: 'normal' },
{ lower: 2500, upper: 3000, state: 'warn', message: 'High RPM' },
{ lower: 3000, state: 'alarm', message: 'Excessive RPM' }
]
},
'propulsion.*.temperature': {
path: 'propulsion.*.temperature',
valueType: SignalKValueType.NUMBER,
units: 'K',
description: 'Engine temperature',
displayName: 'Temp',
zones: [
{ lower: 330, upper: 380, state: 'normal' },
{ lower: 380, upper: 390, state: 'warn', message: 'High temperature' },
{ lower: 390, state: 'alarm', message: 'Overheating' },
{ lower: 0, upper: 330, state: 'warn', message: 'Low temperature' }
]
}
};
// Check for exact path match
if (path in pathMetadata) {
return pathMetadata[path];
}
// Check for wildcard paths
for (const [metadataPath, metadata] of Object.entries(pathMetadata)) {
if (metadataPath.includes('*')) {
const regex = new RegExp('^' + metadataPath.replace('.*.', '\\.[^\\.]+\\.') + '$');
if (regex.test(path)) {
return {
...metadata,
path // Use the actual path instead of the wildcard path
};
}
}
}
return undefined;
}
exports.getSignalKPathMetadata = getSignalKPathMetadata;
//# sourceMappingURL=types-extension.js.map