/// <summary>
        /// Calculate satellite ECI position/velocity for a given time.
        /// </summary>
        /// <param name="tsince">Target time, in minutes-past-epoch format.</param>
        /// <returns>AU-based position/velocity ECI coordinates.</returns>
        /// <remarks>
        /// This procedure returns the ECI position and velocity for the satellite
        /// in the orbit at the given number of minutes since the TLE epoch time.
        /// The algorithm uses NORAD's Simplified General Perturbation 4 deep space
        /// orbit model.
        /// </remarks>
        public override EciTime GetPosition(double tsince)
        {
            // Update for secular gravity and atmospheric drag
            double xmdf   = Orbit.MeanAnomaly + m_xmdot * tsince;
            double omgadf = Orbit.ArgPerigee + m_omgdot * tsince;
            double xnoddf = Orbit.RAAN + m_xnodot * tsince;
            double tsq    = tsince * tsince;
            double xnode  = xnoddf + m_xnodcf * tsq;
            double tempa  = 1.0 - m_c1 * tsince;
            double tempe  = Orbit.BStar * m_c4 * tsince;
            double templ  = m_t2cof * tsq;
            double xn     = m_xnodp;
            double em     = 0.0;
            double xinc   = 0.0;

            DeepSecular(ref xmdf, ref omgadf, ref xnode, ref em, ref xinc, ref xn, ref tsince);

            double a    = Math.Pow(Globals.Xke / xn, 2.0 / 3.0) * Globals.Sqr(tempa);
            double e    = em - tempe;
            double xmam = xmdf + m_xnodp * templ;

            DeepPeriodics(ref e, ref xinc, ref omgadf, ref xnode, ref xmam, tsince);

            double xl = xmam + omgadf + xnode;

            xn = Globals.Xke / Math.Pow(a, 1.5);

            return(FinalPosition(xinc, omgadf, e, a, xl, xnode, xn, tsince));
        }
Beispiel #2
0
        // ///////////////////////////////////////////////////////////////////////////
        // getPosition()
        // This procedure returns the ECI position and velocity for the satellite
        // in the orbit at the given number of minutes since the TLE epoch time
        // using the NORAD Simplified General Perturbation 4, "deep space" orbit
        // model.
        //
        // tsince  - Time in minutes since the TLE epoch (GMT).
        // pECI    - pointer to location to store the ECI data.
        //           To convert the returned ECI position vector to km,
        //           multiply each component by:
        //              (XKMMPER / Globals.AE).
        //           To convert the returned ECI velocity vector to km/sec,
        //           multiply each component by:
        //              (XKMPER / Globals.AE) * (MIN_PER_DAY / 86400).
        public override Eci getPosition(double tsince)
        {
            DeepInit(ref m_eosq, ref m_sinio, ref m_cosio, ref m_betao, ref m_aodp, ref m_theta2,
                     ref m_sing, ref m_cosg, ref m_betao2, ref m_xmdot, ref m_omgdot, ref m_xnodot);

            // Update for secular gravity and atmospheric drag
            double xmdf   = m_Orbit.mnAnomaly() + m_xmdot * tsince;
            double omgadf = m_Orbit.ArgPerigee + m_omgdot * tsince;
            double xnoddf = m_Orbit.RAAN + m_xnodot * tsince;
            double tsq    = tsince * tsince;
            double xnode  = xnoddf + m_xnodcf * tsq;
            double tempa  = 1.0 - m_c1 * tsince;
            double tempe  = m_Orbit.BStar * m_c4 * tsince;
            double templ  = m_t2cof * tsq;
            double xn     = m_xnodp;
            double em     = 0.0;
            double xinc   = 0.0;

            DeepSecular(ref xmdf, ref omgadf, ref xnode, ref em, ref xinc, ref xn, ref tsince);

            double a    = Math.Pow(Globals.XKE / xn, Globals.TWOTHRD) * Globals.Sqr(tempa);
            double e    = em - tempe;
            double xmam = xmdf + m_xnodp * templ;

            DeepPeriodics(ref e, ref xinc, ref omgadf, ref xnode, ref xmam);

            double xl = xmam + omgadf + xnode;

            xn = Globals.XKE / Math.Pow(a, 1.5);

            return(FinalPosition(xinc, omgadf, e, a, xl, xnode, xn, tsince));
        }
Beispiel #3
0
        // ///////////////////////////////////////////////////////////////////
        // Calculate the ECI coordinates of the location "geo" at time "date".
        // Assumes geo coordinates are km-based.
        // Assumes the earth is an oblate spheroid as defined in WGS '72.
        // Reference: The 1992 Astronomical Almanac, page K11
        // Reference: www.celestrak.com (Dr. TS Kelso)
        public Eci(CoordGeo geo, Julian date)
        {
            m_VectorUnits = VectorUnits.Km;

            double mfactor = Globals.TWOPI * (Globals.OMEGA_E / Globals.SEC_PER_DAY);
            double lat     = geo.Latitude;
            double lon     = geo.Longitude;
            double alt     = geo.Altitude;

            // Calculate Local Mean Sidereal Time (theta)
            double theta = date.toLMST(lon);
            double c     = 1.0 / Math.Sqrt(1.0 + Globals.F * (Globals.F - 2.0) * Globals.Sqr(Math.Sin(lat)));
            double s     = Globals.Sqr(1.0 - Globals.F) * c;
            double achcp = (Globals.XKMPER * c + alt) * Math.Cos(lat);

            m_Date = date;

            m_Position = new Vector();

            m_Position.X = achcp * Math.Cos(theta);                    // km
            m_Position.Y = achcp * Math.Sin(theta);                    // km
            m_Position.Z = (Globals.XKMPER * s + alt) * Math.Sin(lat); // km
            m_Position.W = Math.Sqrt(Globals.Sqr(m_Position.X) +
                                     Globals.Sqr(m_Position.Y) +
                                     Globals.Sqr(m_Position.Z)); // range, km

            m_Velocity = new Vector();

            m_Velocity.X = -mfactor * m_Position.Y;            // km / sec
            m_Velocity.Y = mfactor * m_Position.X;
            m_Velocity.Z = 0.0;
            m_Velocity.W = Math.Sqrt(Globals.Sqr(m_Velocity.X) + // range rate km/sec^2
                                     Globals.Sqr(m_Velocity.Y));
        }
