@saber-usa/node-common 1.7.7-alpha.1 → 1.7.7
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/README.md +41 -41
- package/package.json +52 -52
- package/src/FrameConverter.js +1121 -1121
- package/src/LLA.js +179 -179
- package/src/LaunchNominalClass.js +753 -753
- package/src/NodeVector3D.js +71 -71
- package/src/OrbitUtils.js +309 -309
- package/src/PropagateUtils.js +100 -100
- package/src/ShadowGEOCalculator.js +203 -203
- package/src/TimeConverter.js +309 -309
- package/src/astro.js +3301 -3301
- package/src/ballisticPropagator.js +1037 -1037
- package/src/checkNetwork.cjs +20 -20
- package/src/constants.js +37 -37
- package/src/fixDate.js +62 -62
- package/src/index.js +47 -47
- package/src/launchNominal.js +208 -208
- package/src/loggerFactory.cjs +98 -98
- package/src/s3.js +59 -59
- package/src/transform.js +35 -35
- package/src/udl.js +116 -116
- package/src/utils.js +406 -406
|
@@ -1,1037 +1,1037 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Refactored Vinti Ballistic Propagator JavaScript Implementation
|
|
3
|
-
* Uses existing node-common libraries instead of custom implementations
|
|
4
|
-
*
|
|
5
|
-
* This is a refactored version of the complete Vinti Ballistic Propagator
|
|
6
|
-
* that replaces custom implementations with existing node-common libraries.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// Import existing libraries instead of defining custom ones
|
|
10
|
-
import {MU, WGS84_EARTH_EQUATORIAL_RADIUS_KM} from "./constants.js";
|
|
11
|
-
import {NodeVector3D} from "./NodeVector3D.js";
|
|
12
|
-
|
|
13
|
-
// Earth constants using existing constants.js values
|
|
14
|
-
const EarthConstants = {
|
|
15
|
-
EquatorialRadiusKm: WGS84_EARTH_EQUATORIAL_RADIUS_KM, // 6378.137 km
|
|
16
|
-
Mu: MU, // km³/s²
|
|
17
|
-
J2: 1082.62999e-6,
|
|
18
|
-
J3: -2.53215e-6,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Position-Velocity vector pair
|
|
23
|
-
* Enhanced to work with pious-squid Vector3D
|
|
24
|
-
*/
|
|
25
|
-
class PosVelVec {
|
|
26
|
-
constructor(posOrX, velOrY, z, vx, vy, vz) {
|
|
27
|
-
if (posOrX instanceof NodeVector3D) {
|
|
28
|
-
this.position = posOrX;
|
|
29
|
-
this.velocity = velOrY;
|
|
30
|
-
} else {
|
|
31
|
-
this.position = new NodeVector3D(posOrX, velOrY, z);
|
|
32
|
-
this.velocity = new NodeVector3D(vx, vy, vz);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Get a zero vector for position and velocity
|
|
38
|
-
* @return {PosVelVec} zero vector
|
|
39
|
-
*/
|
|
40
|
-
static zero() {
|
|
41
|
-
return new PosVelVec(new NodeVector3D(0, 0, 0), new NodeVector3D(0, 0, 0));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get the position vector
|
|
46
|
-
* @return {NodeVector3D} Position vector
|
|
47
|
-
*/
|
|
48
|
-
get Position() {
|
|
49
|
-
return this.position;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get the velocity vector
|
|
54
|
-
* @return {NodeVector3D} Velocity vector
|
|
55
|
-
*/
|
|
56
|
-
get Velocity() {
|
|
57
|
-
return this.velocity;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Get the value at a specific index
|
|
62
|
-
* @param {*} index
|
|
63
|
-
* @return {number}
|
|
64
|
-
*/
|
|
65
|
-
get(index) {
|
|
66
|
-
switch (index) {
|
|
67
|
-
case 0: return this.position.x;
|
|
68
|
-
case 1: return this.position.y;
|
|
69
|
-
case 2: return this.position.z;
|
|
70
|
-
case 3: return this.velocity.x;
|
|
71
|
-
case 4: return this.velocity.y;
|
|
72
|
-
case 5: return this.velocity.z;
|
|
73
|
-
default: throw new Error(`Index ${index} out of range`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
set(index, value) {
|
|
78
|
-
switch (index) {
|
|
79
|
-
case 0: this.position.x = value; break;
|
|
80
|
-
case 1: this.position.y = value; break;
|
|
81
|
-
case 2: this.position.z = value; break;
|
|
82
|
-
case 3: this.velocity.x = value; break;
|
|
83
|
-
case 4: this.velocity.y = value; break;
|
|
84
|
-
case 5: this.velocity.z = value; break;
|
|
85
|
-
default: throw new Error(`Index ${index} out of range`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Complete Ballistic Propagator Implementation
|
|
92
|
-
* Refactored to use pious-squid Vector3D operations
|
|
93
|
-
*/
|
|
94
|
-
class BallisticPropagatorUtils {
|
|
95
|
-
/**
|
|
96
|
-
* Kepler solver - exact port from C#
|
|
97
|
-
* Now uses pious-squid Vector3D operations
|
|
98
|
-
* @param {*} planet
|
|
99
|
-
* @param {*} t0
|
|
100
|
-
* @param {*} x0
|
|
101
|
-
* @param {*} t1
|
|
102
|
-
* @return {{x1: PosVelVec, xxx: number}} Object with propagated state and auxiliary value
|
|
103
|
-
*/
|
|
104
|
-
static kepler1(planet, t0, x0, t1) {
|
|
105
|
-
const muqr = 1;
|
|
106
|
-
const tlimit = 1.0e-10;
|
|
107
|
-
const kn = 10;
|
|
108
|
-
|
|
109
|
-
const rex = planet[0];
|
|
110
|
-
const gmx = planet[1];
|
|
111
|
-
|
|
112
|
-
let dt = t1 - t0;
|
|
113
|
-
let x1 = PosVelVec.zero();
|
|
114
|
-
let xxx = 0;
|
|
115
|
-
|
|
116
|
-
if (Math.abs(dt) < tlimit) {
|
|
117
|
-
for (let i = 0; i < 6; i++) {
|
|
118
|
-
x1.set(i, x0.get(i));
|
|
119
|
-
}
|
|
120
|
-
return {x1, xxx: 0};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Change from SI units to astronomical units
|
|
124
|
-
const timeFactor = Math.sqrt(rex * rex * rex / gmx);
|
|
125
|
-
const vex = rex / timeFactor;
|
|
126
|
-
dt /= timeFactor;
|
|
127
|
-
|
|
128
|
-
// Use pious-squid Vector3D scale method instead of custom scaleBy
|
|
129
|
-
const r0 = x0.Position.scale(1 / rex);
|
|
130
|
-
const v0 = x0.Velocity.scale(1 / vex);
|
|
131
|
-
|
|
132
|
-
const r0Mag = r0.magnitude();
|
|
133
|
-
const v0Mag = v0.magnitude();
|
|
134
|
-
|
|
135
|
-
const d0 = r0.dot(v0);
|
|
136
|
-
const sigma0 = d0 / muqr;
|
|
137
|
-
const alp0 = 2.0 / r0Mag - v0Mag * v0Mag;
|
|
138
|
-
|
|
139
|
-
// Initial guess
|
|
140
|
-
let x = alp0 * dt;
|
|
141
|
-
if (alp0 <= 0) x = 0.5 * dt / r0Mag;
|
|
142
|
-
|
|
143
|
-
let dfx = 0;
|
|
144
|
-
let u1 = 0; let u2 = 0; let u3 = 0;
|
|
145
|
-
let y = 0; let cy = 0; let sy = 0;
|
|
146
|
-
|
|
147
|
-
// Newton-Raphson iteration
|
|
148
|
-
for (let k = 1; k <= kn; k++) {
|
|
149
|
-
let yqr;
|
|
150
|
-
|
|
151
|
-
if (alp0 < 0) {
|
|
152
|
-
y = alp0 * x * x;
|
|
153
|
-
yqr = Math.sqrt(-y);
|
|
154
|
-
cy = (1 - Math.cosh(yqr)) / y;
|
|
155
|
-
sy = (Math.sinh(yqr) - yqr) / (yqr * yqr * yqr);
|
|
156
|
-
} else if (alp0 === 0) {
|
|
157
|
-
y = 0;
|
|
158
|
-
cy = 0.5;
|
|
159
|
-
sy = 1.0 / 6.0;
|
|
160
|
-
} else if (alp0 > 0) {
|
|
161
|
-
y = alp0 * x * x;
|
|
162
|
-
yqr = Math.sqrt(y);
|
|
163
|
-
cy = (1 - Math.cos(yqr)) / y;
|
|
164
|
-
sy = (yqr - Math.sin(yqr)) / (yqr * yqr * yqr);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
u1 = x * (1 - y * sy);
|
|
168
|
-
u2 = x * x * cy;
|
|
169
|
-
u3 = x * x * x * sy;
|
|
170
|
-
|
|
171
|
-
const fx = r0Mag * u1 + sigma0 * u2 + u3 - dt * muqr;
|
|
172
|
-
dfx = sigma0 * u1 + (1 - alp0 * r0Mag) * u2 + r0Mag;
|
|
173
|
-
const dfx2 = sigma0 * (1 - y * cy) + (1 - alp0 * r0Mag) * u1;
|
|
174
|
-
const sdfx = dfx / Math.abs(dfx);
|
|
175
|
-
|
|
176
|
-
const dx2 = 16 * dfx * dfx - 20 * fx * dfx2;
|
|
177
|
-
|
|
178
|
-
let dx;
|
|
179
|
-
if (dx2 > 0) {
|
|
180
|
-
dx = 5 * fx / (dfx + sdfx * Math.sqrt(dx2));
|
|
181
|
-
} else {
|
|
182
|
-
dx = 0.5 * x;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (Math.abs(dx) < 1.0e-10) break;
|
|
186
|
-
|
|
187
|
-
x -= dx;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Kepler solution converged
|
|
191
|
-
const rmag = dfx;
|
|
192
|
-
const f = 1 - u2 / r0Mag;
|
|
193
|
-
const g = dt - u3 / muqr;
|
|
194
|
-
const df = -muqr * u1 / (rmag * r0Mag);
|
|
195
|
-
const dg = 1 - u2 / rmag;
|
|
196
|
-
|
|
197
|
-
// Use pious-squid Vector3D operations
|
|
198
|
-
const finalPos = r0.scale(f).add(v0.scale(g)).scale(rex);
|
|
199
|
-
const finalVel = r0.scale(df).add(v0.scale(dg)).scale(vex);
|
|
200
|
-
|
|
201
|
-
x1 = new PosVelVec(finalPos, finalVel);
|
|
202
|
-
xxx = x * Math.sqrt(rex);
|
|
203
|
-
|
|
204
|
-
return {x1, xxx};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Main Vinti Ballistic Propagation Algorithm
|
|
209
|
-
* Complete implementation with all steps - using pious-squid Vector3D
|
|
210
|
-
* @param {*} x0
|
|
211
|
-
* @param {*} span
|
|
212
|
-
* @param {*} eqrad
|
|
213
|
-
* @param {*} mu
|
|
214
|
-
* @param {*} j2
|
|
215
|
-
* @param {*} j3
|
|
216
|
-
* @return {PosVelVec} x1
|
|
217
|
-
*/
|
|
218
|
-
static ballisticProp(x0, span, eqrad, mu, j2, j3) {
|
|
219
|
-
// Setup
|
|
220
|
-
// const pi = 3.141592653589793238;
|
|
221
|
-
const pi = Math.PI;
|
|
222
|
-
const twopi = 2 * pi;
|
|
223
|
-
// const degs = 180 / pi; Astrolibrary's use of degs is unusual in that it calculates a value but immediately discards it.
|
|
224
|
-
|
|
225
|
-
const ae = eqrad; // Equatorial radius
|
|
226
|
-
const gm = mu; // Gravitational parameter
|
|
227
|
-
const xj2 = j2; // J2
|
|
228
|
-
const xj3 = j3; // J3
|
|
229
|
-
|
|
230
|
-
const planet = [ae, gm, xj2, xj3];
|
|
231
|
-
|
|
232
|
-
let x1 = PosVelVec.zero();
|
|
233
|
-
|
|
234
|
-
// Compute initial guess using Kepler solver
|
|
235
|
-
const vt0 = 0;
|
|
236
|
-
const vt1 = span;
|
|
237
|
-
|
|
238
|
-
let xhat0 = 0;
|
|
239
|
-
const keplerResult = this.kepler1(planet, vt0, x0, vt1);
|
|
240
|
-
x1 = keplerResult.x1;
|
|
241
|
-
xhat0 = keplerResult.xxx;
|
|
242
|
-
|
|
243
|
-
xhat0 /= Math.sqrt(ae); // Change to astronomical units
|
|
244
|
-
|
|
245
|
-
// Check Vinti's forbidden zone - using pious-squid Vector3D cross product
|
|
246
|
-
const h0 = new NodeVector3D(
|
|
247
|
-
x0.get(1) * x0.get(5) - x0.get(2) * x0.get(4),
|
|
248
|
-
x0.get(2) * x0.get(3) - x0.get(0) * x0.get(5),
|
|
249
|
-
x0.get(0) * x0.get(4) - x0.get(1) * x0.get(3),
|
|
250
|
-
);
|
|
251
|
-
const h02 = h0.magnitude() * h0.magnitude();
|
|
252
|
-
|
|
253
|
-
const r0mag = x0.Position.magnitude();
|
|
254
|
-
const v0mag = x0.Velocity.magnitude();
|
|
255
|
-
|
|
256
|
-
const alp0 = 2.0 / r0mag - v0mag * v0mag / gm;
|
|
257
|
-
|
|
258
|
-
let periapsisRadius; let e0;
|
|
259
|
-
if (Math.abs(alp0) < 1.0e-15) {
|
|
260
|
-
periapsisRadius = h02 / (2.0 * gm); // Parabolic
|
|
261
|
-
} else {
|
|
262
|
-
const a0 = 1.0 / alp0;
|
|
263
|
-
const e02 = 1 - alp0 * h02 / gm;
|
|
264
|
-
|
|
265
|
-
if (e02 <= 0) {
|
|
266
|
-
e0 = 0;
|
|
267
|
-
} else {
|
|
268
|
-
e0 = Math.sqrt(e02);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
periapsisRadius = a0 * (1.0 - e0);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (periapsisRadius < 210) {
|
|
275
|
-
throw new Error("Trajectory enters Vinti forbidden zone [WARNING: SPOOKY].");
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Change from SI units to astronomical units
|
|
279
|
-
const timeFactor = Math.sqrt(ae * ae * ae / gm);
|
|
280
|
-
const ve = ae / timeFactor;
|
|
281
|
-
const t0 = vt0 / timeFactor;
|
|
282
|
-
|
|
283
|
-
// Use pious-squid Vector3D scale method
|
|
284
|
-
const pin = x0.Position.scale(1 / ae);
|
|
285
|
-
const vin = x0.Velocity.scale(1 / ve);
|
|
286
|
-
|
|
287
|
-
const tf = span / timeFactor;
|
|
288
|
-
|
|
289
|
-
// ========== STEP 1: Initial coordinate transformation ==========
|
|
290
|
-
const delta = -xj3 / (2 * xj2);
|
|
291
|
-
const csq = xj2 * (1 - delta * delta / xj2);
|
|
292
|
-
const d0 = Math.sqrt(pin.x * pin.x + pin.y * pin.y);
|
|
293
|
-
let alph0 = Math.atan2(pin.y, pin.x);
|
|
294
|
-
|
|
295
|
-
if (alph0 < 0) alph0 = twopi + alph0;
|
|
296
|
-
|
|
297
|
-
const r02 = d0 * d0 + pin.z * pin.z;
|
|
298
|
-
const zpdelta = pin.z + delta;
|
|
299
|
-
const rhotemp = r02 - csq + delta * (zpdelta + pin.z);
|
|
300
|
-
const rho0 = Math.sqrt(
|
|
301
|
-
rhotemp + Math.sqrt(rhotemp * rhotemp + 4 * csq * (zpdelta * zpdelta)))
|
|
302
|
-
/ Math.sqrt(2.0);
|
|
303
|
-
const rho02 = rho0 * rho0;
|
|
304
|
-
const sigma0 = zpdelta / rho0;
|
|
305
|
-
const rrd = pin.dot(vin); // Using pious-squid dot product
|
|
306
|
-
const delsig0 = delta * sigma0;
|
|
307
|
-
const csqsig0 = csq * sigma0;
|
|
308
|
-
let rcs = rho02 + csqsig0 * sigma0;
|
|
309
|
-
const v = -(rho0 + delsig0) / rcs;
|
|
310
|
-
const v0 = vin.magnitude(); // Using pious-squid magnitude method
|
|
311
|
-
|
|
312
|
-
// ========== STEP 2: First three Jacobi constants ==========
|
|
313
|
-
const alph3 = pin.x * vin.y - pin.y * vin.x;
|
|
314
|
-
const alph32 = alph3 * alph3;
|
|
315
|
-
const alph1 = 0.5 * v0 * v0 + v;
|
|
316
|
-
const sqrf = rho0 * rrd + (csqsig0 + delta * rho0) * vin.z;
|
|
317
|
-
const sqrg = -sigma0 * rrd - (delsig0 - rho0) * vin.z;
|
|
318
|
-
const alph22 = 2 * rho0 + 2 * alph1 * rho02 + (csq * alph32 - sqrf * sqrf) / (rho02 + csq);
|
|
319
|
-
const alph2 = Math.sqrt(alph22);
|
|
320
|
-
const gamma0 = 2 * alph1;
|
|
321
|
-
const csgam0 = csq * gamma0;
|
|
322
|
-
const p0 = alph22;
|
|
323
|
-
const s0 = 1 - alph32 / alph22;
|
|
324
|
-
const pcsgam0 = p0 - csgam0;
|
|
325
|
-
const csqs0p0 = csq * s0 * p0;
|
|
326
|
-
|
|
327
|
-
// ========== STEP 3: Factorizing F and G quartics ==========
|
|
328
|
-
let a1p = 0;
|
|
329
|
-
let b1 = csqs0p0 / pcsgam0;
|
|
330
|
-
let a1 = (csq - b1) / pcsgam0;
|
|
331
|
-
|
|
332
|
-
let p = 0; let p1 = 0; let q1 = 0;
|
|
333
|
-
let gam1 = 0; let pgam1 = 0; let gamma = 0;
|
|
334
|
-
let cneca = 0; let sneca = 0;
|
|
335
|
-
|
|
336
|
-
// Factorize F(rho) quartic
|
|
337
|
-
for (let icf = 1; icf <= 5; icf++) {
|
|
338
|
-
gam1 = 1 + gamma0 * a1;
|
|
339
|
-
pgam1 = pcsgam0 + b1 * gamma0 - 4 * a1 * gam1;
|
|
340
|
-
gamma = gamma0 / gam1;
|
|
341
|
-
p = pgam1 / gam1;
|
|
342
|
-
b1 = csqs0p0 / pgam1;
|
|
343
|
-
a1 = (csq - gam1 * b1) / pgam1;
|
|
344
|
-
const dela1 = a1 - a1p;
|
|
345
|
-
|
|
346
|
-
if (Math.abs(dela1) < 1.0e-15) break;
|
|
347
|
-
a1p = a1;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const oe = [];
|
|
351
|
-
oe[0] = p; // Vinti mean element (conic parameter)
|
|
352
|
-
|
|
353
|
-
let smgam;
|
|
354
|
-
if (gamma < 0) {
|
|
355
|
-
smgam = Math.sqrt(-gamma);
|
|
356
|
-
} else {
|
|
357
|
-
smgam = Math.sqrt(gamma);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Factorize G(sigma) quartic
|
|
361
|
-
let s1p = 0;
|
|
362
|
-
let px = 0;
|
|
363
|
-
let s1 = 1;
|
|
364
|
-
|
|
365
|
-
for (let icg = 1; icg <= 5; icg++) {
|
|
366
|
-
const p0s1 = p0 * s1;
|
|
367
|
-
q1 = -csgam0 / p0s1;
|
|
368
|
-
p1 = 2 * delta / p0s1 - 2 * q1 * px;
|
|
369
|
-
px = delta / p0s1 - s0 * p1 / (2 * s1);
|
|
370
|
-
s1 = (pcsgam0 - s0 * p0 * q1) / ((1 - 2 * px * p1) * p0);
|
|
371
|
-
const dels1 = s1 - s1p;
|
|
372
|
-
|
|
373
|
-
if (Math.abs(dels1) < 1.0e-15) break;
|
|
374
|
-
s1p = s1;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// ========== STEP 4: Initialize R and N integral coefficients ==========
|
|
378
|
-
const gams3 = gamma * smgam;
|
|
379
|
-
const s = s0 / s1;
|
|
380
|
-
const pxs = px * px + s;
|
|
381
|
-
oe[2] = pxs; // Vinti mean element (sin^2(I))
|
|
382
|
-
|
|
383
|
-
let q;
|
|
384
|
-
if (pxs < 0) {
|
|
385
|
-
q = 0;
|
|
386
|
-
} else {
|
|
387
|
-
q = Math.sqrt(pxs);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
let xinc = Math.asin(q);
|
|
391
|
-
|
|
392
|
-
// Check inclination quadrant - CRITICAL FIX from C#
|
|
393
|
-
if (alph3 * Math.cos(xinc) < 0) xinc = pi - xinc;
|
|
394
|
-
|
|
395
|
-
const q2 = q * q;
|
|
396
|
-
const q4 = q2 * q2;
|
|
397
|
-
const betad = 1 + p1 * px - q1 * px * px - q1 * q2;
|
|
398
|
-
const beta = (p1 - 2 * q1 * px) / betad;
|
|
399
|
-
const betasq = beta * beta;
|
|
400
|
-
const g = -beta / (1 + Math.sqrt(1 - betasq * q2));
|
|
401
|
-
const a = px + g * q2;
|
|
402
|
-
const b = 1 + g * px;
|
|
403
|
-
|
|
404
|
-
const g2 = g * g;
|
|
405
|
-
const asq = a * a;
|
|
406
|
-
const bsq = b * b;
|
|
407
|
-
const ab = a * b;
|
|
408
|
-
const d5 = 1 + p1 * a - q1 * asq;
|
|
409
|
-
const xm = (q1 * bsq - p1 * b * g - g2) / d5;
|
|
410
|
-
const xk1 = xm * q2;
|
|
411
|
-
const d1 = Math.sqrt((1 - g2 * q2) / (s1 * d5));
|
|
412
|
-
const ecc2 = 1 + p * gamma;
|
|
413
|
-
const ecc = Math.sqrt(ecc2);
|
|
414
|
-
oe[1] = ecc; // Vinti mean element (eccentricity)
|
|
415
|
-
const rho1 = p / (1 + ecc);
|
|
416
|
-
|
|
417
|
-
// Coefficients for R-integrals
|
|
418
|
-
// A0 = 1, A1 from factorization, A2 to A6
|
|
419
|
-
const a1sq = a1 * a1;
|
|
420
|
-
const b1sq = b1 * b1;
|
|
421
|
-
|
|
422
|
-
const a2 = (3 * a1sq - b1) / 2;
|
|
423
|
-
const a3 = 2.5 * a1sq * a1 - 1.50 * a1 * b1;
|
|
424
|
-
const a4 = 0.375 * (b1sq - 10 * a1sq * b1);
|
|
425
|
-
const a5 = 1.875 * a1 * b1sq;
|
|
426
|
-
const a6 = -0.3125 * b1sq * b1;
|
|
427
|
-
|
|
428
|
-
// W1, W2 ... W6 for the R-integrals
|
|
429
|
-
const e3 = ecc2 * ecc;
|
|
430
|
-
const e4 = ecc2 * ecc2;
|
|
431
|
-
const e5 = e3 * ecc2;
|
|
432
|
-
const e6 = e3 * e3;
|
|
433
|
-
|
|
434
|
-
const psq = p * p;
|
|
435
|
-
|
|
436
|
-
const p3 = psq * p;
|
|
437
|
-
const p4 = psq * psq;
|
|
438
|
-
const p5 = p3 * psq;
|
|
439
|
-
const p6 = p4 * psq;
|
|
440
|
-
|
|
441
|
-
const x21 = 1 / p;
|
|
442
|
-
const x22 = ecc / p;
|
|
443
|
-
|
|
444
|
-
const x33 = 0.5 * ecc2 / psq;
|
|
445
|
-
const x32 = 2 * ecc / psq;
|
|
446
|
-
const x31 = 1 / psq + x33;
|
|
447
|
-
|
|
448
|
-
const x44 = e3 / (3 * p3);
|
|
449
|
-
const x43 = 1.5 * ecc2 / p3;
|
|
450
|
-
const x42 = 3 * ecc / p3 + 2 * x44;
|
|
451
|
-
const x41 = 1 / p3 + x43;
|
|
452
|
-
|
|
453
|
-
const x55 = x33 * x33;
|
|
454
|
-
const x54 = 4 * x44 * x21;
|
|
455
|
-
const x53 = 3 * ecc2 / p4 + 1.5 * x55;
|
|
456
|
-
const x52 = 4 * ecc / p4 + 2 * x54;
|
|
457
|
-
const x51 = 1 / p4 + x53;
|
|
458
|
-
|
|
459
|
-
const x66 = 0.2 * e5 / p5;
|
|
460
|
-
const x65 = 1.25 * e4 / p5;
|
|
461
|
-
const x64 = 10 * e3 / (3 * p5) + 4 * x66 / 3;
|
|
462
|
-
const x63 = 5 * ecc2 / p5 + 1.5 * x65;
|
|
463
|
-
const x62 = 5 * ecc / p5 + 2 * x64;
|
|
464
|
-
const x61 = 1 / p5 + x63;
|
|
465
|
-
|
|
466
|
-
const x77 = e6 / (6 * p6);
|
|
467
|
-
const x76 = 1.2 * e5 / p6;
|
|
468
|
-
const x75 = 3.75 * e4 / p6 + 1.25 * x77;
|
|
469
|
-
const x74 = 20 * e3 / (3 * p6) + x76 / 0.75;
|
|
470
|
-
const x73 = 7.5 * ecc2 / p6 + 1.5 * x75;
|
|
471
|
-
const x72 = 6 * ecc / p6 + 2 * x74;
|
|
472
|
-
const x71 = 1 / p6 + x73;
|
|
473
|
-
|
|
474
|
-
const gg1si = 1.0 / Math.sqrt(gam1);
|
|
475
|
-
const gg1psi = gg1si / Math.sqrt(p);
|
|
476
|
-
|
|
477
|
-
// R1 coefficients
|
|
478
|
-
const cr11 = (rho1 + a1) * gg1si;
|
|
479
|
-
const cr12 = ecc * gg1si;
|
|
480
|
-
const cr13 = a2 * gg1psi;
|
|
481
|
-
const cr14 = a3 * gg1psi;
|
|
482
|
-
const cr15 = a4 * gg1psi;
|
|
483
|
-
const cr16 = a5 * gg1psi;
|
|
484
|
-
const cr17 = a6 * gg1psi;
|
|
485
|
-
|
|
486
|
-
// R2 coefficients
|
|
487
|
-
const cr21 = Math.sqrt(p0 / pgam1);
|
|
488
|
-
const cr22 = a1 * cr21;
|
|
489
|
-
const cr23 = a2 * cr21;
|
|
490
|
-
const cr24 = a3 * cr21;
|
|
491
|
-
const cr25 = a4 * cr21;
|
|
492
|
-
const cr26 = a5 * cr21;
|
|
493
|
-
const cr27 = a6 * cr21;
|
|
494
|
-
|
|
495
|
-
// R3 coefficients
|
|
496
|
-
const cr31 = alph3 * gg1psi;
|
|
497
|
-
const cr32 = a1 * cr31;
|
|
498
|
-
const cr33 = (a2 - csq) * cr31;
|
|
499
|
-
const cr34 = (a3 - a1 * csq) * cr31;
|
|
500
|
-
const cr35 = a4 * cr31 - csq * cr33;
|
|
501
|
-
|
|
502
|
-
// Coefficients for N-integrals
|
|
503
|
-
|
|
504
|
-
// N3 coefficients
|
|
505
|
-
const bmg = b - g;
|
|
506
|
-
const bpg = b + g;
|
|
507
|
-
const d1ma = 1 - a;
|
|
508
|
-
const d1pa = 1 + a;
|
|
509
|
-
const beta1 = bmg / d1ma;
|
|
510
|
-
const beta2 = -bpg / d1pa;
|
|
511
|
-
const b12 = beta1 * beta1;
|
|
512
|
-
const b13 = b12 * beta1;
|
|
513
|
-
const b22 = beta2 * beta2;
|
|
514
|
-
const b23 = b22 * beta2;
|
|
515
|
-
let xmm1 = Math.sqrt(1 - b12 * q2);
|
|
516
|
-
|
|
517
|
-
if (xmm1 * alph3 < 0) xmm1 = -xmm1;
|
|
518
|
-
|
|
519
|
-
let xmm2 = Math.sqrt(1 - b22 * q2);
|
|
520
|
-
|
|
521
|
-
if (xmm2 * alph3 < 0) xmm2 = -xmm2;
|
|
522
|
-
|
|
523
|
-
const d2 = delta / (p0 * (s1 - s0 * q1));
|
|
524
|
-
const d3 = q1 + 2 * p1 * d2;
|
|
525
|
-
const d4 = d1 * alph3 / (2 * alph2);
|
|
526
|
-
|
|
527
|
-
const d1md3 = 1 - d3;
|
|
528
|
-
const bmag = b - a * g;
|
|
529
|
-
|
|
530
|
-
const d10 = bmag / bmg * Math.sqrt(d1md3 / (d5 * (1 - xm / b12) * (1 - 2 * d2)));
|
|
531
|
-
const d20 = bmag / bpg * Math.sqrt(d1md3 / (d5 * (1 - xm / b22) * (1 + 2 * d2)));
|
|
532
|
-
|
|
533
|
-
const dd2 = xm / 2;
|
|
534
|
-
const dd3 = dd2 * g;
|
|
535
|
-
const dd4 = 1.5 * dd2 * dd2;
|
|
536
|
-
const dd5 = dd4 * g;
|
|
537
|
-
const dd6 = dd2 * dd4 / 0.6;
|
|
538
|
-
|
|
539
|
-
const c15 = dd6 / (b13 * b13);
|
|
540
|
-
const c14 = c15 + dd5 / (b12 * b13);
|
|
541
|
-
const c13 = c14 + dd4 / (b12 * b12);
|
|
542
|
-
const c12 = c13 + dd3 / b13;
|
|
543
|
-
const c11 = c12 + dd2 / b12;
|
|
544
|
-
const c10 = c11 + g / beta1;
|
|
545
|
-
|
|
546
|
-
const c25 = dd6 / (b23 * b23);
|
|
547
|
-
const c24 = c25 + dd5 / (b22 * b23);
|
|
548
|
-
const c23 = c24 + dd4 / (b22 * b22);
|
|
549
|
-
const c22 = c23 + dd3 / b23;
|
|
550
|
-
const c21 = c22 + dd2 / b22;
|
|
551
|
-
const c20 = c21 + g / beta2;
|
|
552
|
-
|
|
553
|
-
const b1q = beta1 * q;
|
|
554
|
-
const b1q2 = b1q * b1q;
|
|
555
|
-
const b1q4 = b1q2 * b1q2;
|
|
556
|
-
const b2q = beta2 * q;
|
|
557
|
-
const b2q2 = b2q * b2q;
|
|
558
|
-
const b2q4 = b2q2 * b2q2;
|
|
559
|
-
|
|
560
|
-
// N1 and N2 coefficients
|
|
561
|
-
const xk12 = xk1 * xk1;
|
|
562
|
-
const xk13 = xk12 * xk1;
|
|
563
|
-
|
|
564
|
-
// Byrd and Friedman formula for elliptic integral
|
|
565
|
-
const sq = xk1 / 16 + xk12 / 32 + 21 * xk13 / 1024;
|
|
566
|
-
const sq2 = sq * sq;
|
|
567
|
-
const sq3 = sq2 * sq;
|
|
568
|
-
|
|
569
|
-
const ucf1 = 2 * sq / (1 + sq2);
|
|
570
|
-
const ucf2 = sq2 / (1 + sq2 * sq2);
|
|
571
|
-
const ucf3 = 2.0 * sq3 / (3.0 * (1 + sq3 * sq3));
|
|
572
|
-
|
|
573
|
-
const denystt = 1 + sq + sq;
|
|
574
|
-
const denyst = denystt * denystt * d1;
|
|
575
|
-
|
|
576
|
-
// N1 coefficients
|
|
577
|
-
const d1a2 = d1 / alph2;
|
|
578
|
-
const cn11 = d1a2 * asq;
|
|
579
|
-
const cn12 = d1a2 * 2 * ab * q;
|
|
580
|
-
const cn13 = d1a2 * (bsq - 4 * ab * g) * q2;
|
|
581
|
-
const cn14 = d1a2 * (xm * ab - 2 * bsq * g) * q2 * q;
|
|
582
|
-
const cn15 = d1a2 * (3 * bsq * g2 + xm * bsq / 2) * q4;
|
|
583
|
-
const cn16 = -d1a2 * xm * bsq * g * q4 * q;
|
|
584
|
-
const cn17 = 0.375 * d1a2 * xm * xm * bsq * q4 * q2;
|
|
585
|
-
|
|
586
|
-
// N2 coefficients
|
|
587
|
-
const cn22 = 0.5 * xk1 * d1;
|
|
588
|
-
const cn24 = 0.375 * xk12 * d1;
|
|
589
|
-
const cn26 = 0.3125 * xk13 * d1;
|
|
590
|
-
|
|
591
|
-
// N3 coefficients
|
|
592
|
-
const d41ma = d4 / d1ma;
|
|
593
|
-
const d41pa = d4 / d1pa;
|
|
594
|
-
|
|
595
|
-
const cn31 = -d41ma * c10 - d41pa * c20;
|
|
596
|
-
const cn32 = -d41ma * c11 * b1q - d41pa * c21 * b2q;
|
|
597
|
-
const cn33 = -d41ma * c12 * b1q2 - d41pa * c22 * b2q2;
|
|
598
|
-
const cn34 = -d41ma * c13 * b1q2 * b1q - d41pa * c23 * b2q2 * b2q;
|
|
599
|
-
const cn35 = -d41ma * c14 * b1q4 - d41pa * c24 * b2q4;
|
|
600
|
-
const cn36 = -d41ma * c15 * b1q4 * b1q - d41pa * c25 * b2q4 * b2q;
|
|
601
|
-
|
|
602
|
-
// Avoid singularity at zero inclination
|
|
603
|
-
let u;
|
|
604
|
-
if (q === 0.0) {
|
|
605
|
-
u = 0;
|
|
606
|
-
} else {
|
|
607
|
-
const d5sq = Math.sqrt(s1 * p0 * (1 + p1 * sigma0 - q1 * sigma0 * sigma0));
|
|
608
|
-
const utn = (sigma0 - a) * d5sq;
|
|
609
|
-
const utd = sqrg * Math.sqrt(1 - g2 * q2);
|
|
610
|
-
|
|
611
|
-
u = Math.atan2(utn, utd);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// Calculate Tk = tk, k = 0, T0 = t0 = u. Here k = 1, ... ,6
|
|
615
|
-
let csu = Math.cos(u);
|
|
616
|
-
let snu = Math.sin(u);
|
|
617
|
-
let snu2 = snu * snu;
|
|
618
|
-
let snu4 = snu2 * snu2;
|
|
619
|
-
|
|
620
|
-
let t1 = 1 - csu;
|
|
621
|
-
let t2 = (u - csu * snu) / 2;
|
|
622
|
-
let t3 = (2 * t1 - csu * snu2) / 3;
|
|
623
|
-
let t4 = (3 * t2 - csu * snu2 * snu) / 4;
|
|
624
|
-
let t5 = (4 * t3 - csu * snu4) / 5;
|
|
625
|
-
let t6 = (5 * t4 - csu * snu4 * snu) / 6;
|
|
626
|
-
|
|
627
|
-
// Compute xhat at initial time
|
|
628
|
-
let xhat;
|
|
629
|
-
if (gamma < -1.0e-14) { // Ellipse
|
|
630
|
-
if (Math.abs(ecc) < 1.0e-10
|
|
631
|
-
|| Math.abs(sqrf) < 1.0e-10
|
|
632
|
-
|| Math.abs(rho0 - rho1) < 1e-5) {
|
|
633
|
-
xhat = 0;
|
|
634
|
-
} else {
|
|
635
|
-
const shat = Math.abs(sqrf) / sqrf * Math.sqrt(gamma * rho02 + 2 * rho0 - p) / ecc;
|
|
636
|
-
const cacs = (rho0 - rho1) * gamma / ecc + 1;
|
|
637
|
-
let acs = Math.atan2(shat * smgam, cacs);
|
|
638
|
-
|
|
639
|
-
if (acs < 0) acs = twopi + acs;
|
|
640
|
-
|
|
641
|
-
xhat = acs / smgam;
|
|
642
|
-
}
|
|
643
|
-
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
644
|
-
if (Math.abs(ecc) < 1.0e-10 || Math.abs(sqrf) < 1.0e-10) {
|
|
645
|
-
xhat = 0.0;
|
|
646
|
-
} else {
|
|
647
|
-
const chat = (rho0 - rho1) / ecc;
|
|
648
|
-
const zz = gamma * chat + 1;
|
|
649
|
-
xhat = Math.log(zz + Math.sqrt(zz * zz - 1)) / Math.sqrt(gamma);
|
|
650
|
-
|
|
651
|
-
if (sqrf < 0) xhat = -xhat;
|
|
652
|
-
}
|
|
653
|
-
} else { // Parabola
|
|
654
|
-
xhat = rrd;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// ========== STEP 5: Last three Jacobi constants ==========
|
|
658
|
-
// Determine true anomaly from xhat at t0
|
|
659
|
-
let eca = smgam * xhat;
|
|
660
|
-
let tra; let chat; let shat;
|
|
661
|
-
|
|
662
|
-
if (gamma < -1.0e-14) { // Ellipse
|
|
663
|
-
sneca = Math.sin(eca);
|
|
664
|
-
cneca = Math.cos(eca);
|
|
665
|
-
const s1mes = Math.sqrt(1 - ecc2);
|
|
666
|
-
const temp3 = 2 * Math.atan(ecc * sneca / (1 + s1mes - ecc * cneca));
|
|
667
|
-
tra = eca + temp3;
|
|
668
|
-
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
669
|
-
sneca = Math.sinh(eca);
|
|
670
|
-
cneca = Math.cosh(eca);
|
|
671
|
-
|
|
672
|
-
chat = (cneca - 1) / gamma;
|
|
673
|
-
shat = sneca / smgam;
|
|
674
|
-
tra = Math.atan2(Math.sqrt(p) * shat, rho1 - chat);
|
|
675
|
-
} else { // Parabola
|
|
676
|
-
tra = 2 * Math.atan(xhat / Math.sqrt(p));
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
let snw = Math.sin(tra);
|
|
680
|
-
let cnw = Math.cos(tra);
|
|
681
|
-
let ecccnw = ecc * cnw;
|
|
682
|
-
|
|
683
|
-
// const dw1dx = (1 + ecccnw) / p;
|
|
684
|
-
// const dw2dx = dw1dx * dw1dx; same case. Astrolibrary does not use this instance of dw2dx here but does so later in the code after it is redeclared
|
|
685
|
-
|
|
686
|
-
const v3 = snw * cnw;
|
|
687
|
-
const v4 = v3 * cnw;
|
|
688
|
-
const v5 = v4 * cnw;
|
|
689
|
-
const v6 = v5 * cnw;
|
|
690
|
-
const v7 = v6 * cnw;
|
|
691
|
-
|
|
692
|
-
let w1 = x21 * tra + x22 * snw;
|
|
693
|
-
let w2 = x31 * tra + x32 * snw + x33 * v3;
|
|
694
|
-
let w3 = x41 * tra + x42 * snw + x43 * v3 + x44 * v4;
|
|
695
|
-
let w4 = x51 * tra + x52 * snw + x53 * v3 + x54 * v4 + x55 * v5;
|
|
696
|
-
let w5 = x61 * tra + x62 * snw + x63 * v3 + x64 * v4 + x65 * v5 + x66 * v6;
|
|
697
|
-
let w6 = x71 * tra + x72 * snw + x73 * v3 + x74 * v4 + x75 * v5 + x76 * v6 + x77 * v7;
|
|
698
|
-
|
|
699
|
-
let uhat;
|
|
700
|
-
if (Math.abs(gamma) >= 1.0e-14) { // Circle, ellipse, hyperbola
|
|
701
|
-
chat = (cneca - 1) / gamma;
|
|
702
|
-
uhat = (sneca - eca) / gams3;
|
|
703
|
-
} else { // Parabola
|
|
704
|
-
chat = xhat * xhat / 2;
|
|
705
|
-
uhat = xhat * xhat * xhat / 6;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
const r1 = cr11 * xhat + cr12 * uhat + cr13 * tra
|
|
709
|
-
+ cr14 * w1 + cr15 * w2 + cr16 * w3 + cr17 * w4;
|
|
710
|
-
const r2 = cr21 * tra + cr22 * w1 + cr23 * w2 + cr24
|
|
711
|
-
* w3 + cr25 * w4 + cr26 * w5 + cr27 * w6;
|
|
712
|
-
|
|
713
|
-
let sstar = Math.sin(0.5 * u);
|
|
714
|
-
let cstar = Math.cos(0.5 * u);
|
|
715
|
-
let cb1qs = cstar - b1q * sstar;
|
|
716
|
-
let psi1 = Math.atan(xmm1 * sstar / cb1qs);
|
|
717
|
-
|
|
718
|
-
if (cb1qs * Math.cos(psi1) < 0.0) psi1 = pi + psi1;
|
|
719
|
-
|
|
720
|
-
let cb2qs = cstar - b2q * sstar;
|
|
721
|
-
let psi2 = Math.atan(xmm2 * sstar / cb2qs);
|
|
722
|
-
|
|
723
|
-
if (cb2qs * Math.cos(psi2) < 0.0) psi2 = pi + psi2;
|
|
724
|
-
|
|
725
|
-
let r3 = cr31 * w2 + cr32 * w3 + cr33 * w4 + cr34 * w5 + cr35 * w6;
|
|
726
|
-
|
|
727
|
-
let en3 = d10 * psi1 + d20 * psi2 + cn31 * u + cn32
|
|
728
|
-
* t1 + cn33 * t2 + cn34 * t3 + cn35 * t4 + cn36 * t5;
|
|
729
|
-
const en1 = cn11 * u + cn12 * t1 + cn13 * t2 + cn14
|
|
730
|
-
* t3 + cn15 * t4 + cn16 * t5 + cn17 * t6;
|
|
731
|
-
const en2 = d1 * u + cn22 * t2 + cn24 * t4 + cn26 * t6;
|
|
732
|
-
|
|
733
|
-
const somega = en2 - r2; // beta2
|
|
734
|
-
const capt = t0 - r1 - csq * en1; // -beta1
|
|
735
|
-
const deltat = tf - capt;
|
|
736
|
-
const comega = alph0 + csq * r3 - en3; // beta3
|
|
737
|
-
|
|
738
|
-
oe[3] = -capt * timeFactor; // Vinti mean element "beta1"
|
|
739
|
-
oe[4] = somega; // Vinti mean element "beta2"
|
|
740
|
-
oe[5] = comega; // Vinti mean element "beta3"
|
|
741
|
-
|
|
742
|
-
// ========== STEP 6: Solve kinematical equations ==========
|
|
743
|
-
// The generalized Kepler equation is solved by iteration
|
|
744
|
-
xhat += xhat0;
|
|
745
|
-
|
|
746
|
-
// Variables already declared earlier, will be reassigned in loop
|
|
747
|
-
|
|
748
|
-
for (let ick = 1; ick <= 10; ick++) {
|
|
749
|
-
eca = smgam * xhat;
|
|
750
|
-
|
|
751
|
-
if (gamma < -1.0e-14) { // Ellipse
|
|
752
|
-
sneca = Math.sin(eca);
|
|
753
|
-
cneca = Math.cos(eca);
|
|
754
|
-
const s1mes = Math.sqrt(1 - ecc2);
|
|
755
|
-
const temp3 = 2 * Math.atan(ecc * sneca / (1 + s1mes - ecc * cneca));
|
|
756
|
-
tra = eca + temp3;
|
|
757
|
-
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
758
|
-
sneca = Math.sinh(eca);
|
|
759
|
-
cneca = Math.cosh(eca);
|
|
760
|
-
chat = (cneca - 1) / gamma;
|
|
761
|
-
shat = sneca / smgam;
|
|
762
|
-
tra = Math.atan2(Math.sqrt(p) * shat, rho1 - chat);
|
|
763
|
-
} else { // Parabola
|
|
764
|
-
tra = 2 * Math.atan(xhat / Math.sqrt(p));
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
snw = Math.sin(tra);
|
|
768
|
-
cnw = Math.cos(tra);
|
|
769
|
-
ecccnw = ecc * cnw;
|
|
770
|
-
|
|
771
|
-
const dwdx = (1 + ecccnw) / Math.sqrt(p);
|
|
772
|
-
const dw1dx = (1 + ecccnw) / p;
|
|
773
|
-
const dw2dx = dw1dx * dw1dx;
|
|
774
|
-
const dw3dx = dw1dx * dw2dx;
|
|
775
|
-
const dw4dx = dw2dx * dw2dx;
|
|
776
|
-
|
|
777
|
-
const v3 = snw * cnw;
|
|
778
|
-
const v4 = v3 * cnw;
|
|
779
|
-
const v5 = v4 * cnw;
|
|
780
|
-
const v6 = v5 * cnw;
|
|
781
|
-
const v7 = v6 * cnw;
|
|
782
|
-
|
|
783
|
-
w1 = x21 * tra + x22 * snw;
|
|
784
|
-
w2 = x31 * tra + x32 * snw + x33 * v3;
|
|
785
|
-
w3 = x41 * tra + x42 * snw + x43 * v3 + x44 * v4;
|
|
786
|
-
w4 = x51 * tra + x52 * snw + x53 * v3 + x54 * v4 + x55 * v5;
|
|
787
|
-
w5 = x61 * tra + x62 * snw + x63 * v3 + x64 * v4 + x65 * v5 + x66 * v6;
|
|
788
|
-
w6 = x71 * tra + x72 * snw + x73 * v3 + x74 * v4 + x75 * v5 + x76 * v6 + x77 * v7;
|
|
789
|
-
|
|
790
|
-
if (Math.abs(gamma) >= 1.0e-14) {
|
|
791
|
-
chat = (cneca - 1) / gamma;
|
|
792
|
-
uhat = (sneca - eca) / gams3;
|
|
793
|
-
} else { // Parabola
|
|
794
|
-
chat = xhat * xhat / 2;
|
|
795
|
-
uhat = xhat * xhat * xhat / 6;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
const r1 = cr11 * xhat
|
|
799
|
-
+ cr12 * uhat
|
|
800
|
-
+ cr13 * tra
|
|
801
|
-
+ cr14 * w1
|
|
802
|
-
+ cr15 * w2
|
|
803
|
-
+ cr16 * w3
|
|
804
|
-
+ cr17 * w4;
|
|
805
|
-
const r2
|
|
806
|
-
= cr21 * tra
|
|
807
|
-
+ cr22 * w1
|
|
808
|
-
+ cr23 * w2
|
|
809
|
-
+ cr24 * w3
|
|
810
|
-
+ cr25 * w4
|
|
811
|
-
+ cr26 * w5
|
|
812
|
-
+ cr27 * w6;
|
|
813
|
-
|
|
814
|
-
const ystar = (r2 + somega) / denyst;
|
|
815
|
-
u = ystar
|
|
816
|
-
+ ucf1 * Math.sin(2 * ystar)
|
|
817
|
-
+ ucf2 * Math.sin(4 * ystar)
|
|
818
|
-
+ ucf3 * Math.sin(6 * ystar);
|
|
819
|
-
|
|
820
|
-
csu = Math.cos(u);
|
|
821
|
-
snu = Math.sin(u);
|
|
822
|
-
snu2 = snu * snu;
|
|
823
|
-
snu4 = snu2 * snu2;
|
|
824
|
-
|
|
825
|
-
t1 = 1 - csu;
|
|
826
|
-
t2 = (u - csu * snu) / 2;
|
|
827
|
-
t3 = (2 * t1 - csu * snu2) / 3;
|
|
828
|
-
t4 = (3 * t2 - csu * snu2 * snu) / 4;
|
|
829
|
-
t5 = (4 * t3 - csu * snu4) / 5;
|
|
830
|
-
t6 = (5 * t4 - csu * snu4 * snu) / 6;
|
|
831
|
-
|
|
832
|
-
const en1 = cn11 * u
|
|
833
|
-
+ cn12 * t1
|
|
834
|
-
+ cn13 * t2
|
|
835
|
-
+ cn14 * t3
|
|
836
|
-
+ cn15 * t4
|
|
837
|
-
+ cn16 * t5
|
|
838
|
-
+ cn17 * t6;
|
|
839
|
-
|
|
840
|
-
const cn1r1 = csq * en1 + r1;
|
|
841
|
-
const psixhat = cn1r1 - deltat; // Function
|
|
842
|
-
|
|
843
|
-
const dpsx1 = cr13 + cr14 * dw1dx + cr15 * dw2dx + cr16 * dw3dx + cr17 * dw4dx;
|
|
844
|
-
const dpsx = cr11 + cr12 * chat + dpsx1 * dwdx; // 1st derivative
|
|
845
|
-
const delx = psixhat / dpsx;
|
|
846
|
-
|
|
847
|
-
xhat -= delx;
|
|
848
|
-
|
|
849
|
-
if (Math.abs(delx) < 1.0e-14) break;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
// ========== STEP 7: Final coordinate transformation ==========
|
|
853
|
-
// OSC state vector is (rhof, sigmaf, alphaf, drhof, dsigf, dalphf)
|
|
854
|
-
// ECI state vector is (pf, vf)
|
|
855
|
-
|
|
856
|
-
sstar = Math.sin(0.5 * u);
|
|
857
|
-
cstar = Math.cos(0.5 * u);
|
|
858
|
-
cb1qs = cstar - b1q * sstar;
|
|
859
|
-
psi1 = Math.atan(xmm1 * sstar / cb1qs);
|
|
860
|
-
|
|
861
|
-
if (cb1qs * Math.cos(psi1) < 0) psi1 = pi + psi1;
|
|
862
|
-
|
|
863
|
-
cb2qs = cstar - b2q * sstar;
|
|
864
|
-
psi2 = Math.atan(xmm2 * sstar / cb2qs);
|
|
865
|
-
|
|
866
|
-
if (cb2qs * Math.cos(psi2) < 0) psi2 = pi + psi2;
|
|
867
|
-
|
|
868
|
-
r3 = cr31 * w2 + cr32 * w3 + cr33 * w4 + cr34 * w5 + cr35 * w6;
|
|
869
|
-
en3 = d10 * psi1
|
|
870
|
-
+ d20 * psi2
|
|
871
|
-
+ cn31 * u
|
|
872
|
-
+ cn32 * t1
|
|
873
|
-
+ cn33 * t2
|
|
874
|
-
+ cn34 * t3
|
|
875
|
-
+ cn35 * t4
|
|
876
|
-
+ cn36 * t5;
|
|
877
|
-
const qsnu = q * snu;
|
|
878
|
-
const alphaf = comega - csq * r3 + en3;
|
|
879
|
-
const rhof = rho1 + ecc * chat;
|
|
880
|
-
const sigmaf = (a + b * qsnu) / (1 + g * qsnu);
|
|
881
|
-
|
|
882
|
-
const rhof2 = rhof * rhof;
|
|
883
|
-
const sigf2 = sigmaf * sigmaf;
|
|
884
|
-
|
|
885
|
-
const rhocsq = rhof2 + csq;
|
|
886
|
-
const df = Math.sqrt(rhocsq * (1 - sigf2));
|
|
887
|
-
const snalp = Math.sin(alphaf);
|
|
888
|
-
const csalp = Math.cos(alphaf);
|
|
889
|
-
|
|
890
|
-
const pf = new NodeVector3D(df * csalp, df * snalp, rhof * sigmaf - delta);
|
|
891
|
-
|
|
892
|
-
shat = xhat + gamma * uhat;
|
|
893
|
-
rcs = rhof2 + csq * sigf2;
|
|
894
|
-
|
|
895
|
-
const rhoqd = rhof2 - 2 * a1 * rhof + b1;
|
|
896
|
-
const drhofp = Math.sqrt(gam1 * rhoqd) / rcs;
|
|
897
|
-
const drhof = ecc * shat * drhofp;
|
|
898
|
-
const temp12 = (1 + p1 * sigmaf - q1 * sigf2) * (1 - g2 * q2) * s1;
|
|
899
|
-
const dsigf = alph2 * q * Math.sqrt(temp12) / rcs * csu / (1 + g * qsnu);
|
|
900
|
-
const temp20 = (1 - sigf2) * (rhof * drhof);
|
|
901
|
-
const temp21 = rhocsq * sigmaf * dsigf;
|
|
902
|
-
const dd = (temp20 - temp21) / df;
|
|
903
|
-
const dalphf = alph3 / (df * df);
|
|
904
|
-
|
|
905
|
-
const vf = new NodeVector3D(
|
|
906
|
-
dd * csalp - pf.y * dalphf,
|
|
907
|
-
dd * snalp + pf.x * dalphf,
|
|
908
|
-
sigmaf * drhof + rhof * dsigf,
|
|
909
|
-
);
|
|
910
|
-
|
|
911
|
-
// Change from astronomical units to SI units - using pious-squid Vector3D scale method
|
|
912
|
-
x1.position = pf.scale(ae);
|
|
913
|
-
x1.velocity = vf.scale(ve);
|
|
914
|
-
|
|
915
|
-
return x1;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
/**
|
|
920
|
-
* Main Ballistic Propagator class
|
|
921
|
-
* Refactored to use existing constants and Vector3D class
|
|
922
|
-
*/
|
|
923
|
-
class BallisticPropagator {
|
|
924
|
-
constructor(baseStateVector, options = {}) {
|
|
925
|
-
this.baseStateVector = baseStateVector;
|
|
926
|
-
this.planetEquatorialRadiusKm
|
|
927
|
-
= options.equatorialRadius || EarthConstants.EquatorialRadiusKm;
|
|
928
|
-
this.mu = options.mu || EarthConstants.Mu;
|
|
929
|
-
this.j2 = options.j2 || EarthConstants.J2;
|
|
930
|
-
this.j3 = options.j3 || EarthConstants.J3;
|
|
931
|
-
this.referenceFrame = options.referenceFrame || "J2000";
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* Propagate state vector to target time
|
|
936
|
-
* @param {Date|number} targetTime - Target time as Date or seconds from epoch
|
|
937
|
-
* @return {Object} Propagated state with position and velocity
|
|
938
|
-
*/
|
|
939
|
-
propagate(targetTime) {
|
|
940
|
-
let spanSeconds;
|
|
941
|
-
|
|
942
|
-
if (targetTime instanceof Date) {
|
|
943
|
-
spanSeconds = (targetTime - this.baseStateVector.epochUtc) / 1000;
|
|
944
|
-
} else {
|
|
945
|
-
spanSeconds = targetTime;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// Create PosVelVec using pious-squid Vector3D
|
|
949
|
-
// Handle both lowercase and uppercase property names, but check for undefined specifically
|
|
950
|
-
const getComponent = (vector, lowerProp, upperProp) => {
|
|
951
|
-
return vector[lowerProp] !== undefined ? vector[lowerProp] : vector[upperProp];
|
|
952
|
-
};
|
|
953
|
-
|
|
954
|
-
const x0 = new PosVelVec(
|
|
955
|
-
new NodeVector3D(
|
|
956
|
-
getComponent(this.baseStateVector.position, "x", "X"),
|
|
957
|
-
getComponent(this.baseStateVector.position, "y", "Y"),
|
|
958
|
-
getComponent(this.baseStateVector.position, "z", "Z"),
|
|
959
|
-
),
|
|
960
|
-
new NodeVector3D(
|
|
961
|
-
getComponent(this.baseStateVector.velocity, "x", "X"),
|
|
962
|
-
getComponent(this.baseStateVector.velocity, "y", "Y"),
|
|
963
|
-
getComponent(this.baseStateVector.velocity, "z", "Z"),
|
|
964
|
-
),
|
|
965
|
-
);
|
|
966
|
-
|
|
967
|
-
const x1 = BallisticPropagatorUtils.ballisticProp(
|
|
968
|
-
x0,
|
|
969
|
-
spanSeconds,
|
|
970
|
-
this.planetEquatorialRadiusKm,
|
|
971
|
-
this.mu,
|
|
972
|
-
this.j2,
|
|
973
|
-
this.j3,
|
|
974
|
-
);
|
|
975
|
-
|
|
976
|
-
return {
|
|
977
|
-
position: x1.position,
|
|
978
|
-
velocity: x1.velocity,
|
|
979
|
-
epochUtc: targetTime instanceof Date
|
|
980
|
-
? targetTime
|
|
981
|
-
: new Date(this.baseStateVector.epochUtc.getTime() + spanSeconds * 1000),
|
|
982
|
-
referenceFrame: this.referenceFrame,
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
// Export for Node.js
|
|
988
|
-
export {BallisticPropagator, BallisticPropagatorUtils, PosVelVec, EarthConstants};
|
|
989
|
-
|
|
990
|
-
/**
|
|
991
|
-
* REFACTORING SUMMARY:
|
|
992
|
-
* ===================
|
|
993
|
-
*
|
|
994
|
-
* REPLACED IMPLEMENTATIONS:
|
|
995
|
-
* 1. EarthConstants - Now uses values from ./constants.js:
|
|
996
|
-
* - EquatorialRadiusKm: WGS84_EARTH_EQUATORIAL_RADIUS_KM (6378.137 km)
|
|
997
|
-
* - Mu: MU converted from m³/s² to km³/s² (398600.4418)
|
|
998
|
-
* - J2 and J3: Kept original values as they're specific to Vinti propagator
|
|
999
|
-
*
|
|
1000
|
-
* 2. Vector3D - Now imports and uses pious-squid's Vector3D class:
|
|
1001
|
-
* - Uses magnitude() instead of length property
|
|
1002
|
-
* - Uses scale() instead of scaleBy() method
|
|
1003
|
-
* - Uses add() and dot() methods directly from pious-squid
|
|
1004
|
-
* - All vector operations now use the robust pious-squid implementation
|
|
1005
|
-
*
|
|
1006
|
-
* 3. Mathematical operations:
|
|
1007
|
-
* - Vector magnitude calculations use pious-squid's magnitude() method
|
|
1008
|
-
* - Vector scaling uses pious-squid's scale() method
|
|
1009
|
-
* - Vector addition uses pious-squid's add() method
|
|
1010
|
-
* - Dot product uses pious-squid's dot() method
|
|
1011
|
-
*
|
|
1012
|
-
* BENEFITS:
|
|
1013
|
-
* - Reduced code duplication (removed ~100 lines of custom Vector3D implementation)
|
|
1014
|
-
* - Uses standardized, well-tested vector operations from pious-squid
|
|
1015
|
-
* - Uses standardized Earth constants from node-common constants.js
|
|
1016
|
-
* - Maintains 100% functional compatibility with original implementation
|
|
1017
|
-
* - Better maintainability through shared library usage
|
|
1018
|
-
*
|
|
1019
|
-
* EXAMPLE USAGE (unchanged):
|
|
1020
|
-
* ==========================
|
|
1021
|
-
*
|
|
1022
|
-
* // ISS-like circular orbit
|
|
1023
|
-
* const initialState = {
|
|
1024
|
-
* position: new Vector3D(6778.137, 0, 0), // km
|
|
1025
|
-
* velocity: new Vector3D(0, 7.66779, 0), // km/s
|
|
1026
|
-
* epochUtc: new Date('2025-01-01T00:00:00Z'),
|
|
1027
|
-
* referenceFrame: 'J2000'
|
|
1028
|
-
* };
|
|
1029
|
-
*
|
|
1030
|
-
* const propagator = new BallisticPropagator(initialState);
|
|
1031
|
-
*
|
|
1032
|
-
* // Propagate for 5 minutes (300 seconds)
|
|
1033
|
-
* const result = propagator.propagate(300);
|
|
1034
|
-
*
|
|
1035
|
-
* console.log('Position after 300s:', result.position);
|
|
1036
|
-
* console.log('Velocity after 300s:', result.velocity);
|
|
1037
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* Refactored Vinti Ballistic Propagator JavaScript Implementation
|
|
3
|
+
* Uses existing node-common libraries instead of custom implementations
|
|
4
|
+
*
|
|
5
|
+
* This is a refactored version of the complete Vinti Ballistic Propagator
|
|
6
|
+
* that replaces custom implementations with existing node-common libraries.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Import existing libraries instead of defining custom ones
|
|
10
|
+
import {MU, WGS84_EARTH_EQUATORIAL_RADIUS_KM} from "./constants.js";
|
|
11
|
+
import {NodeVector3D} from "./NodeVector3D.js";
|
|
12
|
+
|
|
13
|
+
// Earth constants using existing constants.js values
|
|
14
|
+
const EarthConstants = {
|
|
15
|
+
EquatorialRadiusKm: WGS84_EARTH_EQUATORIAL_RADIUS_KM, // 6378.137 km
|
|
16
|
+
Mu: MU, // km³/s²
|
|
17
|
+
J2: 1082.62999e-6,
|
|
18
|
+
J3: -2.53215e-6,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Position-Velocity vector pair
|
|
23
|
+
* Enhanced to work with pious-squid Vector3D
|
|
24
|
+
*/
|
|
25
|
+
class PosVelVec {
|
|
26
|
+
constructor(posOrX, velOrY, z, vx, vy, vz) {
|
|
27
|
+
if (posOrX instanceof NodeVector3D) {
|
|
28
|
+
this.position = posOrX;
|
|
29
|
+
this.velocity = velOrY;
|
|
30
|
+
} else {
|
|
31
|
+
this.position = new NodeVector3D(posOrX, velOrY, z);
|
|
32
|
+
this.velocity = new NodeVector3D(vx, vy, vz);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get a zero vector for position and velocity
|
|
38
|
+
* @return {PosVelVec} zero vector
|
|
39
|
+
*/
|
|
40
|
+
static zero() {
|
|
41
|
+
return new PosVelVec(new NodeVector3D(0, 0, 0), new NodeVector3D(0, 0, 0));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the position vector
|
|
46
|
+
* @return {NodeVector3D} Position vector
|
|
47
|
+
*/
|
|
48
|
+
get Position() {
|
|
49
|
+
return this.position;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the velocity vector
|
|
54
|
+
* @return {NodeVector3D} Velocity vector
|
|
55
|
+
*/
|
|
56
|
+
get Velocity() {
|
|
57
|
+
return this.velocity;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get the value at a specific index
|
|
62
|
+
* @param {*} index
|
|
63
|
+
* @return {number}
|
|
64
|
+
*/
|
|
65
|
+
get(index) {
|
|
66
|
+
switch (index) {
|
|
67
|
+
case 0: return this.position.x;
|
|
68
|
+
case 1: return this.position.y;
|
|
69
|
+
case 2: return this.position.z;
|
|
70
|
+
case 3: return this.velocity.x;
|
|
71
|
+
case 4: return this.velocity.y;
|
|
72
|
+
case 5: return this.velocity.z;
|
|
73
|
+
default: throw new Error(`Index ${index} out of range`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
set(index, value) {
|
|
78
|
+
switch (index) {
|
|
79
|
+
case 0: this.position.x = value; break;
|
|
80
|
+
case 1: this.position.y = value; break;
|
|
81
|
+
case 2: this.position.z = value; break;
|
|
82
|
+
case 3: this.velocity.x = value; break;
|
|
83
|
+
case 4: this.velocity.y = value; break;
|
|
84
|
+
case 5: this.velocity.z = value; break;
|
|
85
|
+
default: throw new Error(`Index ${index} out of range`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Complete Ballistic Propagator Implementation
|
|
92
|
+
* Refactored to use pious-squid Vector3D operations
|
|
93
|
+
*/
|
|
94
|
+
class BallisticPropagatorUtils {
|
|
95
|
+
/**
|
|
96
|
+
* Kepler solver - exact port from C#
|
|
97
|
+
* Now uses pious-squid Vector3D operations
|
|
98
|
+
* @param {*} planet
|
|
99
|
+
* @param {*} t0
|
|
100
|
+
* @param {*} x0
|
|
101
|
+
* @param {*} t1
|
|
102
|
+
* @return {{x1: PosVelVec, xxx: number}} Object with propagated state and auxiliary value
|
|
103
|
+
*/
|
|
104
|
+
static kepler1(planet, t0, x0, t1) {
|
|
105
|
+
const muqr = 1;
|
|
106
|
+
const tlimit = 1.0e-10;
|
|
107
|
+
const kn = 10;
|
|
108
|
+
|
|
109
|
+
const rex = planet[0];
|
|
110
|
+
const gmx = planet[1];
|
|
111
|
+
|
|
112
|
+
let dt = t1 - t0;
|
|
113
|
+
let x1 = PosVelVec.zero();
|
|
114
|
+
let xxx = 0;
|
|
115
|
+
|
|
116
|
+
if (Math.abs(dt) < tlimit) {
|
|
117
|
+
for (let i = 0; i < 6; i++) {
|
|
118
|
+
x1.set(i, x0.get(i));
|
|
119
|
+
}
|
|
120
|
+
return {x1, xxx: 0};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Change from SI units to astronomical units
|
|
124
|
+
const timeFactor = Math.sqrt(rex * rex * rex / gmx);
|
|
125
|
+
const vex = rex / timeFactor;
|
|
126
|
+
dt /= timeFactor;
|
|
127
|
+
|
|
128
|
+
// Use pious-squid Vector3D scale method instead of custom scaleBy
|
|
129
|
+
const r0 = x0.Position.scale(1 / rex);
|
|
130
|
+
const v0 = x0.Velocity.scale(1 / vex);
|
|
131
|
+
|
|
132
|
+
const r0Mag = r0.magnitude();
|
|
133
|
+
const v0Mag = v0.magnitude();
|
|
134
|
+
|
|
135
|
+
const d0 = r0.dot(v0);
|
|
136
|
+
const sigma0 = d0 / muqr;
|
|
137
|
+
const alp0 = 2.0 / r0Mag - v0Mag * v0Mag;
|
|
138
|
+
|
|
139
|
+
// Initial guess
|
|
140
|
+
let x = alp0 * dt;
|
|
141
|
+
if (alp0 <= 0) x = 0.5 * dt / r0Mag;
|
|
142
|
+
|
|
143
|
+
let dfx = 0;
|
|
144
|
+
let u1 = 0; let u2 = 0; let u3 = 0;
|
|
145
|
+
let y = 0; let cy = 0; let sy = 0;
|
|
146
|
+
|
|
147
|
+
// Newton-Raphson iteration
|
|
148
|
+
for (let k = 1; k <= kn; k++) {
|
|
149
|
+
let yqr;
|
|
150
|
+
|
|
151
|
+
if (alp0 < 0) {
|
|
152
|
+
y = alp0 * x * x;
|
|
153
|
+
yqr = Math.sqrt(-y);
|
|
154
|
+
cy = (1 - Math.cosh(yqr)) / y;
|
|
155
|
+
sy = (Math.sinh(yqr) - yqr) / (yqr * yqr * yqr);
|
|
156
|
+
} else if (alp0 === 0) {
|
|
157
|
+
y = 0;
|
|
158
|
+
cy = 0.5;
|
|
159
|
+
sy = 1.0 / 6.0;
|
|
160
|
+
} else if (alp0 > 0) {
|
|
161
|
+
y = alp0 * x * x;
|
|
162
|
+
yqr = Math.sqrt(y);
|
|
163
|
+
cy = (1 - Math.cos(yqr)) / y;
|
|
164
|
+
sy = (yqr - Math.sin(yqr)) / (yqr * yqr * yqr);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
u1 = x * (1 - y * sy);
|
|
168
|
+
u2 = x * x * cy;
|
|
169
|
+
u3 = x * x * x * sy;
|
|
170
|
+
|
|
171
|
+
const fx = r0Mag * u1 + sigma0 * u2 + u3 - dt * muqr;
|
|
172
|
+
dfx = sigma0 * u1 + (1 - alp0 * r0Mag) * u2 + r0Mag;
|
|
173
|
+
const dfx2 = sigma0 * (1 - y * cy) + (1 - alp0 * r0Mag) * u1;
|
|
174
|
+
const sdfx = dfx / Math.abs(dfx);
|
|
175
|
+
|
|
176
|
+
const dx2 = 16 * dfx * dfx - 20 * fx * dfx2;
|
|
177
|
+
|
|
178
|
+
let dx;
|
|
179
|
+
if (dx2 > 0) {
|
|
180
|
+
dx = 5 * fx / (dfx + sdfx * Math.sqrt(dx2));
|
|
181
|
+
} else {
|
|
182
|
+
dx = 0.5 * x;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (Math.abs(dx) < 1.0e-10) break;
|
|
186
|
+
|
|
187
|
+
x -= dx;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Kepler solution converged
|
|
191
|
+
const rmag = dfx;
|
|
192
|
+
const f = 1 - u2 / r0Mag;
|
|
193
|
+
const g = dt - u3 / muqr;
|
|
194
|
+
const df = -muqr * u1 / (rmag * r0Mag);
|
|
195
|
+
const dg = 1 - u2 / rmag;
|
|
196
|
+
|
|
197
|
+
// Use pious-squid Vector3D operations
|
|
198
|
+
const finalPos = r0.scale(f).add(v0.scale(g)).scale(rex);
|
|
199
|
+
const finalVel = r0.scale(df).add(v0.scale(dg)).scale(vex);
|
|
200
|
+
|
|
201
|
+
x1 = new PosVelVec(finalPos, finalVel);
|
|
202
|
+
xxx = x * Math.sqrt(rex);
|
|
203
|
+
|
|
204
|
+
return {x1, xxx};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Main Vinti Ballistic Propagation Algorithm
|
|
209
|
+
* Complete implementation with all steps - using pious-squid Vector3D
|
|
210
|
+
* @param {*} x0
|
|
211
|
+
* @param {*} span
|
|
212
|
+
* @param {*} eqrad
|
|
213
|
+
* @param {*} mu
|
|
214
|
+
* @param {*} j2
|
|
215
|
+
* @param {*} j3
|
|
216
|
+
* @return {PosVelVec} x1
|
|
217
|
+
*/
|
|
218
|
+
static ballisticProp(x0, span, eqrad, mu, j2, j3) {
|
|
219
|
+
// Setup
|
|
220
|
+
// const pi = 3.141592653589793238;
|
|
221
|
+
const pi = Math.PI;
|
|
222
|
+
const twopi = 2 * pi;
|
|
223
|
+
// const degs = 180 / pi; Astrolibrary's use of degs is unusual in that it calculates a value but immediately discards it.
|
|
224
|
+
|
|
225
|
+
const ae = eqrad; // Equatorial radius
|
|
226
|
+
const gm = mu; // Gravitational parameter
|
|
227
|
+
const xj2 = j2; // J2
|
|
228
|
+
const xj3 = j3; // J3
|
|
229
|
+
|
|
230
|
+
const planet = [ae, gm, xj2, xj3];
|
|
231
|
+
|
|
232
|
+
let x1 = PosVelVec.zero();
|
|
233
|
+
|
|
234
|
+
// Compute initial guess using Kepler solver
|
|
235
|
+
const vt0 = 0;
|
|
236
|
+
const vt1 = span;
|
|
237
|
+
|
|
238
|
+
let xhat0 = 0;
|
|
239
|
+
const keplerResult = this.kepler1(planet, vt0, x0, vt1);
|
|
240
|
+
x1 = keplerResult.x1;
|
|
241
|
+
xhat0 = keplerResult.xxx;
|
|
242
|
+
|
|
243
|
+
xhat0 /= Math.sqrt(ae); // Change to astronomical units
|
|
244
|
+
|
|
245
|
+
// Check Vinti's forbidden zone - using pious-squid Vector3D cross product
|
|
246
|
+
const h0 = new NodeVector3D(
|
|
247
|
+
x0.get(1) * x0.get(5) - x0.get(2) * x0.get(4),
|
|
248
|
+
x0.get(2) * x0.get(3) - x0.get(0) * x0.get(5),
|
|
249
|
+
x0.get(0) * x0.get(4) - x0.get(1) * x0.get(3),
|
|
250
|
+
);
|
|
251
|
+
const h02 = h0.magnitude() * h0.magnitude();
|
|
252
|
+
|
|
253
|
+
const r0mag = x0.Position.magnitude();
|
|
254
|
+
const v0mag = x0.Velocity.magnitude();
|
|
255
|
+
|
|
256
|
+
const alp0 = 2.0 / r0mag - v0mag * v0mag / gm;
|
|
257
|
+
|
|
258
|
+
let periapsisRadius; let e0;
|
|
259
|
+
if (Math.abs(alp0) < 1.0e-15) {
|
|
260
|
+
periapsisRadius = h02 / (2.0 * gm); // Parabolic
|
|
261
|
+
} else {
|
|
262
|
+
const a0 = 1.0 / alp0;
|
|
263
|
+
const e02 = 1 - alp0 * h02 / gm;
|
|
264
|
+
|
|
265
|
+
if (e02 <= 0) {
|
|
266
|
+
e0 = 0;
|
|
267
|
+
} else {
|
|
268
|
+
e0 = Math.sqrt(e02);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
periapsisRadius = a0 * (1.0 - e0);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (periapsisRadius < 210) {
|
|
275
|
+
throw new Error("Trajectory enters Vinti forbidden zone [WARNING: SPOOKY].");
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Change from SI units to astronomical units
|
|
279
|
+
const timeFactor = Math.sqrt(ae * ae * ae / gm);
|
|
280
|
+
const ve = ae / timeFactor;
|
|
281
|
+
const t0 = vt0 / timeFactor;
|
|
282
|
+
|
|
283
|
+
// Use pious-squid Vector3D scale method
|
|
284
|
+
const pin = x0.Position.scale(1 / ae);
|
|
285
|
+
const vin = x0.Velocity.scale(1 / ve);
|
|
286
|
+
|
|
287
|
+
const tf = span / timeFactor;
|
|
288
|
+
|
|
289
|
+
// ========== STEP 1: Initial coordinate transformation ==========
|
|
290
|
+
const delta = -xj3 / (2 * xj2);
|
|
291
|
+
const csq = xj2 * (1 - delta * delta / xj2);
|
|
292
|
+
const d0 = Math.sqrt(pin.x * pin.x + pin.y * pin.y);
|
|
293
|
+
let alph0 = Math.atan2(pin.y, pin.x);
|
|
294
|
+
|
|
295
|
+
if (alph0 < 0) alph0 = twopi + alph0;
|
|
296
|
+
|
|
297
|
+
const r02 = d0 * d0 + pin.z * pin.z;
|
|
298
|
+
const zpdelta = pin.z + delta;
|
|
299
|
+
const rhotemp = r02 - csq + delta * (zpdelta + pin.z);
|
|
300
|
+
const rho0 = Math.sqrt(
|
|
301
|
+
rhotemp + Math.sqrt(rhotemp * rhotemp + 4 * csq * (zpdelta * zpdelta)))
|
|
302
|
+
/ Math.sqrt(2.0);
|
|
303
|
+
const rho02 = rho0 * rho0;
|
|
304
|
+
const sigma0 = zpdelta / rho0;
|
|
305
|
+
const rrd = pin.dot(vin); // Using pious-squid dot product
|
|
306
|
+
const delsig0 = delta * sigma0;
|
|
307
|
+
const csqsig0 = csq * sigma0;
|
|
308
|
+
let rcs = rho02 + csqsig0 * sigma0;
|
|
309
|
+
const v = -(rho0 + delsig0) / rcs;
|
|
310
|
+
const v0 = vin.magnitude(); // Using pious-squid magnitude method
|
|
311
|
+
|
|
312
|
+
// ========== STEP 2: First three Jacobi constants ==========
|
|
313
|
+
const alph3 = pin.x * vin.y - pin.y * vin.x;
|
|
314
|
+
const alph32 = alph3 * alph3;
|
|
315
|
+
const alph1 = 0.5 * v0 * v0 + v;
|
|
316
|
+
const sqrf = rho0 * rrd + (csqsig0 + delta * rho0) * vin.z;
|
|
317
|
+
const sqrg = -sigma0 * rrd - (delsig0 - rho0) * vin.z;
|
|
318
|
+
const alph22 = 2 * rho0 + 2 * alph1 * rho02 + (csq * alph32 - sqrf * sqrf) / (rho02 + csq);
|
|
319
|
+
const alph2 = Math.sqrt(alph22);
|
|
320
|
+
const gamma0 = 2 * alph1;
|
|
321
|
+
const csgam0 = csq * gamma0;
|
|
322
|
+
const p0 = alph22;
|
|
323
|
+
const s0 = 1 - alph32 / alph22;
|
|
324
|
+
const pcsgam0 = p0 - csgam0;
|
|
325
|
+
const csqs0p0 = csq * s0 * p0;
|
|
326
|
+
|
|
327
|
+
// ========== STEP 3: Factorizing F and G quartics ==========
|
|
328
|
+
let a1p = 0;
|
|
329
|
+
let b1 = csqs0p0 / pcsgam0;
|
|
330
|
+
let a1 = (csq - b1) / pcsgam0;
|
|
331
|
+
|
|
332
|
+
let p = 0; let p1 = 0; let q1 = 0;
|
|
333
|
+
let gam1 = 0; let pgam1 = 0; let gamma = 0;
|
|
334
|
+
let cneca = 0; let sneca = 0;
|
|
335
|
+
|
|
336
|
+
// Factorize F(rho) quartic
|
|
337
|
+
for (let icf = 1; icf <= 5; icf++) {
|
|
338
|
+
gam1 = 1 + gamma0 * a1;
|
|
339
|
+
pgam1 = pcsgam0 + b1 * gamma0 - 4 * a1 * gam1;
|
|
340
|
+
gamma = gamma0 / gam1;
|
|
341
|
+
p = pgam1 / gam1;
|
|
342
|
+
b1 = csqs0p0 / pgam1;
|
|
343
|
+
a1 = (csq - gam1 * b1) / pgam1;
|
|
344
|
+
const dela1 = a1 - a1p;
|
|
345
|
+
|
|
346
|
+
if (Math.abs(dela1) < 1.0e-15) break;
|
|
347
|
+
a1p = a1;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const oe = [];
|
|
351
|
+
oe[0] = p; // Vinti mean element (conic parameter)
|
|
352
|
+
|
|
353
|
+
let smgam;
|
|
354
|
+
if (gamma < 0) {
|
|
355
|
+
smgam = Math.sqrt(-gamma);
|
|
356
|
+
} else {
|
|
357
|
+
smgam = Math.sqrt(gamma);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Factorize G(sigma) quartic
|
|
361
|
+
let s1p = 0;
|
|
362
|
+
let px = 0;
|
|
363
|
+
let s1 = 1;
|
|
364
|
+
|
|
365
|
+
for (let icg = 1; icg <= 5; icg++) {
|
|
366
|
+
const p0s1 = p0 * s1;
|
|
367
|
+
q1 = -csgam0 / p0s1;
|
|
368
|
+
p1 = 2 * delta / p0s1 - 2 * q1 * px;
|
|
369
|
+
px = delta / p0s1 - s0 * p1 / (2 * s1);
|
|
370
|
+
s1 = (pcsgam0 - s0 * p0 * q1) / ((1 - 2 * px * p1) * p0);
|
|
371
|
+
const dels1 = s1 - s1p;
|
|
372
|
+
|
|
373
|
+
if (Math.abs(dels1) < 1.0e-15) break;
|
|
374
|
+
s1p = s1;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ========== STEP 4: Initialize R and N integral coefficients ==========
|
|
378
|
+
const gams3 = gamma * smgam;
|
|
379
|
+
const s = s0 / s1;
|
|
380
|
+
const pxs = px * px + s;
|
|
381
|
+
oe[2] = pxs; // Vinti mean element (sin^2(I))
|
|
382
|
+
|
|
383
|
+
let q;
|
|
384
|
+
if (pxs < 0) {
|
|
385
|
+
q = 0;
|
|
386
|
+
} else {
|
|
387
|
+
q = Math.sqrt(pxs);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
let xinc = Math.asin(q);
|
|
391
|
+
|
|
392
|
+
// Check inclination quadrant - CRITICAL FIX from C#
|
|
393
|
+
if (alph3 * Math.cos(xinc) < 0) xinc = pi - xinc;
|
|
394
|
+
|
|
395
|
+
const q2 = q * q;
|
|
396
|
+
const q4 = q2 * q2;
|
|
397
|
+
const betad = 1 + p1 * px - q1 * px * px - q1 * q2;
|
|
398
|
+
const beta = (p1 - 2 * q1 * px) / betad;
|
|
399
|
+
const betasq = beta * beta;
|
|
400
|
+
const g = -beta / (1 + Math.sqrt(1 - betasq * q2));
|
|
401
|
+
const a = px + g * q2;
|
|
402
|
+
const b = 1 + g * px;
|
|
403
|
+
|
|
404
|
+
const g2 = g * g;
|
|
405
|
+
const asq = a * a;
|
|
406
|
+
const bsq = b * b;
|
|
407
|
+
const ab = a * b;
|
|
408
|
+
const d5 = 1 + p1 * a - q1 * asq;
|
|
409
|
+
const xm = (q1 * bsq - p1 * b * g - g2) / d5;
|
|
410
|
+
const xk1 = xm * q2;
|
|
411
|
+
const d1 = Math.sqrt((1 - g2 * q2) / (s1 * d5));
|
|
412
|
+
const ecc2 = 1 + p * gamma;
|
|
413
|
+
const ecc = Math.sqrt(ecc2);
|
|
414
|
+
oe[1] = ecc; // Vinti mean element (eccentricity)
|
|
415
|
+
const rho1 = p / (1 + ecc);
|
|
416
|
+
|
|
417
|
+
// Coefficients for R-integrals
|
|
418
|
+
// A0 = 1, A1 from factorization, A2 to A6
|
|
419
|
+
const a1sq = a1 * a1;
|
|
420
|
+
const b1sq = b1 * b1;
|
|
421
|
+
|
|
422
|
+
const a2 = (3 * a1sq - b1) / 2;
|
|
423
|
+
const a3 = 2.5 * a1sq * a1 - 1.50 * a1 * b1;
|
|
424
|
+
const a4 = 0.375 * (b1sq - 10 * a1sq * b1);
|
|
425
|
+
const a5 = 1.875 * a1 * b1sq;
|
|
426
|
+
const a6 = -0.3125 * b1sq * b1;
|
|
427
|
+
|
|
428
|
+
// W1, W2 ... W6 for the R-integrals
|
|
429
|
+
const e3 = ecc2 * ecc;
|
|
430
|
+
const e4 = ecc2 * ecc2;
|
|
431
|
+
const e5 = e3 * ecc2;
|
|
432
|
+
const e6 = e3 * e3;
|
|
433
|
+
|
|
434
|
+
const psq = p * p;
|
|
435
|
+
|
|
436
|
+
const p3 = psq * p;
|
|
437
|
+
const p4 = psq * psq;
|
|
438
|
+
const p5 = p3 * psq;
|
|
439
|
+
const p6 = p4 * psq;
|
|
440
|
+
|
|
441
|
+
const x21 = 1 / p;
|
|
442
|
+
const x22 = ecc / p;
|
|
443
|
+
|
|
444
|
+
const x33 = 0.5 * ecc2 / psq;
|
|
445
|
+
const x32 = 2 * ecc / psq;
|
|
446
|
+
const x31 = 1 / psq + x33;
|
|
447
|
+
|
|
448
|
+
const x44 = e3 / (3 * p3);
|
|
449
|
+
const x43 = 1.5 * ecc2 / p3;
|
|
450
|
+
const x42 = 3 * ecc / p3 + 2 * x44;
|
|
451
|
+
const x41 = 1 / p3 + x43;
|
|
452
|
+
|
|
453
|
+
const x55 = x33 * x33;
|
|
454
|
+
const x54 = 4 * x44 * x21;
|
|
455
|
+
const x53 = 3 * ecc2 / p4 + 1.5 * x55;
|
|
456
|
+
const x52 = 4 * ecc / p4 + 2 * x54;
|
|
457
|
+
const x51 = 1 / p4 + x53;
|
|
458
|
+
|
|
459
|
+
const x66 = 0.2 * e5 / p5;
|
|
460
|
+
const x65 = 1.25 * e4 / p5;
|
|
461
|
+
const x64 = 10 * e3 / (3 * p5) + 4 * x66 / 3;
|
|
462
|
+
const x63 = 5 * ecc2 / p5 + 1.5 * x65;
|
|
463
|
+
const x62 = 5 * ecc / p5 + 2 * x64;
|
|
464
|
+
const x61 = 1 / p5 + x63;
|
|
465
|
+
|
|
466
|
+
const x77 = e6 / (6 * p6);
|
|
467
|
+
const x76 = 1.2 * e5 / p6;
|
|
468
|
+
const x75 = 3.75 * e4 / p6 + 1.25 * x77;
|
|
469
|
+
const x74 = 20 * e3 / (3 * p6) + x76 / 0.75;
|
|
470
|
+
const x73 = 7.5 * ecc2 / p6 + 1.5 * x75;
|
|
471
|
+
const x72 = 6 * ecc / p6 + 2 * x74;
|
|
472
|
+
const x71 = 1 / p6 + x73;
|
|
473
|
+
|
|
474
|
+
const gg1si = 1.0 / Math.sqrt(gam1);
|
|
475
|
+
const gg1psi = gg1si / Math.sqrt(p);
|
|
476
|
+
|
|
477
|
+
// R1 coefficients
|
|
478
|
+
const cr11 = (rho1 + a1) * gg1si;
|
|
479
|
+
const cr12 = ecc * gg1si;
|
|
480
|
+
const cr13 = a2 * gg1psi;
|
|
481
|
+
const cr14 = a3 * gg1psi;
|
|
482
|
+
const cr15 = a4 * gg1psi;
|
|
483
|
+
const cr16 = a5 * gg1psi;
|
|
484
|
+
const cr17 = a6 * gg1psi;
|
|
485
|
+
|
|
486
|
+
// R2 coefficients
|
|
487
|
+
const cr21 = Math.sqrt(p0 / pgam1);
|
|
488
|
+
const cr22 = a1 * cr21;
|
|
489
|
+
const cr23 = a2 * cr21;
|
|
490
|
+
const cr24 = a3 * cr21;
|
|
491
|
+
const cr25 = a4 * cr21;
|
|
492
|
+
const cr26 = a5 * cr21;
|
|
493
|
+
const cr27 = a6 * cr21;
|
|
494
|
+
|
|
495
|
+
// R3 coefficients
|
|
496
|
+
const cr31 = alph3 * gg1psi;
|
|
497
|
+
const cr32 = a1 * cr31;
|
|
498
|
+
const cr33 = (a2 - csq) * cr31;
|
|
499
|
+
const cr34 = (a3 - a1 * csq) * cr31;
|
|
500
|
+
const cr35 = a4 * cr31 - csq * cr33;
|
|
501
|
+
|
|
502
|
+
// Coefficients for N-integrals
|
|
503
|
+
|
|
504
|
+
// N3 coefficients
|
|
505
|
+
const bmg = b - g;
|
|
506
|
+
const bpg = b + g;
|
|
507
|
+
const d1ma = 1 - a;
|
|
508
|
+
const d1pa = 1 + a;
|
|
509
|
+
const beta1 = bmg / d1ma;
|
|
510
|
+
const beta2 = -bpg / d1pa;
|
|
511
|
+
const b12 = beta1 * beta1;
|
|
512
|
+
const b13 = b12 * beta1;
|
|
513
|
+
const b22 = beta2 * beta2;
|
|
514
|
+
const b23 = b22 * beta2;
|
|
515
|
+
let xmm1 = Math.sqrt(1 - b12 * q2);
|
|
516
|
+
|
|
517
|
+
if (xmm1 * alph3 < 0) xmm1 = -xmm1;
|
|
518
|
+
|
|
519
|
+
let xmm2 = Math.sqrt(1 - b22 * q2);
|
|
520
|
+
|
|
521
|
+
if (xmm2 * alph3 < 0) xmm2 = -xmm2;
|
|
522
|
+
|
|
523
|
+
const d2 = delta / (p0 * (s1 - s0 * q1));
|
|
524
|
+
const d3 = q1 + 2 * p1 * d2;
|
|
525
|
+
const d4 = d1 * alph3 / (2 * alph2);
|
|
526
|
+
|
|
527
|
+
const d1md3 = 1 - d3;
|
|
528
|
+
const bmag = b - a * g;
|
|
529
|
+
|
|
530
|
+
const d10 = bmag / bmg * Math.sqrt(d1md3 / (d5 * (1 - xm / b12) * (1 - 2 * d2)));
|
|
531
|
+
const d20 = bmag / bpg * Math.sqrt(d1md3 / (d5 * (1 - xm / b22) * (1 + 2 * d2)));
|
|
532
|
+
|
|
533
|
+
const dd2 = xm / 2;
|
|
534
|
+
const dd3 = dd2 * g;
|
|
535
|
+
const dd4 = 1.5 * dd2 * dd2;
|
|
536
|
+
const dd5 = dd4 * g;
|
|
537
|
+
const dd6 = dd2 * dd4 / 0.6;
|
|
538
|
+
|
|
539
|
+
const c15 = dd6 / (b13 * b13);
|
|
540
|
+
const c14 = c15 + dd5 / (b12 * b13);
|
|
541
|
+
const c13 = c14 + dd4 / (b12 * b12);
|
|
542
|
+
const c12 = c13 + dd3 / b13;
|
|
543
|
+
const c11 = c12 + dd2 / b12;
|
|
544
|
+
const c10 = c11 + g / beta1;
|
|
545
|
+
|
|
546
|
+
const c25 = dd6 / (b23 * b23);
|
|
547
|
+
const c24 = c25 + dd5 / (b22 * b23);
|
|
548
|
+
const c23 = c24 + dd4 / (b22 * b22);
|
|
549
|
+
const c22 = c23 + dd3 / b23;
|
|
550
|
+
const c21 = c22 + dd2 / b22;
|
|
551
|
+
const c20 = c21 + g / beta2;
|
|
552
|
+
|
|
553
|
+
const b1q = beta1 * q;
|
|
554
|
+
const b1q2 = b1q * b1q;
|
|
555
|
+
const b1q4 = b1q2 * b1q2;
|
|
556
|
+
const b2q = beta2 * q;
|
|
557
|
+
const b2q2 = b2q * b2q;
|
|
558
|
+
const b2q4 = b2q2 * b2q2;
|
|
559
|
+
|
|
560
|
+
// N1 and N2 coefficients
|
|
561
|
+
const xk12 = xk1 * xk1;
|
|
562
|
+
const xk13 = xk12 * xk1;
|
|
563
|
+
|
|
564
|
+
// Byrd and Friedman formula for elliptic integral
|
|
565
|
+
const sq = xk1 / 16 + xk12 / 32 + 21 * xk13 / 1024;
|
|
566
|
+
const sq2 = sq * sq;
|
|
567
|
+
const sq3 = sq2 * sq;
|
|
568
|
+
|
|
569
|
+
const ucf1 = 2 * sq / (1 + sq2);
|
|
570
|
+
const ucf2 = sq2 / (1 + sq2 * sq2);
|
|
571
|
+
const ucf3 = 2.0 * sq3 / (3.0 * (1 + sq3 * sq3));
|
|
572
|
+
|
|
573
|
+
const denystt = 1 + sq + sq;
|
|
574
|
+
const denyst = denystt * denystt * d1;
|
|
575
|
+
|
|
576
|
+
// N1 coefficients
|
|
577
|
+
const d1a2 = d1 / alph2;
|
|
578
|
+
const cn11 = d1a2 * asq;
|
|
579
|
+
const cn12 = d1a2 * 2 * ab * q;
|
|
580
|
+
const cn13 = d1a2 * (bsq - 4 * ab * g) * q2;
|
|
581
|
+
const cn14 = d1a2 * (xm * ab - 2 * bsq * g) * q2 * q;
|
|
582
|
+
const cn15 = d1a2 * (3 * bsq * g2 + xm * bsq / 2) * q4;
|
|
583
|
+
const cn16 = -d1a2 * xm * bsq * g * q4 * q;
|
|
584
|
+
const cn17 = 0.375 * d1a2 * xm * xm * bsq * q4 * q2;
|
|
585
|
+
|
|
586
|
+
// N2 coefficients
|
|
587
|
+
const cn22 = 0.5 * xk1 * d1;
|
|
588
|
+
const cn24 = 0.375 * xk12 * d1;
|
|
589
|
+
const cn26 = 0.3125 * xk13 * d1;
|
|
590
|
+
|
|
591
|
+
// N3 coefficients
|
|
592
|
+
const d41ma = d4 / d1ma;
|
|
593
|
+
const d41pa = d4 / d1pa;
|
|
594
|
+
|
|
595
|
+
const cn31 = -d41ma * c10 - d41pa * c20;
|
|
596
|
+
const cn32 = -d41ma * c11 * b1q - d41pa * c21 * b2q;
|
|
597
|
+
const cn33 = -d41ma * c12 * b1q2 - d41pa * c22 * b2q2;
|
|
598
|
+
const cn34 = -d41ma * c13 * b1q2 * b1q - d41pa * c23 * b2q2 * b2q;
|
|
599
|
+
const cn35 = -d41ma * c14 * b1q4 - d41pa * c24 * b2q4;
|
|
600
|
+
const cn36 = -d41ma * c15 * b1q4 * b1q - d41pa * c25 * b2q4 * b2q;
|
|
601
|
+
|
|
602
|
+
// Avoid singularity at zero inclination
|
|
603
|
+
let u;
|
|
604
|
+
if (q === 0.0) {
|
|
605
|
+
u = 0;
|
|
606
|
+
} else {
|
|
607
|
+
const d5sq = Math.sqrt(s1 * p0 * (1 + p1 * sigma0 - q1 * sigma0 * sigma0));
|
|
608
|
+
const utn = (sigma0 - a) * d5sq;
|
|
609
|
+
const utd = sqrg * Math.sqrt(1 - g2 * q2);
|
|
610
|
+
|
|
611
|
+
u = Math.atan2(utn, utd);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Calculate Tk = tk, k = 0, T0 = t0 = u. Here k = 1, ... ,6
|
|
615
|
+
let csu = Math.cos(u);
|
|
616
|
+
let snu = Math.sin(u);
|
|
617
|
+
let snu2 = snu * snu;
|
|
618
|
+
let snu4 = snu2 * snu2;
|
|
619
|
+
|
|
620
|
+
let t1 = 1 - csu;
|
|
621
|
+
let t2 = (u - csu * snu) / 2;
|
|
622
|
+
let t3 = (2 * t1 - csu * snu2) / 3;
|
|
623
|
+
let t4 = (3 * t2 - csu * snu2 * snu) / 4;
|
|
624
|
+
let t5 = (4 * t3 - csu * snu4) / 5;
|
|
625
|
+
let t6 = (5 * t4 - csu * snu4 * snu) / 6;
|
|
626
|
+
|
|
627
|
+
// Compute xhat at initial time
|
|
628
|
+
let xhat;
|
|
629
|
+
if (gamma < -1.0e-14) { // Ellipse
|
|
630
|
+
if (Math.abs(ecc) < 1.0e-10
|
|
631
|
+
|| Math.abs(sqrf) < 1.0e-10
|
|
632
|
+
|| Math.abs(rho0 - rho1) < 1e-5) {
|
|
633
|
+
xhat = 0;
|
|
634
|
+
} else {
|
|
635
|
+
const shat = Math.abs(sqrf) / sqrf * Math.sqrt(gamma * rho02 + 2 * rho0 - p) / ecc;
|
|
636
|
+
const cacs = (rho0 - rho1) * gamma / ecc + 1;
|
|
637
|
+
let acs = Math.atan2(shat * smgam, cacs);
|
|
638
|
+
|
|
639
|
+
if (acs < 0) acs = twopi + acs;
|
|
640
|
+
|
|
641
|
+
xhat = acs / smgam;
|
|
642
|
+
}
|
|
643
|
+
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
644
|
+
if (Math.abs(ecc) < 1.0e-10 || Math.abs(sqrf) < 1.0e-10) {
|
|
645
|
+
xhat = 0.0;
|
|
646
|
+
} else {
|
|
647
|
+
const chat = (rho0 - rho1) / ecc;
|
|
648
|
+
const zz = gamma * chat + 1;
|
|
649
|
+
xhat = Math.log(zz + Math.sqrt(zz * zz - 1)) / Math.sqrt(gamma);
|
|
650
|
+
|
|
651
|
+
if (sqrf < 0) xhat = -xhat;
|
|
652
|
+
}
|
|
653
|
+
} else { // Parabola
|
|
654
|
+
xhat = rrd;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// ========== STEP 5: Last three Jacobi constants ==========
|
|
658
|
+
// Determine true anomaly from xhat at t0
|
|
659
|
+
let eca = smgam * xhat;
|
|
660
|
+
let tra; let chat; let shat;
|
|
661
|
+
|
|
662
|
+
if (gamma < -1.0e-14) { // Ellipse
|
|
663
|
+
sneca = Math.sin(eca);
|
|
664
|
+
cneca = Math.cos(eca);
|
|
665
|
+
const s1mes = Math.sqrt(1 - ecc2);
|
|
666
|
+
const temp3 = 2 * Math.atan(ecc * sneca / (1 + s1mes - ecc * cneca));
|
|
667
|
+
tra = eca + temp3;
|
|
668
|
+
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
669
|
+
sneca = Math.sinh(eca);
|
|
670
|
+
cneca = Math.cosh(eca);
|
|
671
|
+
|
|
672
|
+
chat = (cneca - 1) / gamma;
|
|
673
|
+
shat = sneca / smgam;
|
|
674
|
+
tra = Math.atan2(Math.sqrt(p) * shat, rho1 - chat);
|
|
675
|
+
} else { // Parabola
|
|
676
|
+
tra = 2 * Math.atan(xhat / Math.sqrt(p));
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
let snw = Math.sin(tra);
|
|
680
|
+
let cnw = Math.cos(tra);
|
|
681
|
+
let ecccnw = ecc * cnw;
|
|
682
|
+
|
|
683
|
+
// const dw1dx = (1 + ecccnw) / p;
|
|
684
|
+
// const dw2dx = dw1dx * dw1dx; same case. Astrolibrary does not use this instance of dw2dx here but does so later in the code after it is redeclared
|
|
685
|
+
|
|
686
|
+
const v3 = snw * cnw;
|
|
687
|
+
const v4 = v3 * cnw;
|
|
688
|
+
const v5 = v4 * cnw;
|
|
689
|
+
const v6 = v5 * cnw;
|
|
690
|
+
const v7 = v6 * cnw;
|
|
691
|
+
|
|
692
|
+
let w1 = x21 * tra + x22 * snw;
|
|
693
|
+
let w2 = x31 * tra + x32 * snw + x33 * v3;
|
|
694
|
+
let w3 = x41 * tra + x42 * snw + x43 * v3 + x44 * v4;
|
|
695
|
+
let w4 = x51 * tra + x52 * snw + x53 * v3 + x54 * v4 + x55 * v5;
|
|
696
|
+
let w5 = x61 * tra + x62 * snw + x63 * v3 + x64 * v4 + x65 * v5 + x66 * v6;
|
|
697
|
+
let w6 = x71 * tra + x72 * snw + x73 * v3 + x74 * v4 + x75 * v5 + x76 * v6 + x77 * v7;
|
|
698
|
+
|
|
699
|
+
let uhat;
|
|
700
|
+
if (Math.abs(gamma) >= 1.0e-14) { // Circle, ellipse, hyperbola
|
|
701
|
+
chat = (cneca - 1) / gamma;
|
|
702
|
+
uhat = (sneca - eca) / gams3;
|
|
703
|
+
} else { // Parabola
|
|
704
|
+
chat = xhat * xhat / 2;
|
|
705
|
+
uhat = xhat * xhat * xhat / 6;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const r1 = cr11 * xhat + cr12 * uhat + cr13 * tra
|
|
709
|
+
+ cr14 * w1 + cr15 * w2 + cr16 * w3 + cr17 * w4;
|
|
710
|
+
const r2 = cr21 * tra + cr22 * w1 + cr23 * w2 + cr24
|
|
711
|
+
* w3 + cr25 * w4 + cr26 * w5 + cr27 * w6;
|
|
712
|
+
|
|
713
|
+
let sstar = Math.sin(0.5 * u);
|
|
714
|
+
let cstar = Math.cos(0.5 * u);
|
|
715
|
+
let cb1qs = cstar - b1q * sstar;
|
|
716
|
+
let psi1 = Math.atan(xmm1 * sstar / cb1qs);
|
|
717
|
+
|
|
718
|
+
if (cb1qs * Math.cos(psi1) < 0.0) psi1 = pi + psi1;
|
|
719
|
+
|
|
720
|
+
let cb2qs = cstar - b2q * sstar;
|
|
721
|
+
let psi2 = Math.atan(xmm2 * sstar / cb2qs);
|
|
722
|
+
|
|
723
|
+
if (cb2qs * Math.cos(psi2) < 0.0) psi2 = pi + psi2;
|
|
724
|
+
|
|
725
|
+
let r3 = cr31 * w2 + cr32 * w3 + cr33 * w4 + cr34 * w5 + cr35 * w6;
|
|
726
|
+
|
|
727
|
+
let en3 = d10 * psi1 + d20 * psi2 + cn31 * u + cn32
|
|
728
|
+
* t1 + cn33 * t2 + cn34 * t3 + cn35 * t4 + cn36 * t5;
|
|
729
|
+
const en1 = cn11 * u + cn12 * t1 + cn13 * t2 + cn14
|
|
730
|
+
* t3 + cn15 * t4 + cn16 * t5 + cn17 * t6;
|
|
731
|
+
const en2 = d1 * u + cn22 * t2 + cn24 * t4 + cn26 * t6;
|
|
732
|
+
|
|
733
|
+
const somega = en2 - r2; // beta2
|
|
734
|
+
const capt = t0 - r1 - csq * en1; // -beta1
|
|
735
|
+
const deltat = tf - capt;
|
|
736
|
+
const comega = alph0 + csq * r3 - en3; // beta3
|
|
737
|
+
|
|
738
|
+
oe[3] = -capt * timeFactor; // Vinti mean element "beta1"
|
|
739
|
+
oe[4] = somega; // Vinti mean element "beta2"
|
|
740
|
+
oe[5] = comega; // Vinti mean element "beta3"
|
|
741
|
+
|
|
742
|
+
// ========== STEP 6: Solve kinematical equations ==========
|
|
743
|
+
// The generalized Kepler equation is solved by iteration
|
|
744
|
+
xhat += xhat0;
|
|
745
|
+
|
|
746
|
+
// Variables already declared earlier, will be reassigned in loop
|
|
747
|
+
|
|
748
|
+
for (let ick = 1; ick <= 10; ick++) {
|
|
749
|
+
eca = smgam * xhat;
|
|
750
|
+
|
|
751
|
+
if (gamma < -1.0e-14) { // Ellipse
|
|
752
|
+
sneca = Math.sin(eca);
|
|
753
|
+
cneca = Math.cos(eca);
|
|
754
|
+
const s1mes = Math.sqrt(1 - ecc2);
|
|
755
|
+
const temp3 = 2 * Math.atan(ecc * sneca / (1 + s1mes - ecc * cneca));
|
|
756
|
+
tra = eca + temp3;
|
|
757
|
+
} else if (gamma > 1.0e-14) { // Hyperbola
|
|
758
|
+
sneca = Math.sinh(eca);
|
|
759
|
+
cneca = Math.cosh(eca);
|
|
760
|
+
chat = (cneca - 1) / gamma;
|
|
761
|
+
shat = sneca / smgam;
|
|
762
|
+
tra = Math.atan2(Math.sqrt(p) * shat, rho1 - chat);
|
|
763
|
+
} else { // Parabola
|
|
764
|
+
tra = 2 * Math.atan(xhat / Math.sqrt(p));
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
snw = Math.sin(tra);
|
|
768
|
+
cnw = Math.cos(tra);
|
|
769
|
+
ecccnw = ecc * cnw;
|
|
770
|
+
|
|
771
|
+
const dwdx = (1 + ecccnw) / Math.sqrt(p);
|
|
772
|
+
const dw1dx = (1 + ecccnw) / p;
|
|
773
|
+
const dw2dx = dw1dx * dw1dx;
|
|
774
|
+
const dw3dx = dw1dx * dw2dx;
|
|
775
|
+
const dw4dx = dw2dx * dw2dx;
|
|
776
|
+
|
|
777
|
+
const v3 = snw * cnw;
|
|
778
|
+
const v4 = v3 * cnw;
|
|
779
|
+
const v5 = v4 * cnw;
|
|
780
|
+
const v6 = v5 * cnw;
|
|
781
|
+
const v7 = v6 * cnw;
|
|
782
|
+
|
|
783
|
+
w1 = x21 * tra + x22 * snw;
|
|
784
|
+
w2 = x31 * tra + x32 * snw + x33 * v3;
|
|
785
|
+
w3 = x41 * tra + x42 * snw + x43 * v3 + x44 * v4;
|
|
786
|
+
w4 = x51 * tra + x52 * snw + x53 * v3 + x54 * v4 + x55 * v5;
|
|
787
|
+
w5 = x61 * tra + x62 * snw + x63 * v3 + x64 * v4 + x65 * v5 + x66 * v6;
|
|
788
|
+
w6 = x71 * tra + x72 * snw + x73 * v3 + x74 * v4 + x75 * v5 + x76 * v6 + x77 * v7;
|
|
789
|
+
|
|
790
|
+
if (Math.abs(gamma) >= 1.0e-14) {
|
|
791
|
+
chat = (cneca - 1) / gamma;
|
|
792
|
+
uhat = (sneca - eca) / gams3;
|
|
793
|
+
} else { // Parabola
|
|
794
|
+
chat = xhat * xhat / 2;
|
|
795
|
+
uhat = xhat * xhat * xhat / 6;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const r1 = cr11 * xhat
|
|
799
|
+
+ cr12 * uhat
|
|
800
|
+
+ cr13 * tra
|
|
801
|
+
+ cr14 * w1
|
|
802
|
+
+ cr15 * w2
|
|
803
|
+
+ cr16 * w3
|
|
804
|
+
+ cr17 * w4;
|
|
805
|
+
const r2
|
|
806
|
+
= cr21 * tra
|
|
807
|
+
+ cr22 * w1
|
|
808
|
+
+ cr23 * w2
|
|
809
|
+
+ cr24 * w3
|
|
810
|
+
+ cr25 * w4
|
|
811
|
+
+ cr26 * w5
|
|
812
|
+
+ cr27 * w6;
|
|
813
|
+
|
|
814
|
+
const ystar = (r2 + somega) / denyst;
|
|
815
|
+
u = ystar
|
|
816
|
+
+ ucf1 * Math.sin(2 * ystar)
|
|
817
|
+
+ ucf2 * Math.sin(4 * ystar)
|
|
818
|
+
+ ucf3 * Math.sin(6 * ystar);
|
|
819
|
+
|
|
820
|
+
csu = Math.cos(u);
|
|
821
|
+
snu = Math.sin(u);
|
|
822
|
+
snu2 = snu * snu;
|
|
823
|
+
snu4 = snu2 * snu2;
|
|
824
|
+
|
|
825
|
+
t1 = 1 - csu;
|
|
826
|
+
t2 = (u - csu * snu) / 2;
|
|
827
|
+
t3 = (2 * t1 - csu * snu2) / 3;
|
|
828
|
+
t4 = (3 * t2 - csu * snu2 * snu) / 4;
|
|
829
|
+
t5 = (4 * t3 - csu * snu4) / 5;
|
|
830
|
+
t6 = (5 * t4 - csu * snu4 * snu) / 6;
|
|
831
|
+
|
|
832
|
+
const en1 = cn11 * u
|
|
833
|
+
+ cn12 * t1
|
|
834
|
+
+ cn13 * t2
|
|
835
|
+
+ cn14 * t3
|
|
836
|
+
+ cn15 * t4
|
|
837
|
+
+ cn16 * t5
|
|
838
|
+
+ cn17 * t6;
|
|
839
|
+
|
|
840
|
+
const cn1r1 = csq * en1 + r1;
|
|
841
|
+
const psixhat = cn1r1 - deltat; // Function
|
|
842
|
+
|
|
843
|
+
const dpsx1 = cr13 + cr14 * dw1dx + cr15 * dw2dx + cr16 * dw3dx + cr17 * dw4dx;
|
|
844
|
+
const dpsx = cr11 + cr12 * chat + dpsx1 * dwdx; // 1st derivative
|
|
845
|
+
const delx = psixhat / dpsx;
|
|
846
|
+
|
|
847
|
+
xhat -= delx;
|
|
848
|
+
|
|
849
|
+
if (Math.abs(delx) < 1.0e-14) break;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// ========== STEP 7: Final coordinate transformation ==========
|
|
853
|
+
// OSC state vector is (rhof, sigmaf, alphaf, drhof, dsigf, dalphf)
|
|
854
|
+
// ECI state vector is (pf, vf)
|
|
855
|
+
|
|
856
|
+
sstar = Math.sin(0.5 * u);
|
|
857
|
+
cstar = Math.cos(0.5 * u);
|
|
858
|
+
cb1qs = cstar - b1q * sstar;
|
|
859
|
+
psi1 = Math.atan(xmm1 * sstar / cb1qs);
|
|
860
|
+
|
|
861
|
+
if (cb1qs * Math.cos(psi1) < 0) psi1 = pi + psi1;
|
|
862
|
+
|
|
863
|
+
cb2qs = cstar - b2q * sstar;
|
|
864
|
+
psi2 = Math.atan(xmm2 * sstar / cb2qs);
|
|
865
|
+
|
|
866
|
+
if (cb2qs * Math.cos(psi2) < 0) psi2 = pi + psi2;
|
|
867
|
+
|
|
868
|
+
r3 = cr31 * w2 + cr32 * w3 + cr33 * w4 + cr34 * w5 + cr35 * w6;
|
|
869
|
+
en3 = d10 * psi1
|
|
870
|
+
+ d20 * psi2
|
|
871
|
+
+ cn31 * u
|
|
872
|
+
+ cn32 * t1
|
|
873
|
+
+ cn33 * t2
|
|
874
|
+
+ cn34 * t3
|
|
875
|
+
+ cn35 * t4
|
|
876
|
+
+ cn36 * t5;
|
|
877
|
+
const qsnu = q * snu;
|
|
878
|
+
const alphaf = comega - csq * r3 + en3;
|
|
879
|
+
const rhof = rho1 + ecc * chat;
|
|
880
|
+
const sigmaf = (a + b * qsnu) / (1 + g * qsnu);
|
|
881
|
+
|
|
882
|
+
const rhof2 = rhof * rhof;
|
|
883
|
+
const sigf2 = sigmaf * sigmaf;
|
|
884
|
+
|
|
885
|
+
const rhocsq = rhof2 + csq;
|
|
886
|
+
const df = Math.sqrt(rhocsq * (1 - sigf2));
|
|
887
|
+
const snalp = Math.sin(alphaf);
|
|
888
|
+
const csalp = Math.cos(alphaf);
|
|
889
|
+
|
|
890
|
+
const pf = new NodeVector3D(df * csalp, df * snalp, rhof * sigmaf - delta);
|
|
891
|
+
|
|
892
|
+
shat = xhat + gamma * uhat;
|
|
893
|
+
rcs = rhof2 + csq * sigf2;
|
|
894
|
+
|
|
895
|
+
const rhoqd = rhof2 - 2 * a1 * rhof + b1;
|
|
896
|
+
const drhofp = Math.sqrt(gam1 * rhoqd) / rcs;
|
|
897
|
+
const drhof = ecc * shat * drhofp;
|
|
898
|
+
const temp12 = (1 + p1 * sigmaf - q1 * sigf2) * (1 - g2 * q2) * s1;
|
|
899
|
+
const dsigf = alph2 * q * Math.sqrt(temp12) / rcs * csu / (1 + g * qsnu);
|
|
900
|
+
const temp20 = (1 - sigf2) * (rhof * drhof);
|
|
901
|
+
const temp21 = rhocsq * sigmaf * dsigf;
|
|
902
|
+
const dd = (temp20 - temp21) / df;
|
|
903
|
+
const dalphf = alph3 / (df * df);
|
|
904
|
+
|
|
905
|
+
const vf = new NodeVector3D(
|
|
906
|
+
dd * csalp - pf.y * dalphf,
|
|
907
|
+
dd * snalp + pf.x * dalphf,
|
|
908
|
+
sigmaf * drhof + rhof * dsigf,
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
// Change from astronomical units to SI units - using pious-squid Vector3D scale method
|
|
912
|
+
x1.position = pf.scale(ae);
|
|
913
|
+
x1.velocity = vf.scale(ve);
|
|
914
|
+
|
|
915
|
+
return x1;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Main Ballistic Propagator class
|
|
921
|
+
* Refactored to use existing constants and Vector3D class
|
|
922
|
+
*/
|
|
923
|
+
class BallisticPropagator {
|
|
924
|
+
constructor(baseStateVector, options = {}) {
|
|
925
|
+
this.baseStateVector = baseStateVector;
|
|
926
|
+
this.planetEquatorialRadiusKm
|
|
927
|
+
= options.equatorialRadius || EarthConstants.EquatorialRadiusKm;
|
|
928
|
+
this.mu = options.mu || EarthConstants.Mu;
|
|
929
|
+
this.j2 = options.j2 || EarthConstants.J2;
|
|
930
|
+
this.j3 = options.j3 || EarthConstants.J3;
|
|
931
|
+
this.referenceFrame = options.referenceFrame || "J2000";
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Propagate state vector to target time
|
|
936
|
+
* @param {Date|number} targetTime - Target time as Date or seconds from epoch
|
|
937
|
+
* @return {Object} Propagated state with position and velocity
|
|
938
|
+
*/
|
|
939
|
+
propagate(targetTime) {
|
|
940
|
+
let spanSeconds;
|
|
941
|
+
|
|
942
|
+
if (targetTime instanceof Date) {
|
|
943
|
+
spanSeconds = (targetTime - this.baseStateVector.epochUtc) / 1000;
|
|
944
|
+
} else {
|
|
945
|
+
spanSeconds = targetTime;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Create PosVelVec using pious-squid Vector3D
|
|
949
|
+
// Handle both lowercase and uppercase property names, but check for undefined specifically
|
|
950
|
+
const getComponent = (vector, lowerProp, upperProp) => {
|
|
951
|
+
return vector[lowerProp] !== undefined ? vector[lowerProp] : vector[upperProp];
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
const x0 = new PosVelVec(
|
|
955
|
+
new NodeVector3D(
|
|
956
|
+
getComponent(this.baseStateVector.position, "x", "X"),
|
|
957
|
+
getComponent(this.baseStateVector.position, "y", "Y"),
|
|
958
|
+
getComponent(this.baseStateVector.position, "z", "Z"),
|
|
959
|
+
),
|
|
960
|
+
new NodeVector3D(
|
|
961
|
+
getComponent(this.baseStateVector.velocity, "x", "X"),
|
|
962
|
+
getComponent(this.baseStateVector.velocity, "y", "Y"),
|
|
963
|
+
getComponent(this.baseStateVector.velocity, "z", "Z"),
|
|
964
|
+
),
|
|
965
|
+
);
|
|
966
|
+
|
|
967
|
+
const x1 = BallisticPropagatorUtils.ballisticProp(
|
|
968
|
+
x0,
|
|
969
|
+
spanSeconds,
|
|
970
|
+
this.planetEquatorialRadiusKm,
|
|
971
|
+
this.mu,
|
|
972
|
+
this.j2,
|
|
973
|
+
this.j3,
|
|
974
|
+
);
|
|
975
|
+
|
|
976
|
+
return {
|
|
977
|
+
position: x1.position,
|
|
978
|
+
velocity: x1.velocity,
|
|
979
|
+
epochUtc: targetTime instanceof Date
|
|
980
|
+
? targetTime
|
|
981
|
+
: new Date(this.baseStateVector.epochUtc.getTime() + spanSeconds * 1000),
|
|
982
|
+
referenceFrame: this.referenceFrame,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Export for Node.js
|
|
988
|
+
export {BallisticPropagator, BallisticPropagatorUtils, PosVelVec, EarthConstants};
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* REFACTORING SUMMARY:
|
|
992
|
+
* ===================
|
|
993
|
+
*
|
|
994
|
+
* REPLACED IMPLEMENTATIONS:
|
|
995
|
+
* 1. EarthConstants - Now uses values from ./constants.js:
|
|
996
|
+
* - EquatorialRadiusKm: WGS84_EARTH_EQUATORIAL_RADIUS_KM (6378.137 km)
|
|
997
|
+
* - Mu: MU converted from m³/s² to km³/s² (398600.4418)
|
|
998
|
+
* - J2 and J3: Kept original values as they're specific to Vinti propagator
|
|
999
|
+
*
|
|
1000
|
+
* 2. Vector3D - Now imports and uses pious-squid's Vector3D class:
|
|
1001
|
+
* - Uses magnitude() instead of length property
|
|
1002
|
+
* - Uses scale() instead of scaleBy() method
|
|
1003
|
+
* - Uses add() and dot() methods directly from pious-squid
|
|
1004
|
+
* - All vector operations now use the robust pious-squid implementation
|
|
1005
|
+
*
|
|
1006
|
+
* 3. Mathematical operations:
|
|
1007
|
+
* - Vector magnitude calculations use pious-squid's magnitude() method
|
|
1008
|
+
* - Vector scaling uses pious-squid's scale() method
|
|
1009
|
+
* - Vector addition uses pious-squid's add() method
|
|
1010
|
+
* - Dot product uses pious-squid's dot() method
|
|
1011
|
+
*
|
|
1012
|
+
* BENEFITS:
|
|
1013
|
+
* - Reduced code duplication (removed ~100 lines of custom Vector3D implementation)
|
|
1014
|
+
* - Uses standardized, well-tested vector operations from pious-squid
|
|
1015
|
+
* - Uses standardized Earth constants from node-common constants.js
|
|
1016
|
+
* - Maintains 100% functional compatibility with original implementation
|
|
1017
|
+
* - Better maintainability through shared library usage
|
|
1018
|
+
*
|
|
1019
|
+
* EXAMPLE USAGE (unchanged):
|
|
1020
|
+
* ==========================
|
|
1021
|
+
*
|
|
1022
|
+
* // ISS-like circular orbit
|
|
1023
|
+
* const initialState = {
|
|
1024
|
+
* position: new Vector3D(6778.137, 0, 0), // km
|
|
1025
|
+
* velocity: new Vector3D(0, 7.66779, 0), // km/s
|
|
1026
|
+
* epochUtc: new Date('2025-01-01T00:00:00Z'),
|
|
1027
|
+
* referenceFrame: 'J2000'
|
|
1028
|
+
* };
|
|
1029
|
+
*
|
|
1030
|
+
* const propagator = new BallisticPropagator(initialState);
|
|
1031
|
+
*
|
|
1032
|
+
* // Propagate for 5 minutes (300 seconds)
|
|
1033
|
+
* const result = propagator.propagate(300);
|
|
1034
|
+
*
|
|
1035
|
+
* console.log('Position after 300s:', result.position);
|
|
1036
|
+
* console.log('Velocity after 300s:', result.velocity);
|
|
1037
|
+
*/
|