skycraft: slightly better orbit calculation
This commit is contained in:
parent
4e2d522602
commit
3e9bad8929
@ -362,62 +362,77 @@ function normalizeAngle(theta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Let's be honest I should clean this up.
|
/** Let's be honest I should clean this up.
|
||||||
* Right now it mostly only works with elliptical orbits (e < 1),
|
|
||||||
* which is fine for planets & stuff, but not for my spacecraft (or comets)
|
|
||||||
*
|
*
|
||||||
* This is the part that solves Kepler's equation using Newton's method.
|
* This is the part that solves Kepler's equation using Newton's method.
|
||||||
* For circular-ish orbits, one or two iterations are usually enough.
|
* For circular-ish orbits, one or two iterations are usually enough.
|
||||||
* More excentric orbits can take more (6 or 7?).
|
* More excentric orbits can take more (6 or 7?).
|
||||||
|
*
|
||||||
|
* For near-parabolic orbits (and some others?) it often fails to converge...
|
||||||
*/
|
*/
|
||||||
function getCartesianPosition(orbit, mu, time) {
|
function getCartesianState(orbit, mu, time) {
|
||||||
const {
|
const {
|
||||||
excentricity: e,
|
excentricity: e,
|
||||||
semimajorAxis: a,
|
semimajorAxis: a,
|
||||||
inclination: i,
|
inclination: i,
|
||||||
ascendingNodeLongitude: Om,
|
ascendingNodeLongitude: Om,
|
||||||
periapsisArgument: w,
|
periapsisArgument: w,
|
||||||
|
t0,
|
||||||
} = orbit;
|
} = orbit;
|
||||||
const n = Math.sqrt(mu/(a**3)); // mean motion
|
let n = Math.sqrt(mu/(a**3));
|
||||||
const M = n * time; // mean anomaly
|
if (a < 0) {
|
||||||
// const nu = (
|
n = Math.sqrt(mu/-(a**3)); // mean motion
|
||||||
// M
|
}
|
||||||
// + (2 * e - e**3 / 4) * Math.sin(M)
|
const M = n * (time - t0); // mean anomaly
|
||||||
// + 5/4 * e**2 * Math.sin(2*M)
|
|
||||||
// + 13/12 * e**3 * Math.sin(3*M)
|
|
||||||
// ); // true anomaly, doesn't work :(
|
|
||||||
|
|
||||||
// Newton's method
|
// Newton's method
|
||||||
var E2;
|
var E2 = 0;
|
||||||
var E = M;
|
var E = orbit.lastE || M;
|
||||||
for (var j = 1; j < 20; ++j) {
|
let iterations = 0;
|
||||||
|
// a clever guess? https://link.springer.com/article/10.1023/A:1008200607490
|
||||||
|
// doesn't work at all.
|
||||||
|
|
||||||
|
while (Math.abs(E - E2) > 1e-10) {
|
||||||
if (e < 0.001) {
|
if (e < 0.001) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
E = E2;
|
||||||
if (e < 1) {
|
if (e < 1) {
|
||||||
E2 = E - (E - e * Math.sin(E) - M) / (1 - e * Math.cos(E));
|
E2 = E - (E - e * Math.sin(E) - M) / (1 - e * Math.cos(E));
|
||||||
} else if (e > 1) {
|
} else if (e > 1) {
|
||||||
E2 = E - (-E + e * sinh(E) - M) / (e * cosh(E) - 1);
|
E2 = E - (-E + e * Math.sinh(E) - M) / (e * Math.cosh(E) - 1);
|
||||||
} else {
|
} else {
|
||||||
E2 = E - (E + E*E*E/3 - M) / (1 + E*E);
|
E2 = E - (E + E*E*E/3 - M) / (1 + E*E);
|
||||||
}
|
}
|
||||||
if (Math.abs(E - E2) < 1e-10) {
|
|
||||||
break;
|
iterations++;
|
||||||
|
if (iterations > 100) {
|
||||||
|
console.log('numerical instability');
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
E = E2;
|
|
||||||
}
|
}
|
||||||
const nu = 2 * Math.atan(Math.sqrt((1+e) / (1-e)) * Math.tan(E/2));
|
orbit.lastE = E;
|
||||||
const r = a * (1 - e**2) / (1 + e * Math.cos(nu));
|
let nu;
|
||||||
|
if (e > 1) {
|
||||||
|
nu = 2 * Math.atan(Math.sqrt((e+1) / (e-1)) * Math.tanh(E/2));
|
||||||
|
} else {
|
||||||
|
nu = 2 * Math.atan(Math.sqrt((1+e) / (1-e)) * Math.tan(E/2));
|
||||||
|
}
|
||||||
|
const p = a * (1 - e**2);
|
||||||
|
const r = p / (1 + e * Math.cos(nu));// * ((a < 0) ? -1 : 1);
|
||||||
|
const rd = e * Math.sqrt(mu / p) * Math.sin(nu);
|
||||||
|
|
||||||
const cOm = Math.cos(Om);
|
if (orbit.tf === undefined) {
|
||||||
const sOm = Math.sin(Om);
|
orbit.tf = [se3.rotz(Om), se3.rotx(i), se3.rotz(w)].reduce(se3.product);
|
||||||
const cwnu = Math.cos(w + nu);
|
}
|
||||||
const swnu = Math.sin(w + nu);
|
|
||||||
|
|
||||||
const x = r * Math.cos(i) * (cOm * cwnu - sOm * swnu);
|
const tf = se3.product(orbit.tf, se3.rotz(nu));
|
||||||
const y = r * (sOm * cwnu + cOm * swnu);
|
const pos = se3.apply(tf, [r, 0, 0, 1]);
|
||||||
const z = r * Math.sin(i) * cwnu;
|
const vel = se3.apply(tf, [rd, Math.sqrt(p * mu) / r, 0, 1]);
|
||||||
|
|
||||||
return [x, y, z];
|
return {
|
||||||
|
position: pos.slice(0, 3),
|
||||||
|
velocity: vel.slice(0, 3),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrientation(body, time) {
|
function getOrientation(body, time) {
|
||||||
|
Loading…
Reference in New Issue
Block a user