Beispiel #4
0
        // ///////////////////////////////////////////////////////////////////////////
        // Return the corresponding geodetic position (based on the current ECI
        // coordinates/Julian date).
        // Assumes the earth is an oblate spheroid as defined in WGS '72.
        // Side effects: Converts the position and velocity vectors to km-based units.
        // Reference: The 1992 Astronomical Almanac, page K12.
        // Reference: www.celestrak.com (Dr. TS Kelso)
        public CoordGeo toGeo()
        {
            ae2km(); // Vectors must be in kilometer-based units

            double theta = Globals.AcTan(m_Position.Y, m_Position.X);
            double lon   = (theta - m_Date.toGMST()) % Globals.TWOPI;

            if (lon < 0.0)
            {
                lon += Globals.TWOPI; // "wrap" negative modulo
            }
            double r   = Math.Sqrt(Globals.Sqr(m_Position.X) + Globals.Sqr(m_Position.Y));
            double e2  = Globals.F * (2.0 - Globals.F);
            double lat = Globals.AcTan(m_Position.Z, r);

            const double DELTA = 1.0e-07;
            double       phi;
            double       c;

            do
            {
                phi = lat;
                c   = 1.0 / Math.Sqrt(1.0 - e2 * Globals.Sqr(Math.Sin(phi)));
                lat = Globals.AcTan(m_Position.Z + Globals.XKMPER * c * e2 * Math.Sin(phi), r);
            }while (Math.Abs(lat - phi) > DELTA);

            double alt = r / Math.Cos(lat) - Globals.XKMPER * c;

            return(new CoordGeo(lat, lon, alt)); // radians, radians, kilometers
        }
Beispiel #5
0
        /// <summary>
        /// Creates a instance of the class from geodetic coordinates.
        /// </summary>
        /// <param name="geo">The geocentric coordinates.</param>
        /// <param name="date">The Julian date.</param>
        /// <remarks>
        /// Assumes the Earth is an oblate spheroid.
        /// Reference: The 1992 Astronomical Almanac, page K11
        /// Reference: www.celestrak.com (Dr. T.S. Kelso)
        /// </remarks>
        public Eci(Geo geo, Julian date)
        {
            double lat = geo.LatitudeRad;
            double lon = geo.LongitudeRad;
            double alt = geo.Altitude;

            // Calculate Local Mean Sidereal Time (theta)
            double theta = date.ToLmst(lon);
            double c     = 1.0 / Math.Sqrt(1.0 + Globals.F * (Globals.F - 2.0) *
                                           Globals.Sqr(Math.Sin(lat)));
            double s     = Globals.Sqr(1.0 - Globals.F) * c;
            double achcp = (Globals.Xkmper * c + alt) * Math.Cos(lat);

            Position = new Vector();

            Position.X = achcp * Math.Cos(theta);                    // km
            Position.Y = achcp * Math.Sin(theta);                    // km
            Position.Z = (Globals.Xkmper * s + alt) * Math.Sin(lat); // km
            Position.W = Math.Sqrt(Globals.Sqr(Position.X) +
                                   Globals.Sqr(Position.Y) +
                                   Globals.Sqr(Position.Z)); // range, km

            Velocity = new Vector();
            double mfactor = Globals.TwoPi * (Globals.OmegaE / Globals.SecPerDay);

            Velocity.X = -mfactor * Position.Y;              // km / sec
            Velocity.Y = mfactor * Position.X;               // km / sec
            Velocity.Z = 0.0;                                // km / sec
            Velocity.W = Math.Sqrt(Globals.Sqr(Velocity.X) + // range rate km/sec^2
                                   Globals.Sqr(Velocity.Y));
        }
Beispiel #6
0
        /// <summary>
        /// Creates a new instance of the class given XYZ coordinates.
        /// </summary>
        private Geo(Vector pos, double theta)
        {
            theta = theta % Globals.TwoPi;

            if (theta < 0.0)
            {
                // "wrap" negative modulo
                theta += Globals.TwoPi;
            }

            double r   = Math.Sqrt(Globals.Sqr(pos.X) + Globals.Sqr(pos.Y));
            double e2  = Globals.F * (2.0 - Globals.F);
            double lat = Globals.AcTan(pos.Z, r);

            const double DELTA = 1.0e-07;
            double       phi;
            double       c;

            do
            {
                phi = lat;
                c   = 1.0 / Math.Sqrt(1.0 - e2 * Globals.Sqr(Math.Sin(phi)));
                lat = Globals.AcTan(pos.Z + Globals.Xkmper * c * e2 * Math.Sin(phi), r);
            }while(Math.Abs(lat - phi) > DELTA);

            LatitudeRad  = lat;
            LongitudeRad = theta;
            Altitude     = (r / Math.Cos(lat)) - Globals.Xkmper * c;
        }
