예제 #1
0
        /// <summary>
        /// Gets precessional elements to convert equatorial coordinates of a point from one epoch to another.
        /// Equatorial coordinates of a point must be reffered to system FK5.
        /// </summary>
        /// <param name="jd0">Initial epoch, in Julian Days.</param>
        /// <param name="jd">Target (final) epoch, in Julian Days.</param>
        /// <returns>
        /// <see cref="PrecessionalElements"/> to convert equatorial coordinates of a point from
        /// one epoch (<paramref name="jd0"/>) to another (<paramref name="jd"/>).
        /// </returns>
        /// <remarks>
        /// This method is taken from AA(I), chapter 20 ("Precession", topic "Rigorous method").
        /// </remarks>
        public static PrecessionalElements ElementsFK5(double jd0, double jd)
        {
            PrecessionalElements p = new PrecessionalElements();

            p.InitialEpoch = jd0;
            p.TargetEpoch  = jd;

            double T = (jd0 - 2451545.0) / 36525.0;
            double t = (jd - jd0) / 36525.0;

            double T2 = T * T;
            double t2 = t * t;
            double t3 = t2 * t;

            // all values in seconds of arc
            p.zeta = (2306.2181 + 1.39656 * T - 0.000139 * T2) * t
                     + (0.30188 - 0.000344 * T) * t2 + 0.017998 * t3;
            p.z = (2306.2181 + 1.39656 * T - 0.000139 * T2) * t
                  + (1.09468 + 0.000066 * T) * t2 + 0.018203 * t3;
            p.theta = (2004.3109 - 0.85330 * T - 0.000217 * T2) * t
                      - (0.42665 + 0.000217 * T) * t2 - 0.041833 * t3;

            // convert to degress
            p.zeta  /= 3600;
            p.z     /= 3600;
            p.theta /= 3600;

            return(p);
        }
예제 #2
0
        /// <summary>
        /// Performs reduction of equatorial coordinates from one epoch to another
        /// with using of precessional elements.
        /// </summary>
        /// <param name="eq0">Equatorial coordinates for initial epoch.</param>
        /// <param name="p">Precessional elements for reduction from initial epoch to target (final) epoch.</param>
        /// <returns>Equatorial coordinates for target (final) epoch.</returns>
        /// <remarks>
        /// This method is taken from AA(I), formula 20.4.
        /// </remarks>
        public static CrdsEquatorial GetEquatorialCoordinates(CrdsEquatorial eq0, PrecessionalElements p)
        {
            CrdsEquatorial eq = new CrdsEquatorial();

            double sinDelta0     = Math.Sin(Angle.ToRadians(eq0.Delta));
            double cosDelta0     = Math.Cos(Angle.ToRadians(eq0.Delta));
            double sinTheta      = Math.Sin(Angle.ToRadians(p.theta));
            double cosTheta      = Math.Cos(Angle.ToRadians(p.theta));
            double sinAlpha0Zeta = Math.Sin(Angle.ToRadians(eq0.Alpha + p.zeta));
            double cosAlpha0Zeta = Math.Cos(Angle.ToRadians(eq0.Alpha + p.zeta));

            double A = cosDelta0 * sinAlpha0Zeta;
            double B = cosTheta * cosDelta0 * cosAlpha0Zeta - sinTheta * sinDelta0;
            double C = sinTheta * cosDelta0 * cosAlpha0Zeta + cosTheta * sinDelta0;

            eq.Alpha = Angle.ToDegrees(Math.Atan2(A, B)) + p.z;
            eq.Alpha = Angle.To360(eq.Alpha);

            if (Math.Abs(C) == 1)
            {
                eq.Delta = Angle.ToDegrees(Math.Acos(A * A + B * B));
            }
            else
            {
                eq.Delta = Angle.ToDegrees(Math.Asin(C));
            }

            return(eq);
        }
