Skip to content

Commit

Permalink
test: ✅ add tests for StateVector
Browse files Browse the repository at this point in the history
  • Loading branch information
thkruz committed Jan 15, 2024
1 parent d2533d7 commit d923dae
Show file tree
Hide file tree
Showing 8 changed files with 392 additions and 195 deletions.
16 changes: 8 additions & 8 deletions examples/satellite-js-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
calcGmst,
DEG2RAD,
Degrees,
GroundPosition,
GroundObject,
Kilometers,
lla2eci,
Radians,
Expand All @@ -28,9 +28,9 @@ const satellite = new Satellite({
tle2,
});

const elements = satellite.getClassicalElements(new Date(1705109326817)).toEquinoctialElements();
const period = satellite.toJ2000(new Date(1705109326817)).period;

console.warn(elements);
console.warn(period);

/*
* You can still propagate a satellite using time since epoch (in minutes), but
Expand Down Expand Up @@ -62,7 +62,7 @@ const positionEci2 = satellite.eci().position; // This is correctly typed
* Set the Observer at 71°W, 41°N, 0.37 km altitude using DEGREES because who
* likes using Radians?
*/
const observer = new GroundPosition({
const observer = new GroundObject({
lon: -71.0308 as Degrees,
lat: 41.9613422 as Degrees,
alt: 0.37 as Kilometers,
Expand All @@ -78,7 +78,7 @@ const { gmst, j } = calcGmst(new Date());
const positionEcf = satellite.ecf(exampleDate);
const observerEcf = observer.ecf();
const positionGd = satellite.lla(exampleDate);
const lookAngles = satellite.rae(observer, exampleDate);
const lookAngles = satellite.toRae(observer, exampleDate);
// This never worked in satellite.js, but it does now!
const uplinkFreq = 420e6;
const dopplerFactor = satellite.dopplerFactor(observer, exampleDate);
Expand Down Expand Up @@ -110,9 +110,9 @@ const rangeRate = lookAngles.rangeRate; // Kilometers/Second
* There is a built in cache to allow fast retrieval of repeated calculations.
* This means you can make repeat calls to `.rae()` for minimal performance hit.
*/
const rangeCache = satellite.rae(observer, exampleDate).range;
const azimuthCached = satellite.rae(observer, exampleDate).azimuth;
const elevationCached = satellite.rae(observer, exampleDate).elevation;
const rangeCache = satellite.rae(observer, exampleDate).rng;
const azimuthCached = satellite.rae(observer, exampleDate).az;
const elevationCached = satellite.rae(observer, exampleDate).el;
const latitudeCached = satellite.lla(exampleDate).lat;
const longitudeCached = satellite.lla(exampleDate).lon;
const heightCached = satellite.lla(exampleDate).alt;
Expand Down
5 changes: 3 additions & 2 deletions src/coordinate/ClassicalElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { earthGravityParam, RAD2DEG, sec2min, secondsPerDay, TAU } from '../util
import { clamp, matchHalfPlane, newtonNu } from '../utils/functions';
import { EquinoctialElements } from './EquinoctialElements';
import { OrbitRegime } from '../enums/OrbitRegime';
import { PositionVelocity, StateVector } from './StateVector';
import { StateVector } from './StateVector';
import { PositionVelocity } from 'src/types/types';
import { ClassicalElementsParams } from '../interfaces/ClassicalElementsParams';

/**
Expand Down Expand Up @@ -70,7 +71,7 @@ export class ClassicalElements {
}
const pos = state.position;
const vel = state.velocity;
const a = state.semimajorAxis();
const a = state.semimajorAxis;
const eVecA = pos.scale(vel.magnitude() ** 2 - mu / pos.magnitude());
const eVecB = vel.scale(pos.dot(vel));
const eVec = eVecA.subtract(eVecB).scale(1 / mu);
Expand Down
2 changes: 1 addition & 1 deletion src/coordinate/EquinoctialElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EpochUTC } from '../time/EpochUTC';
import { earthGravityParam, secondsPerDay, TAU } from '../utils/constants';
import { newtonM } from '../utils/functions';
import { ClassicalElements } from './ClassicalElements';
import { PositionVelocity } from './StateVector';
import { PositionVelocity } from 'src/types/types';
import { EquinoctialElementsParams } from '../interfaces/EquinoctialElementsParams';

/**
Expand Down
81 changes: 59 additions & 22 deletions src/coordinate/StateVector.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import { Kilometers } from 'src/main';
import { Kilometers, Minutes } from 'src/main';
import { Earth } from '../body/Earth';
import type { Vector3D } from '../operations/Vector3D';
import type { EpochUTC } from '../time/EpochUTC';
import { TAU } from '../utils/constants';
import { ClassicalElements } from './ClassicalElements';

// / Position and velocity [Vector3D] container.
export type PositionVelocity = {
/**
* A state vector is a set of coordinates used to specify the position and
* velocity of an object in a particular reference frame.
*/
export abstract class StateVector {
epoch: EpochUTC;
position: Vector3D<Kilometers>;
velocity: Vector3D<Kilometers>;
};

// / Base class for state vectors.
export abstract class StateVector {
constructor(
public epoch: EpochUTC,
public position: Vector3D<Kilometers>,
public velocity: Vector3D<Kilometers>,
) {
// Nothing to do here.
constructor(epoch: EpochUTC, position: Vector3D<Kilometers>, velocity: Vector3D<Kilometers>) {
this.epoch = epoch;
this.position = position;
this.velocity = velocity;
}

/**
* The name of the reference frame in which the state vector is defined.
*/
abstract get name(): string;

/**
* Whether the state vector is defined in an inertial reference frame.
*/
abstract get inertial(): boolean;

/**
* Returns a string representation of the StateVector object. The string
* includes the name, epoch, position, and velocity.
* @returns A string representation of the StateVector object.
*/
toString(): string {
return [
`[${this.name}]`,
Expand All @@ -34,31 +43,59 @@ export abstract class StateVector {
].join('\n');
}

mechanicalEnergy(): number {
/**
* Calculates the mechanical energy of the state vector.
*
* @returns The mechanical energy value.
*/
get mechanicalEnergy(): number {
const r = this.position.magnitude();
const v = this.velocity.magnitude();

return v * v * 0.5 - Earth.mu / r;
}

semimajorAxis(): number {
const energy = this.mechanicalEnergy();
/**
* Calculates the semimajor axis of the state vector.
*
* @returns The semimajor axis in kilometers.
*/
get semimajorAxis(): Kilometers {
const energy = this.mechanicalEnergy;

return -Earth.mu / (2.0 * energy);
return (-Earth.mu / (2.0 * energy)) as Kilometers;
}

period(): number {
const a = this.semimajorAxis();
/**
* Gets the period of the state vector in minutes.
*
* @returns The period in minutes.
*/
get period(): Minutes {
const a = this.semimajorAxis;
const periodSeconds = TAU * Math.sqrt((a * a * a) / Earth.mu);

return TAU * Math.sqrt((a * a * a) / Earth.mu);
return (periodSeconds / 60.0) as Minutes;
}

angularRate(): number {
const a = this.semimajorAxis();
/**
* Gets the angular rate of the state vector.
*
* @returns The angular rate.
*/
get angularRate(): number {
const a = this.semimajorAxis;

return Math.sqrt(Earth.mu / (a * a * a));
}

/**
* Converts the state vector to classical elements.
* @param mu The gravitational parameter of the celestial body. Defaults to
* Earth's gravitational parameter. @returns The classical elements
* corresponding to the state vector. @throws Error if classical elements are
* undefined for fixed frames.
*/
toClassicalElements({ mu = Earth.mu }: { mu?: number } = {}): ClassicalElements {
if (!this.inertial) {
throw new Error('Classical elements are undefined for fixed frames.');
Expand Down
Loading

0 comments on commit d923dae

Please sign in to comment.