UNPKG

ootk

Version:

Orbital Object Toolkit including Multiple Propagators, Initial Orbit Determination, and Maneuver Calculations.

110 lines (97 loc) 3.46 kB
/** * @author @thkruz Theodore Kruczek * @license AGPL-3.0-or-later * @copyright (c) 2025 Kruczek Labs LLC * * Orbital Object ToolKit is free software: you can redistribute it and/or modify it under the * terms of the GNU Affero General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * Orbital Object ToolKit is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with * Orbital Object ToolKit. If not, see <http://www.gnu.org/licenses/>. */ /* eslint-disable require-jsdoc */ /* eslint-disable func-style */ import { evalPoly } from '../main.js'; import { DownhillSimplex } from './DownhillSimplex.js'; import { PolynomicalRegressionResult } from './PolynomicalRegressionResult.js'; // / Polynomial regression optimizer. export class PolynomialRegression { private constructor() { // disable constructor } private static _bayesInformationCriterea(n: number, k: number, sse: number): number { return n * Math.log(sse) + k * Math.log(n); } /** * Optimize polynomial coefficients to fit data series [xs] and [ys] for the * provided polynomial [order]. * @param xs x values * @param ys y values * @param order Polynomial order * @param root0 Root0 * @param root0.printIter Root0.printIter * @returns The optimal input value. */ static solve( xs: Float64Array, ys: Float64Array, order: number, { printIter = false }: { printIter?: boolean } = {}, ): PolynomicalRegressionResult { const simplex = DownhillSimplex.generateSimplex(Float64Array.from(Array(order + 1).fill(1.0))); /** * Sum of squared errors. * @param coeffs Polynomial coefficients * @returns Sum of squared errors */ function f(coeffs: Float64Array): number { let sse = 0.0; for (let i = 0; i < xs.length; i++) { const diff = ys[i] - evalPoly(xs[i], coeffs); sse += diff * diff; } return sse; } const result = DownhillSimplex.solveSimplex(f, simplex, { adaptive: true, printIter, }); const sse = f(result); return new PolynomicalRegressionResult( result, Math.sqrt(sse), PolynomialRegression._bayesInformationCriterea(xs.length, order, sse), ); } /** * Optimize polynomial coefficients to fit data series [xs] and [ys], and * attempt to find an optimal order within the [minOrder] and * [maxOrder] bounds. * @param xs x values * @param ys y values * @param minOrder Minimum polynomial order * @param maxOrder Maximum polynomial order * @param root0 Root0 * @param root0.printIter Root0.printIter * @returns The optimal input value. */ static solveOrder( xs: Float64Array, ys: Float64Array, minOrder: number, maxOrder: number, { printIter = false }: { printIter?: boolean } = {}, ): PolynomicalRegressionResult { const cache: PolynomicalRegressionResult[] = []; for (let order = minOrder; order <= maxOrder; order++) { cache.push(PolynomialRegression.solve(xs, ys, order, { printIter })); } cache.sort((a, b) => a.bic - b.bic); return cache[0]; } }