UNPKG

ootk

Version:

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

162 lines 6.4 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/>. */ import { EpochUTC } from '../main.js'; import { VerletBlendInterpolator } from '../interpolator/VerletBlendInterpolator.js'; import { GoldenSection } from './../optimize/GoldenSection.js'; // Propagator base class. export class Propagator { /* * Generate a [VerletBlendInterpolator] containing ephemeris over the * [start] and [stop] propagation period, with an optional * ephemeris [interval]. */ ephemeris(start, stop, interval = 60.0) { const output = [this.propagate(start)]; let tempEpoch = start; while (tempEpoch <= stop) { tempEpoch = tempEpoch.roll(interval); output.push(this.propagate(tempEpoch)); } return new VerletBlendInterpolator(output); } /* * Generate a list of [J2000] states integrating over a maneuver. * * If the maneuver is impulsive, the list will only contain a single state. */ maneuver(maneuver, interval = 60.0) { const output = []; const tempEpoch = maneuver.start; const stop = maneuver.stop; output.push(this.propagate(tempEpoch)); let current = tempEpoch; while (current <= stop) { current = current.roll(interval); output.push(this.propagate(current)); } return output; } /* * Generate a [VerletBlendInterpolator] containing maneuver ephemeris over * the [start] and [finish] interval, with an optional ephemeris [interval]. */ ephemerisManeuver(start, finish, maneuvers, interval = 60.0) { const output = []; const tempEpoch = start; output.push(this.propagate(tempEpoch)); const stop = finish; let current = tempEpoch; while (current <= stop) { current = current.roll(interval); output.push(this.propagate(current)); } return new VerletBlendInterpolator(output); } // Return the epoch of the ascending node after the [start] epoch. ascendingNodeEpoch(start) { const period = this.state.period / 60; const step = period / 8; let current = start; const stop = current.roll(period); this.propagate(current); let previous = this.state.position.z; while (current <= stop) { current = current.roll(step); this.propagate(current); if (Math.sign(this.state.position.z) === Math.sign(-previous) && this.state.velocity.z > 0) { break; } previous = this.state.position.z; } const t = GoldenSection.search((x) => { this.propagate(new EpochUTC(x)); return Math.abs(this.state.position.z); }, current.posix - step, current.posix, { tolerance: 1e-3 }); return new EpochUTC(t); } // Return the epoch of the descending node after the [start] epoch. descendingNodeEpoch(start) { const period = this.state.period / 60; const step = period / 8; let current = start; const stop = current.roll(period); this.propagate(current); let previous = this.state.position.z; while (current <= stop) { current = current.roll(step); this.propagate(current); if (Math.sign(this.state.position.z) === Math.sign(-previous) && this.state.velocity.z < 0) { break; } previous = this.state.position.z; } const t = GoldenSection.search((x) => { this.propagate(new EpochUTC(x)); return Math.abs(this.state.position.z); }, current.posix - step, current.posix, { tolerance: 1e-3 }); return new EpochUTC(t); } // Return the epoch of apogee after the [start] epoch. apogeeEpoch(start) { const slice = 8; const period = this.state.period / 60; const step = period / slice; let current = start; this.propagate(current); let tCache = current; let rCache = this.state.position.magnitude(); for (let i = 0; i < slice; i++) { current = current.roll(step); const t = new EpochUTC(GoldenSection.search((x) => { this.propagate(new EpochUTC(x)); return this.state.position.magnitude(); }, current.posix - step, current.posix, { tolerance: 1e-3, solveMax: true })); this.propagate(t); const r = this.state.position.magnitude(); if (r > rCache) { tCache = t; rCache = r; } } return tCache; } // Return the epoch of perigee after the [start] epoch. perigeeEpoch(start) { const slice = 8; const period = this.state.period / 60; const step = period / slice; let current = start; this.propagate(current); let tCache = current; let rCache = this.state.position.magnitude(); for (let i = 0; i < slice; i++) { current = current.roll(step); const t = new EpochUTC(GoldenSection.search((x) => { this.propagate(new EpochUTC(x)); return this.state.position.magnitude(); }, current.posix - step, current.posix, { tolerance: 1e-3, solveMax: false })); this.propagate(t); const r = this.state.position.magnitude(); if (r < rCache) { tCache = t; rCache = r; } } return tCache; } } //# sourceMappingURL=Propagator.js.map