@interstellar-tools/equations 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/__tests__/combine-burns-delta-v.spec.d.ts +2 -0
  2. package/dist/__tests__/combine-burns-delta-v.spec.d.ts.map +1 -0
  3. package/dist/__tests__/combine-burns-delta-v.spec.js +102 -0
  4. package/dist/__tests__/combine-burns-delta-v.spec.js.map +1 -0
  5. package/dist/__tests__/helpers/index.d.ts +2 -1
  6. package/dist/__tests__/helpers/index.d.ts.map +1 -1
  7. package/dist/__tests__/helpers/index.js +1 -0
  8. package/dist/__tests__/helpers/index.js.map +1 -1
  9. package/dist/__tests__/hohmann-transfer.spec.d.ts +2 -0
  10. package/dist/__tests__/hohmann-transfer.spec.d.ts.map +1 -0
  11. package/dist/__tests__/hohmann-transfer.spec.js +101 -0
  12. package/dist/__tests__/hohmann-transfer.spec.js.map +1 -0
  13. package/dist/__tests__/oberth-energy-gain.spec.d.ts +2 -0
  14. package/dist/__tests__/oberth-energy-gain.spec.d.ts.map +1 -0
  15. package/dist/__tests__/oberth-energy-gain.spec.js +71 -0
  16. package/dist/__tests__/oberth-energy-gain.spec.js.map +1 -0
  17. package/dist/__tests__/plane-change-delta-v.spec.d.ts +2 -0
  18. package/dist/__tests__/plane-change-delta-v.spec.d.ts.map +1 -0
  19. package/dist/__tests__/plane-change-delta-v.spec.js +89 -0
  20. package/dist/__tests__/plane-change-delta-v.spec.js.map +1 -0
  21. package/dist/categories/manoeuvres/combine-burns-delta-v.d.ts +69 -0
  22. package/dist/categories/manoeuvres/combine-burns-delta-v.d.ts.map +1 -0
  23. package/dist/categories/manoeuvres/combine-burns-delta-v.js +93 -0
  24. package/dist/categories/manoeuvres/combine-burns-delta-v.js.map +1 -0
  25. package/dist/categories/manoeuvres/hohmann-transfer.d.ts +74 -0
  26. package/dist/categories/manoeuvres/hohmann-transfer.d.ts.map +1 -0
  27. package/dist/categories/manoeuvres/hohmann-transfer.js +120 -0
  28. package/dist/categories/manoeuvres/hohmann-transfer.js.map +1 -0
  29. package/dist/categories/manoeuvres/oberth-energy-gain.d.ts +66 -0
  30. package/dist/categories/manoeuvres/oberth-energy-gain.d.ts.map +1 -0
  31. package/dist/categories/manoeuvres/oberth-energy-gain.js +78 -0
  32. package/dist/categories/manoeuvres/oberth-energy-gain.js.map +1 -0
  33. package/dist/categories/manoeuvres/plane-change-delta-v.d.ts +57 -0
  34. package/dist/categories/manoeuvres/plane-change-delta-v.d.ts.map +1 -0
  35. package/dist/categories/manoeuvres/plane-change-delta-v.js +69 -0
  36. package/dist/categories/manoeuvres/plane-change-delta-v.js.map +1 -0
  37. package/dist/index.d.ts +13 -9
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +14 -9
  40. package/dist/index.js.map +1 -1
  41. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=combine-burns-delta-v.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combine-burns-delta-v.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/combine-burns-delta-v.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { combineBurnsDeltaV } from '../categories/manoeuvres/combine-burns-delta-v';
