/// <summary> /// 构造函数(注意单位的一致性) /// </summary> /// <param name="t0">初始时刻(s),没有多大意义</param> /// <param name="elements">初始轨道根数</param> /// <param name="j2UnnormalizedValue">J2项系数</param> /// <param name="referenceDistance">参考椭球体半长轴</param> public J2NumericalPropagator(double t0, KeplerianElements elements, double j2UnnormalizedValue, double referenceDistance) : this(elements.GravitationalParameter, j2UnnormalizedValue, referenceDistance) { this.T0 = t0; // 初始位置、速度 InitialCondition = elements.ToCartesian(); }
/// <summary> /// Propagate a Platform using a NumericalPropagator configured with the entered KeplerianElements, /// ForceModels, NumericalIntegrator, and start and stop dates. /// </summary> private void PropagateSatellite() { KeplerianElements orbitalElements = m_keplerianOrbitalElementsEntry.KeplerianElementValues; if (orbitalElements == null) { return; } Motion <Cartesian> initialMotion = orbitalElements.ToCartesian(); PropagationNewtonianPoint point = new PropagationNewtonianPoint(m_elementID, m_forceModelSettings.CurrentCentralBody.InertialFrame, initialMotion.Value, initialMotion.FirstDerivative); point.Mass = new ScalarFixed(double.Parse(m_mass.Text)); m_forceModelSettings.SetForceModelsOnPoint(point, new ScalarFixed(double.Parse(m_area.Text))); CentralBody primaryCentralBody = m_forceModelSettings.CurrentCentralBody; NumericalPropagatorDefinition state = new NumericalPropagatorDefinition(); state.IntegrationElements.Add(point); state.Integrator = m_integratorSettings.GetIntegrator(); JulianDate start = new JulianDate(GregorianDate.ParseExact(m_start.Text, DateFormat, null)); JulianDate end = new JulianDate(GregorianDate.ParseExact(m_end.Text, DateFormat, null)); state.Epoch = start; NumericalPropagator propagator = state.CreatePropagator(); propagator.StepTaken += (sender, args) => { // Telling the propagator to stop if we get too close to the central body Cartesian position = propagator.Converter.ConvertState <Cartesian>(m_elementID, args.CurrentState).Value; if (position.Magnitude <= primaryCentralBody.Shape.SemimajorAxisLength + 10000) { args.Indication = PropagationEventIndication.StopPropagationAfterStep; } }; DateMotionCollection <Cartesian> answer = null; var backgroundCalculation = new BackgroundCalculation(); backgroundCalculation.DoWork += (sender, e) => { // actually propagate var result = propagator.Propagate(end.Subtract(start), 1, backgroundCalculation); answer = result.GetDateMotionCollection <Cartesian>(m_elementID); }; backgroundCalculation.ProgressChanged += (sender, e) => m_propagationProgress.Value = e.ProgressPercentage; backgroundCalculation.RunWorkerCompleted += (sender, e) => { // when finished, draw the satellite DrawSatellite(answer, primaryCentralBody.InertialFrame); m_propagate.Enabled = true; }; m_propagate.Enabled = false; backgroundCalculation.RunWorkerAsync(); }
/// <summary> /// 计算两轨道面夹角、北半球交线的纬度幅角 /// </summary> /// <param name="element1"></param> /// <param name="element2"></param> /// <param name="u1"></param> /// <param name="u2"></param> /// <param name="theta"></param> public static void TwoOrbitPlaneIntersection(KeplerianElements element1, KeplerianElements element2, out double u1, out double u2, out double theta) { double inc1 = element1.Inclination; double inc2 = element2.Inclination; double raan1 = element1.RightAscensionOfAscendingNode; double raan2 = element2.RightAscensionOfAscendingNode; TwoOrbitPlaneIntersection(inc1, inc2, raan1, raan2, out u1, out u2, out theta); }
/// <summary> /// kepler根数TA对应的r,V,theta的转换(注意参数单位统一) /// </summary> /// <param name="elements">kepler根数</param> /// <param name="r">地心距</param> /// <param name="V">速度</param> /// <param name="theta">水平飞行路径角(rad)</param> public static void KeplerElements2rvtheta(KeplerianElements elements, out double r, out double v, out double theta) { double a = elements.SemimajorAxis; double e = elements.Eccentricity; double f = elements.TrueAnomaly; double Gm = elements.GravitationalParameter; r = a * (1 - e * e) / (1 + e * Math.Cos(f)); v = Math.Sqrt(Gm * (1 + 2 * e * Math.Cos(f) + e * e) / a / (1 - e * e)); theta = Math.Asin(e * Math.Sin(f) / Math.Sqrt(1 + 2 * e * Math.Cos(f) + e * e)); }
/// <summary> /// 计算真近点角从f1飞行到f2的时间(f1,f2的区间在[0,2*pi]),f1沿逆时针飞行到f2 /// </summary> /// <param name="f1">初始真近点角(rad)</param> /// <param name="f2">终点真近点角(rad)</param> /// <param name="sma">半长轴</param> /// <param name="ecc">偏心率</param> /// <param name="mu">引力常数</param> /// <returns></returns> public static double ComputeTimeOfFlight(double f1, double f2, double sma, double ecc, double mu) { double dt = KeplerianElements.ComputeTimeOfFlight(Round0_2Pi(f1), Round0_2Pi(f2), sma, ecc, mu); if (dt < 0) { dt = KeplerianElements.SemimajorAxisToPeriod(sma, mu) + dt; } return(dt); }
/// <summary> /// 计算Dt时间后的平均根数(RAAN,omg,M考虑一阶长期项,RAAN考虑二阶长期项) /// </summary> /// <param name="dt">一段时间(s)</param> /// <returns></returns> public KeplerianElements ComputeMeanElementAfterDt(double dt) { // 无量纲时间 dt = dt / unitT; double RAANt = Round2Pi(RAAN + (RAANdot + RAANdot2) * dt); double omgt = Round2Pi(omg + omgdot * dt); double mat = Round2Pi(ma + (n + madot) * dt); double tat = KeplerianElements.MeanAnomalyToTrueAnomaly(mat, ecc); // 返回dt时间后的平均根数 return new KeplerianElements(sma * Re, ecc, inc, omgt, RAANt, tat, Mu); }
public static OrbitModKep ToModKep(KeplerianElements elements, double mu) { return OrbitModKep.OrbitMK( elements.p, elements.ecc, elements.inc / 180.0 * OrbMath.PI, elements.argPe / 180.0 * OrbMath.PI, elements.raan / 180.0 * OrbMath.PI, elements.ta0 / 180.0 * OrbMath.PI, elements.t0, mu ); }
public static void testTimeOfFlight() { double mu = 3.986004418e5; double sma = 7078.14; double ecc = 0.1; double f1 = 0.0; double f2 = Math.PI * 2.0; double t0 = ComputeTimeOfFlight(f1, f2, sma, ecc, mu); double t1 = ComputeTimeOfFlight(0, 2.0, sma, ecc, mu); double t2 = ComputeTimeOfFlight(-2.0, 0, sma, ecc, mu); double t2p = KeplerianElements.ComputeTimeOfFlight(-2.0, 0, sma, ecc, mu); double T = KeplerianElements.SemimajorAxisToPeriod(sma, mu); }
/// <summary> /// 求解Dt时间后的轨道根数 /// </summary> /// <param name="elem0">初始轨道根数</param> /// <param name="dt">时间</param> /// <returns></returns> public static KeplerianElements KeplerElementsAfterDt(KeplerianElements elem0, double dt) { //double M0 = elem0.ComputeMeanMotion(); //double Mt = M0 + elem0.ComputeMeanMotion() * dt; double t0 = KeplerianElements.ComputeTimePastPeriapsis(elem0.TrueAnomaly, elem0.SemimajorAxis, elem0.Eccentricity, elem0.GravitationalParameter); double ta = KeplerianElements.TimePastPeriapsisToTrueAnomaly(t0 + dt, elem0.SemimajorAxis, elem0.Eccentricity, elem0.GravitationalParameter); return(new KeplerianElements(elem0.SemimajorAxis, elem0.Eccentricity, elem0.Inclination, elem0.ArgumentOfPeriapsis, elem0.RightAscensionOfAscendingNode, ta, elem0.GravitationalParameter)); }
//######################################################################################### /// <summary> /// 构造函数 /// </summary> /// <param name="elements">初始轨道根数(平瞬根数由inputIsMean决定)</param> /// <param name="inputIsMean">true:平均根数;false:瞬时根数</param> /// <param name="j2UnnormalizedValue">未归一化的J2项系数</param> /// <param name="referenceDistance">参考半径(与elements单位一致)</param> public J2MeanElements(KeplerianElements elements, bool inputIsMean, double j2UnnormalizedValue, double referenceDistance) { Name = "DefaultName"; Mu = elements.GravitationalParameter; J2 = j2UnnormalizedValue; Re = referenceDistance; unitT = Math.Sqrt(Re * Re * Re / Mu); // 保留初始输入的根数 InitialElement = elements; // 利用kozai方法计算平均根数 KozaiIzsakMeanElements kozaiElement = new KozaiIzsakMeanElements(elements, inputIsMean, j2UnnormalizedValue, referenceDistance); // 初始平均根数(Kozai) KozaiMeanElement = kozaiElement.ToMeanKeplerianElements(); this.sma = KozaiMeanElement.SemimajorAxis / Re; this.ecc = KozaiMeanElement.Eccentricity; this.inc = KozaiMeanElement.Inclination; this.RAAN = KozaiMeanElement.RightAscensionOfAscendingNode; this.omg = KozaiMeanElement.ArgumentOfPeriapsis; this.ma = KozaiMeanElement.ComputeMeanAnomaly(); // 计算长期项 // 以下公式皆为无量纲 double A2 = 1.5 * J2; double sini2 = Math.Sin(inc) * Math.Sin(inc); double sq1e2 = Math.Sqrt(1.0 - ecc * ecc); double p2 = sma * sma * (1.0 - ecc * ecc) * (1.0 - ecc * ecc); n = Math.Sqrt(1.0 / sma / sma / sma); // 平近点角的一阶长期项 madot = A2 / p2 * n * (1 - 1.5 * sini2) * sq1e2; // RAAN和Argument Of Periapse的一阶长期项 RAANdot = -A2 / p2 * n * Math.Cos(inc); omgdot = A2 / p2 * n * (2 - 2.5 * sini2); // RAAN的二阶长期项 RAANdot2 = -A2 * A2 / p2 / p2 * n * Math.Cos(inc) * ((1.5 + ecc * ecc / 6.0 + sq1e2) - (5.0 / 3.0 - 5.0 * ecc * ecc / 24.0 + 1.5 * sq1e2) * sini2); }
public static void TestLamber1() { double Gm = 3.986e14; double sma = 7000000; double ecc = 0.09956; double f1 = 0.0; double f2 = Math.PI; //double f2 = 1.0; //double f2 = 5.0; KeplerianElements k1 = new KeplerianElements(sma, ecc, 0.2, 0.4, 1.0, f1, Gm); KeplerianElements k2 = new KeplerianElements(sma, ecc, 0.2, 0.4, 1.0, f2, Gm); double tof = KeplerianElements.ComputeTimeOfFlight(f1, f2, sma, ecc, Gm); Motion <Cartesian> rv1 = k1.ToCartesian(); Motion <Cartesian> rv2 = k2.ToCartesian(); Cartesian v1p, v2p; Lambert_RhGooding(Gm, rv1.Value, rv1.FirstDerivative, rv2.Value, rv2.FirstDerivative, tof, out v1p, out v2p); Cartesian dv1 = v1p - rv1.FirstDerivative; Cartesian dv2 = v2p - rv2.FirstDerivative; }
/// <summary> /// 构造函数 /// </summary> /// <param name="elements">初始轨道根数(平瞬根数由inputIsMean决定)</param> /// <param name="inputIsMean">true:平均根数;false:瞬时根数</param> /// <param name="j2UnnormalizedValue">未归一化的J2项系数</param> /// <param name="referenceDistance">参考半径(与elements单位一致)</param> /// <param name="name">名称</param> public J2MeanElements(KeplerianElements elements, bool inputIsMean, double j2UnnormalizedValue, double referenceDistance, string name) : this(elements, inputIsMean, j2UnnormalizedValue, referenceDistance) { Name = name; }
private static KeplerianElements stateVectorToKeplerian(Vector3d position, Vector3d velocity, double mu) { // Work in units of km and seconds var r = position * UiTools.KilometersPerAu; var v = velocity / 86400.0 * UiTools.KilometersPerAu; var rmag = r.Length(); var vmag = v.Length(); var sma = 1.0 / (2.0 / rmag - vmag * vmag / mu); // h is the orbital angular momentum vector var h = Vector3d.Cross(r, v); // ecc is the eccentricity vector, which points from the // planet at periapsis to the center point. var ecc = Vector3d.Cross(v, h) / mu - r / rmag; var e = ecc.Length(); h.Normalize(); ecc.Normalize(); // h, s, and ecc are orthogonal vectors that define a coordinate // system. h is normal to the orbital plane. var s = Vector3d.Cross(h, ecc); // Calculate the sine and cosine of the true anomaly r.Normalize(); var cosNu = Vector3d.Dot(ecc, r); var sinNu = Vector3d.Dot(s, r); // Compute the eccentric anomaly var E = Math.Atan2(Math.Sqrt(1 - e * e) * sinNu, e + cosNu); // Mean anomaly not required // double M = E - e * Math.Sin(E); var elements = new KeplerianElements(); // Create a rotation matrix given the three orthogonal vectors: // ecc - eccentricity vector // s - in the orbital plane, perpendicular to ecc // h - angular momentum vector, normal to orbital plane elements.orientation = new Matrix3d(ecc.X, ecc.Y, ecc.Z, 0.0, s.X, s.Y, s.Z, 0.0, h.X, h.Y, h.Z, 0.0, 0.0, 0.0, 0.0, 1.0); elements.a = sma; elements.e = e; elements.E = E; return elements; }
private static void DrawSingleOrbit(RenderContext11 renderContext, int eclipticColor, int id, Vector3d centerPoint, double xstartAngle, Vector3d planetNow, KeplerianElements el) { double scaleFactor; switch (id) { case (int)SolarSystemObjects.Moon: if (Settings.Active.SolarSystemScale > 1) scaleFactor = Settings.Active.SolarSystemScale / 2; else scaleFactor = 1.0; break; case (int)SolarSystemObjects.Io: case (int)SolarSystemObjects.Europa: case (int)SolarSystemObjects.Ganymede: case (int)SolarSystemObjects.Callisto: scaleFactor = Settings.Active.SolarSystemScale; break; default: scaleFactor = 1.0; break; } var translation = -centerPoint; if (id == (int)SolarSystemObjects.Moon) { translation += planet3dLocations[(int)SolarSystemObjects.Earth]; } else if (id == (int)SolarSystemObjects.Io || id == (int)SolarSystemObjects.Europa || id == (int)SolarSystemObjects.Ganymede || id == (int)SolarSystemObjects.Callisto) { translation += planet3dLocations[(int)SolarSystemObjects.Jupiter]; } var currentPosition = planetNow - centerPoint; if (orbitTraces[id] != null) { var worldMatrix = Matrix3d.Translation(translation) * renderContext.World; orbitTraces[id].render(renderContext, Color.FromArgb(eclipticColor), worldMatrix, jNow, currentPosition, 0.0); } else { var worldMatrix = el.orientation * Matrix3d.Translation(translation) * renderContext.World; EllipseRenderer.DrawEllipse(renderContext, el.a / UiTools.KilometersPerAu * scaleFactor, el.e, el.E, Color.FromArgb(eclipticColor), worldMatrix, currentPosition); } }