예제 #3
0
        /// <summary>
        /// Calculates ecliptical coordinates of Triton, largest moon of Neptune.
        /// </summary>
        /// <param name="jd">Julian Day of calculation</param>
        /// <param name="neptune">Ecliptical coordinates of Neptune for the Julian Day specified.</param>
        /// <returns>Ecliptical coordinates of Triton for specified date.</returns>
        /// <remarks>
        ///
        /// The method is based on following works:
        ///
        /// 1. Harris, A.W. (1984), "Physical Properties of Neptune and Triton Inferred from the Orbit of Triton" NASA CP-2330, pages 357-373:
        ///    http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1984NASCP2330..357H&defaultprint=YES&filetype=.pdf
        ///
        /// 2. Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
        ///    University Science Book, Mill Valley (California), 1992,
        ///    Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 373, 6.61-1 Triton
        ///    https://archive.org/download/131123ExplanatorySupplementAstronomicalAlmanac/131123-explanatory-supplement-astronomical-almanac.pdf
        ///
        /// </remarks>
        private static CrdsEcliptical TritonPosition(double jd, CrdsEcliptical neptune)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to J1950 epoch, as algorithm requires
            CrdsEquatorial       eq            = neptune.ToEquatorial(epsilon);
            PrecessionalElements pe1950        = Precession.ElementsFK5(jd, Date.EPOCH_J1950);
            CrdsEquatorial       eqNeptune1950 = Precession.GetEquatorialCoordinates(eq, pe1950);

            const double t0 = 2433282.5;       // 1.0 Jan 1950
            const double a  = 0.0023683;       // semimajor axis of Triton, in a.u.

            const double n       = 61.2588532; // nodal mean motion, degrees per day
            const double lambda0 = 200.913;    // longitude from ascending node through the invariable plane at epoch
            const double i       = 158.996;    // inclination of orbit to the invariable plane

            const double Omega0 = 151.401;     // angle from the intersection of invariable plane with the earth's
                                               // equatorial plane of 1950.0 to the ascending node
                                               // of the orbit through the invariable plane

            const double OmegaDot = 0.57806;   // nodal precision rate, degrees per year

            // Calculate J2000.0 RA and Declination of the pole of the invariable plane
            // These formulae are taken from the book:
            // Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
            // University Science Book, Mill Valley (California), 1992,
            // Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 373, 6.61-1 Triton
            double T  = (jd - 2451545.0) / 36525.0;
            double N  = ToRadians(359.28 + 54.308 * T);
            double ap = 298.72 + 2.58 * Sin(N) - 0.04 * Sin(2 * N);
            double dp = 42.63 - 1.90 * Cos(N) + 0.01 * Cos(2 * N);

            // Convert pole coordinates to J1950
            CrdsEquatorial eqPole1950 = Precession.GetEquatorialCoordinates(new CrdsEquatorial(ap, dp), pe1950);

            ap = eqPole1950.Alpha;
            dp = eqPole1950.Delta;

            // take light-time effect into account
            double tau = PlanetPositions.LightTimeEffect(neptune.Distance);

            double lambda = To360(lambda0 + n * (jd - t0 - tau));
            double omega  = Omega0 + OmegaDot * (jd - t0 - tau) / 365.25;

            // cartesian state vector of Triton
            var r =
                Matrix.R3(ToRadians(-ap - 90)) *
                Matrix.R1(ToRadians(dp - 90)) *
                Matrix.R3(ToRadians(-omega)) *
                Matrix.R1(ToRadians(-i)) *
                new Matrix(new[, ] {
                { a *Cos(ToRadians(lambda)) }, { a *Sin(ToRadians(lambda)) }, { 0 }
            });

            // normalize by distance to Neptune
            r.Values[0, 0] /= neptune.Distance;
            r.Values[1, 0] /= neptune.Distance;
            r.Values[2, 0] /= neptune.Distance;

            // offsets vector
            var d =
                Matrix.R2(ToRadians(-eqNeptune1950.Delta)) *
                Matrix.R3(ToRadians(eqNeptune1950.Alpha)) *
                r;

            // radial component, positive away from observer
            // converted to degrees
            double x = ToDegrees(d.Values[0, 0]);

            // semimajor axis, expressed in degrees, as visible from Earth
            double theta = ToDegrees(Atan(a / neptune.Distance));

            // offsets values in degrees
            double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
            double dDelta         = ToDegrees(d.Values[2, 0]);

            double delta  = eqNeptune1950.Delta + dDelta;
            double dAlpha = dAlphaCosDelta / Cos(ToRadians(eqNeptune1950.Delta));
            double alpha  = eqNeptune1950.Alpha + dAlpha;

            CrdsEquatorial eqTriton1950 = new CrdsEquatorial(alpha, delta);

            // convert J1950 equatorial coordinates to current epoch
            // and to ecliptical
            PrecessionalElements pe        = Precession.ElementsFK5(Date.EPOCH_J1950, jd);
            CrdsEquatorial       eqTriton  = Precession.GetEquatorialCoordinates(eqTriton1950, pe);
            CrdsEcliptical       eclTriton = eqTriton.ToEcliptical(epsilon);

            // calculate distance to Earth
            eclTriton.Distance = neptune.Distance + x / theta * a;

            return(eclTriton);
        }