Beispiel #7
0
        /// <summary>
        /// Standard constructor.
        /// </summary>
        /// <param name="tle">Two-line element orbital parameters.</param>
        public Orbit(Tle tle)
        {
            Tle   = tle;
            Epoch = Tle.EpochJulian;

            m_Inclination   = GetRad(Tle.Field.Inclination);
            m_Eccentricity  = Tle.GetField(Tle.Field.Eccentricity);
            m_RAAN          = GetRad(Tle.Field.Raan);
            m_ArgPerigee    = GetRad(Tle.Field.ArgPerigee);
            m_BStar         = Tle.GetField(Tle.Field.BStarDrag);
            m_Drag          = Tle.GetField(Tle.Field.MeanMotionDt);
            m_MeanAnomaly   = GetRad(Tle.Field.MeanAnomaly);
            m_TleMeanMotion = Tle.GetField(Tle.Field.MeanMotion);

            // Recover the original mean motion and semimajor axis from the
            // input elements.
            double mm    = TleMeanMotion;
            double rpmin = mm * Globals.TwoPi / Globals.MinPerDay; // rads per minute

            double a1   = Math.Pow(Globals.Xke / rpmin, 2.0 / 3.0);
            double e    = Eccentricity;
            double i    = Inclination;
            double temp = (1.5 * Globals.Ck2 * (3.0 * Globals.Sqr(Math.Cos(i)) - 1.0) /
                           Math.Pow(1.0 - e * e, 1.5));
            double delta1 = temp / (a1 * a1);
            double a0     = a1 *
                            (1.0 - delta1 *
                             ((1.0 / 3.0) + delta1 *
                              (1.0 + 134.0 / 81.0 * delta1)));

            double delta0 = temp / (a0 * a0);

            m_rmMeanMotionRec    = rpmin / (1.0 + delta0);
            m_aeAxisSemiMajorRec = a0 / (1.0 - delta0);
            m_aeAxisSemiMinorRec = m_aeAxisSemiMajorRec * Math.Sqrt(1.0 - (e * e));
            m_kmPerigeeRec       = Globals.Xkmper * (m_aeAxisSemiMajorRec * (1.0 - e) - Globals.Ae);
            m_kmApogeeRec        = Globals.Xkmper * (m_aeAxisSemiMajorRec * (1.0 + e) - Globals.Ae);

            if (Period.TotalMinutes >= 225.0)
            {
                // SDP4 - period >= 225 minutes.
                NoradModel = new NoradSDP4(this);
            }
            else
            {
                // SGP4 - period < 225 minutes
                NoradModel = new NoradSGP4(this);
            }
        }
