public void GetEllipse(ref Vector3[] positions, int resolution) { if (resolution < 2) { positions = new Vector3[0]; return; } if (positions == null || positions.Length != resolution) { positions = new Vector3[resolution]; } period = GetPeriod(); double slice = period / resolution; OrbitData clone = new OrbitData(this); positions[0] = (Vector3)(clone.Position * OrbitUtils.KM2AU); for (int j = 1; j < resolution; j++) { clone.Epoch += slice; positions[j] = (Vector3)(clone.Position * OrbitUtils.KM2AU); } }
// TODO: This function does not behave as expected and/or has not been successfully tested/implemented. public static void GetPositionsAlongEllipse(ref Vector3[] positions, OrbitData orbit, int resolution) { if (resolution < 2) { positions = new Vector3[0]; return; } double a = orbit.SemiMajorAxis; double ecc = orbit.Eccentricity; double w = orbit.ArgumentOfPerifocus; double nu = orbit.TrueAnomaly; // Trigometrics for any values used more than once in calculations double cosI = Math.Cos(orbit.Inclination); double cosOm = Math.Cos(orbit.LongitudeOfAscendingNode); double sinOm = Math.Sin(orbit.LongitudeOfAscendingNode); double angle = TwoPI / resolution; if (ecc < 1.0 && ecc >= 0.0) { if (positions == null || positions.Length != resolution) { positions = new Vector3[resolution]; } for (int j = 0; j < resolution; j++) { // Radial distance [km] double r = orbit.SemiMajorAxis * (1.0 - ecc * ecc) / (1.0 + ecc * Math.Cos(j * angle)); // Flight path angle [rad] //double fpa = Math.Atan2(1.0 + ecc * Math.Cos(nu), ecc * Math.Sin(nu)); double fpa = Math.Atan(ecc * Math.Sin(nu) / (1.0 + ecc * Math.Cos(nu))); double cosNuPlusW = Math.Cos(nu + w); double sinNuPlusW = Math.Sin(nu + w); float x = (float)(r * (cosNuPlusW * cosOm - sinNuPlusW * cosI * sinOm)); float y = (float)(r * (cosNuPlusW * sinOm + sinNuPlusW * cosI * cosOm)); float z = (float)(r * (sinNuPlusW * Math.Sin(orbit.Inclination))); positions[j] = new Vector3(x, y, z); } } else { Debug.LogWarning("Cannot draw orbital ellipse: orbit is parabolic/hyperbolic"); } }
public LambertSolution(int nRevs, double TA, double pTA, double Vinf, double C3, double Vimp, Vector3d arrDV, double VimpDotProduct, OrbitData transferOrbit) { this.nRevs = nRevs; this.TA = TA; this.pTA = pTA; this.Vinf = Vinf; this.C3 = C3; this.arrDV = arrDV; this.Vimp = Vimp; this.VimpDotProduct = VimpDotProduct; this.TransferOrbit = transferOrbit; }
/// <summary> /// Calculates the change in velocity of an object from an impact/deflection /// with a smaller body (e.g. kinetic impactor spacecraft) in the ecliptic plane. /// </summary> /// <returns>The delta V of <paramref name="deflected"/> in the ecliptic.</returns> /// <param name="deflected">Orbit of the object being deflected at time of impact [km-s].</param> /// <param name="impactor">Orbit of the impacting object at time of impact [km-s].</param> /// <param name="massDeflected">Mass of the object being deflected [kg].</param> /// <param name="massImpactor">Mass of the impacting object [kg].</param> /// <param name="beta">The momentum enhancement factor from ejecta (1 = no enhacement).</param> public static Vector3d CalculateDeflectionDeltaVEcliptic(OrbitData deflected, OrbitData impactor, double massDeflected, double massImpactor, double beta = 1.0) { // Velocity of the impactor relative to the object being deflected. Vector3d vrel = impactor.Velocity - deflected.Velocity; //Vector3d vhat = deflected.Velocity.normalized; //Vector3d vrelhat = vrel.normalized; //double Vimp = vrel.magnitude; //double VimpDotP = Vector3d.Dot(vhat, vrelhat); // Delta V from deflection, in the ecliptic plane. return(vrel * beta * massImpactor / massDeflected); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="other">Orbit to copy.</param> public OrbitData(OrbitData other) { epoch = other.epoch; mu = other.mu; a = other.a; ecc = other.ecc; i = other.i; Om = other.Om; w = other.w; M = other.M; nu = other.nu; E = other.E; pos = other.pos; vel = other.vel; N = other.N; period = other.period; }
/// <summary> /// Calculates the change in velocity of an object from an impact/deflection /// with a smaller body (e.g. kinetic impactor spacecraft) in the as (ΔVA, ΔVC, ΔVN). /// </summary> /// <remarks> /// The ACN coordinate system is a coordinate system set up at the center of mass /// of the asteroid at the time of deflection and used to express the magnitude /// and direction of the velocity change imparted to the asteroid. Its pricipal /// directions are: /// Along-track direction (A): in the asteroid's orbital plane and along the /// direction of the asteroid's current velocity vector about the Sun, /// Normal direction (N): perpendicular to the asteroid's orbit plane and is /// aligned with the positive orbital angular momentum vector (<c>r x v</c>) /// where r is the vector from the Sun to the asteroid's current position, /// Cross-track direction (C): in the orbital plane, perpendicular to the /// along-track direction (<c>C = N x A</c>), and positive in the general /// direction of the Sun. /// References: NDA Handbook v6.3 /// Transformation from ecliptic to ACN coordinate system /// provided by Jason Anderson of Aerospace 07-2018. /// </remarks> /// <returns>The delta V of <paramref name="deflected"/> in the ACN coordinate system.</returns> /// <param name="deflected">Orbit of the object being deflected at time of impact [km-s].</param> /// <param name="impactor">Orbit of the impacting object at time of impact [km-s].</param> /// <param name="massDeflected">Mass of the object being deflected [kg].</param> /// <param name="massImpactor">Mass of the impacting object [kg].</param> /// <param name="beta">The momentum enhacement factor from ejecta (1 = no enhancement).</param> public static Vector3d CalculateDeflectionDeltaVInAcn(OrbitData deflected, OrbitData impactor, double massDeflected, double massImpactor, double beta = 1.0) { Vector3d deltaVEcliptic = CalculateDeflectionDeltaVEcliptic(deflected, impactor, massDeflected, massImpactor, beta); // Velocity unit vector of object to deflect. Vector3d vhat = deflected.Velocity.normalized; // Angular momentum vector unit vector: hhat = pos x vel Vector3d hhat = Vector3d.Cross(deflected.Position, deflected.Velocity).normalized; Vector3d along = vhat; Vector3d normal = hhat.normalized; Vector3d cross = Vector3d.Cross(normal, along); double va = Vector3d.Dot(deltaVEcliptic, along); double vc = Vector3d.Dot(deltaVEcliptic, cross); double vn = Vector3d.Dot(deltaVEcliptic, normal); return(new Vector3d(va, vc, vn)); }
/// <summary> /// Gets a new Lambert solution. /// </summary> /// <param name="from">Departure body orbit at time of impact.</param> /// <param name="to">Arrival body orbit at time of impact.</param> /// <param name="D">Number of days before impact the deflection is to occur.</param> /// <param name="TOF_days">Time of flight [days]</param> /// <param name="nRevs">Number of revolutions or -1 to search for optimal</param> public static LambertSolution GetTransferOrbit(OrbitData from, OrbitData to, double D, double TOF_days, int nRevs = -1) { Debug.Assert(Math.Abs(from.Epoch - to.Epoch) <= double.Epsilon); // Make local copies of orbit parameters (passed by reference). OrbitData dep = new OrbitData(from); OrbitData arr = new OrbitData(to); dep.Step(-(D + TOF_days)); arr.Step(-D); Vector3d pos1 = dep.Position; Vector3d vel1 = dep.Velocity; Vector3d pos2 = arr.Position; Vector3d vel2 = arr.Velocity; Vector3d[] depDV = new Vector3d[2]; Vector3d[] arrDV = new Vector3d[2]; double[] TA = new double[2]; // Transfer angle double[] Vinf = new double[2]; // Earth departure V-infinity double[] C3 = new double[2]; int i; if (nRevs < 0) { // Search for the best number of revolutions... // Start the search with 0 and 1 revolutions. for (i = 0; i < 2; i++) { nRevs = i; // Calculate the Lambert arc from state1 to state2 in TOF days; // Return the departure delta V and the arrival delta V. CalcLambert(nRevs, pos1, vel1, pos2, vel2, TOF_days, ref depDV[i], ref arrDV[i], out TA[i]); // Earth departure V-infinity. Vinf[i] = depDV[i].magnitude; C3[i] = Vinf[i] * Vinf[i]; Debug.Log("Rev #" + nRevs + ": C3 = " + C3[i]); } // Storage index. i = 1; // Run until C3 does not improve. while (C3[i == 1 ? 1 : 0] < C3[i == 1 ? 0 : 1]) { // Alternate storing index. i = (i == 0 ? 1 : 0); // Next revolution. nRevs++; // Calculate the Lambert arc from state1 to state2 in TOF days; // Return the departure delta V and the arrival delta V. CalcLambert(nRevs, pos1, vel1, pos2, vel2, TOF_days, ref depDV[i], ref arrDV[i], out TA[i]); // Earth departure V-infinity. Vinf[i] = depDV[i].magnitude; C3[i] = Vinf[i] * Vinf[i]; Debug.Log("Rev #" + nRevs + ": C3 = " + C3[i]); } // Best solution is the previous iteration. nRevs--; i = (i == 0 ? 1: 0); } else { // Storage index. i = 0; // Calculate the Lambert arc from state1 to state2 in TOF days; // Return the departure delta V and the arrival delta V. CalcLambert(nRevs, pos1, vel1, pos2, vel2, TOF_days, ref depDV[i], ref arrDV[i], out TA[i]); // Earth departure V-infinity. Vinf[i] = depDV[i].magnitude; C3[i] = Vinf[i] * Vinf[i]; } if (depDV[i] == Vector3d.zero) { return(null); } // Object impact velocity. double Vimp = arrDV[i].magnitude; // Planar transfer angle. double pTA = Math.Atan2(pos2.y, pos2.x) - Math.Atan2(pos1.y, pos1.x); if (pTA < 0.0) { pTA += OrbitUtils.TwoPI; } double VimpDotProduct = -arrDV[i].x * vel2.x - arrDV[i].y * vel2.y - arrDV[i].z * vel2.z / arrDV[i].magnitude / vel2.magnitude; vel1 += depDV[i]; // Transfer orbit velocity at departure OrbitData transferOrbit = new OrbitData(dep.Epoch, pos1, vel1, OrbitUtils.GM_SUN); return(new LambertSolution(nRevs, TA[i], pTA, Vinf[i], C3[i], Vimp, -arrDV[i], VimpDotProduct, transferOrbit)); }