From e0aabf44318015814a15b6e0752b687828e898f4 Mon Sep 17 00:00:00 2001 From: Jaap van Ekris <82339657+JaapvanEkris@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:06:53 +0100 Subject: [PATCH] Code cleanup and improvement Added the option to do quadratic analysis of two datapoints --- app/engine/utils/FullTSQuadraticSeries.js | 88 ++++++++++++++--------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/app/engine/utils/FullTSQuadraticSeries.js b/app/engine/utils/FullTSQuadraticSeries.js index f35241c167..932ce53558 100644 --- a/app/engine/utils/FullTSQuadraticSeries.js +++ b/app/engine/utils/FullTSQuadraticSeries.js @@ -36,13 +36,14 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { let _C = 0 function push (x, y) { - const linearResidu = createTSLinearSeries(maxSeriesLength) + // Invariant: A contains all a's (as in the general formula y = a * x^2 + b * x + c) - // Where the a's are labeled in the Binary Search Tree with their xi when they BEGIN in the point (xi, yi) + // Where the a's are labeled in the Binary Search Tree with their Xi when they BEGIN in the point (Xi, Yi) + if (maxSeriesLength > 0 && X.length() >= maxSeriesLength) { - // The maximum of the array has been reached, so when pushing the x,y the array gets shifted, - // thus we have to remove the a's belonging to the current position X0 as well before this value is trashed + // The maximum of the array has been reached, so when pushing the new datapoint (x,y), the array will get shifted, + // thus we have to remove all the A's that start with the old position X0 BEFORE this value gets thrown away A.remove(X.get(0)) } @@ -50,38 +51,51 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { Y.push(y) // Calculate the coefficient a for the new interval by adding the newly added datapoint - if (X.length() > 2) { - // There are at least two points in the X and Y arrays, so let's add the new datapoint - let i = 0 - let j = 0 - while (i < X.length() - 2) { - j = i + 1 - while (j < X.length() - 1) { - A.push(X.get(i), calculateA(i, j, X.length() - 1)) - j++ + switch (true) { + case (X.length() > 2): + // There are now at least three datapoints in the X and Y arrays, so let's calculate the A portion belonging for the new datapoint via Quadratic Theil-Sen regression + // First we calculate the A for the formula + let i = 0 + let j = 0 + while (i < X.length() - 2) { + j = i + 1 + while (j < X.length() - 1) { + A.push(X.get(i), calculateA(i, j, X.length() - 1)) + j++ + } + i++ } - i++ - } - _A = A.median() - - // Calculate the remaining two coefficients for this new interval - i = 0 - linearResidu.reset() - while (i < X.length() - 1) { - linearResidu.push(X.get(i), Y.get(i) - (_A * Math.pow(X.get(i), 2))) - i++ - } - _B = linearResidu.coefficientA() - _C = linearResidu.coefficientB() - } else { - _A = 0 - _B = 0 - _C = 0 + + + _A = A.median() + + // Next, we calculate the B and C via Linear regression over the residu + i = 0 + const linearResidu = createTSLinearSeries(maxSeriesLength) + while (i < X.length() - 1) { + linearResidu.push(X.get(i), Y.get(i) - (_A * Math.pow(X.get(i), 2))) + i++ + } + _B = linearResidu.coefficientA() + _C = linearResidu.coefficientB() + break + case (X.length() === 2 && X.get(1) - X.get(0) !== 0): + // There are only two datapoints, so we need to be creative to get to a quadratic solution + // As we know this is part of a 'linear' acceleration, we know that the second derivative should obey 2 * _A = angular acceleration = 2 * angular distance / (delta t)^2 + _A = (Y.get(1) - Y.get(0)) / Math.pow(X.get(1) - X.get(0), 2) + // As the first derivative should match angular velocity (= angular acceleration * (delta t)) + _B = -2 * _A * X.get(0) + _C = 0 + break + default: + _A = 0 + _B = 0 + _C = 0 } } function firstDerivativeAtPosition (position) { - if (X.length() > 2 && position < X.length()) { + if (X.length() > 1 && position < X.length()) { return ((_A * 2 * X.get(position)) + _B) } else { return 0 @@ -89,7 +103,7 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { } function secondDerivativeAtPosition (position) { - if (X.length() > 2 && position < X.length()) { + if (X.length() > 1 && position < X.length()) { return (_A * 2) } else { return 0 @@ -221,6 +235,14 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { return Y.maximum() } + function xAverage () { + return X.average() + } + + function yAverage () { + return Y.average() + } + function xSeries () { return X.series() } @@ -276,6 +298,8 @@ function createTSQuadraticSeries (maxSeriesLength = 0) { minimumY, maximumX, maximumY, + xAverage, + yAverage, xSum, ySum, xSeries,