Beispiel #8
0
        // ///////////////////////////////////////////////////////////////////
        public Orbit(Tle tle)
        {
            m_tle     = tle;
            m_jdEpoch = m_tle.EpochJulian;

            // Recover the original mean motion and semimajor axis from the
            // input elements.
            double mm    = mnMotion;
            double rpmin = mm * Globals.TWOPI / Globals.MIN_PER_DAY; // rads per minute

            double a1   = Math.Pow(Globals.XKE / rpmin, Globals.TWOTHRD);
            double e    = Eccentricity;
            double i    = Inclination;
            double temp = (1.5 * Globals.CK2 * (3.0 * Globals.Sqr(Math.Cos(i)) - 1.0) /
                           Math.Pow(1.0 - e * e, 1.5));
            double delta1 = temp / (a1 * a1);
            double a0     = a1 *
                            (1.0 - delta1 *
                             ((1.0 / 3.0) + delta1 *
                              (1.0 + 134.0 / 81.0 * delta1)));

            double delta0 = temp / (a0 * a0);

            m_rmMeanMotionRec    = rpmin / (1.0 + delta0);
            m_aeAxisSemiMajorRec = a0 / (1.0 - delta0);
            m_aeAxisSemiMinorRec = m_aeAxisSemiMajorRec * Math.Sqrt(1.0 - (e * e));
            m_kmPerigeeRec       = Globals.XKMPER * (m_aeAxisSemiMajorRec * (1.0 - e) - Globals.AE);
            m_kmApogeeRec        = Globals.XKMPER * (m_aeAxisSemiMajorRec * (1.0 + e) - Globals.AE);

            if (Period.TotalMinutes >= 225.0)
            {
                // SDP4 - period >= 225 minutes.
                m_NoradModel = new NoradSDP4(this);
            }
            else
            {
                // SGP4 - period < 225 minutes
                m_NoradModel = new NoradSGP4(this);
            }
        }
        bool gp_sync; // geopotential synchronous

        // ///////////////////////////////////////////////////////////////////////////
        public NoradSDP4(Orbit orbit) :
            base(orbit)
        {
            double sinarg = Math.Sin(Orbit.ArgPerigee);
            double cosarg = Math.Cos(Orbit.ArgPerigee);

            // Deep space initialization
            Julian jd = Orbit.Epoch;

            dp_thgr = jd.ToGmst();

            double eq   = Orbit.Eccentricity;
            double aqnv = 1.0 / Orbit.SemiMajor;

            dp_xqncl = Orbit.Inclination;

            double xmao   = Orbit.MeanAnomaly;
            double xpidot = m_omgdot + m_xnodot;
            double sinq   = Math.Sin(Orbit.RAAN);
            double cosq   = Math.Cos(Orbit.RAAN);

            dp_omegaq = Orbit.ArgPerigee;

            #region Lunar / Solar terms

            // Initialize lunar solar terms
            double day = jd.FromJan0_12h_1900();

            double dpi_xnodce = 4.5236020 - 9.2422029E-4 * day;
            double dpi_stem   = Math.Sin(dpi_xnodce);
            double dpi_ctem   = Math.Cos(dpi_xnodce);
            double dpi_zcosil = 0.91375164 - 0.03568096 * dpi_ctem;
            double dpi_zsinil = Math.Sqrt(1.0 - dpi_zcosil * dpi_zcosil);
            double dpi_zsinhl = 0.089683511 * dpi_stem / dpi_zsinil;
            double dpi_zcoshl = Math.Sqrt(1.0 - dpi_zsinhl * dpi_zsinhl);
            double dpi_c      = 4.7199672 + 0.22997150 * day;
            double dpi_gam    = 5.8351514 + 0.0019443680 * day;

            dp_zmol = Globals.Fmod2p(dpi_c - dpi_gam);

            double dpi_zx = 0.39785416 * dpi_stem / dpi_zsinil;
            double dpi_zy = dpi_zcoshl * dpi_ctem + 0.91744867 * dpi_zsinhl * dpi_stem;

            dpi_zx = Globals.AcTan(dpi_zx, dpi_zy) + dpi_gam - dpi_xnodce;

            double dpi_zcosgl = Math.Cos(dpi_zx);
            double dpi_zsingl = Math.Sin(dpi_zx);

            dp_zmos = 6.2565837 + 0.017201977 * day;
            dp_zmos = Globals.Fmod2p(dp_zmos);

            const double zcosis = 0.91744867;
            const double zsinis = 0.39785416;
            const double zsings = -0.98088458;
            const double zcosgs = 0.1945905;
            const double c1ss   = 2.9864797E-6;

            double zcosg = zcosgs;
            double zsing = zsings;
            double zcosi = zcosis;
            double zsini = zsinis;
            double zcosh = cosq;
            double zsinh = sinq;
            double cc    = c1ss;
            double zn    = zns;
            double ze    = zes;
            double xnoi  = 1.0 / Orbit.MeanMotion;

            double a1;  double a3;  double a7;  double a8;  double a9;  double a10;
            double a2;  double a4;  double a5;  double a6;  double x1;  double x2;
            double x3;  double x4;  double x5;  double x6;  double x7;  double x8;
            double z31; double z32; double z33; double z1;  double z2;  double z3;
            double z11; double z12; double z13; double z21; double z22; double z23;
            double s3;  double s2;  double s4;  double s1;  double s5;  double s6;
            double s7;

            double se  = 0.0;
            double si  = 0.0;
            double sl  = 0.0;
            double sgh = 0.0;
            double sh  = 0.0;

            double eosq = Globals.Sqr(Orbit.Eccentricity);

            // Apply the solar and lunar terms on the first pass, then re-apply the
            // solar terms again on the second pass.

            for (int pass = 1; pass <= 2; pass++)
            {
                // Do solar terms
                a1  = zcosg * zcosh + zsing * zcosi * zsinh;
                a3  = -zsing * zcosh + zcosg * zcosi * zsinh;
                a7  = -zcosg * zsinh + zsing * zcosi * zcosh;
                a8  = zsing * zsini;
                a9  = zsing * zsinh + zcosg * zcosi * zcosh;
                a10 = zcosg * zsini;
                a2  = m_cosio * a7 + m_sinio * a8;
                a4  = m_cosio * a9 + m_sinio * a10;
                a5  = -m_sinio * a7 + m_cosio * a8;
                a6  = -m_sinio * a9 + m_cosio * a10;
                x1  = a1 * cosarg + a2 * sinarg;
                x2  = a3 * cosarg + a4 * sinarg;
                x3  = -a1 * sinarg + a2 * cosarg;
                x4  = -a3 * sinarg + a4 * cosarg;
                x5  = a5 * sinarg;
                x6  = a6 * sinarg;
                x7  = a5 * cosarg;
                x8  = a6 * cosarg;
                z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3;
                z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4;
                z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4;
                z1  = 3.0 * (a1 * a1 + a2 * a2) + z31 * eosq;
                z2  = 6.0 * (a1 * a3 + a2 * a4) + z32 * eosq;
                z3  = 3.0 * (a3 * a3 + a4 * a4) + z33 * eosq;
                z11 = -6.0 * a1 * a5 + eosq * (-24.0 * x1 * x7 - 6.0 * x3 * x5);
                z12 = -6.0 * (a1 * a6 + a3 * a5) +
                      eosq * (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5));
                z13 = -6.0 * a3 * a6 + eosq * (-24.0 * x2 * x8 - 6.0 * x4 * x6);
                z21 = 6.0 * a2 * a5 + eosq * (24.0 * x1 * x5 - 6.0 * x3 * x7);
                z22 = 6.0 * (a4 * a5 + a2 * a6) +
                      eosq * (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8));
                z23 = 6.0 * a4 * a6 + eosq * (24.0 * x2 * x6 - 6.0 * x4 * x8);
                z1  = z1 + z1 + m_betao2 * z31;
                z2  = z2 + z2 + m_betao2 * z32;
                z3  = z3 + z3 + m_betao2 * z33;
                s3  = cc * xnoi;
                s2  = -0.5 * s3 / m_betao;
                s4  = s3 * m_betao;
                s1  = -15.0 * eq * s4;
                s5  = x1 * x3 + x2 * x4;
                s6  = x2 * x3 + x1 * x4;
                s7  = x2 * x4 - x1 * x3;
                se  = s1 * zn * s5;
                si  = s2 * zn * (z11 + z13);
                sl  = -zn * s3 * (z1 + z3 - 14.0 - 6.0 * eosq);
                sgh = s4 * zn * (z31 + z33 - 6.0);

                if (Orbit.Inclination < 5.2359877E-2)
                {
                    sh = 0.0;
                }
                else
                {
                    sh = -zn * s2 * (z21 + z23);
                }

                dp_ee2  = 2.0 * s1 * s6;
                dp_e3   = 2.0 * s1 * s7;
                dp_xi2  = 2.0 * s2 * z12;
                dp_xi3  = 2.0 * s2 * (z13 - z11);
                dp_xl2  = -2.0 * s3 * z2;
                dp_xl3  = -2.0 * s3 * (z3 - z1);
                dp_xl4  = -2.0 * s3 * (-21.0 - 9.0 * eosq) * ze;
                dp_xgh2 = 2.0 * s4 * z32;
                dp_xgh3 = 2.0 * s4 * (z33 - z31);
                dp_xgh4 = -18.0 * s4 * ze;
                dp_xh2  = -2.0 * s2 * z22;
                dp_xh3  = -2.0 * s2 * (z23 - z21);

                if (pass == 1)
                {
                    // Do lunar terms
                    dp_sse  = se;
                    dp_ssi  = si;
                    dp_ssl  = sl;
                    dp_ssh  = sh / m_sinio;
                    dp_ssg  = sgh - m_cosio * dp_ssh;
                    dp_se2  = dp_ee2;
                    dp_si2  = dp_xi2;
                    dp_sl2  = dp_xl2;
                    dp_sgh2 = dp_xgh2;
                    dp_sh2  = dp_xh2;
                    dp_se3  = dp_e3;
                    dp_si3  = dp_xi3;
                    dp_sl3  = dp_xl3;
                    dp_sgh3 = dp_xgh3;
                    dp_sh3  = dp_xh3;
                    dp_sl4  = dp_xl4;
                    dp_sgh4 = dp_xgh4;
                    zcosg   = dpi_zcosgl;
                    zsing   = dpi_zsingl;
                    zcosi   = dpi_zcosil;
                    zsini   = dpi_zsinil;
                    zcosh   = dpi_zcoshl * cosq + dpi_zsinhl * sinq;
                    zsinh   = sinq * dpi_zcoshl - cosq * dpi_zsinhl;
                    zn      = znl;

                    const double c1l = 4.7968065E-7;

                    cc = c1l;
                    ze = zel;
                }
            }

            #endregion

            dp_sse = dp_sse + se;
            dp_ssi = dp_ssi + si;
            dp_ssl = dp_ssl + sl;
            dp_ssg = dp_ssg + sgh - m_cosio / m_sinio * sh;
            dp_ssh = dp_ssh + sh / m_sinio;

            // Geopotential resonance initialization for 12 hour orbits
            gp_reso = false;
            gp_sync = false;

            double g310;
            double f220;
            double bfact = 0.0;

            // Determine if orbit is 12- or 24-hour resonant.
            // Mean motion is given in radians per minute.
            if ((Orbit.MeanMotion > 0.0034906585) && (Orbit.MeanMotion < 0.0052359877))
            {
                // Orbit is within the Clarke Belt (period is 24-hour resonant).
                // Synchronous resonance terms initialization
                gp_reso = true;
                gp_sync = true;

                #region 24-hour resonant

                double g200 = 1.0 + eosq * (-2.5 + 0.8125 * eosq);

                g310 = 1.0 + 2.0 * eosq;

                double g300 = 1.0 + eosq * (-6.0 + 6.60937 * eosq);

                f220 = 0.75 * (1.0 + m_cosio) * (1.0 + m_cosio);

                double f311 = 0.9375 * m_sinio * m_sinio * (1.0 + 3 * m_cosio) - 0.75 * (1.0 + m_cosio);
                double f330 = 1.0 + m_cosio;

                f330 = 1.875 * f330 * f330 * f330;

                const double q22 = 1.7891679e-06;
                const double q33 = 2.2123015e-07;
                const double q31 = 2.1460748e-06;

                dp_del1 = 3.0 * m_xnodp * m_xnodp * aqnv * aqnv;
                dp_del2 = 2.0 * dp_del1 * f220 * g200 * q22;
                dp_del3 = 3.0 * dp_del1 * f330 * g300 * q33 * aqnv;

                dp_del1  = dp_del1 * f311 * g310 * q31 * aqnv;
                dp_xlamo = xmao + Orbit.RAAN + Orbit.ArgPerigee - dp_thgr;
                bfact    = m_xmdot + xpidot - thdt;
                bfact    = bfact + dp_ssl + dp_ssg + dp_ssh;

                #endregion
            }
            else if (((Orbit.MeanMotion >= 8.26E-3) && (Orbit.MeanMotion <= 9.24E-3)) && (eq >= 0.5))
            {
                // Period is 12-hour resonant
                gp_reso = true;

                #region 12-hour resonant

                double eoc  = eq * eosq;
                double g201 = -0.306 - (eq - 0.64) * 0.440;

                double g211; double g322;
                double g410; double g422;
                double g520;

                if (eq <= 0.65)
                {
                    g211 = 3.616 - 13.247 * eq + 16.290 * eosq;
                    g310 = -19.302 + 117.390 * eq - 228.419 * eosq + 156.591 * eoc;
                    g322 = -18.9068 + 109.7927 * eq - 214.6334 * eosq + 146.5816 * eoc;
                    g410 = -41.122 + 242.694 * eq - 471.094 * eosq + 313.953 * eoc;
                    g422 = -146.407 + 841.880 * eq - 1629.014 * eosq + 1083.435 * eoc;
                    g520 = -532.114 + 3017.977 * eq - 5740.0 * eosq + 3708.276 * eoc;
                }
                else
                {
                    g211 = -72.099 + 331.819 * eq - 508.738 * eosq + 266.724 * eoc;
                    g310 = -346.844 + 1582.851 * eq - 2415.925 * eosq + 1246.113 * eoc;
                    g322 = -342.585 + 1554.908 * eq - 2366.899 * eosq + 1215.972 * eoc;
                    g410 = -1052.797 + 4758.686 * eq - 7193.992 * eosq + 3651.957 * eoc;
                    g422 = -3581.69 + 16178.11 * eq - 24462.77 * eosq + 12422.52 * eoc;

                    if (eq <= 0.715)
                    {
                        g520 = 1464.74 - 4664.75 * eq + 3763.64 * eosq;
                    }
                    else
                    {
                        g520 = -5149.66 + 29936.92 * eq - 54087.36 * eosq + 31324.56 * eoc;
                    }
                }

                double g533;
                double g521;
                double g532;

                if (eq < 0.7)
                {
                    g533 = -919.2277 + 4988.61 * eq - 9064.77 * eosq + 5542.21 * eoc;
                    g521 = -822.71072 + 4568.6173 * eq - 8491.4146 * eosq + 5337.524 * eoc;
                    g532 = -853.666 + 4690.25 * eq - 8624.77 * eosq + 5341.4 * eoc;
                }
                else
                {
                    g533 = -37995.78 + 161616.52 * eq - 229838.2 * eosq + 109377.94 * eoc;
                    g521 = -51752.104 + 218913.95 * eq - 309468.16 * eosq + 146349.42 * eoc;
                    g532 = -40023.88 + 170470.89 * eq - 242699.48 * eosq + 115605.82 * eoc;
                }

                double sini2 = m_sinio * m_sinio;
                double cosi2 = m_cosio * m_cosio;

                f220 = 0.75 * (1.0 + 2.0 * m_cosio + cosi2);

                double f221 = 1.5 * sini2;
                double f321 = 1.875 * m_sinio * (1.0 - 2.0 * m_cosio - 3.0 * cosi2);
                double f322 = -1.875 * m_sinio * (1.0 + 2.0 * m_cosio - 3.0 * cosi2);
                double f441 = 35.0 * sini2 * f220;
                double f442 = 39.3750 * sini2 * sini2;
                double f522 = 9.84375 * m_sinio * (sini2 * (1.0 - 2.0 * m_cosio - 5.0 * cosi2) +
                                                   0.33333333 * (-2.0 + 4.0 * m_cosio + 6.0 * cosi2));
                double f523 = m_sinio * (4.92187512 * sini2 * (-2.0 - 4.0 * m_cosio + 10.0 * cosi2) +
                                         6.56250012 * (1.0 + 2.0 * m_cosio - 3.0 * cosi2));
                double f542  = 29.53125 * m_sinio * (2.0 - 8.0 * m_cosio + cosi2 * (-12.0 + 8.0 * m_cosio + 10.0 * cosi2));
                double f543  = 29.53125 * m_sinio * (-2.0 - 8.0 * m_cosio + cosi2 * (12.0 + 8.0 * m_cosio - 10.0 * cosi2));
                double xno2  = m_xnodp * m_xnodp;
                double ainv2 = aqnv * aqnv;
                double temp1 = 3.0 * xno2 * ainv2;

                const double root22 = 1.7891679E-6;
                const double root32 = 3.7393792E-7;
                const double root44 = 7.3636953E-9;
                const double root52 = 1.1428639E-7;
                const double root54 = 2.1765803E-9;

                double temp = temp1 * root22;

                dp_d2201 = temp * f220 * g201;
                dp_d2211 = temp * f221 * g211;
                temp1    = temp1 * aqnv;
                temp     = temp1 * root32;
                dp_d3210 = temp * f321 * g310;
                dp_d3222 = temp * f322 * g322;
                temp1    = temp1 * aqnv;
                temp     = 2.0 * temp1 * root44;
                dp_d4410 = temp * f441 * g410;
                dp_d4422 = temp * f442 * g422;
                temp1    = temp1 * aqnv;
                temp     = temp1 * root52;
                dp_d5220 = temp * f522 * g520;
                dp_d5232 = temp * f523 * g532;
                temp     = 2.0 * temp1 * root54;
                dp_d5421 = temp * f542 * g521;
                dp_d5433 = temp * f543 * g533;
                dp_xlamo = xmao + Orbit.RAAN + Orbit.RAAN - dp_thgr - dp_thgr;
                bfact    = m_xmdot + m_xnodot + m_xnodot - thdt - thdt;
                bfact    = bfact + dp_ssl + dp_ssh + dp_ssh;

                #endregion
            }

            if (gp_reso || gp_sync)
            {
                dp_xfact = bfact - m_xnodp;

                // Initialize integrator
                dp_xli = dp_xlamo;
                dp_xni = m_xnodp;
                // dp_atime = 0.0; // performed by runtime
                dp_stepp = 720.0;
                dp_stepn = -720.0;
                dp_step2 = 259200.0;
            }
        }
