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);
    }
Example #3
0
    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;
        }
    }