@interstellar-tools/equations 1.3.0 → 1.5.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/categories/cartography/body-fixed-to-geodetic.d.ts +77 -0
- package/dist/categories/cartography/body-fixed-to-geodetic.d.ts.map +1 -0
- package/dist/categories/cartography/body-fixed-to-geodetic.js +111 -0
- package/dist/categories/cartography/body-fixed-to-geodetic.js.map +1 -0
- package/dist/categories/cartography/geodetic-to-body-fixed.d.ts +73 -0
- package/dist/categories/cartography/geodetic-to-body-fixed.d.ts.map +1 -0
- package/dist/categories/cartography/geodetic-to-body-fixed.js +97 -0
- package/dist/categories/cartography/geodetic-to-body-fixed.js.map +1 -0
- package/dist/categories/entry/ballistic-coefficient.d.ts +44 -0
- package/dist/categories/entry/ballistic-coefficient.d.ts.map +1 -0
- package/dist/categories/entry/ballistic-coefficient.js +54 -0
- package/dist/categories/entry/ballistic-coefficient.js.map +1 -0
- package/dist/categories/entry/ballistic-entry-speed.d.ts +52 -0
- package/dist/categories/entry/ballistic-entry-speed.d.ts.map +1 -0
- package/dist/categories/entry/ballistic-entry-speed.js +71 -0
- package/dist/categories/entry/ballistic-entry-speed.js.map +1 -0
- package/dist/categories/entry/ballistic-peak-deceleration-altitude.d.ts +47 -0
- package/dist/categories/entry/ballistic-peak-deceleration-altitude.d.ts.map +1 -0
- package/dist/categories/entry/ballistic-peak-deceleration-altitude.js +62 -0
- package/dist/categories/entry/ballistic-peak-deceleration-altitude.js.map +1 -0
- package/dist/categories/entry/ballistic-peak-deceleration.d.ts +63 -0
- package/dist/categories/entry/ballistic-peak-deceleration.d.ts.map +1 -0
- package/dist/categories/entry/ballistic-peak-deceleration.js +76 -0
- package/dist/categories/entry/ballistic-peak-deceleration.js.map +1 -0
- package/dist/categories/entry/stagnation-heat-flux.d.ts +46 -0
- package/dist/categories/entry/stagnation-heat-flux.d.ts.map +1 -0
- package/dist/categories/entry/stagnation-heat-flux.js +57 -0
- package/dist/categories/entry/stagnation-heat-flux.js.map +1 -0
- package/dist/categories/entry/terminal-velocity.d.ts +48 -0
- package/dist/categories/entry/terminal-velocity.d.ts.map +1 -0
- package/dist/categories/entry/terminal-velocity.js +60 -0
- package/dist/categories/entry/terminal-velocity.js.map +1 -0
- package/dist/categories/entry/validate.d.ts +7 -0
- package/dist/categories/entry/validate.d.ts.map +1 -0
- package/dist/categories/entry/validate.js +20 -0
- package/dist/categories/entry/validate.js.map +1 -0
- package/dist/categories/orbits/inclination-from-launch-azimuth.d.ts +6 -4
- package/dist/categories/orbits/inclination-from-launch-azimuth.d.ts.map +1 -1
- package/dist/categories/orbits/inclination-from-launch-azimuth.js +6 -4
- package/dist/categories/orbits/inclination-from-launch-azimuth.js.map +1 -1
- package/dist/categories/orbits/surface-rotation-speed.d.ts +1 -1
- package/dist/categories/orbits/surface-rotation-speed.js +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { GeodeticCoordinatesInterface } from '@interstellar-tools/types';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a **body-fixed Cartesian** position (ECEF for Earth) to **geodetic coordinates**: latitude, longitude and height.
|
|
4
|
+
*
|
|
5
|
+
* There's no closed form for the latitude. This uses Bowring's iteration on the parametric latitude $ \beta $:
|
|
6
|
+
*
|
|
7
|
+
* $$
|
|
8
|
+
* \tan\varphi = \frac{z + e'^2 b \sin^3\beta}{p - e^2 a \cos^3\beta},
|
|
9
|
+
* \qquad
|
|
10
|
+
* \tan\beta = \frac{b}{a}\tan\varphi
|
|
11
|
+
* $$
|
|
12
|
+
*
|
|
13
|
+
* and then
|
|
14
|
+
*
|
|
15
|
+
* $$
|
|
16
|
+
* \lambda = \operatorname{atan2}(y, x), \qquad
|
|
17
|
+
* h = p\cos\varphi + z\sin\varphi - a\sqrt{1 - e^2\sin^2\varphi}
|
|
18
|
+
* $$
|
|
19
|
+
*
|
|
20
|
+
* Where:
|
|
21
|
+
* - $ p = \sqrt{x^2 + y^2} $ is the distance from the rotation axis (m)
|
|
22
|
+
* - $ a $ is the equatorial radius, $ b = a\sqrt{1 - e^2} $ the polar radius (m)
|
|
23
|
+
* - $ e^2 $ is the first eccentricity squared, $ e'^2 = e^2 / (1 - e^2) $ the second
|
|
24
|
+
*
|
|
25
|
+
* **Units**
|
|
26
|
+
* - Inputs: `x`, `y`, `z` and `a` in **m**, `eSquared` dimensionless.
|
|
27
|
+
* - Output: `phi` and `lambda` in **radians**, `h` in **m**.
|
|
28
|
+
*
|
|
29
|
+
* ::: info Notes
|
|
30
|
+
*
|
|
31
|
+
* - Starting from $ \tan\beta = a z / (b p) $, two iterations reach sub-millimetre accuracy for points near Earth's surface; the loop runs until $ \beta $ stops changing, to at most 10 iterations.
|
|
32
|
+
* - The height formula is stable everywhere, the poles included. On the rotation axis, `phi` is ±π/2 and `lambda` is 0.
|
|
33
|
+
* - For a point on the surface, `phi` equals {@link planetographicLatitudeOblate}; this one also handles points above and below it.
|
|
34
|
+
* - {@link geodeticToBodyFixed} goes the other way.
|
|
35
|
+
*
|
|
36
|
+
* :::
|
|
37
|
+
*
|
|
38
|
+
* ::: practice Apollo 11, in Earth orbit
|
|
39
|
+
*
|
|
40
|
+
* **32.672° N, 191.1 km up**
|
|
41
|
+
*
|
|
42
|
+
* _At orbit insertion: 6 563.0 km from Earth's centre, at 32.502° N geocentric_
|
|
43
|
+
*
|
|
44
|
+
* Seen from Earth's centre, the insertion point was at 32.502°, the latitude that fixes the orbit's inclination. On a map it was 0.170° further north, the latitude the flight evaluation report gives.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* const lat = toRad(32.502);
|
|
48
|
+
* const r = 6_563_041;
|
|
49
|
+
* bodyFixedToGeodetic(r * Math.cos(lat), 0, r * Math.sin(lat), 6_378_137, 0.00669437999014);
|
|
50
|
+
* // phi ≈ 32.672°, h ≈ 191.1 km
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* :::
|
|
54
|
+
*
|
|
55
|
+
* @param x - Body-fixed $ x $ in **m** (finite), through the prime meridian.
|
|
56
|
+
* @param y - Body-fixed $ y $ in **m** (finite), through 90° east.
|
|
57
|
+
* @param z - Body-fixed $ z $ in **m** (finite), along the rotation axis.
|
|
58
|
+
* @param a - Equatorial radius $ a $ in **m** (finite, > 0).
|
|
59
|
+
* @param eSquared - First eccentricity squared $ e^2 $ (finite, in [0, 1)).
|
|
60
|
+
* @returns The geodetic latitude, longitude and height.
|
|
61
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
62
|
+
* @throws {RangeError} If `a <= 0`, `eSquared` is outside [0, 1), or the point is at the centre.
|
|
63
|
+
* @group Cartography
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* // 1 km above the North Pole on WGS84
|
|
68
|
+
* const { phi, h } = bodyFixedToGeodetic(0, 0, 6_357_752.314, 6_378_137, 0.00669437999014);
|
|
69
|
+
* // phi = π/2, h ≈ 1 000 m
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @see {@link geodeticToBodyFixed}
|
|
73
|
+
* @see {@link planetographicLatitudeOblate}
|
|
74
|
+
* @see https://en.wikipedia.org/wiki/Geographic_coordinate_conversion Geographic coordinate conversion
|
|
75
|
+
*/
|
|
76
|
+
export declare const bodyFixedToGeodetic: (x: number, y: number, z: number, a: number, eSquared: number) => GeodeticCoordinatesInterface;
|
|
77
|
+
//# sourceMappingURL=body-fixed-to-geodetic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body-fixed-to-geodetic.d.ts","sourceRoot":"","sources":["../../../src/categories/cartography/body-fixed-to-geodetic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAE7B,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,GAAG,MAAM,EACT,GAAG,MAAM,EACT,GAAG,MAAM,EACT,GAAG,MAAM,EACT,UAAU,MAAM,KACf,4BAiDF,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a **body-fixed Cartesian** position (ECEF for Earth) to **geodetic coordinates**: latitude, longitude and height.
|
|
3
|
+
*
|
|
4
|
+
* There's no closed form for the latitude. This uses Bowring's iteration on the parametric latitude $ \beta $:
|
|
5
|
+
*
|
|
6
|
+
* $$
|
|
7
|
+
* \tan\varphi = \frac{z + e'^2 b \sin^3\beta}{p - e^2 a \cos^3\beta},
|
|
8
|
+
* \qquad
|
|
9
|
+
* \tan\beta = \frac{b}{a}\tan\varphi
|
|
10
|
+
* $$
|
|
11
|
+
*
|
|
12
|
+
* and then
|
|
13
|
+
*
|
|
14
|
+
* $$
|
|
15
|
+
* \lambda = \operatorname{atan2}(y, x), \qquad
|
|
16
|
+
* h = p\cos\varphi + z\sin\varphi - a\sqrt{1 - e^2\sin^2\varphi}
|
|
17
|
+
* $$
|
|
18
|
+
*
|
|
19
|
+
* Where:
|
|
20
|
+
* - $ p = \sqrt{x^2 + y^2} $ is the distance from the rotation axis (m)
|
|
21
|
+
* - $ a $ is the equatorial radius, $ b = a\sqrt{1 - e^2} $ the polar radius (m)
|
|
22
|
+
* - $ e^2 $ is the first eccentricity squared, $ e'^2 = e^2 / (1 - e^2) $ the second
|
|
23
|
+
*
|
|
24
|
+
* **Units**
|
|
25
|
+
* - Inputs: `x`, `y`, `z` and `a` in **m**, `eSquared` dimensionless.
|
|
26
|
+
* - Output: `phi` and `lambda` in **radians**, `h` in **m**.
|
|
27
|
+
*
|
|
28
|
+
* ::: info Notes
|
|
29
|
+
*
|
|
30
|
+
* - Starting from $ \tan\beta = a z / (b p) $, two iterations reach sub-millimetre accuracy for points near Earth's surface; the loop runs until $ \beta $ stops changing, to at most 10 iterations.
|
|
31
|
+
* - The height formula is stable everywhere, the poles included. On the rotation axis, `phi` is ±π/2 and `lambda` is 0.
|
|
32
|
+
* - For a point on the surface, `phi` equals {@link planetographicLatitudeOblate}; this one also handles points above and below it.
|
|
33
|
+
* - {@link geodeticToBodyFixed} goes the other way.
|
|
34
|
+
*
|
|
35
|
+
* :::
|
|
36
|
+
*
|
|
37
|
+
* ::: practice Apollo 11, in Earth orbit
|
|
38
|
+
*
|
|
39
|
+
* **32.672° N, 191.1 km up**
|
|
40
|
+
*
|
|
41
|
+
* _At orbit insertion: 6 563.0 km from Earth's centre, at 32.502° N geocentric_
|
|
42
|
+
*
|
|
43
|
+
* Seen from Earth's centre, the insertion point was at 32.502°, the latitude that fixes the orbit's inclination. On a map it was 0.170° further north, the latitude the flight evaluation report gives.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const lat = toRad(32.502);
|
|
47
|
+
* const r = 6_563_041;
|
|
48
|
+
* bodyFixedToGeodetic(r * Math.cos(lat), 0, r * Math.sin(lat), 6_378_137, 0.00669437999014);
|
|
49
|
+
* // phi ≈ 32.672°, h ≈ 191.1 km
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* :::
|
|
53
|
+
*
|
|
54
|
+
* @param x - Body-fixed $ x $ in **m** (finite), through the prime meridian.
|
|
55
|
+
* @param y - Body-fixed $ y $ in **m** (finite), through 90° east.
|
|
56
|
+
* @param z - Body-fixed $ z $ in **m** (finite), along the rotation axis.
|
|
57
|
+
* @param a - Equatorial radius $ a $ in **m** (finite, > 0).
|
|
58
|
+
* @param eSquared - First eccentricity squared $ e^2 $ (finite, in [0, 1)).
|
|
59
|
+
* @returns The geodetic latitude, longitude and height.
|
|
60
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
61
|
+
* @throws {RangeError} If `a <= 0`, `eSquared` is outside [0, 1), or the point is at the centre.
|
|
62
|
+
* @group Cartography
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* // 1 km above the North Pole on WGS84
|
|
67
|
+
* const { phi, h } = bodyFixedToGeodetic(0, 0, 6_357_752.314, 6_378_137, 0.00669437999014);
|
|
68
|
+
* // phi = π/2, h ≈ 1 000 m
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @see {@link geodeticToBodyFixed}
|
|
72
|
+
* @see {@link planetographicLatitudeOblate}
|
|
73
|
+
* @see https://en.wikipedia.org/wiki/Geographic_coordinate_conversion Geographic coordinate conversion
|
|
74
|
+
*/
|
|
75
|
+
export const bodyFixedToGeodetic = (x, y, z, a, eSquared) => {
|
|
76
|
+
for (const [name, v] of [
|
|
77
|
+
['x', x],
|
|
78
|
+
['y', y],
|
|
79
|
+
['z', z],
|
|
80
|
+
['a', a],
|
|
81
|
+
['eSquared', eSquared]
|
|
82
|
+
]) {
|
|
83
|
+
if (!Number.isFinite(v))
|
|
84
|
+
throw new TypeError(`${name} must be a finite number. Received: ${v}`);
|
|
85
|
+
}
|
|
86
|
+
if (a <= 0)
|
|
87
|
+
throw new RangeError(`a must be > 0. Received: ${a}`);
|
|
88
|
+
if (eSquared < 0 || eSquared >= 1)
|
|
89
|
+
throw new RangeError(`eSquared must be in [0, 1). Received: ${eSquared}`);
|
|
90
|
+
const p = Math.hypot(x, y);
|
|
91
|
+
if (p === 0 && z === 0)
|
|
92
|
+
throw new RangeError('The point must not be at the centre of the body.');
|
|
93
|
+
const lambda = (p === 0 ? 0 : Math.atan2(y, x));
|
|
94
|
+
const b = a * Math.sqrt(1 - eSquared);
|
|
95
|
+
const ePrimeSquared = eSquared / (1 - eSquared);
|
|
96
|
+
let beta = Math.atan2(a * z, b * p);
|
|
97
|
+
let phi = 0;
|
|
98
|
+
for (let k = 0; k < 10; k++) {
|
|
99
|
+
phi = Math.atan2(z + ePrimeSquared * b * Math.sin(beta) ** 3, p - eSquared * a * Math.cos(beta) ** 3);
|
|
100
|
+
const next = Math.atan2(b * Math.sin(phi), a * Math.cos(phi));
|
|
101
|
+
if (Math.abs(next - beta) < 1e-15)
|
|
102
|
+
break;
|
|
103
|
+
beta = next;
|
|
104
|
+
}
|
|
105
|
+
const sinPhi = Math.sin(phi);
|
|
106
|
+
const h = p * Math.cos(phi) +
|
|
107
|
+
z * sinPhi -
|
|
108
|
+
a * Math.sqrt(1 - eSquared * sinPhi * sinPhi);
|
|
109
|
+
return { phi: phi, lambda, h };
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=body-fixed-to-geodetic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body-fixed-to-geodetic.js","sourceRoot":"","sources":["../../../src/categories/cartography/body-fixed-to-geodetic.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,CAAS,EACT,CAAS,EACT,CAAS,EACT,CAAS,EACT,QAAgB,EACc,EAAE;IAChC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;QACtB,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,UAAU,EAAE,QAAQ,CAAC;KACd,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACrB,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,uCAAuC,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAC;IAElE,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;IAE5E,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,kDAAkD,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAY,CAAC;IAC3D,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,QAAQ,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IAEhD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,GAAG,GAAG,IAAI,CAAC,KAAK,CACd,CAAC,GAAG,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAC3C,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CACvC,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAE9D,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,KAAK;YAAE,MAAM;QAEzC,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,CAAC,GACL,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACjB,CAAC,GAAG,MAAM;QACV,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,EAAE,GAAc,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AAC5C,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Radians, Vector3DTupleType } from '@interstellar-tools/types';
|
|
2
|
+
/**
|
|
3
|
+
* Convert **geodetic coordinates** (latitude, longitude, height) to a **body-fixed Cartesian** position, ECEF for Earth.
|
|
4
|
+
*
|
|
5
|
+
* $$
|
|
6
|
+
* \begin{aligned}
|
|
7
|
+
* x &= (N + h)\cos\varphi\cos\lambda \\
|
|
8
|
+
* y &= (N + h)\cos\varphi\sin\lambda \\
|
|
9
|
+
* z &= \big(N(1 - e^2) + h\big)\sin\varphi
|
|
10
|
+
* \end{aligned}
|
|
11
|
+
* \qquad
|
|
12
|
+
* N = \frac{a}{\sqrt{1 - e^2\sin^2\varphi}}
|
|
13
|
+
* $$
|
|
14
|
+
*
|
|
15
|
+
* Where:
|
|
16
|
+
* - $ \varphi $ is the geodetic latitude and $ \lambda $ the longitude (rad)
|
|
17
|
+
* - $ h $ is the height above the ellipsoid, along its normal (m)
|
|
18
|
+
* - $ a $ is the equatorial radius (m) and $ e^2 $ the first eccentricity squared
|
|
19
|
+
* - $ N $ is the prime vertical radius of curvature (m)
|
|
20
|
+
*
|
|
21
|
+
* **Units**
|
|
22
|
+
* - Inputs: `phi` and `lambda` in **radians**, `h` and `a` in **m**, `eSquared` dimensionless.
|
|
23
|
+
* - Output: `[x, y, z]` in **m**, with $ z $ along the rotation axis and $ x $ through the prime meridian.
|
|
24
|
+
*
|
|
25
|
+
* ::: info Notes
|
|
26
|
+
*
|
|
27
|
+
* - Geodetic latitude is the angle of the ellipsoid's normal, the latitude on maps. The geocentric latitude, the angle seen from the centre, is `atan2(z, hypot(x, y))` of the result, and is smaller everywhere but the equator and the poles.
|
|
28
|
+
* - WGS84: $ a = 6\,378\,137 $ m, $ e^2 = 0.00669437999014 $. Get $ e^2 $ from the radii with {@link eccentricitySquaredOblateSpheroid}.
|
|
29
|
+
* - {@link bodyFixedToGeodetic} goes the other way.
|
|
30
|
+
*
|
|
31
|
+
* :::
|
|
32
|
+
*
|
|
33
|
+
* ::: practice Apollo 11, on Pad 39A
|
|
34
|
+
*
|
|
35
|
+
* **6 373.3 km**
|
|
36
|
+
*
|
|
37
|
+
* _From Earth's centre, at 28.608° N geodetic, 80.604° W on the WGS84 ellipsoid_
|
|
38
|
+
*
|
|
39
|
+
* The geocentric latitude is 28.447°, 0.161° less than on the map. That's the latitude the launch-site formulas such as `surfaceRotationSpeed` need.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const [x, y, z] = geodeticToBodyFixed(toRad(28.608422), toRad(-80.604133), 0, 6_378_137, 0.00669437999014);
|
|
43
|
+
* Math.hypot(x, y, z); // ≈ 6 373 266 m
|
|
44
|
+
* toDeg(Math.atan2(z, Math.hypot(x, y))); // ≈ 28.447°
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* :::
|
|
48
|
+
*
|
|
49
|
+
* @param phi - Geodetic latitude $ \varphi $ in **radians** (finite, in [-π/2, π/2]).
|
|
50
|
+
* @param lambda - Longitude $ \lambda $ in **radians**, east positive (finite).
|
|
51
|
+
* @param h - Height $ h $ above the ellipsoid in **m** (finite; negative below it).
|
|
52
|
+
* @param a - Equatorial radius $ a $ in **m** (finite, > 0).
|
|
53
|
+
* @param eSquared - First eccentricity squared $ e^2 $ (finite, in [0, 1)).
|
|
54
|
+
* @returns Body-fixed position `[x, y, z]` in **m**.
|
|
55
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
56
|
+
* @throws {RangeError} If `phi` is outside [-π/2, π/2], `a <= 0`, or `eSquared` is outside [0, 1).
|
|
57
|
+
* @group Cartography
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import type { Radians } from '@interstellar-tools/types';
|
|
62
|
+
*
|
|
63
|
+
* // On the equator at the prime meridian, 100 m up
|
|
64
|
+
* geodeticToBodyFixed(0 as Radians, 0 as Radians, 100, 6_378_137, 0.00669437999014);
|
|
65
|
+
* // [6 378 237, 0, 0]
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @see {@link bodyFixedToGeodetic}
|
|
69
|
+
* @see {@link eccentricitySquaredOblateSpheroid}
|
|
70
|
+
* @see https://en.wikipedia.org/wiki/Geographic_coordinate_conversion Geographic coordinate conversion
|
|
71
|
+
*/
|
|
72
|
+
export declare const geodeticToBodyFixed: (phi: Radians, lambda: Radians, h: number, a: number, eSquared: number) => Vector3DTupleType;
|
|
73
|
+
//# sourceMappingURL=geodetic-to-body-fixed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geodetic-to-body-fixed.d.ts","sourceRoot":"","sources":["../../../src/categories/cartography/geodetic-to-body-fixed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,KAAK,OAAO,EACZ,QAAQ,OAAO,EACf,GAAG,MAAM,EACT,GAAG,MAAM,EACT,UAAU,MAAM,KACf,iBA6BF,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert **geodetic coordinates** (latitude, longitude, height) to a **body-fixed Cartesian** position, ECEF for Earth.
|
|
3
|
+
*
|
|
4
|
+
* $$
|
|
5
|
+
* \begin{aligned}
|
|
6
|
+
* x &= (N + h)\cos\varphi\cos\lambda \\
|
|
7
|
+
* y &= (N + h)\cos\varphi\sin\lambda \\
|
|
8
|
+
* z &= \big(N(1 - e^2) + h\big)\sin\varphi
|
|
9
|
+
* \end{aligned}
|
|
10
|
+
* \qquad
|
|
11
|
+
* N = \frac{a}{\sqrt{1 - e^2\sin^2\varphi}}
|
|
12
|
+
* $$
|
|
13
|
+
*
|
|
14
|
+
* Where:
|
|
15
|
+
* - $ \varphi $ is the geodetic latitude and $ \lambda $ the longitude (rad)
|
|
16
|
+
* - $ h $ is the height above the ellipsoid, along its normal (m)
|
|
17
|
+
* - $ a $ is the equatorial radius (m) and $ e^2 $ the first eccentricity squared
|
|
18
|
+
* - $ N $ is the prime vertical radius of curvature (m)
|
|
19
|
+
*
|
|
20
|
+
* **Units**
|
|
21
|
+
* - Inputs: `phi` and `lambda` in **radians**, `h` and `a` in **m**, `eSquared` dimensionless.
|
|
22
|
+
* - Output: `[x, y, z]` in **m**, with $ z $ along the rotation axis and $ x $ through the prime meridian.
|
|
23
|
+
*
|
|
24
|
+
* ::: info Notes
|
|
25
|
+
*
|
|
26
|
+
* - Geodetic latitude is the angle of the ellipsoid's normal, the latitude on maps. The geocentric latitude, the angle seen from the centre, is `atan2(z, hypot(x, y))` of the result, and is smaller everywhere but the equator and the poles.
|
|
27
|
+
* - WGS84: $ a = 6\,378\,137 $ m, $ e^2 = 0.00669437999014 $. Get $ e^2 $ from the radii with {@link eccentricitySquaredOblateSpheroid}.
|
|
28
|
+
* - {@link bodyFixedToGeodetic} goes the other way.
|
|
29
|
+
*
|
|
30
|
+
* :::
|
|
31
|
+
*
|
|
32
|
+
* ::: practice Apollo 11, on Pad 39A
|
|
33
|
+
*
|
|
34
|
+
* **6 373.3 km**
|
|
35
|
+
*
|
|
36
|
+
* _From Earth's centre, at 28.608° N geodetic, 80.604° W on the WGS84 ellipsoid_
|
|
37
|
+
*
|
|
38
|
+
* The geocentric latitude is 28.447°, 0.161° less than on the map. That's the latitude the launch-site formulas such as `surfaceRotationSpeed` need.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* const [x, y, z] = geodeticToBodyFixed(toRad(28.608422), toRad(-80.604133), 0, 6_378_137, 0.00669437999014);
|
|
42
|
+
* Math.hypot(x, y, z); // ≈ 6 373 266 m
|
|
43
|
+
* toDeg(Math.atan2(z, Math.hypot(x, y))); // ≈ 28.447°
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* :::
|
|
47
|
+
*
|
|
48
|
+
* @param phi - Geodetic latitude $ \varphi $ in **radians** (finite, in [-π/2, π/2]).
|
|
49
|
+
* @param lambda - Longitude $ \lambda $ in **radians**, east positive (finite).
|
|
50
|
+
* @param h - Height $ h $ above the ellipsoid in **m** (finite; negative below it).
|
|
51
|
+
* @param a - Equatorial radius $ a $ in **m** (finite, > 0).
|
|
52
|
+
* @param eSquared - First eccentricity squared $ e^2 $ (finite, in [0, 1)).
|
|
53
|
+
* @returns Body-fixed position `[x, y, z]` in **m**.
|
|
54
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
55
|
+
* @throws {RangeError} If `phi` is outside [-π/2, π/2], `a <= 0`, or `eSquared` is outside [0, 1).
|
|
56
|
+
* @group Cartography
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* import type { Radians } from '@interstellar-tools/types';
|
|
61
|
+
*
|
|
62
|
+
* // On the equator at the prime meridian, 100 m up
|
|
63
|
+
* geodeticToBodyFixed(0 as Radians, 0 as Radians, 100, 6_378_137, 0.00669437999014);
|
|
64
|
+
* // [6 378 237, 0, 0]
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @see {@link bodyFixedToGeodetic}
|
|
68
|
+
* @see {@link eccentricitySquaredOblateSpheroid}
|
|
69
|
+
* @see https://en.wikipedia.org/wiki/Geographic_coordinate_conversion Geographic coordinate conversion
|
|
70
|
+
*/
|
|
71
|
+
export const geodeticToBodyFixed = (phi, lambda, h, a, eSquared) => {
|
|
72
|
+
for (const [name, x] of [
|
|
73
|
+
['phi', phi],
|
|
74
|
+
['lambda', lambda],
|
|
75
|
+
['h', h],
|
|
76
|
+
['a', a],
|
|
77
|
+
['eSquared', eSquared]
|
|
78
|
+
]) {
|
|
79
|
+
if (!Number.isFinite(x))
|
|
80
|
+
throw new TypeError(`${name} must be a finite number. Received: ${x}`);
|
|
81
|
+
}
|
|
82
|
+
if (Math.abs(phi) > Math.PI / 2)
|
|
83
|
+
throw new RangeError(`phi must be in [-π/2, π/2]. Received: ${phi}`);
|
|
84
|
+
if (a <= 0)
|
|
85
|
+
throw new RangeError(`a must be > 0. Received: ${a}`);
|
|
86
|
+
if (eSquared < 0 || eSquared >= 1)
|
|
87
|
+
throw new RangeError(`eSquared must be in [0, 1). Received: ${eSquared}`);
|
|
88
|
+
const sinPhi = Math.sin(phi);
|
|
89
|
+
const cosPhi = Math.cos(phi);
|
|
90
|
+
const N = a / Math.sqrt(1 - eSquared * sinPhi * sinPhi);
|
|
91
|
+
return [
|
|
92
|
+
(N + h) * cosPhi * Math.cos(lambda),
|
|
93
|
+
(N + h) * cosPhi * Math.sin(lambda),
|
|
94
|
+
(N * (1 - eSquared) + h) * sinPhi
|
|
95
|
+
];
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=geodetic-to-body-fixed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geodetic-to-body-fixed.js","sourceRoot":"","sources":["../../../src/categories/cartography/geodetic-to-body-fixed.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,GAAY,EACZ,MAAe,EACf,CAAS,EACT,CAAS,EACT,QAAgB,EACG,EAAE;IACrB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;QACtB,CAAC,KAAK,EAAE,GAAG,CAAC;QACZ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAClB,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,UAAU,EAAE,QAAQ,CAAC;KACd,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACrB,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,uCAAuC,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;QAC7B,MAAM,IAAI,UAAU,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;IAEvE,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAC;IAElE,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC;IAExD,OAAO;QACL,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QACnC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QACnC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;KAClC,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the **ballistic coefficient** of an entry vehicle: how much mass it has per unit of drag.
|
|
3
|
+
*
|
|
4
|
+
* $$
|
|
5
|
+
* \beta = \frac{m}{C_D A}
|
|
6
|
+
* $$
|
|
7
|
+
*
|
|
8
|
+
* Where:
|
|
9
|
+
* - $ m $ is the vehicle's mass (kg)
|
|
10
|
+
* - $ C_D $ is its drag coefficient (dimensionless)
|
|
11
|
+
* - $ A $ is its reference area, usually the frontal area (m²)
|
|
12
|
+
*
|
|
13
|
+
* **Units**
|
|
14
|
+
* - Inputs: `m` in **kg**, `Cd` dimensionless, `A` in **m²**.
|
|
15
|
+
* - Output: $ \beta $ in **kg/m²**.
|
|
16
|
+
*
|
|
17
|
+
* ::: info Notes
|
|
18
|
+
*
|
|
19
|
+
* - A low $ \beta $ slows down high in the thin upper atmosphere; a high $ \beta $ plunges deeper before it slows.
|
|
20
|
+
* - The drag deceleration is $ a = \rho V^2 / (2\beta) $.
|
|
21
|
+
* - Some texts define it the other way up, as $ C_D A / m $. This library uses $ m / (C_D A) $ throughout.
|
|
22
|
+
*
|
|
23
|
+
* :::
|
|
24
|
+
*
|
|
25
|
+
* @param m - Mass $ m $ in **kg** (finite, > 0).
|
|
26
|
+
* @param Cd - Drag coefficient $ C_D $ (finite, > 0).
|
|
27
|
+
* @param A - Reference area $ A $ in **m²** (finite, > 0).
|
|
28
|
+
* @returns Ballistic coefficient $ \beta $ in **kg/m²**.
|
|
29
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
30
|
+
* @throws {RangeError} If any input is `<= 0`.
|
|
31
|
+
* @group Entry
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // A 5000 kg capsule, 3.9 m across, with Cd = 1.3
|
|
36
|
+
* const beta = ballisticCoefficient(5000, 1.3, Math.PI * 1.95 ** 2);
|
|
37
|
+
* // beta ≈ 322 kg/m²
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link ballisticEntrySpeed}
|
|
41
|
+
* @see https://en.wikipedia.org/wiki/Ballistic_coefficient Ballistic coefficient
|
|
42
|
+
*/
|
|
43
|
+
export declare const ballisticCoefficient: (m: number, Cd: number, A: number) => number;
|
|
44
|
+
//# sourceMappingURL=ballistic-coefficient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ballistic-coefficient.d.ts","sourceRoot":"","sources":["../../../src/categories/entry/ballistic-coefficient.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,oBAAoB,GAC/B,GAAG,MAAM,EACT,IAAI,MAAM,EACV,GAAG,MAAM,KACR,MAWF,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { assertFinite, assertPositive } from './validate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compute the **ballistic coefficient** of an entry vehicle: how much mass it has per unit of drag.
|
|
4
|
+
*
|
|
5
|
+
* $$
|
|
6
|
+
* \beta = \frac{m}{C_D A}
|
|
7
|
+
* $$
|
|
8
|
+
*
|
|
9
|
+
* Where:
|
|
10
|
+
* - $ m $ is the vehicle's mass (kg)
|
|
11
|
+
* - $ C_D $ is its drag coefficient (dimensionless)
|
|
12
|
+
* - $ A $ is its reference area, usually the frontal area (m²)
|
|
13
|
+
*
|
|
14
|
+
* **Units**
|
|
15
|
+
* - Inputs: `m` in **kg**, `Cd` dimensionless, `A` in **m²**.
|
|
16
|
+
* - Output: $ \beta $ in **kg/m²**.
|
|
17
|
+
*
|
|
18
|
+
* ::: info Notes
|
|
19
|
+
*
|
|
20
|
+
* - A low $ \beta $ slows down high in the thin upper atmosphere; a high $ \beta $ plunges deeper before it slows.
|
|
21
|
+
* - The drag deceleration is $ a = \rho V^2 / (2\beta) $.
|
|
22
|
+
* - Some texts define it the other way up, as $ C_D A / m $. This library uses $ m / (C_D A) $ throughout.
|
|
23
|
+
*
|
|
24
|
+
* :::
|
|
25
|
+
*
|
|
26
|
+
* @param m - Mass $ m $ in **kg** (finite, > 0).
|
|
27
|
+
* @param Cd - Drag coefficient $ C_D $ (finite, > 0).
|
|
28
|
+
* @param A - Reference area $ A $ in **m²** (finite, > 0).
|
|
29
|
+
* @returns Ballistic coefficient $ \beta $ in **kg/m²**.
|
|
30
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
31
|
+
* @throws {RangeError} If any input is `<= 0`.
|
|
32
|
+
* @group Entry
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // A 5000 kg capsule, 3.9 m across, with Cd = 1.3
|
|
37
|
+
* const beta = ballisticCoefficient(5000, 1.3, Math.PI * 1.95 ** 2);
|
|
38
|
+
* // beta ≈ 322 kg/m²
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @see {@link ballisticEntrySpeed}
|
|
42
|
+
* @see https://en.wikipedia.org/wiki/Ballistic_coefficient Ballistic coefficient
|
|
43
|
+
*/
|
|
44
|
+
export const ballisticCoefficient = (m, Cd, A) => {
|
|
45
|
+
const inputs = [
|
|
46
|
+
['m', m],
|
|
47
|
+
['Cd', Cd],
|
|
48
|
+
['A', A]
|
|
49
|
+
];
|
|
50
|
+
assertFinite(inputs);
|
|
51
|
+
assertPositive(inputs);
|
|
52
|
+
return m / (Cd * A);
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=ballistic-coefficient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ballistic-coefficient.js","sourceRoot":"","sources":["../../../src/categories/entry/ballistic-coefficient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,CAAS,EACT,EAAU,EACV,CAAS,EACD,EAAE;IACV,MAAM,MAAM,GAAG;QACb,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,IAAI,EAAE,EAAE,CAAC;QACV,CAAC,GAAG,EAAE,CAAC,CAAC;KACA,CAAC;IAEX,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the **speed of a ballistic entry** at an altitude, with the Allen–Eggers solution.
|
|
3
|
+
*
|
|
4
|
+
* $$
|
|
5
|
+
* V(h) = V_E \exp\left(-\frac{\rho_0 H}{2\beta\sin\lvert\gamma\rvert}\, e^{-h/H}\right)
|
|
6
|
+
* $$
|
|
7
|
+
*
|
|
8
|
+
* Where:
|
|
9
|
+
* - $ V_E $ is the speed at entry (m/s)
|
|
10
|
+
* - $ \gamma $ is the flight-path angle, constant along the straight path (rad)
|
|
11
|
+
* - $ \beta $ is the ballistic coefficient (kg/m²)
|
|
12
|
+
* - $ \rho_0 $ and $ H $ describe an exponential atmosphere, $ \rho = \rho_0 e^{-h/H} $
|
|
13
|
+
*
|
|
14
|
+
* **Units**
|
|
15
|
+
* - Inputs: `h` and `H` in **m**, `VE` in **m/s**, `gamma` in **radians**, `beta` in **kg/m²**, `rho0` in **kg/m³**.
|
|
16
|
+
* - Output: $ V $ in **m/s**.
|
|
17
|
+
*
|
|
18
|
+
* ::: info Notes
|
|
19
|
+
*
|
|
20
|
+
* - Assumes drag dominates: no lift, no gravity, and a straight path at a constant angle. That holds well for steep, fast entries of non-lifting bodies.
|
|
21
|
+
* - The deceleration at any altitude is $ \rho V^2 / (2\beta) $; its peak is {@link ballisticPeakDeceleration}, at {@link ballisticPeakDecelerationAltitude}.
|
|
22
|
+
* - `gamma` can be given as negative (descending, the usual convention) or positive: only its size is used.
|
|
23
|
+
* - Earth's lower atmosphere is roughly $ \rho_0 = 1.225 $ kg/m³ with $ H \approx 7.2 $ km. A single exponential is a rough fit; see the density models in [#226](https://github.com/phun-ky/interstellar-tools/issues/226).
|
|
24
|
+
*
|
|
25
|
+
* :::
|
|
26
|
+
*
|
|
27
|
+
* @param h - Altitude $ h $ in **m** (finite).
|
|
28
|
+
* @param VE - Entry speed $ V_E $ in **m/s** (finite, > 0).
|
|
29
|
+
* @param gamma - Flight-path angle $ \gamma $ in **radians** (finite, non-zero, within [-π/2, π/2]).
|
|
30
|
+
* @param beta - Ballistic coefficient $ \beta $ in **kg/m²** (finite, > 0).
|
|
31
|
+
* @param rho0 - Reference density $ \rho_0 $ in **kg/m³** (finite, > 0).
|
|
32
|
+
* @param H - Scale height $ H $ in **m** (finite, > 0).
|
|
33
|
+
* @returns Speed $ V $ in **m/s**.
|
|
34
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
35
|
+
* @throws {RangeError} If `VE`, `beta`, `rho0` or `H` is `<= 0`, or `gamma` is zero or past vertical.
|
|
36
|
+
* @group Entry
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import type { Radians } from '@interstellar-tools/types';
|
|
41
|
+
*
|
|
42
|
+
* // A 322 kg/m² capsule entering at 11 km/s, 6.5° below horizontal
|
|
43
|
+
* const v = ballisticEntrySpeed(40_000, 11_000, (-6.5 * Math.PI / 180) as Radians, 322, 1.225, 7200);
|
|
44
|
+
* // v ≈ 6.9 km/s at 40 km
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link ballisticCoefficient}
|
|
48
|
+
* @see {@link ballisticPeakDeceleration}
|
|
49
|
+
* @see https://en.wikipedia.org/wiki/Atmospheric_entry Atmospheric entry
|
|
50
|
+
*/
|
|
51
|
+
export declare const ballisticEntrySpeed: (h: number, VE: number, gamma: number, beta: number, rho0: number, H: number) => number;
|
|
52
|
+
//# sourceMappingURL=ballistic-entry-speed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ballistic-entry-speed.d.ts","sourceRoot":"","sources":["../../../src/categories/entry/ballistic-entry-speed.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,eAAO,MAAM,mBAAmB,GAC9B,GAAG,MAAM,EACT,IAAI,MAAM,EACV,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,GAAG,MAAM,KACR,MAoBF,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { assertFinite, assertFlightPathAngle, assertPositive } from './validate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compute the **speed of a ballistic entry** at an altitude, with the Allen–Eggers solution.
|
|
4
|
+
*
|
|
5
|
+
* $$
|
|
6
|
+
* V(h) = V_E \exp\left(-\frac{\rho_0 H}{2\beta\sin\lvert\gamma\rvert}\, e^{-h/H}\right)
|
|
7
|
+
* $$
|
|
8
|
+
*
|
|
9
|
+
* Where:
|
|
10
|
+
* - $ V_E $ is the speed at entry (m/s)
|
|
11
|
+
* - $ \gamma $ is the flight-path angle, constant along the straight path (rad)
|
|
12
|
+
* - $ \beta $ is the ballistic coefficient (kg/m²)
|
|
13
|
+
* - $ \rho_0 $ and $ H $ describe an exponential atmosphere, $ \rho = \rho_0 e^{-h/H} $
|
|
14
|
+
*
|
|
15
|
+
* **Units**
|
|
16
|
+
* - Inputs: `h` and `H` in **m**, `VE` in **m/s**, `gamma` in **radians**, `beta` in **kg/m²**, `rho0` in **kg/m³**.
|
|
17
|
+
* - Output: $ V $ in **m/s**.
|
|
18
|
+
*
|
|
19
|
+
* ::: info Notes
|
|
20
|
+
*
|
|
21
|
+
* - Assumes drag dominates: no lift, no gravity, and a straight path at a constant angle. That holds well for steep, fast entries of non-lifting bodies.
|
|
22
|
+
* - The deceleration at any altitude is $ \rho V^2 / (2\beta) $; its peak is {@link ballisticPeakDeceleration}, at {@link ballisticPeakDecelerationAltitude}.
|
|
23
|
+
* - `gamma` can be given as negative (descending, the usual convention) or positive: only its size is used.
|
|
24
|
+
* - Earth's lower atmosphere is roughly $ \rho_0 = 1.225 $ kg/m³ with $ H \approx 7.2 $ km. A single exponential is a rough fit; see the density models in [#226](https://github.com/phun-ky/interstellar-tools/issues/226).
|
|
25
|
+
*
|
|
26
|
+
* :::
|
|
27
|
+
*
|
|
28
|
+
* @param h - Altitude $ h $ in **m** (finite).
|
|
29
|
+
* @param VE - Entry speed $ V_E $ in **m/s** (finite, > 0).
|
|
30
|
+
* @param gamma - Flight-path angle $ \gamma $ in **radians** (finite, non-zero, within [-π/2, π/2]).
|
|
31
|
+
* @param beta - Ballistic coefficient $ \beta $ in **kg/m²** (finite, > 0).
|
|
32
|
+
* @param rho0 - Reference density $ \rho_0 $ in **kg/m³** (finite, > 0).
|
|
33
|
+
* @param H - Scale height $ H $ in **m** (finite, > 0).
|
|
34
|
+
* @returns Speed $ V $ in **m/s**.
|
|
35
|
+
* @throws {TypeError} If any input is not a finite number.
|
|
36
|
+
* @throws {RangeError} If `VE`, `beta`, `rho0` or `H` is `<= 0`, or `gamma` is zero or past vertical.
|
|
37
|
+
* @group Entry
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import type { Radians } from '@interstellar-tools/types';
|
|
42
|
+
*
|
|
43
|
+
* // A 322 kg/m² capsule entering at 11 km/s, 6.5° below horizontal
|
|
44
|
+
* const v = ballisticEntrySpeed(40_000, 11_000, (-6.5 * Math.PI / 180) as Radians, 322, 1.225, 7200);
|
|
45
|
+
* // v ≈ 6.9 km/s at 40 km
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @see {@link ballisticCoefficient}
|
|
49
|
+
* @see {@link ballisticPeakDeceleration}
|
|
50
|
+
* @see https://en.wikipedia.org/wiki/Atmospheric_entry Atmospheric entry
|
|
51
|
+
*/
|
|
52
|
+
export const ballisticEntrySpeed = (h, VE, gamma, beta, rho0, H) => {
|
|
53
|
+
assertFinite([
|
|
54
|
+
['h', h],
|
|
55
|
+
['VE', VE],
|
|
56
|
+
['gamma', gamma],
|
|
57
|
+
['beta', beta],
|
|
58
|
+
['rho0', rho0],
|
|
59
|
+
['H', H]
|
|
60
|
+
]);
|
|
61
|
+
assertPositive([
|
|
62
|
+
['VE', VE],
|
|
63
|
+
['beta', beta],
|
|
64
|
+
['rho0', rho0],
|
|
65
|
+
['H', H]
|
|
66
|
+
]);
|
|
67
|
+
assertFlightPathAngle(gamma);
|
|
68
|
+
const k = (rho0 * H) / (2 * beta * Math.sin(Math.abs(gamma)));
|
|
69
|
+
return VE * Math.exp(-k * Math.exp(-h / H));
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=ballistic-entry-speed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ballistic-entry-speed.js","sourceRoot":"","sources":["../../../src/categories/entry/ballistic-entry-speed.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACf,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,CAAS,EACT,EAAU,EACV,KAAa,EACb,IAAY,EACZ,IAAY,EACZ,CAAS,EACD,EAAE;IACV,YAAY,CAAC;QACX,CAAC,GAAG,EAAE,CAAC,CAAC;QACR,CAAC,IAAI,EAAE,EAAE,CAAC;QACV,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,GAAG,EAAE,CAAC,CAAC;KACT,CAAC,CAAC;IACH,cAAc,CAAC;QACb,CAAC,IAAI,EAAE,EAAE,CAAC;QACV,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,GAAG,EAAE,CAAC,CAAC;KACT,CAAC,CAAC;IACH,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAE7B,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9D,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC,CAAC"}
|