Beispiel #10
0
        /// <summary>
        /// Returns the topo-centric (azimuth, elevation, etc.) coordinates for
        /// a target object described by the given ECI coordinates.
        /// </summary>
        /// <param name="eci">The ECI coordinates of the target object.</param>
        /// <returns>The look angle to the target object.</returns>
        public TopoTime GetLookAngle(EciTime eci)
        {
            // Calculate the ECI coordinates for this Site object at the time
            // of interest.
            Julian  date      = eci.Date;
            EciTime eciSite   = PositionEci(date);
            Vector  vecRgRate = new Vector(eci.Velocity.X - eciSite.Velocity.X,
                                           eci.Velocity.Y - eciSite.Velocity.Y,
                                           eci.Velocity.Z - eciSite.Velocity.Z);

            double x = eci.Position.X - eciSite.Position.X;
            double y = eci.Position.Y - eciSite.Position.Y;
            double z = eci.Position.Z - eciSite.Position.Z;
            double w = Math.Sqrt(Globals.Sqr(x) + Globals.Sqr(y) + Globals.Sqr(z));

            Vector vecRange = new Vector(x, y, z, w);

            // The site's Local Mean Sidereal Time at the time of interest.
            double theta = date.ToLmst(LongitudeRad);

            double sin_lat   = Math.Sin(LatitudeRad);
            double cos_lat   = Math.Cos(LatitudeRad);
            double sin_theta = Math.Sin(theta);
            double cos_theta = Math.Cos(theta);

            double top_s = sin_lat * cos_theta * vecRange.X +
                           sin_lat * sin_theta * vecRange.Y -
                           cos_lat * vecRange.Z;
            double top_e = -sin_theta * vecRange.X +
                           cos_theta * vecRange.Y;
            double top_z = cos_lat * cos_theta * vecRange.X +
                           cos_lat * sin_theta * vecRange.Y +
                           sin_lat * vecRange.Z;
            double az = Math.Atan(-top_e / top_s);

            if (top_s > 0.0)
            {
                az += Globals.Pi;
            }

            if (az < 0.0)
            {
                az += 2.0 * Globals.Pi;
            }

            double el   = Math.Asin(top_z / vecRange.W);
            double rate = (vecRange.X * vecRgRate.X +
                           vecRange.Y * vecRgRate.Y +
                           vecRange.Z * vecRgRate.Z) / vecRange.W;

            TopoTime topo = new TopoTime(az,         // azimuth, radians
                                         el,         // elevation, radians
                                         vecRange.W, // range, km
                                         rate,       // rate, km / sec
                                         eci.Date);

#if WANT_ATMOSPHERIC_CORRECTION
            // Elevation correction for atmospheric refraction.
            // Reference:  Astronomical Algorithms by Jean Meeus, pp. 101-104
            // Note:  Correction is meaningless when apparent elevation is below horizon
            topo.ElevationRad += Globals.ToRadians((1.02 /
                                                    Math.Tan(Globals.ToRadians(Globals.ToDegrees(el) + 10.3 /
                                                                               (Globals.ToDegrees(el) + 5.11)))) / 60.0);
            if (topo.ElevationRad < 0.0)
            {
                topo.ElevationRad = el; // Reset to true elevation
            }

            if (topo.ElevationRad > (Math.PI / 2.0))
            {
                topo.ElevationRad = (Math.PI / 2.0);
            }
#endif
            return(topo);
        }