4
+ import { absClose, toRad } from './helpers';
5
+ const PI = Math.PI;
6
+ const relClose = (a, b, rel = 1e-12, abs = 1e-12, msg) => {
7
+ const denom = Math.max(1, Math.abs(a), Math.abs(b));
8
+ assert.ok(Math.abs(a - b) <= Math.max(abs, rel * denom), msg);
9
+ };
10
+ describe('combineBurnsDeltaV', () => {
11
+ test('collinear same direction (Δθ=0): Δv = |v1 - v2|', () => {
12
+ const v1 = 3000;
13
+ const v2 = 800;
14
+ const dv = combineBurnsDeltaV(v1, v2, 0);
15
+ absClose(dv, Math.abs(v1 - v2));
16
+ });
17
+ test('collinear opposite (Δθ=π): Δv = v1 + v2', () => {
18
+ const v1 = 2500;
19
+ const v2 = 900;
20
+ const dv = combineBurnsDeltaV(v1, v2, PI);
21
+ absClose(dv, v1 + v2);
22
+ });
23
+ test('quadrature (Δθ=90°): Δv = sqrt(v1^2 + v2^2)', () => {
24
+ const v1 = 2100;
25
+ const v2 = 1400;
26
+ const dv = combineBurnsDeltaV(v1, v2, toRad(90));
27
+ absClose(dv, Math.hypot(v1, v2));
28
+ });
29
+ test('general case matches law of cosines', () => {
30
+ const cases = [
31
+ { v1: 1000, v2: 500, deg: 35 },
32
+ { v1: 2800, v2: 1200, deg: 60 },
33
+ { v1: 750, v2: 750, deg: 123 }
34
+ ];
35
+ for (const { v1, v2, deg } of cases) {
36
+ const th = toRad(deg);
37
+ const expected = Math.sqrt(v1 * v1 + v2 * v2 - 2 * v1 * v2 * Math.cos(th));
38
+ const dv = combineBurnsDeltaV(v1, v2, th);
39
+ relClose(dv, expected, 1e-12, 1e-12, `mismatch for v1=${v1}, v2=${v2}, Δθ=${deg}°`);
40
+ }
41
+ });
42
+ test('symmetry: swapping v1 and v2 gives same Δv', () => {
43
+ const v1 = 1900;
44
+ const v2 = 1300;
45
+ const th = toRad(47);
46
+ const a = combineBurnsDeltaV(v1, v2, th);
47
+ const b = combineBurnsDeltaV(v2, v1, th);
48
+ absClose(a, b);
49
+ });
50
+ test('zero burn in either vector returns the other magnitude (Δθ arbitrary)', () => {
51
+ const v = 1234;
52
+ const angles = [0, 0.4, 1.2, Math.PI];
53
+ for (const th of angles) {
54
+ absClose(combineBurnsDeltaV(0, v, th), v);
55
+ absClose(combineBurnsDeltaV(v, 0, th), v);
56
+ }
57
+ });
58
+ // ---------------- monotonic / bounds ----------------
59
+ test('for fixed v1 = v2 = v, Δv increases monotonically with Δθ on [0, π]', () => {
60
+ const v = 1500;
61
+ const seq = [0, 15, 30, 60, 90, 135, 180].map(toRad);
62
+ let last = -1;
63
+ for (const th of seq) {
64
+ const dv = combineBurnsDeltaV(v, v, th);
65
+ assert.ok(dv >= last - 1e-12, `not monotone at Δθ=${(th * 180) / PI}°`);
66
+ last = dv;
67
+ }
68
+ });
69
+ test('bounds: result in [|v1-v2|, v1+v2]', () => {
70
+ const v1 = 2600, v2 = 900;
71
+ for (const deg of [0, 20, 45, 100, 150, 180]) {
72
+ const dv = combineBurnsDeltaV(v1, v2, toRad(deg));
73
+ assert.ok(dv >= Math.abs(v1 - v2) - 1e-12, 'below lower bound');
74
+ assert.ok(dv <= v1 + v2 + 1e-12, 'above upper bound');
75
+ }
76
+ });
77
+ // ---------------- numerical guard ----------------
78
+ test('FP guard: tiny negative radicand clamps to 0 near Δθ=0 with equal burns', () => {
79
+ const v = 2000;
80
+ // angle so small that theoretical Δv ≈ 0; numerical should return ~0 (not throw)
81
+ const th = 1e-12;
82
+ const dv = combineBurnsDeltaV(v, v, th);
83
+ assert.ok(dv >= 0, 'Δv should be non-negative');
84
+ assert.ok(dv < 1e-6, `Δv should be ~0, got ${dv}`);
85
+ });
86
+ // ---------------- validation ----------------
87
+ test('TypeError on non-number inputs', () => {
88
+ assert.throws(() => combineBurnsDeltaV('1000', 200, 0), TypeError);
89
+ assert.throws(() => combineBurnsDeltaV(1000, '200', 0), TypeError);
90
+ assert.throws(() => combineBurnsDeltaV(1000, 200, '0'), TypeError);
91
+ });
92
+ test('RangeError on non-finite or out-of-domain values', () => {
93
+ assert.throws(() => combineBurnsDeltaV(NaN, 200, 0), RangeError);
94
+ assert.throws(() => combineBurnsDeltaV(1000, Infinity, 0), RangeError);
95
+ assert.throws(() => combineBurnsDeltaV(-1, 200, 0), RangeError);
96
+ assert.throws(() => combineBurnsDeltaV(1000, -1, 0), RangeError);
97
+ assert.throws(() => combineBurnsDeltaV(1000, 200, NaN), RangeError);
98
+ assert.throws(() => combineBurnsDeltaV(1000, 200, -1e-6), RangeError);
99
+ assert.throws(() => combineBurnsDeltaV(1000, 200, (PI + 1e-6)), RangeError);
100
+ });
101
+ });
102
+ //# sourceMappingURL=combine-burns-delta-v.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combine-burns-delta-v.spec.js","sourceRoot":"","sources":["../../src/__tests__/combine-burns-delta-v.spec.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Vector3DTupleType } from '@interstellar-tools/types';
1
+ import { Radians, Vector3DTupleType } from '@interstellar-tools/types';
2
2
  export declare const relClose: (a: number | null, b: number, eps?: number, msg?: string) => void;
