mirror of
https://github.com/nasa/openmct.git
synced 2025-01-29 15:43:52 +00:00
[Plots] Gracefully handle Float32Array breaking values (#7138)
* WIP * guaranteeing float32breaking values for swgs when option is set * cleaning up and clarity * more clarity * removing randomization of float breaking number, as it is not necessary * logging the values that could not be plotted for awareness * remving auto-added imports --------- Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
This commit is contained in:
parent
7bf983210c
commit
d94fe8806b
@ -29,7 +29,8 @@ define(['./WorkerInterface'], function (WorkerInterface) {
|
||||
randomness: 0,
|
||||
phase: 0,
|
||||
loadDelay: 0,
|
||||
infinityValues: false
|
||||
infinityValues: false,
|
||||
exceedFloat32: false
|
||||
};
|
||||
|
||||
function GeneratorProvider(openmct, StalenessProvider) {
|
||||
@ -53,7 +54,8 @@ define(['./WorkerInterface'], function (WorkerInterface) {
|
||||
'randomness',
|
||||
'phase',
|
||||
'loadDelay',
|
||||
'infinityValues'
|
||||
'infinityValues',
|
||||
'exceedFloat32'
|
||||
];
|
||||
|
||||
request = request || {};
|
||||
|
@ -85,7 +85,8 @@
|
||||
data.offset,
|
||||
data.phase,
|
||||
data.randomness,
|
||||
data.infinityValues
|
||||
data.infinityValues,
|
||||
data.exceedFloat32
|
||||
),
|
||||
wavelengths: wavelengths(),
|
||||
intensities: intensities(),
|
||||
@ -96,7 +97,8 @@
|
||||
data.offset,
|
||||
data.phase,
|
||||
data.randomness,
|
||||
data.infinityValues
|
||||
data.infinityValues,
|
||||
data.exceedFloat32
|
||||
)
|
||||
}
|
||||
});
|
||||
@ -136,6 +138,7 @@
|
||||
var randomness = request.randomness;
|
||||
var loadDelay = Math.max(request.loadDelay, 0);
|
||||
var infinityValues = request.infinityValues;
|
||||
var exceedFloat32 = request.exceedFloat32;
|
||||
|
||||
var step = 1000 / dataRateInHz;
|
||||
var nextStep = start - (start % step) + step;
|
||||
@ -146,10 +149,28 @@
|
||||
data.push({
|
||||
utc: nextStep,
|
||||
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
||||
sin: sin(nextStep, period, amplitude, offset, phase, randomness, infinityValues),
|
||||
sin: sin(
|
||||
nextStep,
|
||||
period,
|
||||
amplitude,
|
||||
offset,
|
||||
phase,
|
||||
randomness,
|
||||
infinityValues,
|
||||
exceedFloat32
|
||||
),
|
||||
wavelengths: wavelengths(),
|
||||
intensities: intensities(),
|
||||
cos: cos(nextStep, period, amplitude, offset, phase, randomness, infinityValues)
|
||||
cos: cos(
|
||||
nextStep,
|
||||
period,
|
||||
amplitude,
|
||||
offset,
|
||||
phase,
|
||||
randomness,
|
||||
infinityValues,
|
||||
exceedFloat32
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@ -176,9 +197,26 @@
|
||||
});
|
||||
}
|
||||
|
||||
function cos(timestamp, period, amplitude, offset, phase, randomness, infinityValues) {
|
||||
if (infinityValues && Math.random() > 0.5) {
|
||||
function cos(
|
||||
timestamp,
|
||||
period,
|
||||
amplitude,
|
||||
offset,
|
||||
phase,
|
||||
randomness,
|
||||
infinityValues,
|
||||
exceedFloat32
|
||||
) {
|
||||
if (infinityValues && exceedFloat32) {
|
||||
if (Math.random() > 0.5) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if (Math.random() < 0.01) {
|
||||
return getRandomFloat32OverflowValue();
|
||||
}
|
||||
} else if (infinityValues && Math.random() > 0.5) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if (exceedFloat32 && Math.random() < 0.01) {
|
||||
return getRandomFloat32OverflowValue();
|
||||
}
|
||||
|
||||
return (
|
||||
@ -188,9 +226,26 @@
|
||||
);
|
||||
}
|
||||
|
||||
function sin(timestamp, period, amplitude, offset, phase, randomness, infinityValues) {
|
||||
if (infinityValues && Math.random() > 0.5) {
|
||||
function sin(
|
||||
timestamp,
|
||||
period,
|
||||
amplitude,
|
||||
offset,
|
||||
phase,
|
||||
randomness,
|
||||
infinityValues,
|
||||
exceedFloat32
|
||||
) {
|
||||
if (infinityValues && exceedFloat32) {
|
||||
if (Math.random() > 0.5) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if (Math.random() < 0.01) {
|
||||
return getRandomFloat32OverflowValue();
|
||||
}
|
||||
} else if (infinityValues && Math.random() > 0.5) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if (exceedFloat32 && Math.random() < 0.01) {
|
||||
return getRandomFloat32OverflowValue();
|
||||
}
|
||||
|
||||
return (
|
||||
@ -200,6 +255,13 @@
|
||||
);
|
||||
}
|
||||
|
||||
// Values exceeding float32 range (Positive: 3.4+38, Negative: -3.4+38)
|
||||
function getRandomFloat32OverflowValue() {
|
||||
const sign = Math.random() > 0.5 ? 1 : -1;
|
||||
|
||||
return sign * 3.4e39;
|
||||
}
|
||||
|
||||
function wavelengths() {
|
||||
let values = [];
|
||||
while (values.length < 5) {
|
||||
|
@ -122,6 +122,13 @@ export default function (openmct) {
|
||||
key: 'infinityValues',
|
||||
property: ['telemetry', 'infinityValues']
|
||||
},
|
||||
{
|
||||
name: 'Exceed Float32 Limits',
|
||||
control: 'toggleSwitch',
|
||||
cssClass: 'l-input',
|
||||
key: 'exceedFloat32',
|
||||
property: ['telemetry', 'exceedFloat32']
|
||||
},
|
||||
{
|
||||
name: 'Provide Staleness Updates',
|
||||
control: 'toggleSwitch',
|
||||
@ -140,6 +147,7 @@ export default function (openmct) {
|
||||
randomness: 0,
|
||||
loadDelay: 0,
|
||||
infinityValues: false,
|
||||
exceedFloat32: false,
|
||||
staleness: false
|
||||
};
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import _ from 'lodash';
|
||||
|
||||
import configStore from '../configuration/ConfigStore';
|
||||
import { MARKER_SHAPES } from '../draw/MarkerShapes';
|
||||
import { symlog } from '../mathUtils';
|
||||
@ -64,6 +62,10 @@ import Model from './Model';
|
||||
*
|
||||
* @extends {Model<PlotSeriesModelType, PlotSeriesModelOptions>}
|
||||
*/
|
||||
|
||||
const FLOAT32_MAX = 3.4e38;
|
||||
const FLOAT32_MIN = -3.4e38;
|
||||
|
||||
export default class PlotSeries extends Model {
|
||||
logMode = false;
|
||||
|
||||
@ -371,7 +373,7 @@ export default class PlotSeries extends Model {
|
||||
let stats = this.get('stats');
|
||||
let changed = false;
|
||||
if (!stats) {
|
||||
if ([Infinity, -Infinity].includes(value)) {
|
||||
if ([Infinity, -Infinity].includes(value) || !this.isValidFloat32(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -383,13 +385,13 @@ export default class PlotSeries extends Model {
|
||||
};
|
||||
changed = true;
|
||||
} else {
|
||||
if (stats.maxValue < value && value !== Infinity) {
|
||||
if (stats.maxValue < value && value !== Infinity && this.isValidFloat32(value)) {
|
||||
stats.maxValue = value;
|
||||
stats.maxPoint = point;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (stats.minValue > value && value !== -Infinity) {
|
||||
if (stats.minValue > value && value !== -Infinity && this.isValidFloat32(value)) {
|
||||
stats.minValue = value;
|
||||
stats.minPoint = point;
|
||||
changed = true;
|
||||
@ -425,7 +427,7 @@ export default class PlotSeries extends Model {
|
||||
const lastYVal = this.getYVal(data[insertIndex - 1]);
|
||||
|
||||
if (this.isValueInvalid(currentYVal) && this.isValueInvalid(lastYVal)) {
|
||||
console.warn('[Plot] Invalid Y Values detected');
|
||||
console.warn(`[Plot] Invalid Y Values detected: ${currentYVal} ${lastYVal}`);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -453,7 +455,15 @@ export default class PlotSeries extends Model {
|
||||
* @private
|
||||
*/
|
||||
isValueInvalid(val) {
|
||||
return Number.isNaN(val) || this.unPlottableValues.includes(val);
|
||||
return Number.isNaN(val) || this.unPlottableValues.includes(val) || !this.isValidFloat32(val);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
isValidFloat32(val) {
|
||||
return val < FLOAT32_MAX && val > FLOAT32_MIN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user