예제 #4
0
        /// <summary>
        /// Calculates ecliptical coordinates of Nereid, the third-largest moon of Neptune.
        /// </summary>
        /// <param name="jd">Julian Day of calculation</param>
        /// <param name="neptune">Ecliptical coordinates of Neptune for the Julian Day specified.</param>
        /// <returns>Ecliptical coordinates of Nereid for specified date.</returns>
        /// <remarks>
        ///
        /// The method is based on work of F. Mignard (1981), "The Mean Elements of Nereid",
        /// The Astronomical Journal, Vol 86, Number 11, pages 1728-1729
        /// The work can be found by link: http://adsabs.harvard.edu/full/1981AJ.....86.1728M
        ///
        /// There are some changes from the original algorithm were made,
        /// to be compliant with ephemeris provided by Nasa JPL Horizons system (https://ssd.jpl.nasa.gov/?ephemerides):
        ///
        /// 1. Other value of mean motion (n) is used:
        ///    - original work : n = 0.999552
        ///    - implementation: n = 360.0 / 360.1362 (where 360.1362 is an orbital period)
        ///
        /// 2. Rotation around Z axis by angle OmegaN should by taken with NEGATIVE sign,
        ///    insted of POSITIVE sign in original work (possible typo?),
        ///    note the NEGATIVE sign for "Ne" angle (same meaning as "OmegaN" in original work) in the book:
        ///    Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
        ///    University Science Book, Mill Valley (California), 1992,
        ///    Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 376, formula 6.62-3
        ///
        /// </remarks>
        private static CrdsEcliptical NereidPosition(double jd, CrdsEcliptical neptune)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to J1950 epoch, as algorithm requires
            CrdsEquatorial       eq            = neptune.ToEquatorial(epsilon);
            PrecessionalElements pe1950        = Precession.ElementsFK5(jd, Date.EPOCH_J1950);
            CrdsEquatorial       eqNeptune1950 = Precession.GetEquatorialCoordinates(eq, pe1950);

            const double jd0 = 2433680.5;           // Initial Epoch: 3.0 Feb 1951

            const double a      = 0.036868;         // Semi-major axis, in a.u.
            const double e0     = 0.74515;          // Orbit eccentricity for jd0 epoch
            const double i0     = 10.041;           // Inclination of the orbit for jd0 epoch, in degrees
            const double Omega0 = 329.3;            // Longitude of the node of the orbit for jd0 epoch, in degrees
            const double M0     = 358.91;           // Mean anomaly for jd0 epoch, in degrees
            const double n      = 360.0 / 360.1362; // Mean motion, in degrees per day
            const double OmegaN = 3.552;            // Longitude of ascending node of the orbit of Neptune, for J1950.0 epoch, in degrees
            const double gamma  = 22.313;           // Inclination of the orbit of Neptune, for J1950.0 epoch, in degrees

            // take light-time effect into account
            double tau = PlanetPositions.LightTimeEffect(neptune.Distance);

            double t = jd - tau - jd0;          // in days
            double T = t / 36525.0;             // in Julian centuries

            double psi      = ToRadians(To360(282.9 + 2.68 * T));
            double twoTheta = ToRadians(To360(107.4 + 0.01196 * t));

            // Equation to found omega, argument of pericenter
            Func <double, double> omegaEquation = (om) => To360(282.9 + 2.68 * T - 19.25 * Sin(2 * psi) + 3.23 * Sin(4 * psi) - 0.725 * Sin(6 * psi) - 0.351 * Sin(twoTheta) - 0.7 * Sin(ToRadians(2 * om) - twoTheta)) - om;

            // Solve equation (find root: omega value)
            double omega = ToRadians(FindRoots(omegaEquation, 0, 360, 1e-8));

            // Find longitude of the node
            double Omega = Omega0 - 2.4 * T + 19.7 * Sin(2 * psi) - 3.3 * Sin(4 * psi) + 0.7 * Sin(6 * psi) + 0.357 * Sin(twoTheta) + 0.276 * Sin(2 * omega - twoTheta);

            // Find orbit eccentricity
            double e = e0 - 0.006 * Cos(2 * psi) + 0.0056 * Cos(2 * omega - twoTheta);

            // Find mean anomaly
            double M = To360(M0 + n * t - 0.38 * Sin(2 * psi) + 1.0 * Sin(2 * omega - twoTheta));

            // Find inclination
            double cosi = Cos(ToRadians(i0)) - 9.4e-3 * Cos(2 * psi);
            double i    = Acos(cosi);

            // Find eccentric anomaly by solving Kepler equation
            double E = SolveKepler(M, e);

            double X = a * (Cos(E) - e);
            double Y = a * Sqrt(1 - e * e) * Sin(E);

            Matrix d =
                Matrix.R2(ToRadians(-eqNeptune1950.Delta)) *
                Matrix.R3(ToRadians(eqNeptune1950.Alpha)) *
                Matrix.R3(ToRadians(-OmegaN)) *
                Matrix.R1(ToRadians(-gamma)) *
                Matrix.R3(ToRadians(-Omega)) *
                Matrix.R1(-i) *
                Matrix.R3(-omega) *
                new Matrix(new double[, ] {
                { X / neptune.Distance }, { Y / neptune.Distance }, { 0 }
            });

            // radial component, positive away from observer
            // converted to degrees
            double x = ToDegrees(d.Values[0, 0]);

            // offsets values in degrees
            double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
            double dDelta         = ToDegrees(d.Values[2, 0]);

            double delta  = eqNeptune1950.Delta + dDelta;
            double dAlpha = dAlphaCosDelta / Cos(ToRadians(eqNeptune1950.Delta));
            double alpha  = eqNeptune1950.Alpha + dAlpha;

            CrdsEquatorial eqNereid1950 = new CrdsEquatorial(alpha, delta);

            // convert J1950 equatorial coordinates to current epoch
            // and to ecliptical
            PrecessionalElements pe        = Precession.ElementsFK5(Date.EPOCH_J1950, jd);
            CrdsEquatorial       eqNereid  = Precession.GetEquatorialCoordinates(eqNereid1950, pe);
            CrdsEcliptical       eclNereid = eqNereid.ToEcliptical(epsilon);

            // semimajor axis, expressed in degrees, as visible from Earth
            double theta = ToDegrees(Atan(a / neptune.Distance));

            // calculate distance to Earth
            eclNereid.Distance = neptune.Distance + x / theta * a;

            return(eclNereid);
        }