3
3
  export declare const vecRelClose: (a: Vector3DTupleType, b: Vector3DTupleType, eps?: number, msg?: string) => void;
4
4
  export declare const norm: (v: Vector3DTupleType) => number;
@@ -9,4 +9,5 @@ export declare const dot: (a: Vector3DTupleType, b: Vector3DTupleType) => number
9
9
  export declare const norm2pi: (x: number) => number;
10
10
  export declare const angleClose: (a: number, b: number, eps?: number) => void;
11
11
  export declare const residual: (E: number, e: number, M: number) => number;
12
+ export declare const toRad: (deg: number) => Radians;
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,eAAO,MAAM,QAAQ,GACnB,GAAG,MAAM,GAAG,IAAI,EAChB,GAAG,MAAM,EACT,YAAW,EACX,MAAM,MAAM,SAUb,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,GAAG,iBAAiB,EACpB,GAAG,iBAAiB,EACpB,YAAW,EACX,MAAM,MAAM,SAOb,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,GAAG,iBAAiB,WAExC,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,GAAG,iBAAiB,EAAE,GAAG,MAAM,KAAG,iBAEvD,CAAC;AAEF,eAAO,MAAM,GAAG,GACd,GAAG,iBAAiB,EACpB,GAAG,iBAAiB,KACnB,iBAEF,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,YAAW,EAAE,MAAM,MAAM,SAEvE,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,GAAG,iBAAiB,EAAE,GAAG,iBAAiB,WAE7D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,KAAG,MAEnC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,YAAW,SAI3D,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGvE,eAAO,MAAM,QAAQ,GACnB,GAAG,MAAM,GAAG,IAAI,EAChB,GAAG,MAAM,EACT,YAAW,EACX,MAAM,MAAM,SAUb,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,GAAG,iBAAiB,EACpB,GAAG,iBAAiB,EACpB,YAAW,EACX,MAAM,MAAM,SAOb,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,GAAG,iBAAiB,WAExC,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,GAAG,iBAAiB,EAAE,GAAG,MAAM,KAAG,iBAEvD,CAAC;AAEF,eAAO,MAAM,GAAG,GACd,GAAG,iBAAiB,EACpB,GAAG,iBAAiB,KACnB,iBAEF,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,YAAW,EAAE,MAAM,MAAM,SAEvE,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,GAAG,iBAAiB,EAAE,GAAG,iBAAiB,WAE7D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,KAAG,MAEnC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,YAAW,SAI3D,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,KAAgC,OAAO,CAAC"}
@@ -41,4 +41,5 @@ export const residual = (E, e, M) => {
41
41
  const Mm = norm2pi(M);
42
42
  return E - e * Math.sin(E) - Mm;
43
43
  };
