Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Plots] Gracefully handle Float32Array breaking values #7138

Merged
merged 13 commits into from
Oct 24, 2023
Merged
6 changes: 4 additions & 2 deletions example/generator/GeneratorProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ define(['./WorkerInterface'], function (WorkerInterface) {
randomness: 0,
phase: 0,
loadDelay: 0,
infinityValues: false
infinityValues: false,
exceedFloat32: false
};

function GeneratorProvider(openmct, StalenessProvider) {
Expand All @@ -53,7 +54,8 @@ define(['./WorkerInterface'], function (WorkerInterface) {
'randomness',
'phase',
'loadDelay',
'infinityValues'
'infinityValues',
'exceedFloat32'
];

request = request || {};
Expand Down
78 changes: 70 additions & 8 deletions example/generator/generatorWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@
data.offset,
data.phase,
data.randomness,
data.infinityValues
data.infinityValues,
data.exceedFloat32
),
wavelengths: wavelengths(),
intensities: intensities(),
Expand All @@ -96,7 +97,8 @@
data.offset,
data.phase,
data.randomness,
data.infinityValues
data.infinityValues,
data.exceedFloat32
)
}
});
Expand Down Expand Up @@ -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;
Expand All @@ -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
)
});
}

Expand All @@ -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 (
Expand All @@ -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 (
Expand All @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions example/generator/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -140,6 +147,7 @@ export default function (openmct) {
randomness: 0,
loadDelay: 0,
infinityValues: false,
exceedFloat32: false,
staleness: false
};
}
Expand Down
24 changes: 17 additions & 7 deletions src/plugins/plot/configuration/PlotSeries.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

/**
Expand Down
Loading