Beispiel #11
0
        /// <summary>
        /// Calculate satellite ECI position/velocity for a given time.
        /// </summary>
        /// <param name="tsince">Target time, in minutes-past-epoch format.</param>
        /// <returns>AU-based position/velocity ECI coordinates.</returns>
        /// <remarks>
        /// This procedure returns the ECI position and velocity for the satellite
        /// in the orbit at the given number of minutes since the TLE epoch time.
        /// The algorithm uses NORAD's Simplified General Perturbation 4 near earth
        /// orbit model.
        /// </remarks>
        public override EciTime GetPosition(double tsince)
        {
            // For m_perigee less than 220 kilometers, the isimp flag is set and
            // the equations are truncated to linear variation in square root of a
            // and quadratic variation in mean anomaly.  Also, the m_c3 term, the
            // delta omega term, and the delta m term are dropped.
            bool isimp = false || (m_aodp * (1.0 - m_satEcc) / Globals.Ae) < (220.0 / Globals.Xkmper + Globals.Ae);

            double d2 = 0.0;
            double d3 = 0.0;
            double d4 = 0.0;

            double t3cof = 0.0;
            double t4cof = 0.0;
            double t5cof = 0.0;

            if (!isimp)
            {
                double c1sq = m_c1 * m_c1;

                d2 = 4.0 * m_aodp * m_tsi * c1sq;

                double temp = d2 * m_tsi * m_c1 / 3.0;

                d3 = (17.0 * m_aodp + m_s4) * temp;
                d4 = 0.5 * temp * m_aodp * m_tsi *
                     (221.0 * m_aodp + 31.0 * m_s4) * m_c1;
                t3cof = d2 + 2.0 * c1sq;
                t4cof = 0.25 * (3.0 * d3 + m_c1 * (12.0 * d2 + 10.0 * c1sq));
                t5cof = 0.2 * (3.0 * d4 + 12.0 * m_c1 * d3 + 6.0 *
                               d2 * d2 + 15.0 * c1sq * (2.0 * d2 + c1sq));
            }

            // Update for secular gravity and atmospheric drag.
            double xmdf   = Orbit.MeanAnomaly + m_xmdot * tsince;
            double omgadf = Orbit.ArgPerigee + m_omgdot * tsince;
            double xnoddf = Orbit.RAAN + m_xnodot * tsince;
            double omega  = omgadf;
            double xmp    = xmdf;
            double tsq    = tsince * tsince;
            double xnode  = xnoddf + m_xnodcf * tsq;
            double tempa  = 1.0 - m_c1 * tsince;
            double tempe  = Orbit.BStar * m_c4 * tsince;
            double templ  = m_t2cof * tsq;

            if (!isimp)
            {
                double delomg = m_omgcof * tsince;
                double delm   = m_xmcof * (Math.Pow(1.0 + m_eta * Math.Cos(xmdf), 3.0) - m_delmo);
                double temp   = delomg + delm;

                xmp   = xmdf + temp;
                omega = omgadf - temp;

                double tcube = tsq * tsince;
                double tfour = tsince * tcube;

                tempa = tempa - d2 * tsq - d3 * tcube - d4 * tfour;
                tempe = tempe + Orbit.BStar * m_c5 * (Math.Sin(xmp) - m_sinmo);
                templ = templ + t3cof * tcube + tfour * (t4cof + tsince * t5cof);
            }

            double a = m_aodp * Globals.Sqr(tempa);
            double e = m_satEcc - tempe;

            double xl = xmp + omega + xnode + m_xnodp * templ;
            double xn = Globals.Xke / Math.Pow(a, 1.5);

            return(FinalPosition(m_satInc, omgadf, e, a, xl, xnode, xn, tsince));
        }