예제 #5
0
        public static CrdsEcliptical Position(double jd, GenericSatelliteOrbit orbit, CrdsEcliptical planet)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to epoch, as algorithm requires
            CrdsEquatorial       eq            = planet.ToEquatorial(epsilon);
            PrecessionalElements peEpoch       = Precession.ElementsFK5(jd, Date.EPOCH_J2000);
            CrdsEquatorial       eqPlanetEpoch = Precession.GetEquatorialCoordinates(eq, peEpoch);

            // ecliptical pole
            CrdsEquatorial pole = new CrdsEcliptical(0, 90).ToEquatorial(epsilon);

            double distance0;
            double distance = planet.Distance;

            CrdsEcliptical eclSatellite;

            do
            {
                distance0 = distance;

                // take light-time effect into account
                double tau = PlanetPositions.LightTimeEffect(distance);

                double t = jd - tau - orbit.jd;

                double M = To360(orbit.M + orbit.n * t);

                double omega = To360(orbit.w + t * 360.0 / (orbit.Pw * 365.25));
                double node  = To360(orbit.Om + t * 360.0 / (orbit.POm * 365.25));

                // Find eccentric anomaly by solving Kepler equation
                double E = SolveKepler(M, orbit.e);

                double X = orbit.a * (Cos(E) - orbit.e);
                double Y = orbit.a * Sqrt(1 - orbit.e * orbit.e) * Sin(E);

                // cartesian state vector of satellite
                var d =
                    Matrix.R2(ToRadians(-eqPlanetEpoch.Delta)) *
                    Matrix.R3(ToRadians(eqPlanetEpoch.Alpha)) *
                    Matrix.R3(ToRadians(-pole.Alpha - 90)) *
                    Matrix.R1(ToRadians(pole.Delta - 90)) *
                    Matrix.R3(ToRadians(-node)) *
                    Matrix.R1(ToRadians(-orbit.i)) *
                    Matrix.R3(ToRadians(-omega)) *
                    new Matrix(new double[, ] {
                    { X / distance }, { Y / distance }, { 0 }
                });

                // radial component, positive away from observer
                // converted to degrees
                double x = ToDegrees(d.Values[0, 0]);

                // semimajor axis, expressed in degrees, as visible from Earth
                double theta = ToDegrees(Atan(orbit.a / distance));

                // offsets values in degrees
                double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
                double dDelta         = ToDegrees(d.Values[2, 0]);

                double delta  = eqPlanetEpoch.Delta + dDelta;
                double dAlpha = dAlphaCosDelta / Cos(ToRadians(delta));
                double alpha  = eqPlanetEpoch.Alpha + dAlpha;

                CrdsEquatorial eqSatelliteEpoch = new CrdsEquatorial(alpha, delta);

                // convert jd0 equatorial coordinates to current epoch
                // and to ecliptical
                PrecessionalElements pe          = Precession.ElementsFK5(Date.EPOCH_J2000, jd);
                CrdsEquatorial       eqSatellite = Precession.GetEquatorialCoordinates(eqSatelliteEpoch, pe);
                eclSatellite = eqSatellite.ToEcliptical(epsilon);

                // calculate distance to Earth
                distance = planet.Distance + x / theta * orbit.a;
            }while (Abs(distance - distance0) > 1e-6);

            eclSatellite.Distance = distance;

            return(eclSatellite);
        }