@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.
- package/dist/__tests__/combine-burns-delta-v.spec.d.ts +2 -0
- package/dist/__tests__/combine-burns-delta-v.spec.d.ts.map +1 -0
- package/dist/__tests__/combine-burns-delta-v.spec.js +102 -0
- package/dist/__tests__/combine-burns-delta-v.spec.js.map +1 -0
- package/dist/__tests__/helpers/index.d.ts +2 -1
- package/dist/__tests__/helpers/index.d.ts.map +1 -1
- package/dist/__tests__/helpers/index.js +1 -0
- package/dist/__tests__/helpers/index.js.map +1 -1
- package/dist/__tests__/hohmann-transfer.spec.d.ts +2 -0
- package/dist/__tests__/hohmann-transfer.spec.d.ts.map +1 -0
- package/dist/__tests__/hohmann-transfer.spec.js +101 -0
- package/dist/__tests__/hohmann-transfer.spec.js.map +1 -0
- package/dist/__tests__/oberth-energy-gain.spec.d.ts +2 -0
- package/dist/__tests__/oberth-energy-gain.spec.d.ts.map +1 -0
- package/dist/__tests__/oberth-energy-gain.spec.js +71 -0
- package/dist/__tests__/oberth-energy-gain.spec.js.map +1 -0
- package/dist/__tests__/plane-change-delta-v.spec.d.ts +2 -0
- package/dist/__tests__/plane-change-delta-v.spec.d.ts.map +1 -0
- package/dist/__tests__/plane-change-delta-v.spec.js +89 -0
- package/dist/__tests__/plane-change-delta-v.spec.js.map +1 -0
- package/dist/categories/manoeuvres/combine-burns-delta-v.d.ts +69 -0
- package/dist/categories/manoeuvres/combine-burns-delta-v.d.ts.map +1 -0
- package/dist/categories/manoeuvres/combine-burns-delta-v.js +93 -0
- package/dist/categories/manoeuvres/combine-burns-delta-v.js.map +1 -0
- package/dist/categories/manoeuvres/hohmann-transfer.d.ts +74 -0
- package/dist/categories/manoeuvres/hohmann-transfer.d.ts.map +1 -0
- package/dist/categories/manoeuvres/hohmann-transfer.js +120 -0
- package/dist/categories/manoeuvres/hohmann-transfer.js.map +1 -0
- package/dist/categories/manoeuvres/oberth-energy-gain.d.ts +66 -0
- package/dist/categories/manoeuvres/oberth-energy-gain.d.ts.map +1 -0
- package/dist/categories/manoeuvres/oberth-energy-gain.js +78 -0
- package/dist/categories/manoeuvres/oberth-energy-gain.js.map +1 -0
- package/dist/categories/manoeuvres/plane-change-delta-v.d.ts +57 -0
- package/dist/categories/manoeuvres/plane-change-delta-v.d.ts.map +1 -0
- package/dist/categories/manoeuvres/plane-change-delta-v.js +69 -0
- package/dist/categories/manoeuvres/plane-change-delta-v.js.map +1 -0
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* node:coverage disable */
|
|
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
|
+
/* node:coverage enable */
|
|
69
|
+
export const combineBurnsDeltaV = (v1, v2, deltaTheta) => {
|
|
70
|
+
if (typeof v1 !== 'number' || typeof v2 !== 'number')
|
|
71
|
+
throw new TypeError('v1 and v2 must be numbers (m/s).');
|
|
72
|
+
if (typeof deltaTheta !== 'number')
|
|
73
|
+
throw new TypeError('deltaTheta must be a number (radians).');
|
|
74
|
+
if (!Number.isFinite(v1) || v1 < 0)
|
|
75
|
+
throw new RangeError('v1 must be finite and ≥ 0 (m/s).');
|
|
76
|
+
if (!Number.isFinite(v2) || v2 < 0)
|
|
77
|
+
throw new RangeError('v2 must be finite and ≥ 0 (m/s).');
|
|
78
|
+
if (!Number.isFinite(deltaTheta))
|
|
79
|
+
throw new RangeError('deltaTheta must be finite (radians).');
|
|
80
|
+
if (deltaTheta < 0 || deltaTheta > Math.PI)
|
|
81
|
+
throw new RangeError('deltaTheta must be in [0, π] radians.');
|
|
82
|
+
const c = Math.cos(deltaTheta);
|
|
83
|
+
const radicand = v1 * v1 + v2 * v2 - 2 * v1 * v2 * c;
|
|
84
|
+
// FP guard: clamp tiny negative to zero
|
|
85
|
+
if (radicand < 0) {
|
|
86
|
+
const tol = 1e-12 * (v1 * v1 + v2 * v2);
|
|
87
|
+
if (radicand > -tol)
|
|
88
|
+
return 0;
|
|
89
|
+
throw new RangeError(`Numerically invalid radicand for given inputs (v1=${v1}, v2=${v2}, Δθ=${deltaTheta}).`);
|
|
90
|
+
}
|
|
91
|
+
return Math.sqrt(radicand);
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=combine-burns-delta-v.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combine-burns-delta-v.js","sourceRoot":"","sources":["../../../src/categories/manoeuvres/combine-burns-delta-v.ts"],"names":[],"mappings":"AAEA,2BAA2B;AAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,0BAA0B;AAC1B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,EAAU,EACV,EAAU,EACV,UAAmB,EACX,EAAE;IACV,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ;QAClD,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAE1D,IAAI,OAAO,UAAU,KAAK,QAAQ;QAChC,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAEhE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC;QAChC,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;IAE3D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC;QAChC,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;IAE3D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC9B,MAAM,IAAI,UAAU,CAAC,sCAAsC,CAAC,CAAC;IAE/D,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,IAAI,CAAC,EAAE;QACxC,MAAM,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAC;IAEhE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,UAAoB,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAErD,wCAAwC;IACxC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAExC,IAAI,QAAQ,GAAG,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC;QAE9B,MAAM,IAAI,UAAU,CAClB,qDAAqD,EAAE,QAAQ,EAAE,QAAQ,UAAU,IAAI,CACxF,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC7B,CAAC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export type HohmannTransferReturnType = {
|
|
2
|
+
at: number;
|
|
3
|
+
dv1: number;
|
|
4
|
+
dv2: number;
|
|
5
|
+
dvTotal: number;
|
|
6
|
+
tTransfer: number;
|
|
7
|
+
dir1: 'prograde' | 'retrograde' | 'none';
|
|
8
|
+
dir2: 'prograde' | 'retrograde' | 'none';
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* **Hohmann transfer** (coplanar, circular ($ r_1 \to r_2 $)).
|
|
12
|
+
*
|
|
13
|
+
* **Definitions**
|
|
14
|
+
*
|
|
15
|
+
* $$
|
|
16
|
+
* a_t=\frac{r_1+r_2}{2}
|
|
17
|
+
* $$
|
|
18
|
+
* $$
|
|
19
|
+
* \Delta v_1=\sqrt{\frac{\mu}{r_1}}\!\left(\sqrt{\frac{2r_2}{r_1+r_2}}-1\right),\qquad
|
|
20
|
+
* \Delta v_2=\sqrt{\frac{\mu}{r_2}}\!\left(1-\sqrt{\frac{2r_1}{r_1+r_2}}\right)
|
|
21
|
+
* $$
|
|
22
|
+
* $$
|
|
23
|
+
* \Delta v_{\text{total}}=\Delta v_1+\Delta v_2,\qquad
|
|
24
|
+
* t_t=\pi \sqrt{\frac{a_t^3}{\mu}}
|
|
25
|
+
* $$
|
|
26
|
+
*
|
|
27
|
+
* **Conventions**
|
|
28
|
+
* - Inputs in **SI**: ($ r_1,r_2 $) in **meters**, ($ \mu $) in **m³/s²**.
|
|
29
|
+
* - The returned ($ \Delta v_1,\Delta v_2 $) are **magnitudes** (non-negative).
|
|
30
|
+
* Their **signs** (prograde/retrograde) are provided separately for clarity.
|
|
31
|
+
* - Works for ($ r_2>r_1 $) (raise) and ($ r_2<r_1 $) (lower). If ($ r_1=r_2 $): ($ \Delta v $)s are 0 and ($ t_t $) is half the circular period.
|
|
32
|
+
*
|
|
33
|
+
* **Domain**
|
|
34
|
+
* - ($ r_1>0,\ r_2>0,\ \mu>0 $)
|
|
35
|
+
*
|
|
36
|
+
* @param {number} r1 Initial circular-orbit radius (m).
|
|
37
|
+
* @param {number} r2 Target circular-orbit radius (m).
|
|
38
|
+
* @param {number} mu Standard gravitational parameter ($ \mu $) (m³/s²).
|
|
39
|
+
* @returns {HohmannTransferReturnType}
|
|
40
|
+
* Object with transfer semi-major axis `at` (m), burn magnitudes `dv1`, `dv2`, their sum `dvTotal` (m/s), transfer time `tTransfer` (s),
|
|
41
|
+
* and burn directions `dir1`, `dir2`.
|
|
42
|
+
*
|
|
43
|
+
* @throws {TypeError} If an input is not a number.
|
|
44
|
+
* @throws {RangeError} If ($ r_1\le 0 $), ($ r_2\le 0 $), or ($ \mu\le 0 $), or a value is non-finite.
|
|
45
|
+
*
|
|
46
|
+
* @group Manoeuvres
|
|
47
|
+
*/
|
|
48
|
+
export declare const hohmannTransfer: (r1: number, r2: number, mu: number) => HohmannTransferReturnType;
|
|
49
|
+
/**
|
|
50
|
+
* Convenience: compute only the **semi-major axis** ($ a_t $) (m) of the Hohmann transfer.
|
|
51
|
+
*
|
|
52
|
+
* $$ a_t=\frac{r_1+r_2}{2} $$
|
|
53
|
+
*
|
|
54
|
+
* @param {number} r1 Initial circular-orbit radius (m).
|
|
55
|
+
* @param {number} r2 Target circular-orbit radius (m).
|
|
56
|
+
* @returns {number} ($ a_t $) (m).
|
|
57
|
+
* @throws {TypeError|RangeError} On invalid inputs.
|
|
58
|
+
* @group Manoeuvres
|
|
59
|
+
*/
|
|
60
|
+
export declare const hohmannSemiMajorAxis: (r1: number, r2: number) => number;
|
|
61
|
+
/**
|
|
62
|
+
* Convenience: compute only the **transfer time** ($ t_t $) (s).
|
|
63
|
+
*
|
|
64
|
+
* $$ t_t=\pi \sqrt{\frac{a_t^3}{\mu}} $$
|
|
65
|
+
*
|
|
66
|
+
* @param {number} r1 Initial radius (m).
|
|
67
|
+
* @param {number} r2 Target radius (m).
|
|
68
|
+
* @param {number} mu Gravitational parameter (m³/s²).
|
|
69
|
+
* @returns {number} Transfer time ($ t_t $) (s).
|
|
70
|
+
* @throws {TypeError|RangeError} On invalid inputs.
|
|
71
|
+
* @group Manoeuvres
|
|
72
|
+
*/
|
|
73
|
+
export declare const hohmannTransferTime: (r1: number, r2: number, mu: number) => number;
|
|
74
|
+
//# sourceMappingURL=hohmann-transfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hohmann-transfer.d.ts","sourceRoot":"","sources":["../../../src/categories/manoeuvres/hohmann-transfer.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IACzC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,EACV,IAAI,MAAM,EACV,IAAI,MAAM,KACT,yBAkDF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,EAAE,IAAI,MAAM,KAAG,MAU7D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC9B,IAAI,MAAM,EACV,IAAI,MAAM,EACV,IAAI,MAAM,KACT,MASF,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Hohmann transfer** (coplanar, circular ($ r_1 \to r_2 $)).
|
|
3
|
+
*
|
|
4
|
+
* **Definitions**
|
|
5
|
+
*
|
|
6
|
+
* $$
|
|
7
|
+
* a_t=\frac{r_1+r_2}{2}
|
|
8
|
+
* $$
|
|
9
|
+
* $$
|
|
10
|
+
* \Delta v_1=\sqrt{\frac{\mu}{r_1}}\!\left(\sqrt{\frac{2r_2}{r_1+r_2}}-1\right),\qquad
|
|
11
|
+
* \Delta v_2=\sqrt{\frac{\mu}{r_2}}\!\left(1-\sqrt{\frac{2r_1}{r_1+r_2}}\right)
|
|
12
|
+
* $$
|
|
13
|
+
* $$
|
|
14
|
+
* \Delta v_{\text{total}}=\Delta v_1+\Delta v_2,\qquad
|
|
15
|
+
* t_t=\pi \sqrt{\frac{a_t^3}{\mu}}
|
|
16
|
+
* $$
|
|
17
|
+
*
|
|
18
|
+
* **Conventions**
|
|
19
|
+
* - Inputs in **SI**: ($ r_1,r_2 $) in **meters**, ($ \mu $) in **m³/s²**.
|
|
20
|
+
* - The returned ($ \Delta v_1,\Delta v_2 $) are **magnitudes** (non-negative).
|
|
21
|
+
* Their **signs** (prograde/retrograde) are provided separately for clarity.
|
|
22
|
+
* - Works for ($ r_2>r_1 $) (raise) and ($ r_2<r_1 $) (lower). If ($ r_1=r_2 $): ($ \Delta v $)s are 0 and ($ t_t $) is half the circular period.
|
|
23
|
+
*
|
|
24
|
+
* **Domain**
|
|
25
|
+
* - ($ r_1>0,\ r_2>0,\ \mu>0 $)
|
|
26
|
+
*
|
|
27
|
+
* @param {number} r1 Initial circular-orbit radius (m).
|
|
28
|
+
* @param {number} r2 Target circular-orbit radius (m).
|
|
29
|
+
* @param {number} mu Standard gravitational parameter ($ \mu $) (m³/s²).
|
|
30
|
+
* @returns {HohmannTransferReturnType}
|
|
31
|
+
* Object with transfer semi-major axis `at` (m), burn magnitudes `dv1`, `dv2`, their sum `dvTotal` (m/s), transfer time `tTransfer` (s),
|
|
32
|
+
* and burn directions `dir1`, `dir2`.
|
|
33
|
+
*
|
|
34
|
+
* @throws {TypeError} If an input is not a number.
|
|
35
|
+
* @throws {RangeError} If ($ r_1\le 0 $), ($ r_2\le 0 $), or ($ \mu\le 0 $), or a value is non-finite.
|
|
36
|
+
*
|
|
37
|
+
* @group Manoeuvres
|
|
38
|
+
*/
|
|
39
|
+
export const hohmannTransfer = (r1, r2, mu) => {
|
|
40
|
+
// Type & range checks
|
|
41
|
+
if (typeof r1 !== 'number' ||
|
|
42
|
+
typeof r2 !== 'number' ||
|
|
43
|
+
typeof mu !== 'number') {
|
|
44
|
+
throw new TypeError('r1, r2, and mu must be numbers.');
|
|
45
|
+
}
|
|
46
|
+
if (!Number.isFinite(r1) || !Number.isFinite(r2) || !Number.isFinite(mu)) {
|
|
47
|
+
throw new RangeError('r1, r2, and mu must be finite.');
|
|
48
|
+
}
|
|
49
|
+
if (r1 <= 0 || r2 <= 0 || mu <= 0) {
|
|
50
|
+
throw new RangeError('r1 and r2 must be > 0 (m), mu must be > 0 (m^3/s^2).');
|
|
51
|
+
}
|
|
52
|
+
const at = 0.5 * (r1 + r2);
|
|
53
|
+
// Circular speeds at the endpoints
|
|
54
|
+
const v1c = Math.sqrt(mu / r1);
|
|
55
|
+
const v2c = Math.sqrt(mu / r2);
|
|
56
|
+
// Transfer-ellipse speeds at peri/apo
|
|
57
|
+
const vPeriTrans = Math.sqrt(mu * (2 / r1 - 1 / at)); // speed at r1 on transfer
|
|
58
|
+
const vApoTrans = Math.sqrt(mu * (2 / r2 - 1 / at)); // speed at r2 on transfer
|
|
59
|
+
// Signed burns relative to local circular velocity direction.
|
|
60
|
+
// Positive => prograde (speed up), negative => retrograde (slow down).
|
|
61
|
+
const signedDv1 = vPeriTrans - v1c;
|
|
62
|
+
const signedDv2 = v2c - vApoTrans;
|
|
63
|
+
const dv1 = Math.abs(signedDv1);
|
|
64
|
+
const dv2 = Math.abs(signedDv2);
|
|
65
|
+
const dvTotal = dv1 + dv2;
|
|
66
|
+
const dir1 = Math.abs(signedDv1) < 1e-15
|
|
67
|
+
? 'none'
|
|
68
|
+
: signedDv1 > 0
|
|
69
|
+
? 'prograde'
|
|
70
|
+
: 'retrograde';
|
|
71
|
+
const dir2 = Math.abs(signedDv2) < 1e-15
|
|
72
|
+
? 'none'
|
|
73
|
+
: signedDv2 > 0
|
|
74
|
+
? 'prograde'
|
|
75
|
+
: 'retrograde';
|
|
76
|
+
// Half the period of the transfer ellipse
|
|
77
|
+
const tTransfer = Math.PI * Math.sqrt((at * at * at) / mu);
|
|
78
|
+
return { at, dv1, dv2, dvTotal, tTransfer, dir1, dir2 };
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Convenience: compute only the **semi-major axis** ($ a_t $) (m) of the Hohmann transfer.
|
|
82
|
+
*
|
|
83
|
+
* $$ a_t=\frac{r_1+r_2}{2} $$
|
|
84
|
+
*
|
|
85
|
+
* @param {number} r1 Initial circular-orbit radius (m).
|
|
86
|
+
* @param {number} r2 Target circular-orbit radius (m).
|
|
87
|
+
* @returns {number} ($ a_t $) (m).
|
|
88
|
+
* @throws {TypeError|RangeError} On invalid inputs.
|
|
89
|
+
* @group Manoeuvres
|
|
90
|
+
*/
|
|
91
|
+
export const hohmannSemiMajorAxis = (r1, r2) => {
|
|
92
|
+
if (typeof r1 !== 'number' || typeof r2 !== 'number')
|
|
93
|
+
throw new TypeError('r1 and r2 must be numbers.');
|
|
94
|
+
if (!Number.isFinite(r1) || !Number.isFinite(r2))
|
|
95
|
+
throw new RangeError('r1 and r2 must be finite.');
|
|
96
|
+
if (r1 <= 0 || r2 <= 0)
|
|
97
|
+
throw new RangeError('r1 and r2 must be > 0 (m).');
|
|
98
|
+
return 0.5 * (r1 + r2);
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Convenience: compute only the **transfer time** ($ t_t $) (s).
|
|
102
|
+
*
|
|
103
|
+
* $$ t_t=\pi \sqrt{\frac{a_t^3}{\mu}} $$
|
|
104
|
+
*
|
|
105
|
+
* @param {number} r1 Initial radius (m).
|
|
106
|
+
* @param {number} r2 Target radius (m).
|
|
107
|
+
* @param {number} mu Gravitational parameter (m³/s²).
|
|
108
|
+
* @returns {number} Transfer time ($ t_t $) (s).
|
|
109
|
+
* @throws {TypeError|RangeError} On invalid inputs.
|
|
110
|
+
* @group Manoeuvres
|
|
111
|
+
*/
|
|
112
|
+
export const hohmannTransferTime = (r1, r2, mu) => {
|
|
113
|
+
const at = hohmannSemiMajorAxis(r1, r2);
|
|
114
|
+
if (typeof mu !== 'number')
|
|
115
|
+
throw new TypeError('mu must be a number.');
|
|
116
|
+
if (!Number.isFinite(mu) || mu <= 0)
|
|
117
|
+
throw new RangeError('mu must be finite and > 0 (m^3/s^2).');
|
|
118
|
+
return Math.PI * Math.sqrt((at * at * at) / mu);
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=hohmann-transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hohmann-transfer.js","sourceRoot":"","sources":["../../../src/categories/manoeuvres/hohmann-transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Oberth effect (specific energy gain near periapsis)**.
|
|
3
|
+
*
|
|
4
|
+
* **Approximation**
|
|
5
|
+
*
|
|
6
|
+
* $$
|
|
7
|
+
* \Delta \varepsilon \;\approx\; v\,\Delta v
|
|
8
|
+
* $$
|
|
9
|
+
*
|
|
10
|
+
* where:
|
|
11
|
+
* - ($ v $) is the instantaneous **speed** at the burn point (typically periapsis),
|
|
12
|
+
* - ($ \Delta v $) is the **impulsive** prograde burn magnitude,
|
|
13
|
+
* - ($ \Delta \varepsilon $) is the change in **specific mechanical energy** (J/kg ≡ m²/s²).
|
|
14
|
+
*
|
|
15
|
+
* **Units**
|
|
16
|
+
* - Inputs: ($ v $) in **m/s**, ($ \Delta v $) in **m/s**.
|
|
17
|
+
* - Output: ($ \Delta \varepsilon $) in **J/kg** (m²/s²).
|
|
18
|
+
*
|
|
19
|
+
* ::: info Notes
|
|
20
|
+
*
|
|
21
|
+
* - This approximation assumes a **small**, **prograde** impulse (aligned with velocity) and
|
|
22
|
+
* neglects higher-order terms ($ \tfrac{1}{2}(\Delta v)^2 $).
|
|
23
|
+
* - A more general small-angle form is ($ \Delta \varepsilon \approx v\,\Delta v\cos\phi $),
|
|
24
|
+
* where ($ \phi $) is the angle between the velocity vector and the burn direction.
|
|
25
|
+
*
|
|
26
|
+
* :::
|
|
27
|
+
*
|
|
28
|
+
* @param {number} v Instantaneous speed at burn point (m/s). Must be finite and ≥ 0.
|
|
29
|
+
* @param {number} dv Impulsive prograde Δv magnitude (m/s). Must be finite and ≥ 0.
|
|
30
|
+
* @returns {number} Specific energy gain ($ \Delta \varepsilon $) (J/kg).
|
|
31
|
+
* @throws {TypeError} If inputs are not numbers.
|
|
32
|
+
* @throws {RangeError} If inputs are non-finite or negative.
|
|
33
|
+
* @group Manoeuvres
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { oberthEnergyGain, circularSpeed } from "@interstellar-tools/equations";
|
|
37
|
+
*
|
|
38
|
+
* // Earth's GM (μ) in m^3/s^2
|
|
39
|
+
* const muEarth = 3.986004418e14;
|
|
40
|
+
*
|
|
41
|
+
* // Example: small prograde burn at LEO periapsis (~400 km altitude)
|
|
42
|
+
* const rLEO = 6378e3 + 400e3; // m
|
|
43
|
+
* const vLEO = circularSpeed(rLEO, muEarth); // m/s ≈ 7670
|
|
44
|
+
*
|
|
45
|
+
* // Suppose guidance commands a small impulsive burn Δv = 50 m/s at periapsis
|
|
46
|
+
* const dv = 50; // m/s
|
|
47
|
+
*
|
|
48
|
+
* // Oberth approximation: Δε ≈ v · Δv (specific energy gain, J/kg ≡ m^2/s^2)
|
|
49
|
+
* const deltaEps = oberthEnergyGain(vLEO, dv);
|
|
50
|
+
*
|
|
51
|
+
* // For intuition, translate Δε to an approximate change in semi-major axis (elliptic case):
|
|
52
|
+
* // ε = -μ/(2a) ⇒ Δa ≈ (a^2 / μ) · Δε (valid for small changes around circular LEO)
|
|
53
|
+
* const aLEO = rLEO; // circular → a = r
|
|
54
|
+
* const deltaA = (aLEO * aLEO / muEarth) * deltaEps; // meters
|
|
55
|
+
*
|
|
56
|
+
* console.log(`LEO speed v ≈ ${vLEO.toFixed(1)} m/s`);
|
|
57
|
+
* console.log(`Prograde Δv = ${dv.toFixed(1)} m/s`);
|
|
58
|
+
* console.log(`Specific energy gain Δε ≈ ${deltaEps.toFixed(0)} J/kg`);
|
|
59
|
+
* console.log(`Approx. semi-major axis change Δa ≈ ${deltaA.toFixed(0)} m`);
|
|
60
|
+
*
|
|
61
|
+
* // Tip: If the burn is not perfectly prograde by angle φ (in radians),
|
|
62
|
+
* // scale by cos φ: Δε ≈ v · Δv · cos φ (small-angle approximation).
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare const oberthEnergyGain: (v: number, dv: number) => number;
|
|
66
|
+
//# sourceMappingURL=oberth-energy-gain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oberth-energy-gain.d.ts","sourceRoot":"","sources":["../../../src/categories/manoeuvres/oberth-energy-gain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,EAAE,IAAI,MAAM,KAAG,MAexD,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Oberth effect (specific energy gain near periapsis)**.
|
|
3
|
+
*
|
|
4
|
+
* **Approximation**
|
|
5
|
+
*
|
|
6
|
+
* $$
|
|
7
|
+
* \Delta \varepsilon \;\approx\; v\,\Delta v
|
|
8
|
+
* $$
|
|
9
|
+
*
|
|
10
|
+
* where:
|
|
11
|
+
* - ($ v $) is the instantaneous **speed** at the burn point (typically periapsis),
|
|
12
|
+
* - ($ \Delta v $) is the **impulsive** prograde burn magnitude,
|
|
13
|
+
* - ($ \Delta \varepsilon $) is the change in **specific mechanical energy** (J/kg ≡ m²/s²).
|
|
14
|
+
*
|
|
15
|
+
* **Units**
|
|
16
|
+
* - Inputs: ($ v $) in **m/s**, ($ \Delta v $) in **m/s**.
|
|
17
|
+
* - Output: ($ \Delta \varepsilon $) in **J/kg** (m²/s²).
|
|
18
|
+
*
|
|
19
|
+
* ::: info Notes
|
|
20
|
+
*
|
|
21
|
+
* - This approximation assumes a **small**, **prograde** impulse (aligned with velocity) and
|
|
22
|
+
* neglects higher-order terms ($ \tfrac{1}{2}(\Delta v)^2 $).
|
|
23
|
+
* - A more general small-angle form is ($ \Delta \varepsilon \approx v\,\Delta v\cos\phi $),
|
|
24
|
+
* where ($ \phi $) is the angle between the velocity vector and the burn direction.
|
|
25
|
+
*
|
|
26
|
+
* :::
|
|
27
|
+
*
|
|
28
|
+
* @param {number} v Instantaneous speed at burn point (m/s). Must be finite and ≥ 0.
|
|
29
|
+
* @param {number} dv Impulsive prograde Δv magnitude (m/s). Must be finite and ≥ 0.
|
|
30
|
+
* @returns {number} Specific energy gain ($ \Delta \varepsilon $) (J/kg).
|
|
31
|
+
* @throws {TypeError} If inputs are not numbers.
|
|
32
|
+
* @throws {RangeError} If inputs are non-finite or negative.
|
|
33
|
+
* @group Manoeuvres
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { oberthEnergyGain, circularSpeed } from "@interstellar-tools/equations";
|
|
37
|
+
*
|
|
38
|
+
* // Earth's GM (μ) in m^3/s^2
|
|
39
|
+
* const muEarth = 3.986004418e14;
|
|
40
|
+
*
|
|
41
|
+
* // Example: small prograde burn at LEO periapsis (~400 km altitude)
|
|
42
|
+
* const rLEO = 6378e3 + 400e3; // m
|
|
43
|
+
* const vLEO = circularSpeed(rLEO, muEarth); // m/s ≈ 7670
|
|
44
|
+
*
|
|
45
|
+
* // Suppose guidance commands a small impulsive burn Δv = 50 m/s at periapsis
|
|
46
|
+
* const dv = 50; // m/s
|
|
47
|
+
*
|
|
48
|
+
* // Oberth approximation: Δε ≈ v · Δv (specific energy gain, J/kg ≡ m^2/s^2)
|
|
49
|
+
* const deltaEps = oberthEnergyGain(vLEO, dv);
|
|
50
|
+
*
|
|
51
|
+
* // For intuition, translate Δε to an approximate change in semi-major axis (elliptic case):
|
|
52
|
+
* // ε = -μ/(2a) ⇒ Δa ≈ (a^2 / μ) · Δε (valid for small changes around circular LEO)
|
|
53
|
+
* const aLEO = rLEO; // circular → a = r
|
|
54
|
+
* const deltaA = (aLEO * aLEO / muEarth) * deltaEps; // meters
|
|
55
|
+
*
|
|
56
|
+
* console.log(`LEO speed v ≈ ${vLEO.toFixed(1)} m/s`);
|
|
57
|
+
* console.log(`Prograde Δv = ${dv.toFixed(1)} m/s`);
|
|
58
|
+
* console.log(`Specific energy gain Δε ≈ ${deltaEps.toFixed(0)} J/kg`);
|
|
59
|
+
* console.log(`Approx. semi-major axis change Δa ≈ ${deltaA.toFixed(0)} m`);
|
|
60
|
+
*
|
|
61
|
+
* // Tip: If the burn is not perfectly prograde by angle φ (in radians),
|
|
62
|
+
* // scale by cos φ: Δε ≈ v · Δv · cos φ (small-angle approximation).
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export const oberthEnergyGain = (v, dv) => {
|
|
66
|
+
if (typeof v !== 'number' || typeof dv !== 'number') {
|
|
67
|
+
throw new TypeError('v and dv must be numbers (m/s).');
|
|
68
|
+
}
|
|
69
|
+
if (!Number.isFinite(v) || v < 0) {
|
|
70
|
+
throw new RangeError('v must be finite and ≥ 0 (m/s).');
|
|
71
|
+
}
|
|
72
|
+
if (!Number.isFinite(dv) || dv < 0) {
|
|
73
|
+
throw new RangeError('dv must be finite and ≥ 0 (m/s).');
|
|
74
|
+
}
|
|
75
|
+
// Δε ≈ v · Δv (prograde, small-Δv approximation)
|
|
76
|
+
return v * dv;
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=oberth-energy-gain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oberth-energy-gain.js","sourceRoot":"","sources":["../../../src/categories/manoeuvres/oberth-energy-gain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAS,EAAE,EAAU,EAAU,EAAE;IAChE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,UAAU,CAAC,iCAAiC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;IAC3D,CAAC;IAED,kDAAkD;IAClD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Radians } from '@interstellar-tools/types';
|
|
2
|
+
/**
|
|
3
|
+
* **Inclination (plane) change** Δv at speed ($ v $).
|
|
4
|
+
*
|
|
5
|
+
* **Definition**
|
|
6
|
+
*
|
|
7
|
+
* $$
|
|
8
|
+
* \Delta v = 2\,v\,\sin\!\left(\frac{\Delta i}{2}\right)
|
|
9
|
+
* $$
|
|
10
|
+
*
|
|
11
|
+
* **Units**
|
|
12
|
+
* - Inputs: ($ v $) in **m/s**, ($ \Delta i $) in **radians**.
|
|
13
|
+
* - Output: ($ \Delta v $) in **m/s**.
|
|
14
|
+
*
|
|
15
|
+
* ::: info Notes
|
|
16
|
+
*
|
|
17
|
+
* - Valid for an **instantaneous** plane change (impulsive) performed at speed ($ v $)
|
|
18
|
+
* (e.g., at a node). For best efficiency, perform at **apogee** (lowest speed) when possible.
|
|
19
|
+
* - Domain for ($ \Delta i $) is ( $[0,\pi] $) (0–180°). Larger angles can be reduced modulo ($ 2\pi $).
|
|
20
|
+
*
|
|
21
|
+
* :::
|
|
22
|
+
*
|
|
23
|
+
* @param {number} v Current speed magnitude (m/s). Must be finite and ≥ 0.
|
|
24
|
+
* @param {Radians} deltaI Inclination change angle Δi (radians). Must be finite and 0 ≤ Δi ≤ π.
|
|
25
|
+
* @returns {number} Required impulsive Δv (m/s).
|
|
26
|
+
* @throws {TypeError} If `v` is not a number or `deltaI` not a number (radians).
|
|
27
|
+
* @throws {RangeError} If `v` is non-finite or < 0; if `deltaI` is non-finite or outside [0, π].
|
|
28
|
+
* @group Manoeuvres
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { planeChangeDeltaV, circularSpeed } from "@interstellar-tools/equations";
|
|
32
|
+
* import type { Radians } from "@interstellar-tools/types";
|
|
33
|
+
*
|
|
34
|
+
* // Helper: degrees → radians (branded)
|
|
35
|
+
* const toRadians = (deg: number): Radians => ((deg * Math.PI) / 180) as Radians;
|
|
36
|
+
*
|
|
37
|
+
* // Earth’s GM (μ) in m^3/s^2
|
|
38
|
+
* const muEarth = 3.986004418e14;
|
|
39
|
+
*
|
|
40
|
+
* // Example: instantaneous plane change at LEO (~400 km altitude)
|
|
41
|
+
* const rLEO = 6378e3 + 400e3; // meters
|
|
42
|
+
* const vLEO = circularSpeed(rLEO, muEarth); // m/s
|
|
43
|
+
*
|
|
44
|
+
* // Change from 28.5° (Kennedy inclination) to equatorial (0°) → Δi = 28.5°
|
|
45
|
+
* const deltaI = toRadians(28.5);
|
|
46
|
+
* const dv_LEO = planeChangeDeltaV(vLEO, deltaI);
|
|
47
|
+
*
|
|
48
|
+
* console.log(`LEO speed: ${vLEO.toFixed(1)} m/s`);
|
|
49
|
+
* console.log(`Δi: 28.5° → Δv ≈ ${dv_LEO.toFixed(1)} m/s`);
|
|
50
|
+
*
|
|
51
|
+
* // Another quick check: a modest 10° plane change at the same altitude
|
|
52
|
+
* const dv_10deg = planeChangeDeltaV(vLEO, toRadians(10));
|
|
53
|
+
* console.log(`Δi: 10° → Δv ≈ ${dv_10deg.toFixed(1)} m/s`);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const planeChangeDeltaV: (v: number, deltaI: Radians) => number;
|
|
57
|
+
//# sourceMappingURL=plane-change-delta-v.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plane-change-delta-v.d.ts","sourceRoot":"","sources":["../../../src/categories/manoeuvres/plane-change-delta-v.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,EAAE,QAAQ,OAAO,KAAG,MAiB9D,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Inclination (plane) change** Δv at speed ($ v $).
|
|
3
|
+
*
|
|
4
|
+
* **Definition**
|
|
5
|
+
*
|
|
6
|
+
* $$
|
|
7
|
+
* \Delta v = 2\,v\,\sin\!\left(\frac{\Delta i}{2}\right)
|
|
8
|
+
* $$
|
|
9
|
+
*
|
|
10
|
+
* **Units**
|
|
11
|
+
* - Inputs: ($ v $) in **m/s**, ($ \Delta i $) in **radians**.
|
|
12
|
+
* - Output: ($ \Delta v $) in **m/s**.
|
|
13
|
+
*
|
|
14
|
+
* ::: info Notes
|
|
15
|
+
*
|
|
16
|
+
* - Valid for an **instantaneous** plane change (impulsive) performed at speed ($ v $)
|
|
17
|
+
* (e.g., at a node). For best efficiency, perform at **apogee** (lowest speed) when possible.
|
|
18
|
+
* - Domain for ($ \Delta i $) is ( $[0,\pi] $) (0–180°). Larger angles can be reduced modulo ($ 2\pi $).
|
|
19
|
+
*
|
|
20
|
+
* :::
|
|
21
|
+
*
|
|
22
|
+
* @param {number} v Current speed magnitude (m/s). Must be finite and ≥ 0.
|
|
23
|
+
* @param {Radians} deltaI Inclination change angle Δi (radians). Must be finite and 0 ≤ Δi ≤ π.
|
|
24
|
+
* @returns {number} Required impulsive Δv (m/s).
|
|
25
|
+
* @throws {TypeError} If `v` is not a number or `deltaI` not a number (radians).
|
|
26
|
+
* @throws {RangeError} If `v` is non-finite or < 0; if `deltaI` is non-finite or outside [0, π].
|
|
27
|
+
* @group Manoeuvres
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { planeChangeDeltaV, circularSpeed } from "@interstellar-tools/equations";
|
|
31
|
+
* import type { Radians } from "@interstellar-tools/types";
|
|
32
|
+
*
|
|
33
|
+
* // Helper: degrees → radians (branded)
|
|
34
|
+
* const toRadians = (deg: number): Radians => ((deg * Math.PI) / 180) as Radians;
|
|
35
|
+
*
|
|
36
|
+
* // Earth’s GM (μ) in m^3/s^2
|
|
37
|
+
* const muEarth = 3.986004418e14;
|
|
38
|
+
*
|
|
39
|
+
* // Example: instantaneous plane change at LEO (~400 km altitude)
|
|
40
|
+
* const rLEO = 6378e3 + 400e3; // meters
|
|
41
|
+
* const vLEO = circularSpeed(rLEO, muEarth); // m/s
|
|
42
|
+
*
|
|
43
|
+
* // Change from 28.5° (Kennedy inclination) to equatorial (0°) → Δi = 28.5°
|
|
44
|
+
* const deltaI = toRadians(28.5);
|
|
45
|
+
* const dv_LEO = planeChangeDeltaV(vLEO, deltaI);
|
|
46
|
+
*
|
|
47
|
+
* console.log(`LEO speed: ${vLEO.toFixed(1)} m/s`);
|
|
48
|
+
* console.log(`Δi: 28.5° → Δv ≈ ${dv_LEO.toFixed(1)} m/s`);
|
|
49
|
+
*
|
|
50
|
+
* // Another quick check: a modest 10° plane change at the same altitude
|
|
51
|
+
* const dv_10deg = planeChangeDeltaV(vLEO, toRadians(10));
|
|
52
|
+
* console.log(`Δi: 10° → Δv ≈ ${dv_10deg.toFixed(1)} m/s`);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const planeChangeDeltaV = (v, deltaI) => {
|
|
56
|
+
if (typeof v !== 'number')
|
|
57
|
+
throw new TypeError('v must be a number (m/s).');
|
|
58
|
+
if (!Number.isFinite(v) || v < 0)
|
|
59
|
+
throw new RangeError('v must be finite and ≥ 0 (m/s).');
|
|
60
|
+
if (typeof deltaI !== 'number')
|
|
61
|
+
throw new TypeError('deltaI must be a number (radians).');
|
|
62
|
+
if (!Number.isFinite(deltaI))
|
|
63
|
+
throw new RangeError('deltaI must be finite (radians).');
|
|
64
|
+
if (deltaI < 0 || deltaI > Math.PI)
|
|
65
|
+
throw new RangeError('deltaI must be in [0, π] radians.');
|
|
66
|
+
// Δv = 2 v sin(Δi / 2)
|
|
67
|
+
return 2 * v * Math.sin(deltaI / 2);
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=plane-change-delta-v.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plane-change-delta-v.js","sourceRoot":"","sources":["../../../src/categories/manoeuvres/plane-change-delta-v.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAS,EAAE,MAAe,EAAU,EAAE;IACtE,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAE5E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC9B,MAAM,IAAI,UAAU,CAAC,iCAAiC,CAAC,CAAC;IAE1D,IAAI,OAAO,MAAM,KAAK,QAAQ;QAC5B,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;IAE5D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;IAE3D,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,EAAE;QAChC,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAE5D,uBAAuB;IACvB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAE,MAAiB,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,23 +5,27 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export * from './categories/angle/compute-angle';
|
|
7
7
|
export * from './categories/angle/wrap-angle';
|
|
8
|
-
export * from './categories/anomalies/mean-to-eccentric-anomaly';
|
|
9
8
|
export * from './categories/anomalies/eccentric-to-true-anomaly';
|
|
9
|
+
export * from './categories/anomalies/mean-to-eccentric-anomaly';
|
|
10
10
|
export * from './categories/anomalies/true-to-mean-anomaly';
|
|
11
|
-
export * from './categories/kepler/solve-kepler';
|
|
12
|
-
export * from './categories/kepler/solve-kepler-newton-raphson';
|
|
13
11
|
export * from './categories/kepler/solve-kepler-bisection';
|
|
14
12
|
export * from './categories/kepler/solve-kepler-high-eccentricity';
|
|
15
|
-
export * from './categories/
|
|
16
|
-
export * from './categories/
|
|
17
|
-
export * from './categories/gravity/force-on1-by2';
|
|
13
|
+
export * from './categories/kepler/solve-kepler-newton-raphson';
|
|
14
|
+
export * from './categories/kepler/solve-kepler';
|
|
18
15
|
export * from './categories/gravity/acceleration-on1-by2';
|
|
19
|
-
export * from './categories/
|
|
16
|
+
export * from './categories/gravity/force-on1-by2';
|
|
17
|
+
export * from './categories/gravity/gravitational-force';
|
|
18
|
+
export * from './categories/gravity/gravitational-parameter';
|
|
20
19
|
export * from './categories/orbits/circular-speed';
|
|
21
20
|
export * from './categories/orbits/escape-speed';
|
|
21
|
+
export * from './categories/orbits/flight-path-angle-from-true-anomaly';
|
|
22
22
|
export * from './categories/orbits/kepler-period';
|
|
23
|
-
export * from './categories/orbits/specific-angular-momentum';
|
|
24
23
|
export * from './categories/orbits/specific-angular-momentum-from-elements';
|
|
24
|
+
export * from './categories/orbits/specific-angular-momentum';
|
|
25
25
|
export * from './categories/orbits/specific-mechanical-energy';
|
|
26
|
-
export * from './categories/orbits/
|
|
26
|
+
export * from './categories/orbits/vis-viva-speed';
|
|
27
|
+
export * from './categories/manoeuvres/combine-burns-delta-v';
|
|
28
|
+
export * from './categories/manoeuvres/hohmann-transfer';
|
|
29
|
+
export * from './categories/manoeuvres/oberth-energy-gain';
|
|
30
|
+
export * from './categories/manoeuvres/plane-change-delta-v';
|
|
27
31
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;AAI9C,cAAc,kDAAkD,CAAC;AAEjE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,6CAA6C,CAAC;AAI5D,cAAc,4CAA4C,CAAC;AAE3D,cAAc,oDAAoD,CAAC;AAEnE,cAAc,iDAAiD,CAAC;AAEhE,cAAc,kCAAkC,CAAC;AAIjD,cAAc,2CAA2C,CAAC;AAE1D,cAAc,oCAAoC,CAAC;AAEnD,cAAc,0CAA0C,CAAC;AAEzD,cAAc,8CAA8C,CAAC;AAI7D,cAAc,oCAAoC,CAAC;AAEnD,cAAc,kCAAkC,CAAC;AAEjD,cAAc,yDAAyD,CAAC;AAExE,cAAc,mCAAmC,CAAC;AAElD,cAAc,6DAA6D,CAAC;AAE5E,cAAc,+CAA+C,CAAC;AAE9D,cAAc,gDAAgD,CAAC;AAE/D,cAAc,oCAAoC,CAAC;AAInD,cAAc,+CAA+C,CAAC;AAE9D,cAAc,0CAA0C,CAAC;AAEzD,cAAc,4CAA4C,CAAC;AAE3D,cAAc,8CAA8C,CAAC"}
|