Beispiel #12
0
        // ///////////////////////////////////////////////////////////////////////////
        // getLookAngle()
        // Return the topocentric (azimuth, elevation, etc.) coordinates for a target
        // object described by the input ECI coordinates.
        public CoordTopo getLookAngle(Eci eci)
        {
            // Calculate the ECI coordinates for this Site object at the time
            // of interest.
            Julian date    = eci.Date;
            Eci    eciSite = new Eci(m_geo, date);

            // The Site ECI units are km-based; ensure target ECI units are same
            if (!eci.UnitsAreKm())
            {
                throw new Exception("ECI units must be kilometer-based");
            }

            Vector vecRgRate = new Vector(eci.Velocity.X - eciSite.Velocity.X,
                                          eci.Velocity.Y - eciSite.Velocity.Y,
                                          eci.Velocity.Z - eciSite.Velocity.Z);

            double x = eci.Position.X - eciSite.Position.X;
            double y = eci.Position.Y - eciSite.Position.Y;
            double z = eci.Position.Z - eciSite.Position.Z;
            double w = Math.Sqrt(Globals.Sqr(x) + Globals.Sqr(y) + Globals.Sqr(z));

            Vector vecRange = new Vector(x, y, z, w);

            // The site's Local Mean Sidereal Time at the time of interest.
            double theta = date.toLMST(Longitude);

            double sin_lat   = Math.Sin(Latitude);
            double cos_lat   = Math.Cos(Latitude);
            double sin_theta = Math.Sin(theta);
            double cos_theta = Math.Cos(theta);

            double top_s = sin_lat * cos_theta * vecRange.X +
                           sin_lat * sin_theta * vecRange.Y -
                           cos_lat * vecRange.Z;
            double top_e = -sin_theta * vecRange.X +
                           cos_theta * vecRange.Y;
            double top_z = cos_lat * cos_theta * vecRange.X +
                           cos_lat * sin_theta * vecRange.Y +
                           sin_lat * vecRange.Z;
            double az = Math.Atan(-top_e / top_s);

            if (top_s > 0.0)
            {
                az += Globals.PI;
            }

            if (az < 0.0)
            {
                az += 2.0 * Globals.PI;
            }

            double el   = Math.Asin(top_z / vecRange.W);
            double rate = (vecRange.X * vecRgRate.X +
                           vecRange.Y * vecRgRate.Y +
                           vecRange.Z * vecRgRate.Z) / vecRange.W;

            CoordTopo topo = new CoordTopo(az,         // azimuth, radians
                                           el,         // elevation, radians
                                           vecRange.W, // range, km
                                           rate);      // rate, km / sec

#if WANT_ATMOSPHERIC_CORRECTION
            // Elevation correction for atmospheric refraction.
            // Reference:  Astronomical Algorithms by Jean Meeus, pp. 101-104
            // Note:  Correction is meaningless when apparent elevation is below horizon
            topo.m_El += Globals.Deg2Rad((1.02 /
                                          Math.Tan(Globals.Deg2Rad(Globals.Rad2Deg(el) + 10.3 /
                                                                   (Globals.Rad2Deg(el) + 5.11)))) / 60.0);
            if (topo.m_El < 0.0)
            {
                topo.m_El = el; // Reset to true elevation
            }
            if (topo.m_El > (Globals.PI / 2))
            {
                topo.m_El = (Globals.PI / 2);
            }
#endif
            return(topo);
        }