44
+ export const toRad = (deg) => ((deg * Math.PI) / 180);
44
45
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/__tests__/helpers/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/__tests__/helpers/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hohmann-transfer.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/hohmann-transfer.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { hohmannSemiMajorAxis, hohmannTransfer, hohmannTransferTime } from '../categories/manoeuvres/hohmann-transfer';
4
+ import { absClose, relClose } from './helpers';
5
+ describe('hohmannTransfer', () => {
6
+ test('semi-major axis: at = (r1 + r2) / 2', () => {
7
+ const r1 = 7000e3;
8
+ const r2 = 42164e3;
9
+ const at = hohmannSemiMajorAxis(r1, r2);
10
+ absClose(at, 0.5 * (r1 + r2));
11
+ });
12
+ test('transfer time: t = π sqrt(at^3 / μ)', () => {
13
+ const mu = 3.986004418e14; // Earth μ (m^3/s^2)
14
+ const r1 = 7000e3;
15
+ const r2 = 42164e3;
16
+ const at = 0.5 * (r1 + r2);
17
+ const expected = Math.PI * Math.sqrt((at * at * at) / mu);
18
+ const t = hohmannTransferTime(r1, r2, mu);
19
+ relClose(t, expected, 1e-12);
20
+ });
21
+ test('raise orbit (r2 > r1): dv1,dv2 magnitudes & directions (prograde, prograde)', () => {
22
+ const mu = 3.986004418e14; // Earth μ
23
+ const r1 = 7000e3;
24
+ const r2 = 12000e3;
25
+ const res = hohmannTransfer(r1, r2, mu);
26
+ // Expected magnitudes from textbook formulas
27
+ const at = 0.5 * (r1 + r2);
28
+ const dv1Exp = Math.sqrt(mu / r1) * (Math.sqrt((2 * r2) / (r1 + r2)) - 1);
29
+ const dv2Exp = Math.sqrt(mu / r2) * (1 - Math.sqrt((2 * r1) / (r1 + r2)));
30
+ assert.ok(res.dv1 >= 0 && res.dv2 >= 0, 'Δv magnitudes must be non-negative');
31
+ relClose(res.at, at);
32
+ relClose(res.dv1, dv1Exp, 1e-12);
33
+ relClose(res.dv2, dv2Exp, 1e-12);
34
+ relClose(res.dvTotal, res.dv1 + res.dv2, 1e-12);
35
+ assert.equal(res.dir1, 'prograde');
36
+ assert.equal(res.dir2, 'prograde');
37
+ // Transfer time check
38
+ const tExp = Math.PI * Math.sqrt((at * at * at) / mu);
39
+ relClose(res.tTransfer, tExp, 1e-12);
40
+ });
41
+ test('lower orbit (r2 < r1): dv1,dv2 magnitudes & directions (retrograde, retrograde)', () => {
42
+ const mu = 3.986004418e14;
43
+ const r1 = 12000e3;
44
+ const r2 = 7000e3;
45
+ const res = hohmannTransfer(r1, r2, mu);
46
+ const at = 0.5 * (r1 + r2);
47
+ const dv1Exp = Math.sqrt(mu / r1) * (Math.sqrt((2 * r2) / (r1 + r2)) - 1);
48
+ const dv2Exp = Math.sqrt(mu / r2) * (1 - Math.sqrt((2 * r1) / (r1 + r2)));
49
+ // Magnitudes compare against absolute values of textbook (which are negative here)
50
+ relClose(res.at, at);
51
+ relClose(res.dv1, Math.abs(dv1Exp), 1e-12);
52
+ relClose(res.dv2, Math.abs(dv2Exp), 1e-12);
53
+ relClose(res.dvTotal, res.dv1 + res.dv2, 1e-12);
54
+ assert.equal(res.dir1, 'retrograde');
55
+ assert.equal(res.dir2, 'retrograde');
56
+ const tExp = Math.PI * Math.sqrt((at * at * at) / mu);
57
+ relClose(res.tTransfer, tExp, 1e-12);
58
+ });
59
+ test('symmetry: total Δv is same for r1→r2 and r2→r1', () => {
60
+ const mu = 3.986004418e14;
61
+ const r1 = 9000e3;
62
+ const r2 = 14000e3;
63
+ const up = hohmannTransfer(r1, r2, mu);
64
+ const down = hohmannTransfer(r2, r1, mu);
65
+ relClose(up.dvTotal, down.dvTotal, 1e-12);
66
+ });
67
+ test('degenerate: r1 == r2 → dv1=dv2=0, t = half circular period', () => {
68
+ const mu = 3.986004418e14;
69
+ const r = 7000e3;
70
+ const res = hohmannTransfer(r, r, mu);
71
+ absClose(res.dv1, 0, 1e-12);
72
+ absClose(res.dv2, 0, 1e-12);
73
+ absClose(res.dvTotal, 0, 1e-12);
74
+ assert.equal(res.dir1, 'none');
75
+ assert.equal(res.dir2, 'none');
76
+ const T_circ = 2 * Math.PI * Math.sqrt((r * r * r) / mu);
77
+ const half = 0.5 * T_circ;
78
+ relClose(res.tTransfer, half, 1e-12);
79
+ });
80
+ test('input validation: type and range errors', () => {
81
+ const mu = 3.986004418e14;
82
+ // TypeError: non-number inputs
83
+ assert.throws(() => hohmannTransfer('x', 7000e3, mu), TypeError);
84
+ assert.throws(() => hohmannTransfer(7000e3, 'y', mu), TypeError);
85
+ assert.throws(() => hohmannTransfer(7000e3, 8000e3, 'z'), TypeError);
86
+ // RangeError: non-finite / non-positive
87
+ assert.throws(() => hohmannTransfer(NaN, 8000e3, mu), RangeError);
88
+ assert.throws(() => hohmannTransfer(7000e3, Infinity, mu), RangeError);
89
+ assert.throws(() => hohmannTransfer(7000e3, 8000e3, 0), RangeError);
90
+ assert.throws(() => hohmannTransfer(-1, 8000e3, mu), RangeError);
91
+ assert.throws(() => hohmannTransfer(7000e3, -1, mu), RangeError);
92
+ // Semi-major axis helper
93
+ assert.throws(() => hohmannSemiMajorAxis('a', 1), TypeError);
94
+ assert.throws(() => hohmannSemiMajorAxis(1, NaN), RangeError);
95
+ assert.throws(() => hohmannSemiMajorAxis(0, 1), RangeError);
96
+ // Transfer time helper
97
+ assert.throws(() => hohmannTransferTime(1, 1, 0), RangeError);
98
+ assert.throws(() => hohmannTransferTime(1, 1, 'mu'), TypeError);
99
+ });
100
+ });
101
+ //# sourceMappingURL=hohmann-transfer.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.spec.js","sourceRoot":"","sources":["../../src/__tests__/hohmann-transfer.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=oberth-energy-gain.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oberth-energy-gain.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/oberth-energy-gain.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { oberthEnergyGain } from '../categories/manoeuvres/oberth-energy-gain';
4
+ import { absClose } from './helpers';
5
+ const relClose = (a, b, rel = 1e-12, abs = 1e-12, msg) => {
6
+ const denom = Math.max(1, Math.abs(a), Math.abs(b));
7
+ assert.ok(Math.abs(a - b) <= Math.max(abs, rel * denom), msg);
8
+ };
9
+ describe('oberthEnergyGain', () => {
10
+ test('basic: Δε ≈ v·Δv', () => {
11
+ const v = 7800; // m/s (LEO-ish)
12
+ const dv = 100; // m/s
13
+ const dE = oberthEnergyGain(v, dv);
14
+ absClose(dE, v * dv);
15
+ });
16
+ test('zeros: dv=0 → 0; v=0 → 0', () => {
17
+ absClose(oberthEnergyGain(7500, 0), 0);
18
+ absClose(oberthEnergyGain(0, 25), 0);
19
+ });
20
+ test('scaling: scale v and dv by k ⇒ Δε scales by k^2', () => {
21
+ const v = 5000, dv = 20;
22
+ const k = 3.5;
23
+ const base = oberthEnergyGain(v, dv);
24
+ const scaled = oberthEnergyGain(k * v, k * dv);
25
+ relClose(scaled, k * k * base, 1e-12, 1e-12);
26
+ });
27
+ test('monotonicity: Δε increases with v for fixed dv', () => {
28
+ const dv = 15;
29
+ const values = [2000, 4000, 8000, 12000].map((v) => oberthEnergyGain(v, dv));
30
+ for (let i = 1; i < values.length; i++) {
31
+ assert.ok(values[i] > values[i - 1]);
32
+ }
33
+ });
34
+ test('monotonicity: Δε increases with dv for fixed v', () => {
35
+ const v = 9000;
36
+ const values = [1, 5, 25, 50, 100].map((dv) => oberthEnergyGain(v, dv));
37
+ for (let i = 1; i < values.length; i++) {
38
+ assert.ok(values[i] > values[i - 1]);
39
+ }
40
+ });
41
+ // ---------------- approximation sanity vs. exact small-impulse energy change ----------------
42
+ test('approximation check vs. exact Δε = v·Δv + 0.5·Δv² (prograde)', () => {
43
+ const v = 9000; // m/s
44
+ const dv = 10; // small impulse
45
+ const approx = oberthEnergyGain(v, dv);
46
+ const exact = v * dv + 0.5 * dv * dv; // neglecting gravity/curvature during the burn
47
+ // The approximation should be lower than exact by ~0.5*dv^2
48
+ absClose(exact - approx, 0.5 * dv * dv);
49
+ });
50
+ // ---------------- validation ----------------
51
+ test('TypeError on non-number inputs', () => {
52
+ assert.throws(() => oberthEnergyGain('7800', 50), TypeError);
53
+ assert.throws(() => oberthEnergyGain(7800, '50'), TypeError);
54
+ });
55
+ test('RangeError on non-finite/negative v or dv', () => {
56
+ assert.throws(() => oberthEnergyGain(NaN, 10), RangeError);
57
+ assert.throws(() => oberthEnergyGain(7500, NaN), RangeError);
58
+ assert.throws(() => oberthEnergyGain(Infinity, 10), RangeError);
59
+ assert.throws(() => oberthEnergyGain(7500, Infinity), RangeError);
60
+ assert.throws(() => oberthEnergyGain(-1, 10), RangeError);
61
+ assert.throws(() => oberthEnergyGain(7500, -0.1), RangeError);
62
+ });
63
+ // ---------------- large but finite values ----------------
64
+ test('handles large finite numbers without overflow', () => {
65
+ const v = 1e6; // m/s (synthetic test)
66
+ const dv = 1e3; // m/s
67
+ const dE = oberthEnergyGain(v, dv);
68
+ absClose(dE, v * dv);
69
+ });
70
+ });
71
+ //# sourceMappingURL=oberth-energy-gain.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oberth-energy-gain.spec.js","sourceRoot":"","sources":["../../src/__tests__/oberth-energy-gain.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plane-change-delta-v.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plane-change-delta-v.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/plane-change-delta-v.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { planeChangeDeltaV } from '../categories/manoeuvres/plane-change-delta-v';
4
+ import { absClose, relClose, toRad } from './helpers';
5
+ const PI = Math.PI;
6
+ describe('planeChangeDeltaV', () => {
7
+ test('Δi = 0 → Δv = 0', () => {
8
+ const v = 7600; // m/s
9
+ const dv = planeChangeDeltaV(v, 0);
10
+ absClose(dv, 0);
11
+ });
12
+ test('Δi = π (180°) → Δv = 2v', () => {
13
+ const v = 7600;
14
+ const dv = planeChangeDeltaV(v, PI);
15
+ absClose(dv, 2 * v);
16
+ });
17
+ test('Δi = 90° → Δv = 2 v sin(45°) = √2 v', () => {
18
+ const v = 7600;
19
+ const dv = planeChangeDeltaV(v, toRad(90));
20
+ relClose(dv, Math.SQRT2 * v, 1e-12);
21
+ });
22
+ test('correctness for several angles (equality with formula)', () => {
23
+ const v = 7500;
24
+ const angles = [
25
+ toRad(5),
26
+ toRad(10),
27
+ toRad(30),
28
+ toRad(60),
29
+ toRad(120)
30
+ ];
31
+ for (const di of angles) {
32
+ const expected = 2 * v * Math.sin(di / 2);
33
+ const dv = planeChangeDeltaV(v, di);
34
+ absClose(dv, expected, 1e-12, `mismatch for Δi=${di}`);
35
+ }
36
+ });
37
+ test('monotonicity: Δv increases with Δi on [0, π]', () => {
38
+ const v = 8000;
39
+ const seq = [
40
+ toRad(0),
41
+ toRad(10),
42
+ toRad(30),
43
+ toRad(60),
44
+ toRad(120),
45
+ toRad(180)
46
+ ];
47
+ let last = -1;
48
+ for (const di of seq) {
49
+ const dv = planeChangeDeltaV(v, di);
50
+ assert.ok(dv >= last - 1e-12, `not monotone at Δi=${di}: ${dv} < ${last}`);
51
+ last = dv;
52
+ }
53
+ });
54
+ test('scales linearly with speed v', () => {
55
+ const di = toRad(25);
56
+ const v1 = 6000;
57
+ const v2 = 9000;
58
+ const dv1 = planeChangeDeltaV(v1, di);
59
+ const dv2 = planeChangeDeltaV(v2, di);
60
+ absClose(dv2 / dv1, v2 / v1, 1e-12);
61
+ });
62
+ test('input validation: TypeError for non-number v', () => {
63
+ assert.throws(() => planeChangeDeltaV('7600', toRad(10)), TypeError);
64
+ });
65
+ test('input validation: RangeError for v non-finite or negative', () => {
66
+ assert.throws(() => planeChangeDeltaV(NaN, toRad(10)), RangeError);
67
+ assert.throws(() => planeChangeDeltaV(Infinity, toRad(10)), RangeError);
68
+ assert.throws(() => planeChangeDeltaV(-1, toRad(10)), RangeError);
69
+ });
70
+ test('input validation: TypeError for non-number deltaI', () => {
71
+ assert.throws(() => planeChangeDeltaV(7600, '0.1'), TypeError);
72
+ });
73
+ test('input validation: RangeError for deltaI non-finite', () => {
74
+ assert.throws(() => planeChangeDeltaV(7600, NaN), RangeError);
75
+ assert.throws(() => planeChangeDeltaV(7600, Infinity), RangeError);
76
+ });
77
+ test('input validation: RangeError for deltaI out of [0, π]', () => {
78
+ assert.throws(() => planeChangeDeltaV(7600, -1e-6), RangeError);
79
+ assert.throws(() => planeChangeDeltaV(7600, (PI + 1e-6)), RangeError);
80
+ });
81
+ test('edge tolerances: very small Δi returns ≈ 2 v * (Δi/2) = v*Δi', () => {
82
+ const v = 7800;
83
+ const di = 1e-9;
84
+ const dv = planeChangeDeltaV(v, di);
85
+ const smallAngleApprox = v * di;
86
+ absClose(dv, smallAngleApprox, 1e-12);
87
+ });
88
+ });
89
+ //# sourceMappingURL=plane-change-delta-v.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plane-change-delta-v.spec.js","sourceRoot":"","sources":["../../src/__tests__/plane-change-delta-v.spec.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;AAEnB,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM;QACtB,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,CAAY,CAAC,CAAC;QAC9C,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,EAAa,CAAC,CAAC;QAC/C,QAAQ,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3C,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,MAAM,GAAc;YACxB,KAAK,CAAC,CAAC,CAAC;YACR,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,GAAG,CAAC;SACX,CAAC;QACF,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAE,EAAa,GAAG,CAAC,CAAC,CAAC;YACtD,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,GAAG,GAAc;YACrB,KAAK,CAAC,CAAC,CAAC;YACR,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,GAAG,CAAC;YACV,KAAK,CAAC,GAAG,CAAC;SACX,CAAC;QACF,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;QACd,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,MAAM,CAAC,EAAE,CACP,EAAE,IAAI,IAAI,GAAG,KAAK,EAClB,sBAAsB,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,CAC5C,CAAC;YACF,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACxC,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC;QAChB,MAAM,EAAE,GAAG,IAAI,CAAC;QAChB,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,QAAQ,CAAC,GAAG,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAa,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QACnE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAY,CAAC,EAAE,SAAS,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,GAAyB,CAAC,EACxD,UAAU,CACX,CAAC;QACF,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAA8B,CAAC,EAC7D,UAAU,CACX,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,IAAe,CAAC,EAAE,UAAU,CAAC,CAAC;QAC3E,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAY,CAAC,EACrD,UAAU,CACX,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,GAAG,IAAe,CAAC;QAC3B,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,gBAAgB,GAAG,CAAC,GAAI,EAAa,CAAC;QAC5C,QAAQ,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { Radians } from '@interstellar-tools/types';
2
+ /**
3
+ * **Combine non-collinear burns** (vector law / law of cosines for velocities).
4
+ *
5
+ * **Definition**
6
+ *
7
+ * $$
8
+ * \Delta v=\sqrt{v_1^2+v_2^2-2\,v_1 v_2\cos\Delta\theta}
9
+ * $$
10
+ *
11
+ * where:
12
+ * - ($ v_1 $) and ($ v_2 $) are the **magnitudes** of two impulsive burns, and
13
+ * - ($ \Delta\theta $) is the **angle between their directions** (radians).
14
+ *
15
+ * **Units**
16
+ * - Inputs: ($ v_1,v_2 $) in **m/s**, ($ \Delta\theta $) in **radians**.
17
+ * - Output: ($ \Delta v $) in **m/s**.
18
+ *
19
+ * **Domain**
20
+ * - ($ v_1 \ge 0,\ v_2 \ge 0,\ \Delta\theta \in [0,\pi] $).
21
+ *
22
+ * ::: info Notes
23
+ *
24
+ * - Special cases:
25
+ * - ($ \Delta\theta=0 $) (same direction) → ($ \Delta v = |v_1 - v_2| $).
26
+ * - ($ \Delta\theta=\pi $) (opposite) → ($ \Delta v = v_1 + v_2 $).
27
+ * - This computes the **single equivalent impulse** from two burns applied
28
+ * with mutual angle ($ \Delta\theta $) (i.e., magnitude of the vector sum).
29
+ *
30
+ * :::
31
+ *
32
+ * @param {number} v1 Magnitude of burn 1 (m/s). Must be finite and ≥ 0.
33
+ * @param {number} v2 Magnitude of burn 2 (m/s). Must be finite and ≥ 0.
34
+ * @param {Radians} deltaTheta Angle between burn directions (radians), in [0, π].
35
+ * @returns {number} Equivalent single ($ \Delta v $) (m/s).
36
+ * @throws {TypeError} If any input is not a number.
37
+ * @throws {RangeError} If inputs are non-finite or out of domain.
38
+ * @group Manoeuvres
39
+ * @example
40
+ * ```ts
41
+ * import { combineBurnsDeltaV } from "@interstellar-tools/equations";
42
+ * import type { Radians } from "@interstellar-tools/types";
43
+ *
44
+ * // Helper: degrees → branded radians
45
+ * const toRadians = (deg: number): Radians => ((deg * Math.PI) / 180) as Radians;
46
+ *
47
+ * // Two burns (magnitudes in m/s)
48
+ * const v1 = 500; // first impulse
49
+ * const v2 = 300; // second impulse
50
+ *
51
+ * // 1) Same direction (Δθ = 0°) → Δv = |v1 - v2|
52
+ * const dv_same = combineBurnsDeltaV(v1, v2, toRadians(0));
53
+ * console.log("Δθ = 0° → Δv =", dv_same.toFixed(3), "m/s");
54
+ *
55
+ * // 2) Opposite directions (Δθ = 180°) → Δv = v1 + v2
56
+ * const dv_opp = combineBurnsDeltaV(v1, v2, toRadians(180));
57
+ * console.log("Δθ = 180° → Δv =", dv_opp.toFixed(3), "m/s");
58
+ *
59
+ * // 3) General non-collinear case (e.g., Δθ = 60°)
60
+ * const dv_60 = combineBurnsDeltaV(v1, v2, toRadians(60));
61
+ * console.log("Δθ = 60° → Δv =", dv_60.toFixed(3), "m/s");
62
+ *
63
+ * // 4) Another example (Δθ = 25°)
64
+ * const dv_25 = combineBurnsDeltaV(1200, 800, toRadians(25));
65
+ * console.log("Δθ = 25° → Δv =", dv_25.toFixed(3), "m/s");
66
+ * ```
67
+ */
68
+ export declare const combineBurnsDeltaV: (v1: number, v2: number, deltaTheta: Radians) => number;
69
+ //# sourceMappingURL=combine-burns-delta-v.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combine-burns-delta-v.d.ts","sourceRoot":"","sources":["../../../src/categories/manoeuvres/combine-burns-delta-v.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,MAAM,EACV,IAAI,MAAM,EACV,YAAY,OAAO,KAClB,MAkCF,CAAC"}