/// <summary> /// Compute the transfer time for the minimum energy transfer. /// </summary> /// <returns></returns> private double ComputeMinTime(ref double[] r0, ref double[] r, NBody centerBody, bool shortPath) { // Fundamentals of Astrodynamics and Applications, Vallado, 4th Ed., Algorithm 56 p475 // Take r0, r => a_min, e_min, t_min // This approach assumes r > r0. // If we have r0 > r then need to flip them and then reverse the velocities when doing the // maneuver determination double[] center = new double[] { 0, 0, 0 }; GravityEngine ge = GravityEngine.Instance(); ge.GetPositionDouble(centerBody, ref center); Vector3d center3d = new Vector3d(ref center); Vector3d r0_vec = new Vector3d(ref r0) - center3d; Vector3d r_vec = new Vector3d(ref r) - center3d; double r0_mag = Vector3d.Magnitude(r0_vec); double r_mag = Vector3d.Magnitude(r_vec); double cos_delta_nu = Vector3d.Dot(r0_vec, r_vec) / (r0_mag * r_mag); double c = System.Math.Sqrt(r0_mag * r0_mag + r_mag * r_mag - 2 * r0_mag * r_mag * cos_delta_nu); double s = (r0_mag + r_mag + c) / 2; a_min = s / 2; // double p_min = r0_mag * r_mag * (1 - cos_delta_nu) / c; // e_min = System.Math.Sqrt(1 - 2 * p_min / s); // alpha for elliptical xfer, min energy double alpha_e = System.Math.PI; // p471: set beta_e negative if delta_nu > 18 double beta_e = 2.0 * System.Math.Asin(System.Math.Sqrt((s - c) / s)); // t_min for a_min // +/- in front of (beta_e...). Which sign? Negative for shorter path. double sign = -1; if (!shortPath) { sign = 1; } t_min = System.Math.Sqrt(a_min * a_min * a_min / mu) * (alpha_e + sign * (beta_e - System.Math.Sin(beta_e))); return(t_min); }
/// <summary> /// Setup for Lambert Universal construction. Calculation is done via ComputeXfer and may be /// done more than once for different transit times. /// /// Initial conditions are passed in when created. /// /// The transfer assumes there is an active NBody at the fromOrbit to be maneuvered to the /// orbit specified by the toOrbit. One of the from/to orbit data elements must have a /// centerNBody. /// /// </summary> /// <param name="fromOrbit"></param> /// <param name="toOrbit"></param> /// <param name="shortPath">Take shortest path along the ellipse (if xfer is an ellipse)</param> public LambertUniversal(OrbitData _fromOrbit, OrbitData _toOrbit, bool shortPath) : base(_fromOrbit, _toOrbit) { name = "LambertUniversal"; // Fundamentals of Astrodynamics and Applications, Vallado, 4th Ed., Algorithm 56 p475 // Take r0, r => a_min, e_min, t_min, v0 double[] r1_array = new double[] { 0, 0, 0 }; double[] r2_array = new double[] { 0, 0, 0 }; double[] center = new double[] { 0, 0, 0 }; GravityEngine ge = GravityEngine.Instance(); // If Nbody is available get position directly. If not (target marker) then // use orbit phase to compute position ge.GetPositionDouble(centerBody, ref center); center3d = new Vector3d(ref center); if (fromOrbit.nbody != null) { ge.GetPositionDouble(fromOrbit.nbody, ref r1_array); } else { Vector3 pos = toOrbit.GetPhysicsPositionforEllipse(fromOrbit.phase); r1_array = new double[] { pos.x, pos.y, pos.z }; } if (toOrbit.nbody != null) { ge.GetPositionDouble(toOrbit.nbody, ref r2_array); } else { Vector3 pos = toOrbit.GetPhysicsPositionforEllipse(toOrbit.phase); r2_array = new double[] { pos.x, pos.y, pos.z }; } r1 = new Vector3d(ref r1_array) - center3d; r2 = new Vector3d(ref r2_array) - center3d; if (fromOrbit.a < toOrbit.a) { innerOrbit = fromOrbit; outerOrbit = toOrbit; innerToOuter = true; } else { innerOrbit = toOrbit; outerOrbit = fromOrbit; innerToOuter = false; } mu = ge.GetPhysicsMass(fromOrbit.centralMass); // determine t_min. // If Nbody is available get position directly. If not (target marker) then // use orbit phase to compute position double[] r0 = new double[] { 0, 0, 0 }; double[] r = new double[] { 0, 0, 0 }; if (innerOrbit.nbody != null) { ge.GetPositionDouble(innerOrbit.nbody, ref r0); } else { Vector3 pos = toOrbit.GetPhysicsPositionforEllipse(innerOrbit.phase); r0 = new double[] { pos.x, pos.y, pos.z }; } if (outerOrbit.nbody != null) { ge.GetPositionDouble(outerOrbit.nbody, ref r); } else { Vector3 pos = toOrbit.GetPhysicsPositionforEllipse(outerOrbit.phase); r = new double[] { pos.x, pos.y, pos.z }; } ComputeMinTime(ref r0, ref r, fromOrbit.centralMass, shortPath); }