File size: 1,757 Bytes
9f21d0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { describe, expect, it } from "vitest";

import { EARTH, initialState, propagate, type PropagationRequest } from "./propagator";

const request = (): PropagationRequest => ({
  altitudeKm: 500,
  eccentricity: 0,
  inclinationDeg: 51.6,
  raanDeg: 0,
  argumentOfPeriapsisDeg: 0,
  trueAnomalyDeg: 0,
  durationSeconds: 5_600,
  sampleCount: 121,
  massKg: 1_000,
  areaM2: 10,
  dragCoefficient: 2.2,
  reflectivityCoefficient: 1.2,
  forces: { gravity: true, j2: false, drag: false, moon: false, sun: false, solarRadiationPressure: false },
});

function specificEnergy(state: readonly number[]): number {
  const radius = Math.hypot(state[0]!, state[1]!, state[2]!);
  const speed = Math.hypot(state[3]!, state[4]!, state[5]!);
  return speed ** 2 / 2 - EARTH.mu / radius;
}

describe("custom propagation", () => {
  it("creates the expected circular LEO state", () => {
    const state = initialState(request());
    expect(Math.hypot(state[0], state[1], state[2]) - EARTH.radius).toBeCloseTo(500_000, -1);
    expect(Math.hypot(state[3], state[4], state[5])).toBeGreaterThan(7_500);
  });

  it("keeps two-body specific energy bounded through one orbit", () => {
    const samples = propagate(request());
    const energies = samples.map(({ state }) => specificEnergy(state));
    expect(Math.max(...energies) - Math.min(...energies)).toBeLessThan(25);
  });

  it("accepts third-body, drag, and radiation-pressure force configurations", () => {
    const samples = propagate({ ...request(), durationSeconds: 600, sampleCount: 31, forces: { gravity: true, j2: true, drag: true, moon: true, sun: true, solarRadiationPressure: true } });
    expect(samples).toHaveLength(31);
    expect(samples.at(-1)?.elapsedSeconds).toBeCloseTo(600);
  });
});