public LambertBattin(OrbitData _fromOrbit, OrbitData _toOrbit) : base(_fromOrbit, _toOrbit) { name = "LambertBattin"; // Fundamentals of Astrodynamics and Applications, Vallado, 4th Ed., Algorithm 56 p475 // Take r0, r => a_min, e_min, t_min, v0 GravityEngine ge = GravityEngine.Instance(); // If Nbody is available get position directly. If not (target marker) then // use orbit phase to compute position center3d = ge.GetPositionDoubleV3(_fromOrbit.centralMass); if (fromOrbit.nbody != null) { r1 = ge.GetPositionDoubleV3(fromOrbit.nbody); r1crossv1 = _fromOrbit.GetAxis(); } else { r1 = new Vector3d(toOrbit.GetPhysicsPositionforEllipse(fromOrbit.phase)); Debug.LogError("Code incomplete need to get v1"); } if (toOrbit.nbody != null) { r2 = ge.GetPositionDoubleV3(toOrbit.nbody); } else { r2 = new Vector3d(toOrbit.GetPhysicsPositionforEllipse(toOrbit.phase)); } r1 = r1 - center3d; r2 = r2 - center3d; if (fromOrbit.a < toOrbit.a) { innerOrbit = fromOrbit; outerOrbit = toOrbit; innerToOuter = true; } else { innerOrbit = toOrbit; outerOrbit = fromOrbit; innerToOuter = false; } fromNBody = fromOrbit.nbody; mu = ge.GetPhysicsMass(fromOrbit.centralMass); }
public CircularizeXfer(OrbitData fromOrbit) : base(fromOrbit) { name = "Circularize"; GravityEngine ge = GravityEngine.Instance(); // find velocity vector perpendicular to r for circular orbit Vector3d r_ship = ge.GetPositionDoubleV3(fromOrbit.nbody); Vector3d v_ship = ge.GetVelocityDoubleV3(fromOrbit.nbody); Vector3d r_center = ge.GetPositionDoubleV3(fromOrbit.centralMass); Vector3d v_center = ge.GetVelocityDoubleV3(fromOrbit.centralMass); Vector3d r = r_ship - r_center; // want velocity relative to central mass (it could be moving) Vector3d v = v_ship - v_center; // to get axis of orbit, can take r x v Vector3d axis = Vector3d.Cross(r, v).normalized; // vis visa for circular orbit double mu = GravityEngine.Instance().GetMass(centerBody); double v_mag = Mathd.Sqrt(mu / r.magnitude); // positive v is counter-clockwise Vector3d v_dir = Vector3d.Cross(axis, r).normalized; Vector3d v_circular = v_mag * v_dir; Maneuver m1; m1 = new Maneuver(); m1.nbody = fromOrbit.nbody; m1.mtype = Maneuver.Mtype.vector; m1.velChange = (v_circular - v).ToVector3(); m1.dV = Vector3.Magnitude(m1.velChange); // maneuver positions and info for KeplerSeq conversion and velocity directions Vector3d h_unit = fromOrbit.GetAxis(); m1.physPosition = r_ship; m1.relativePos = r_ship - r_center; m1.relativeVel = v_circular.magnitude * Vector3d.Cross(h_unit, m1.relativePos).normalized; m1.relativeTo = fromOrbit.centralMass; //Debug.LogFormat("v_ship={0} v_center={1} v_c.x={2}", vel_ship, vel_center, v_center[0]); //Debug.Log(string.Format("v_ship={0} v_circular={1} axis={2} v_dir={3} velChange={4}", // vel_ship, v_circular, axis, v_dir, m1.velChange)); m1.worldTime = ge.GetPhysicalTime(); maneuvers.Add(m1); }
public HohmannXfer(OrbitData fromOrbit, OrbitData toOrbit, bool rendezvous) : base(fromOrbit, toOrbit) { name = "Hohmann"; if (rendezvous) { name += " Rendezvous"; } else { name += " Transfer"; } // Check both objects are orbiting in the same direction if (Vector3d.Dot(fromOrbit.GetAxis(), toOrbit.GetAxis()) < 0) { Debug.LogWarning("Objects orbiting in different directions. Will not proceed."); return; } // Hohmann xfer is via an ellipse from one circle to another. The ellipse is uniquely // defined by the radius of from and to. // Equations from Chobotov Ch 5.4 float r_inner = 0f; float r_outer = 0f; // From orbit result is in physics quantities if (fromOrbit.a < toOrbit.a) { r_inner = fromOrbit.a; r_outer = toOrbit.a; } else { r_inner = toOrbit.a; r_outer = fromOrbit.a; } // (mass scale was applied in Orbit data) float v_inner = Mathf.Sqrt(fromOrbit.mu / r_inner); float rf_ri = r_outer / r_inner; float dV_inner = v_inner * (Mathf.Sqrt(2f * rf_ri / (1f + rf_ri)) - 1f); // Debug.LogFormat("dv_iner={0} v_inner={1} r_i={2} r_o={3}", dV_inner, v_inner, r_inner, r_outer); float v_outer = Mathf.Sqrt(fromOrbit.mu / r_outer); //simplify per Roy (12.22) float dV_outer = v_outer * (1f - Mathf.Sqrt(2 / (1 + rf_ri))); // Debug.LogFormat("r_in={0} r_out={1} v_inner={2} v_outer={3}", r_inner, r_outer, v_inner, v_outer); // transfer time // Need to flip rf_ri for inner orbits to get the correct transfer_time // (should re-derive for this case sometime to see why) transfer_time = 0f; // time to wait for first maneuver (rendezvous case) float tWait = 0f; // Build the manuevers required deltaV = 0f; float worldTime = GravityEngine.Instance().GetPhysicalTime(); Maneuver m1; m1 = new Maneuver(); m1.nbody = fromOrbit.nbody; m1.mtype = Maneuver.Mtype.scalar; m1.worldTime = worldTime; Maneuver m2; m2 = new Maneuver(); m2.nbody = fromOrbit.nbody; m2.mtype = Maneuver.Mtype.scalar; // If the orbit is almost circular, then can be some omega which will impact rendezvous phasing float fromPhase = fromOrbit.phase + fromOrbit.omega_lc; float toPhase = toOrbit.phase + toOrbit.omega_lc; if (fromOrbit.a < toOrbit.a) { // inner to outer float subexpr = 1f + rf_ri; transfer_time = fromOrbit.period / Mathf.Sqrt(32) * Mathf.Sqrt(subexpr * subexpr * subexpr); if (rendezvous) { // need to determine wait time for first maneuver to phase the arrival // find angle by which outer body must lead (radians) // Chobotov 7.3 float subexpr2 = 0.5f * (1f + r_inner / r_outer); float theta_h = Mathf.PI * (1f - Mathf.Sqrt(subexpr2 * subexpr2 * subexpr2)); // find current angular seperation float phase_gap = toPhase - fromPhase; if (phase_gap < 0) { phase_gap += 360f; } // need seperation to be theta_h float dTheta = Mathf.Deg2Rad * phase_gap - theta_h; if (dTheta < 0) { dTheta += TWO_PI; } // need to wait for phase_gap to reduce to this value. It reduces at a speed based on the difference // in the angular velocities. float dOmega = TWO_PI / fromOrbit.period - TWO_PI / toOrbit.period; tWait = dTheta / dOmega; //Debug.LogFormat("inner_phase= {0} out_phase={1} phase_gap(deg)={2} thetaH={3} dTheta(rad)={4} dOmega={5} tWait={6}", // fromOrbit.phase, toOrbit.phase, phase_gap, theta_h, dTheta, dOmega, tWait); } // from inner to outer // first maneuver is to a higher orbit m1.dV = dV_inner; deltaV += dV_inner; maneuvers.Add(m1); // second manuever is opposite to velocity m2.dV = dV_outer; deltaV += dV_outer; maneuvers.Add(m2); } else { // outer to inner float subexpr_in = 1f + r_inner / r_outer; transfer_time = fromOrbit.period / Mathf.Sqrt(32) * Mathf.Sqrt(subexpr_in * subexpr_in * subexpr_in); if (rendezvous) { // Chobotov 7.2/7.3 (modified for outer to inner, use (Pi+Theta) and Pf not Pi float subexpr2 = 0.5f * (1f + r_outer / r_inner); float theta_h = Mathf.PI * (1f + Mathf.Sqrt(subexpr2 * subexpr2 * subexpr2)); // find current angular seperation float phase_gap = fromPhase - toPhase; if (phase_gap < 0) { phase_gap += 360f; } // need seperation to be -theta_h float dTheta = Mathf.Deg2Rad * phase_gap - theta_h; // Can need inner body to go around more than once... while (dTheta < 0) { dTheta += TWO_PI; } // larger (inner) omega first float dOmega = TWO_PI / toOrbit.period - TWO_PI / fromOrbit.period; tWait = dTheta / dOmega; //Debug.LogFormat("inner_phase= {0} out_phase={1} phase_gap(deg)={2} thetaH(deg)={3} dTheta(rad)={4} dOmega={5} tWait={6}", // toOrbit.phase, fromOrbit.phase, phase_gap, Mathf.Rad2Deg*theta_h, dTheta, dOmega, tWait); } // from outer to inner // first maneuver is to a lower orbit m1.dV = -dV_outer; deltaV += dV_outer; maneuvers.Add(m1); // second manuever is opposite to velocity m2.dV = -dV_inner; deltaV += dV_outer; maneuvers.Add(m2); } m1.worldTime = worldTime + tWait; m2.worldTime = worldTime + tWait + transfer_time; deltaT = tWait + transfer_time; // maneuver positions and info for KeplerSeq conversion and velocity directions Vector3d h_unit = fromOrbit.GetAxis(); float phaseAtXfer = fromOrbit.phase + (TWO_PI / fromOrbit.period) * tWait * Mathf.Rad2Deg; m1.physPosition = new Vector3d(fromOrbit.GetPhysicsPositionforEllipse(phaseAtXfer)); m1.relativePos = new Vector3d(fromOrbit.GetPhysicsPositionforEllipseRelative(phaseAtXfer)); m1.relativeVel = Vector3d.Cross(h_unit, m1.relativePos).normalized; m1.relativeTo = fromOrbit.centralMass; m2.physPosition = new Vector3d(toOrbit.GetPhysicsPositionforEllipse(phaseAtXfer + 180f)); m2.relativePos = new Vector3d(toOrbit.GetPhysicsPositionforEllipseRelative(phaseAtXfer + 180f)); m2.relativeVel = Vector3d.Cross(h_unit, m2.relativePos).normalized; m2.relativeTo = fromOrbit.centralMass; // Determine the relative velocities if (fromOrbit.a < toOrbit.a) { // inner to outer m1.relativeVel *= v_inner + m1.dV; m2.relativeVel *= v_outer; } else { // outer to inner m1.relativeVel *= v_outer + m1.dV; m2.relativeVel *= v_inner; } }