| 1 | /* this file contains routines to support Earth satellites.
 | 
|---|
| 2 |  *
 | 
|---|
| 3 |  * Orbit propagation is based on the NORAD SGP4/SDP4 code, as converted from
 | 
|---|
| 4 |  *   the original FORTRAN to C by Magnus Backstrom. The paper "Spacetrack
 | 
|---|
| 5 |  *   Report Number 3: Models for Propagation of NORAD Element Sets" describes
 | 
|---|
| 6 |  *   the calculations.
 | 
|---|
| 7 |  *   See http://www.celestrak.com/NORAD/documentation/spacetrk.pdf.
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * A few topocentric routines are also used from the 'orbit' program which is
 | 
|---|
| 10 |  *   Copyright (c) 1986,1987,1988,1989,1990 Robert W. Berger N3EMO
 | 
|---|
| 11 |  *
 | 
|---|
| 12 |  */
 | 
|---|
| 13 | 
 | 
|---|
| 14 | /* define this to use orbit's propagator
 | 
|---|
| 15 | #define USE_ORBIT_PROPAGATOR
 | 
|---|
| 16 |  */
 | 
|---|
| 17 | 
 | 
|---|
| 18 | /* define this to print some stuff
 | 
|---|
| 19 | #define ESAT_TRACE
 | 
|---|
| 20 |  */
 | 
|---|
| 21 | 
 | 
|---|
| 22 | #include <stdio.h>
 | 
|---|
| 23 | #include <math.h>
 | 
|---|
| 24 | #include <string.h>
 | 
|---|
| 25 | 
 | 
|---|
| 26 | #if defined(__STDC__)
 | 
|---|
| 27 | #include <stdlib.h>
 | 
|---|
| 28 | #endif
 | 
|---|
| 29 | 
 | 
|---|
| 30 | #include "P_.h"
 | 
|---|
| 31 | #include "astro.h"
 | 
|---|
| 32 | #include "circum.h"
 | 
|---|
| 33 | #include "preferences.h"
 | 
|---|
| 34 | 
 | 
|---|
| 35 | #include "vector.h"
 | 
|---|
| 36 | #include "sattypes.h"
 | 
|---|
| 37 | #include "satlib.h"
 | 
|---|
| 38 | 
 | 
|---|
| 39 | 
 | 
|---|
| 40 | #define ESAT_MAG        2       /* fake satellite magnitude */
 | 
|---|
| 41 | 
 | 
|---|
| 42 | typedef double MAT3x3[3][3];
 | 
|---|
| 43 | 
 | 
|---|
| 44 | static void esat_prop P_((Now *np, Obj *op, double *SatX, double *SatY, double
 | 
|---|
| 45 |     *SatZ, double *SatVX, double *SatVY, double *SatVZ));
 | 
|---|
| 46 | static void GetSatelliteParams P_((Obj *op));
 | 
|---|
| 47 | static void GetSiteParams P_((Now *np));
 | 
|---|
| 48 | static double Kepler P_((double MeanAnomaly, double Eccentricity));
 | 
|---|
| 49 | static void GetSubSatPoint P_((double SatX, double SatY, double SatZ,
 | 
|---|
| 50 |     double T, double *Latitude, double *Longitude, double *Height));
 | 
|---|
| 51 | static void GetSatPosition P_((double EpochTime, double EpochRAAN,
 | 
|---|
| 52 |     double EpochArgPerigee, double SemiMajorAxis, double Inclination,
 | 
|---|
| 53 |     double Eccentricity, double RAANPrecession, double PerigeePrecession,
 | 
|---|
| 54 |     double T, double TrueAnomaly, double *X, double *Y, double *Z,
 | 
|---|
| 55 |     double *Radius, double *VX, double *VY, double *VZ));
 | 
|---|
| 56 | static void GetSitPosition P_((double SiteLat, double SiteLong,
 | 
|---|
| 57 |     double SiteElevation, double CrntTime, double *SiteX, double *SiteY,
 | 
|---|
| 58 |     double *SiteZ, double *SiteVX, double *SiteVY, MAT3x3 SiteMatrix));
 | 
|---|
| 59 | static void GetRange P_((double SiteX, double SiteY, double SiteZ,
 | 
|---|
| 60 |     double SiteVX, double SiteVY, double SatX, double SatY, double SatZ,
 | 
|---|
| 61 |     double SatVX, double SatVY, double SatVZ, double *Range,
 | 
|---|
| 62 |     double *RangeRate));
 | 
|---|
| 63 | static void GetTopocentric P_((double SatX, double SatY, double SatZ,
 | 
|---|
| 64 |     double SiteX, double SiteY, double SiteZ, MAT3x3 SiteMatrix, double *X,
 | 
|---|
| 65 |     double *Y, double *Z));
 | 
|---|
| 66 | static void GetBearings P_((double SatX, double SatY, double SatZ,
 | 
|---|
| 67 |     double SiteX, double SiteY, double SiteZ, MAT3x3 SiteMatrix,
 | 
|---|
| 68 |     double *Azimuth, double *Elevation));
 | 
|---|
| 69 | static int Eclipsed P_((double SatX, double SatY, double SatZ,
 | 
|---|
| 70 |     double SatRadius, double CrntTime));
 | 
|---|
| 71 | static void InitOrbitRoutines P_((double EpochDay, int AtEod));
 | 
|---|
| 72 | 
 | 
|---|
| 73 | #ifdef USE_ORBIT_PROPAGATOR 
 | 
|---|
| 74 | static void GetPrecession P_((double SemiMajorAxis, double Eccentricity,
 | 
|---|
| 75 |     double Inclination, double *RAANPrecession, double *PerigeePrecession));
 | 
|---|
| 76 | #endif /* USE_ORBIT_PROPAGATOR */
 | 
|---|
| 77 | 
 | 
|---|
| 78 | /* stuff from orbit */
 | 
|---|
| 79 | /* char VersionStr[] = "N3EMO Orbit Simulator  v3.9"; */
 | 
|---|
| 80 | 
 | 
|---|
| 81 | #ifdef PI2
 | 
|---|
| 82 | #undef PI2
 | 
|---|
| 83 | #endif
 | 
|---|
| 84 | 
 | 
|---|
| 85 | #define PI2 (PI*2)
 | 
|---|
| 86 | 
 | 
|---|
| 87 | #define MinutesPerDay (24*60.0)
 | 
|---|
| 88 | #define SecondsPerDay (60*MinutesPerDay)
 | 
|---|
| 89 | #define HalfSecond (0.5/SecondsPerDay)
 | 
|---|
| 90 | #define EarthRadius 6378.16             /* Kilometers           */
 | 
|---|
| 91 | #define C 2.997925e5                    /* Kilometers/Second    */
 | 
|---|
| 92 | #define RadiansPerDegree (PI/180)
 | 
|---|
| 93 | #define ABS(x) ((x) < 0 ? (-(x)) : (x))
 | 
|---|
| 94 | #define SQR(x) ((x)*(x))
 | 
|---|
| 95 |  
 | 
|---|
| 96 | #define EarthFlat (1/298.25)            /* Earth Flattening Coeff. */
 | 
|---|
| 97 | #define SiderealSolar 1.0027379093
 | 
|---|
| 98 | #define SidRate (PI2*SiderealSolar/SecondsPerDay)       /* radians/second */
 | 
|---|
| 99 | #define GM 398600                       /* Kilometers^3/seconds^2 */
 | 
|---|
| 100 |  
 | 
|---|
| 101 | #define Epsilon (RadiansPerDegree/3600)     /* 1 arc second */
 | 
|---|
| 102 | #define SunRadius 695000                
 | 
|---|
| 103 | #define SunSemiMajorAxis  149598845.0       /* Kilometers                  */
 | 
|---|
| 104 |  
 | 
|---|
| 105 | /*  Keplerian Elements and misc. data for the satellite              */
 | 
|---|
| 106 | static double  EpochDay;                   /* time of epoch                 */
 | 
|---|
| 107 | static double EpochMeanAnomaly;            /* Mean Anomaly at epoch         */
 | 
|---|
| 108 | static long EpochOrbitNum;                 /* Integer orbit # of epoch      */
 | 
|---|
| 109 | static double EpochRAAN;                   /* RAAN at epoch                 */
 | 
|---|
| 110 | static double epochMeanMotion;             /* Revolutions/day               */
 | 
|---|
| 111 | static double OrbitalDecay;                /* Revolutions/day^2             */
 | 
|---|
| 112 | static double EpochArgPerigee;             /* argument of perigee at epoch  */
 | 
|---|
| 113 | static double Eccentricity;
 | 
|---|
| 114 | static double Inclination;
 | 
|---|
| 115 |  
 | 
|---|
| 116 | /* Site Parameters */
 | 
|---|
| 117 | static double SiteLat,SiteLong,SiteAltitude;
 | 
|---|
| 118 | 
 | 
|---|
| 119 | 
 | 
|---|
| 120 | static double SidDay,SidReference;      /* Date and sidereal time       */
 | 
|---|
| 121 | 
 | 
|---|
| 122 | /* Keplerian elements for the sun */
 | 
|---|
| 123 | static double SunEpochTime,SunInclination,SunRAAN,SunEccentricity,
 | 
|---|
| 124 |        SunArgPerigee,SunMeanAnomaly,SunMeanMotion;
 | 
|---|
| 125 | 
 | 
|---|
| 126 | /* values for shadow geometry */
 | 
|---|
| 127 | static double SinPenumbra,CosPenumbra;
 | 
|---|
| 128 | 
 | 
|---|
| 129 | 
 | 
|---|
| 130 | /* given a Now and an Obj with info about an earth satellite in the es_* fields
 | 
|---|
| 131 |  * fill in the s_* sky fields describing the satellite.
 | 
|---|
| 132 |  * as usual, we compute the geocentric ra/dec precessed to np->n_epoch and
 | 
|---|
| 133 |  * compute topocentric altitude accounting for refraction.
 | 
|---|
| 134 |  * return 0 if all ok, else -1.
 | 
|---|
| 135 |  */
 | 
|---|
| 136 | int
 | 
|---|
| 137 | obj_earthsat (np, op)
 | 
|---|
| 138 | Now *np;
 | 
|---|
| 139 | Obj *op;
 | 
|---|
| 140 | {
 | 
|---|
| 141 |         double Radius;              /* From geocenter                  */
 | 
|---|
| 142 |         double SatX,SatY,SatZ;      /* In Right Ascension based system */
 | 
|---|
| 143 |         double SatVX,SatVY,SatVZ;   /* Kilometers/second               */
 | 
|---|
| 144 |         double SiteX,SiteY,SiteZ;
 | 
|---|
| 145 |         double SiteVX,SiteVY;
 | 
|---|
| 146 |         double SiteMatrix[3][3];
 | 
|---|
| 147 |         double Height;
 | 
|---|
| 148 |         double SSPLat,SSPLong;
 | 
|---|
| 149 |         double Azimuth,Elevation,Range;
 | 
|---|
| 150 |         double RangeRate;
 | 
|---|
| 151 |         double dtmp;
 | 
|---|
| 152 |         double CrntTime;
 | 
|---|
| 153 |         double ra, dec;
 | 
|---|
| 154 | 
 | 
|---|
| 155 | #ifdef ESAT_TRACE
 | 
|---|
| 156 |         printf ("\n");
 | 
|---|
| 157 |         printf ("Name = %s\n", op->o_name);
 | 
|---|
| 158 |         printf ("current jd = %13.5f\n", mjd+MJD0);
 | 
|---|
| 159 |         printf ("current mjd = %g\n", mjd);
 | 
|---|
| 160 |         printf ("satellite jd = %13.5f\n", op->es_epoch+MJD0);
 | 
|---|
| 161 |         printf ("satellite mjd = %g\n", op->es_epoch);
 | 
|---|
| 162 | #endif /* ESAT_TRACE */
 | 
|---|
| 163 | 
 | 
|---|
| 164 |         /* xephem uses noon 12/31/1899 as 0; orbit uses midnight 1/1/1900.
 | 
|---|
| 165 |          * thus, xephem runs 12 hours, or 1/2 day, behind of what orbit wants.
 | 
|---|
| 166 |          */
 | 
|---|
| 167 |         CrntTime = mjd + 0.5;
 | 
|---|
| 168 | 
 | 
|---|
| 169 |         /* extract the XEphem data forms into those used by orbit.
 | 
|---|
| 170 |          * (we still use some functions and names from orbit, thank you).
 | 
|---|
| 171 |          */
 | 
|---|
| 172 |         InitOrbitRoutines(CrntTime, 1);
 | 
|---|
| 173 |         GetSatelliteParams(op);
 | 
|---|
| 174 |         GetSiteParams(np);
 | 
|---|
| 175 | 
 | 
|---|
| 176 |         /* propagate to np->n_mjd */
 | 
|---|
| 177 |         esat_prop (np, op, &SatX, &SatY, &SatZ, &SatVX, &SatVY, &SatVZ);
 | 
|---|
| 178 |         Radius = sqrt (SatX*SatX + SatY*SatY + SatZ*SatZ);
 | 
|---|
| 179 | 
 | 
|---|
| 180 |         /* find geocentric EOD equatorial directly from xyz vector */
 | 
|---|
| 181 |         dtmp = atan2 (SatY, SatX);
 | 
|---|
| 182 |         range (&dtmp, 2*PI);
 | 
|---|
| 183 |         op->s_gaera = (float) dtmp;
 | 
|---|
| 184 |         op->s_gaedec = (float) atan2 (SatZ, sqrt(SatX*SatX + SatY*SatY));
 | 
|---|
| 185 | 
 | 
|---|
| 186 |         /* find topocentric from site location */
 | 
|---|
| 187 |         GetSitPosition(SiteLat,SiteLong,SiteAltitude,CrntTime,
 | 
|---|
| 188 |                     &SiteX,&SiteY,&SiteZ,&SiteVX,&SiteVY,SiteMatrix);
 | 
|---|
| 189 |         GetBearings(SatX,SatY,SatZ,SiteX,SiteY,SiteZ,SiteMatrix,
 | 
|---|
| 190 |                     &Azimuth,&Elevation);
 | 
|---|
| 191 | 
 | 
|---|
| 192 |         op->s_az = Azimuth;
 | 
|---|
| 193 |         refract (pressure, temp, Elevation, &dtmp);
 | 
|---|
| 194 |         op->s_alt = dtmp;
 | 
|---|
| 195 | 
 | 
|---|
| 196 |         /* Range: line-of-site distance to satellite, m
 | 
|---|
| 197 |          * RangeRate: m/s
 | 
|---|
| 198 |          */
 | 
|---|
| 199 |         GetRange(SiteX,SiteY,SiteZ,SiteVX,SiteVY,
 | 
|---|
| 200 |             SatX,SatY,SatZ,SatVX,SatVY,SatVZ,&Range,&RangeRate);
 | 
|---|
| 201 | 
 | 
|---|
| 202 |         op->s_range = (float)(Range*1000);      /* we want m */
 | 
|---|
| 203 |         op->s_rangev = (float)(RangeRate*1000); /* we want m/s */
 | 
|---|
| 204 |  
 | 
|---|
| 205 |         /* SSPLat: sub-satellite latitude, rads 
 | 
|---|
| 206 |          * SSPLong: sub-satellite longitude, >0 west, rads 
 | 
|---|
| 207 |          * Height: height of satellite above ground, m
 | 
|---|
| 208 |          */
 | 
|---|
| 209 |         GetSubSatPoint(SatX,SatY,SatZ,CrntTime,
 | 
|---|
| 210 |             &SSPLat,&SSPLong,&Height);
 | 
|---|
| 211 | 
 | 
|---|
| 212 |         op->s_elev = (float)(Height*1000);      /* we want m */
 | 
|---|
| 213 |         op->s_sublat = (float)SSPLat;
 | 
|---|
| 214 |         op->s_sublng = (float)(-SSPLong);       /* we want +E */
 | 
|---|
| 215 | 
 | 
|---|
| 216 |         op->s_eclipsed = Eclipsed(SatX,SatY,SatZ,Radius,CrntTime);
 | 
|---|
| 217 | 
 | 
|---|
| 218 | #ifdef ESAT_TRACE
 | 
|---|
| 219 |         printf ("CrntTime = %g\n", CrntTime);
 | 
|---|
| 220 |         printf ("SatX = %g\n", SatX);
 | 
|---|
| 221 |         printf ("SatY = %g\n", SatY);
 | 
|---|
| 222 |         printf ("SatZ = %g\n", SatZ);
 | 
|---|
| 223 |         printf ("Radius = %g\n", Radius);
 | 
|---|
| 224 |         printf ("SatVX = %g\n", SatVX);
 | 
|---|
| 225 |         printf ("SatVY = %g\n", SatVY);
 | 
|---|
| 226 |         printf ("SatVZ = %g\n", SatVZ);
 | 
|---|
| 227 |         printf ("SiteX = %g\n", SiteX);
 | 
|---|
| 228 |         printf ("SiteY = %g\n", SiteY);
 | 
|---|
| 229 |         printf ("SiteZ = %g\n", SiteZ);
 | 
|---|
| 230 |         printf ("SiteVX = %g\n", SiteVX);
 | 
|---|
| 231 |         printf ("SiteVY = %g\n", SiteVY);
 | 
|---|
| 232 |         printf ("Height = %g\n", Height);
 | 
|---|
| 233 |         printf ("SSPLat = %g\n", SSPLat);
 | 
|---|
| 234 |         printf ("SSPLong = %g\n", SSPLong);
 | 
|---|
| 235 |         printf ("Azimuth = %g\n", Azimuth);
 | 
|---|
| 236 |         printf ("Elevation = %g\n", Elevation);
 | 
|---|
| 237 |         printf ("Range = %g\n", Range);
 | 
|---|
| 238 |         printf ("RangeRate = %g\n", RangeRate);
 | 
|---|
| 239 |         fflush (stdout);
 | 
|---|
| 240 | #endif  /* ESAT_TRACE */
 | 
|---|
| 241 | 
 | 
|---|
| 242 |         /* find s_ra/dec, depending on current options. */
 | 
|---|
| 243 |         if (pref_get(PREF_EQUATORIAL) == PREF_TOPO) {
 | 
|---|
| 244 |             double ha, lst;
 | 
|---|
| 245 |             aa_hadec (lat, (double)op->s_alt, (double)op->s_az, &ha, &dec);
 | 
|---|
| 246 |             now_lst (np, &lst);
 | 
|---|
| 247 |             ra = hrrad(lst) - ha;
 | 
|---|
| 248 |             range (&ra, 2*PI);
 | 
|---|
| 249 |         } else {
 | 
|---|
| 250 |             ra = op->s_gaera;
 | 
|---|
| 251 |             dec = op->s_gaedec;
 | 
|---|
| 252 |         }
 | 
|---|
| 253 |         if (epoch != EOD)
 | 
|---|
| 254 |             precess (mjd, epoch, &ra, &dec);
 | 
|---|
| 255 |         op->s_ra = (float)ra;
 | 
|---|
| 256 |         op->s_dec = (float)dec;
 | 
|---|
| 257 | 
 | 
|---|
| 258 |         /* just make up a size and brightness */
 | 
|---|
| 259 |         set_smag (op, ESAT_MAG);
 | 
|---|
| 260 |         op->s_size = (float)0;
 | 
|---|
| 261 | 
 | 
|---|
| 262 |         return (0);
 | 
|---|
| 263 | }
 | 
|---|
| 264 | 
 | 
|---|
| 265 | /* find position and velocity vector for given Obj at the given time.
 | 
|---|
| 266 |  * set USE_ORBIT_PROPAGATOR depending on desired propagator to use.
 | 
|---|
| 267 |  */
 | 
|---|
| 268 | static void
 | 
|---|
| 269 | esat_prop (np, op, SatX, SatY, SatZ, SatVX, SatVY, SatVZ)
 | 
|---|
| 270 | Now *np;
 | 
|---|
| 271 | Obj *op;
 | 
|---|
| 272 | double *SatX,*SatY,*SatZ;
 | 
|---|
| 273 | double *SatVX,*SatVY,*SatVZ;
 | 
|---|
| 274 | {
 | 
|---|
| 275 | #ifdef USE_ORBIT_PROPAGATOR
 | 
|---|
| 276 |         double ReferenceOrbit;      /* Floating point orbit # at epoch */
 | 
|---|
| 277 |         double CurrentOrbit;
 | 
|---|
| 278 |         long OrbitNum;
 | 
|---|
| 279 |         double RAANPrecession,PerigeePrecession;
 | 
|---|
| 280 |         double MeanAnomaly,TrueAnomaly;
 | 
|---|
| 281 |         double SemiMajorAxis;
 | 
|---|
| 282 |         double AverageMotion,       /* Corrected for drag              */
 | 
|---|
| 283 |             CurrentMotion;
 | 
|---|
| 284 |         double Radius;
 | 
|---|
| 285 |         double CrntTime;
 | 
|---|
| 286 | 
 | 
|---|
| 287 |         SemiMajorAxis = 331.25 * exp(2*log(MinutesPerDay/epochMeanMotion)/3);
 | 
|---|
| 288 |         GetPrecession(SemiMajorAxis,Eccentricity,Inclination,&RAANPrecession,
 | 
|---|
| 289 |                             &PerigeePrecession);
 | 
|---|
| 290 | 
 | 
|---|
| 291 |         ReferenceOrbit = EpochMeanAnomaly/PI2 + EpochOrbitNum;
 | 
|---|
| 292 |      
 | 
|---|
| 293 |         CrntTime = mjd + 0.5;
 | 
|---|
| 294 |         AverageMotion = epochMeanMotion + (CrntTime-EpochDay)*OrbitalDecay/2;
 | 
|---|
| 295 |         CurrentMotion = epochMeanMotion + (CrntTime-EpochDay)*OrbitalDecay;
 | 
|---|
| 296 | 
 | 
|---|
| 297 |         SemiMajorAxis = 331.25 * exp(2*log(MinutesPerDay/CurrentMotion)/3);
 | 
|---|
| 298 |      
 | 
|---|
| 299 |         CurrentOrbit = ReferenceOrbit + (CrntTime-EpochDay)*AverageMotion;
 | 
|---|
| 300 | 
 | 
|---|
| 301 |         OrbitNum = CurrentOrbit;
 | 
|---|
| 302 |      
 | 
|---|
| 303 |         MeanAnomaly = (CurrentOrbit-OrbitNum)*PI2;
 | 
|---|
| 304 |      
 | 
|---|
| 305 |         TrueAnomaly = Kepler(MeanAnomaly,Eccentricity);
 | 
|---|
| 306 | 
 | 
|---|
| 307 |         GetSatPosition(EpochDay,EpochRAAN,EpochArgPerigee,SemiMajorAxis,
 | 
|---|
| 308 |                 Inclination,Eccentricity,RAANPrecession,PerigeePrecession,
 | 
|---|
| 309 |                 CrntTime,TrueAnomaly,SatX,SatY,SatZ,&Radius,SatVX,SatVY,SatVZ);
 | 
|---|
| 310 | 
 | 
|---|
| 311 | #ifdef ESAT_TRACE
 | 
|---|
| 312 |         printf ("O Radius = %g\n", Radius);
 | 
|---|
| 313 |         printf ("ReferenceOrbit = %g\n", ReferenceOrbit);
 | 
|---|
| 314 |         printf ("CurrentOrbit = %g\n", CurrentOrbit);
 | 
|---|
| 315 |         printf ("RAANPrecession = %g\n", RAANPrecession);
 | 
|---|
| 316 |         printf ("PerigeePrecession = %g\n", PerigeePrecession);
 | 
|---|
| 317 |         printf ("MeanAnomaly = %g\n", MeanAnomaly);
 | 
|---|
| 318 |         printf ("TrueAnomaly = %g\n", TrueAnomaly);
 | 
|---|
| 319 |         printf ("SemiMajorAxis = %g\n", SemiMajorAxis);
 | 
|---|
| 320 |         printf ("AverageMotion = %g\n", AverageMotion);
 | 
|---|
| 321 |         printf ("CurrentMotion = %g\n", CurrentMotion);
 | 
|---|
| 322 | #endif  /* ESAT_TRACE */
 | 
|---|
| 323 | 
 | 
|---|
| 324 | #else   /* ! USE_ORBIT_PROPAGATOR */
 | 
|---|
| 325 | #define MPD             1440.0          /* minutes per day */
 | 
|---|
| 326 | 
 | 
|---|
| 327 |         SatElem se;
 | 
|---|
| 328 |         SatData sd;
 | 
|---|
| 329 |         Vec3 posvec, velvec;
 | 
|---|
| 330 |         double dy;
 | 
|---|
| 331 |         double dt;
 | 
|---|
| 332 |         int yr;
 | 
|---|
| 333 | 
 | 
|---|
| 334 |         /* init */
 | 
|---|
| 335 |         memset ((void *)&se, 0, sizeof(se));
 | 
|---|
| 336 |         memset ((void *)&sd, 0, sizeof(sd));
 | 
|---|
| 337 |         sd.elem = &se;
 | 
|---|
| 338 | 
 | 
|---|
| 339 |         /* se_EPOCH is packed as yr*1000 + dy, where yr is years since 1900
 | 
|---|
| 340 |          * and dy is day of year, Jan 1 being 1
 | 
|---|
| 341 |          */
 | 
|---|
| 342 |         mjd_dayno (op->es_epoch, &yr, &dy);
 | 
|---|
| 343 |         yr -= 1900;
 | 
|---|
| 344 |         dy += 1;
 | 
|---|
| 345 |         se.se_EPOCH = yr*1000 + dy;
 | 
|---|
| 346 | 
 | 
|---|
| 347 |         /* others carry over with some change in units */
 | 
|---|
| 348 |         se.se_XNO = op->es_n * (2*PI/MPD);      /* revs/day to rads/min */
 | 
|---|
| 349 |         se.se_XINCL = (float)degrad(op->es_inc);
 | 
|---|
| 350 |         se.se_XNODEO = (float)degrad(op->es_raan);
 | 
|---|
| 351 |         se.se_EO = op->es_e;
 | 
|---|
| 352 |         se.se_OMEGAO = (float)degrad(op->es_ap);
 | 
|---|
| 353 |         se.se_XMO = (float)degrad(op->es_M);
 | 
|---|
| 354 |         se.se_BSTAR = op->es_drag;
 | 
|---|
| 355 |         se.se_XNDT20 = op->es_decay*(2*PI/MPD/MPD); /*rv/dy^^2 to rad/min^^2*/
 | 
|---|
| 356 | 
 | 
|---|
| 357 |         se.se_id.orbit = op->es_orbit;
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         dt = (mjd-op->es_epoch)*MPD;
 | 
|---|
| 360 | 
 | 
|---|
| 361 | #ifdef ESAT_TRACE
 | 
|---|
| 362 |         printf ("se_EPOCH  : %30.20f\n", se.se_EPOCH);
 | 
|---|
| 363 |         printf ("se_XNO    : %30.20f\n", se.se_XNO);
 | 
|---|
| 364 |         printf ("se_XINCL  : %30.20f\n", se.se_XINCL);
 | 
|---|
| 365 |         printf ("se_XNODEO : %30.20f\n", se.se_XNODEO);
 | 
|---|
| 366 |         printf ("se_EO     : %30.20f\n", se.se_EO);
 | 
|---|
| 367 |         printf ("se_OMEGAO : %30.20f\n", se.se_OMEGAO);
 | 
|---|
| 368 |         printf ("se_XMO    : %30.20f\n", se.se_XMO);
 | 
|---|
| 369 |         printf ("se_BSTAR  : %30.20f\n", se.se_BSTAR);
 | 
|---|
| 370 |         printf ("se_XNDT20 : %30.20f\n", se.se_XNDT20);
 | 
|---|
| 371 |         printf ("se_orbit  : %30d\n",    se.se_id.orbit);
 | 
|---|
| 372 |         printf ("dt        : %30.20f\n", dt);
 | 
|---|
| 373 | #endif /* ESAT_TRACE */
 | 
|---|
| 374 | 
 | 
|---|
| 375 |         /* compute the state vectors */
 | 
|---|
| 376 |         if (se.se_XNO >= (1.0/225.0))
 | 
|---|
| 377 |             sgp4(&sd, &posvec, &velvec, dt); /* NEO */
 | 
|---|
| 378 |         else
 | 
|---|
| 379 |             sdp4(&sd, &posvec, &velvec, dt); /* GEO */
 | 
|---|
| 380 |         if (sd.prop.sgp4)
 | 
|---|
| 381 |             free (sd.prop.sgp4);        /* sd.prop.sdp4 is in same union */
 | 
|---|
| 382 |         if (sd.deep)
 | 
|---|
| 383 |             free (sd.deep);
 | 
|---|
| 384 | 
 | 
|---|
| 385 |         *SatX = ERAD*posvec.x/1000;     /* earth radii to km */
 | 
|---|
| 386 |         *SatY = ERAD*posvec.y/1000;
 | 
|---|
| 387 |         *SatZ = ERAD*posvec.z/1000;
 | 
|---|
| 388 |         *SatVX = 100*velvec.x;          /* ?? */
 | 
|---|
| 389 |         *SatVY = 100*velvec.y;
 | 
|---|
| 390 |         *SatVZ = 100*velvec.z;
 | 
|---|
| 391 | #endif
 | 
|---|
| 392 | }
 | 
|---|
| 393 | 
 | 
|---|
| 394 | 
 | 
|---|
| 395 | /* grab the xephem stuff from op and copy into orbit's globals.
 | 
|---|
| 396 |  */
 | 
|---|
| 397 | static void
 | 
|---|
| 398 | GetSatelliteParams(op)
 | 
|---|
| 399 | Obj *op;
 | 
|---|
| 400 | {
 | 
|---|
| 401 |         /* the following are for the orbit functions */
 | 
|---|
| 402 |         /* xephem uses noon 12/31/1899 as 0; orbit uses midnight 1/1/1900 as 1.
 | 
|---|
| 403 |          * thus, xephem runs 12 hours, or 1/2 day, behind of what orbit wants.
 | 
|---|
| 404 |          */
 | 
|---|
| 405 |         EpochDay = op->es_epoch + 0.5;
 | 
|---|
| 406 | 
 | 
|---|
| 407 |         /* xephem stores inc in degrees; orbit wants rads */
 | 
|---|
| 408 |         Inclination = degrad(op->es_inc);
 | 
|---|
| 409 | 
 | 
|---|
| 410 |         /* xephem stores RAAN in degrees; orbit wants rads */
 | 
|---|
| 411 |         EpochRAAN = degrad(op->es_raan);
 | 
|---|
| 412 | 
 | 
|---|
| 413 |         Eccentricity = op->es_e;
 | 
|---|
| 414 | 
 | 
|---|
| 415 |         /* xephem stores arg of perigee in degrees; orbit wants rads */
 | 
|---|
| 416 |         EpochArgPerigee = degrad(op->es_ap);
 | 
|---|
| 417 | 
 | 
|---|
| 418 |         /* xephem stores mean anomaly in degrees; orbit wants rads */
 | 
|---|
| 419 |         EpochMeanAnomaly = degrad (op->es_M);
 | 
|---|
| 420 | 
 | 
|---|
| 421 |         epochMeanMotion = op->es_n;
 | 
|---|
| 422 | 
 | 
|---|
| 423 |         OrbitalDecay = op->es_decay;
 | 
|---|
| 424 | 
 | 
|---|
| 425 |         EpochOrbitNum = op->es_orbit;
 | 
|---|
| 426 | }
 | 
|---|
| 427 | 
 | 
|---|
| 428 | 
 | 
|---|
| 429 |  
 | 
|---|
| 430 | static void
 | 
|---|
| 431 | GetSiteParams(np)
 | 
|---|
| 432 | Now *np;
 | 
|---|
| 433 | {
 | 
|---|
| 434 |         SiteLat = lat;
 | 
|---|
| 435 |      
 | 
|---|
| 436 |         /* xephem stores longitude as >0 east; orbit wants >0 west */
 | 
|---|
| 437 |         SiteLong = 2.0*PI - lng;
 | 
|---|
| 438 |      
 | 
|---|
| 439 |         /* what orbit calls altitude xephem calls elevation and stores it from
 | 
|---|
| 440 |          * sea level in earth radii; orbit wants km
 | 
|---|
| 441 |          */
 | 
|---|
| 442 |         SiteAltitude = elev*ERAD/1000.0;
 | 
|---|
| 443 |      
 | 
|---|
| 444 |         /* we don't implement a minimum horizon altitude cutoff
 | 
|---|
| 445 |         SiteMinElev = 0;
 | 
|---|
| 446 |          */
 | 
|---|
| 447 | 
 | 
|---|
| 448 | #ifdef ESAT_TRACE
 | 
|---|
| 449 |         printf ("SiteLat = %g\n", SiteLat);
 | 
|---|
| 450 |         printf ("SiteLong = %g\n", SiteLong);
 | 
|---|
| 451 |         printf ("SiteAltitude = %g\n", SiteAltitude);
 | 
|---|
| 452 |         fflush (stdout);
 | 
|---|
| 453 | #endif
 | 
|---|
| 454 | }
 | 
|---|
| 455 | 
 | 
|---|
| 456 |  
 | 
|---|
| 457 | /* Solve Kepler's equation                                      */
 | 
|---|
| 458 | /* Inputs:                                                      */
 | 
|---|
| 459 | /*      MeanAnomaly     Time Since last perigee, in radians.    */
 | 
|---|
| 460 | /*                      PI2 = one complete orbit.               */
 | 
|---|
| 461 | /*      Eccentricity    Eccentricity of orbit's ellipse.        */
 | 
|---|
| 462 | /* Output:                                                      */
 | 
|---|
| 463 | /*      TrueAnomaly     Angle between perigee, geocenter, and   */
 | 
|---|
| 464 | /*                      current position.                       */
 | 
|---|
| 465 |  
 | 
|---|
| 466 | static
 | 
|---|
| 467 | double Kepler(MeanAnomaly,Eccentricity)
 | 
|---|
| 468 | register double MeanAnomaly,Eccentricity;
 | 
|---|
| 469 |  
 | 
|---|
| 470 | {
 | 
|---|
| 471 | register double E;              /* Eccentric Anomaly                    */
 | 
|---|
| 472 | register double Error;
 | 
|---|
| 473 | register double TrueAnomaly;
 | 
|---|
| 474 |  
 | 
|---|
| 475 |     E = MeanAnomaly ;/*+ Eccentricity*sin(MeanAnomaly);  -- Initial guess */
 | 
|---|
| 476 |     do
 | 
|---|
| 477 |         {
 | 
|---|
| 478 |         Error = (E - Eccentricity*sin(E) - MeanAnomaly)
 | 
|---|
| 479 |                 / (1 - Eccentricity*cos(E));
 | 
|---|
| 480 |         E -= Error;
 | 
|---|
| 481 |         }
 | 
|---|
| 482 |    while (ABS(Error) >= Epsilon);
 | 
|---|
| 483 | 
 | 
|---|
| 484 |     if (ABS(E-PI) < Epsilon)
 | 
|---|
| 485 |         TrueAnomaly = PI;
 | 
|---|
| 486 |       else
 | 
|---|
| 487 |         TrueAnomaly = 2*atan(sqrt((1+Eccentricity)/(1-Eccentricity))
 | 
|---|
| 488 |                                 *tan(E/2));
 | 
|---|
| 489 |     if (TrueAnomaly < 0)
 | 
|---|
| 490 |         TrueAnomaly += PI2;
 | 
|---|
| 491 |  
 | 
|---|
| 492 |     return TrueAnomaly;
 | 
|---|
| 493 | }
 | 
|---|
| 494 |  
 | 
|---|
| 495 | static void
 | 
|---|
| 496 | GetSubSatPoint(SatX,SatY,SatZ,T,Latitude,Longitude,Height)
 | 
|---|
| 497 | double SatX,SatY,SatZ,T;
 | 
|---|
| 498 | double *Latitude,*Longitude,*Height;
 | 
|---|
| 499 | {
 | 
|---|
| 500 |     double r;
 | 
|---|
| 501 |     /* ECD: long i; */
 | 
|---|
| 502 | 
 | 
|---|
| 503 |     r = sqrt(SQR(SatX) + SQR(SatY) + SQR(SatZ));
 | 
|---|
| 504 | 
 | 
|---|
| 505 |     *Longitude = PI2*((T-SidDay)*SiderealSolar + SidReference)
 | 
|---|
| 506 |                     - atan2(SatY,SatX);
 | 
|---|
| 507 | 
 | 
|---|
| 508 |     /* ECD:
 | 
|---|
| 509 |      * want Longitude in range -PI to PI , +W
 | 
|---|
| 510 |      */
 | 
|---|
| 511 |     range (Longitude, 2*PI);
 | 
|---|
| 512 |     if (*Longitude > PI)
 | 
|---|
| 513 |         *Longitude -= 2*PI;
 | 
|---|
| 514 | 
 | 
|---|
| 515 |     *Latitude = atan(SatZ/sqrt(SQR(SatX) + SQR(SatY)));
 | 
|---|
| 516 | 
 | 
|---|
| 517 | #if SSPELLIPSE
 | 
|---|
| 518 | #else
 | 
|---|
| 519 |     *Height = r - EarthRadius;
 | 
|---|
| 520 | #endif
 | 
|---|
| 521 | }
 | 
|---|
| 522 |  
 | 
|---|
| 523 |  
 | 
|---|
| 524 | #ifdef USE_ORBIT_PROPAGATOR
 | 
|---|
| 525 | static void
 | 
|---|
| 526 | GetPrecession(SemiMajorAxis,Eccentricity,Inclination,
 | 
|---|
| 527 |         RAANPrecession,PerigeePrecession)
 | 
|---|
| 528 | double SemiMajorAxis,Eccentricity,Inclination;
 | 
|---|
| 529 | double *RAANPrecession,*PerigeePrecession;
 | 
|---|
| 530 | {
 | 
|---|
| 531 |   *RAANPrecession = 9.95*pow(EarthRadius/SemiMajorAxis,3.5) * cos(Inclination)
 | 
|---|
| 532 |                  / SQR(1-SQR(Eccentricity)) * RadiansPerDegree;
 | 
|---|
| 533 |  
 | 
|---|
| 534 |   *PerigeePrecession = 4.97*pow(EarthRadius/SemiMajorAxis,3.5)
 | 
|---|
| 535 |          * (5*SQR(cos(Inclination))-1)
 | 
|---|
| 536 |                  / SQR(1-SQR(Eccentricity)) * RadiansPerDegree;
 | 
|---|
| 537 | }
 | 
|---|
| 538 | #endif /* USE_ORBIT_PROPAGATOR */
 | 
|---|
| 539 |  
 | 
|---|
| 540 | /* Compute the satellite postion and velocity in the RA based coordinate
 | 
|---|
| 541 |  * system.
 | 
|---|
| 542 |  * ECD: take care not to let Radius get below EarthRadius.
 | 
|---|
| 543 |  */
 | 
|---|
| 544 | 
 | 
|---|
| 545 | static void
 | 
|---|
| 546 | GetSatPosition(EpochTime,EpochRAAN,EpochArgPerigee,SemiMajorAxis,
 | 
|---|
| 547 |         Inclination,Eccentricity,RAANPrecession,PerigeePrecession,
 | 
|---|
| 548 |         T,TrueAnomaly,X,Y,Z,Radius,VX,VY,VZ)
 | 
|---|
| 549 |  
 | 
|---|
| 550 | double EpochTime,EpochRAAN,EpochArgPerigee;
 | 
|---|
| 551 | double SemiMajorAxis,Inclination,Eccentricity;
 | 
|---|
| 552 | double RAANPrecession,PerigeePrecession,T, TrueAnomaly;
 | 
|---|
| 553 | double *X,*Y,*Z,*Radius,*VX,*VY,*VZ;
 | 
|---|
| 554 | 
 | 
|---|
| 555 | {
 | 
|---|
| 556 |     double RAAN,ArgPerigee;
 | 
|---|
| 557 |  
 | 
|---|
| 558 | 
 | 
|---|
| 559 |     double Xw,Yw,VXw,VYw;       /* In orbital plane */
 | 
|---|
| 560 |     double Tmp;
 | 
|---|
| 561 |     double Px,Qx,Py,Qy,Pz,Qz;   /* Escobal transformation 31 */
 | 
|---|
| 562 |     double CosArgPerigee,SinArgPerigee;
 | 
|---|
| 563 |     double CosRAAN,SinRAAN,CoSinclination,SinInclination;
 | 
|---|
| 564 | 
 | 
|---|
| 565 |     *Radius = SemiMajorAxis*(1-SQR(Eccentricity))
 | 
|---|
| 566 |                         / (1+Eccentricity*cos(TrueAnomaly));
 | 
|---|
| 567 | 
 | 
|---|
| 568 |     if (*Radius <= EarthRadius)
 | 
|---|
| 569 |         *Radius = EarthRadius;
 | 
|---|
| 570 | 
 | 
|---|
| 571 | 
 | 
|---|
| 572 |     Xw = *Radius * cos(TrueAnomaly);
 | 
|---|
| 573 |     Yw = *Radius * sin(TrueAnomaly);
 | 
|---|
| 574 |     
 | 
|---|
| 575 |     Tmp = sqrt(GM/(SemiMajorAxis*(1-SQR(Eccentricity))));
 | 
|---|
| 576 | 
 | 
|---|
| 577 |     VXw = -Tmp*sin(TrueAnomaly);
 | 
|---|
| 578 |     VYw = Tmp*(cos(TrueAnomaly) + Eccentricity);
 | 
|---|
| 579 | 
 | 
|---|
| 580 |     ArgPerigee = EpochArgPerigee + (T-EpochTime)*PerigeePrecession;
 | 
|---|
| 581 |     RAAN = EpochRAAN - (T-EpochTime)*RAANPrecession;
 | 
|---|
| 582 | 
 | 
|---|
| 583 |     CosRAAN = cos(RAAN); SinRAAN = sin(RAAN);
 | 
|---|
| 584 |     CosArgPerigee = cos(ArgPerigee); SinArgPerigee = sin(ArgPerigee);
 | 
|---|
| 585 |     CoSinclination = cos(Inclination); SinInclination = sin(Inclination);
 | 
|---|
| 586 |     
 | 
|---|
| 587 |     Px = CosArgPerigee*CosRAAN - SinArgPerigee*SinRAAN*CoSinclination;
 | 
|---|
| 588 |     Py = CosArgPerigee*SinRAAN + SinArgPerigee*CosRAAN*CoSinclination;
 | 
|---|
| 589 |     Pz = SinArgPerigee*SinInclination;
 | 
|---|
| 590 |     Qx = -SinArgPerigee*CosRAAN - CosArgPerigee*SinRAAN*CoSinclination;
 | 
|---|
| 591 |     Qy = -SinArgPerigee*SinRAAN + CosArgPerigee*CosRAAN*CoSinclination;
 | 
|---|
| 592 |     Qz = CosArgPerigee*SinInclination;
 | 
|---|
| 593 | 
 | 
|---|
| 594 |     *X = Px*Xw + Qx*Yw;         /* Escobal, transformation #31 */
 | 
|---|
| 595 |     *Y = Py*Xw + Qy*Yw;
 | 
|---|
| 596 |     *Z = Pz*Xw + Qz*Yw;
 | 
|---|
| 597 | 
 | 
|---|
| 598 |     *VX = Px*VXw + Qx*VYw;
 | 
|---|
| 599 |     *VY = Py*VXw + Qy*VYw;
 | 
|---|
| 600 |     *VZ = Pz*VXw + Qz*VYw;
 | 
|---|
| 601 | }
 | 
|---|
| 602 | 
 | 
|---|
| 603 | /* Compute the site postion and velocity in the RA based coordinate
 | 
|---|
| 604 |    system. SiteMatrix is set to a matrix which is used by GetTopoCentric
 | 
|---|
| 605 |    to convert geocentric coordinates to topocentric (observer-centered)
 | 
|---|
| 606 |     coordinates. */
 | 
|---|
| 607 | 
 | 
|---|
| 608 | static void
 | 
|---|
| 609 | GetSitPosition(SiteLat,SiteLong,SiteElevation,CrntTime,
 | 
|---|
| 610 |              SiteX,SiteY,SiteZ,SiteVX,SiteVY,SiteMatrix)
 | 
|---|
| 611 | 
 | 
|---|
| 612 | double SiteLat,SiteLong,SiteElevation,CrntTime;
 | 
|---|
| 613 | double *SiteX,*SiteY,*SiteZ,*SiteVX,*SiteVY;
 | 
|---|
| 614 | MAT3x3 SiteMatrix;
 | 
|---|
| 615 | 
 | 
|---|
| 616 | {
 | 
|---|
| 617 |     static double G1,G2; /* Used to correct for flattening of the Earth */
 | 
|---|
| 618 |     static double CosLat,SinLat;
 | 
|---|
| 619 |     static double OldSiteLat = -100000;  /* Used to avoid unneccesary recomputation */
 | 
|---|
| 620 |     static double OldSiteElevation = -100000;
 | 
|---|
| 621 |     double Lat;
 | 
|---|
| 622 |     double SiteRA;      /* Right Ascension of site                      */
 | 
|---|
| 623 |     double CosRA,SinRA;
 | 
|---|
| 624 | 
 | 
|---|
| 625 |     if ((SiteLat != OldSiteLat) || (SiteElevation != OldSiteElevation))
 | 
|---|
| 626 |         {
 | 
|---|
| 627 |         OldSiteLat = SiteLat;
 | 
|---|
| 628 |         OldSiteElevation = SiteElevation;
 | 
|---|
| 629 |         Lat = atan(1/(1-SQR(EarthFlat))*tan(SiteLat));
 | 
|---|
| 630 | 
 | 
|---|
| 631 |         CosLat = cos(Lat);
 | 
|---|
| 632 |         SinLat = sin(Lat);
 | 
|---|
| 633 | 
 | 
|---|
| 634 |         G1 = EarthRadius/(sqrt(1-(2*EarthFlat-SQR(EarthFlat))*SQR(SinLat)));
 | 
|---|
| 635 |         G2 = G1*SQR(1-EarthFlat);
 | 
|---|
| 636 |         G1 += SiteElevation;
 | 
|---|
| 637 |         G2 += SiteElevation;
 | 
|---|
| 638 |         }
 | 
|---|
| 639 | 
 | 
|---|
| 640 | 
 | 
|---|
| 641 |     SiteRA = PI2*((CrntTime-SidDay)*SiderealSolar + SidReference)
 | 
|---|
| 642 |                  - SiteLong;
 | 
|---|
| 643 |     CosRA = cos(SiteRA);
 | 
|---|
| 644 |     SinRA = sin(SiteRA);
 | 
|---|
| 645 |     
 | 
|---|
| 646 | 
 | 
|---|
| 647 |     *SiteX = G1*CosLat*CosRA;
 | 
|---|
| 648 |     *SiteY = G1*CosLat*SinRA;
 | 
|---|
| 649 |     *SiteZ = G2*SinLat;
 | 
|---|
| 650 |     *SiteVX = -SidRate * *SiteY;
 | 
|---|
| 651 |     *SiteVY = SidRate * *SiteX;
 | 
|---|
| 652 | 
 | 
|---|
| 653 |     SiteMatrix[0][0] = SinLat*CosRA;
 | 
|---|
| 654 |     SiteMatrix[0][1] = SinLat*SinRA;
 | 
|---|
| 655 |     SiteMatrix[0][2] = -CosLat;
 | 
|---|
| 656 |     SiteMatrix[1][0] = -SinRA;
 | 
|---|
| 657 |     SiteMatrix[1][1] = CosRA;
 | 
|---|
| 658 |     SiteMatrix[1][2] = 0.0;
 | 
|---|
| 659 |     SiteMatrix[2][0] = CosRA*CosLat;
 | 
|---|
| 660 |     SiteMatrix[2][1] = SinRA*CosLat;
 | 
|---|
| 661 |     SiteMatrix[2][2] = SinLat;
 | 
|---|
| 662 | }
 | 
|---|
| 663 | 
 | 
|---|
| 664 | static void
 | 
|---|
| 665 | GetRange(SiteX,SiteY,SiteZ,SiteVX,SiteVY,
 | 
|---|
| 666 |         SatX,SatY,SatZ,SatVX,SatVY,SatVZ,Range,RangeRate)
 | 
|---|
| 667 | 
 | 
|---|
| 668 | double SiteX,SiteY,SiteZ,SiteVX,SiteVY;
 | 
|---|
| 669 | double SatX,SatY,SatZ,SatVX,SatVY,SatVZ;
 | 
|---|
| 670 | double *Range,*RangeRate;
 | 
|---|
| 671 | {
 | 
|---|
| 672 |     double DX,DY,DZ;
 | 
|---|
| 673 | 
 | 
|---|
| 674 |     DX = SatX - SiteX; DY = SatY - SiteY; DZ = SatZ - SiteZ;
 | 
|---|
| 675 | 
 | 
|---|
| 676 |     *Range = sqrt(SQR(DX)+SQR(DY)+SQR(DZ));    
 | 
|---|
| 677 | 
 | 
|---|
| 678 |     *RangeRate = ((SatVX-SiteVX)*DX + (SatVY-SiteVY)*DY + SatVZ*DZ)
 | 
|---|
| 679 |                         / *Range;
 | 
|---|
| 680 | }
 | 
|---|
| 681 | 
 | 
|---|
| 682 | /* Convert from geocentric RA based coordinates to topocentric
 | 
|---|
| 683 |    (observer centered) coordinates */
 | 
|---|
| 684 | 
 | 
|---|
| 685 | static void
 | 
|---|
| 686 | GetTopocentric(SatX,SatY,SatZ,SiteX,SiteY,SiteZ,SiteMatrix,X,Y,Z)
 | 
|---|
| 687 | double SatX,SatY,SatZ,SiteX,SiteY,SiteZ;
 | 
|---|
| 688 | double *X,*Y,*Z;
 | 
|---|
| 689 | MAT3x3 SiteMatrix;
 | 
|---|
| 690 | {
 | 
|---|
| 691 |     SatX -= SiteX;
 | 
|---|
| 692 |     SatY -= SiteY;
 | 
|---|
| 693 |     SatZ -= SiteZ;
 | 
|---|
| 694 | 
 | 
|---|
| 695 |     *X = SiteMatrix[0][0]*SatX + SiteMatrix[0][1]*SatY
 | 
|---|
| 696 |         + SiteMatrix[0][2]*SatZ; 
 | 
|---|
| 697 |     *Y = SiteMatrix[1][0]*SatX + SiteMatrix[1][1]*SatY
 | 
|---|
| 698 |         + SiteMatrix[1][2]*SatZ; 
 | 
|---|
| 699 |     *Z = SiteMatrix[2][0]*SatX + SiteMatrix[2][1]*SatY
 | 
|---|
| 700 |         + SiteMatrix[2][2]*SatZ; 
 | 
|---|
| 701 | }
 | 
|---|
| 702 | 
 | 
|---|
| 703 | static void
 | 
|---|
| 704 | GetBearings(SatX,SatY,SatZ,SiteX,SiteY,SiteZ,SiteMatrix,Azimuth,Elevation)
 | 
|---|
| 705 | double SatX,SatY,SatZ,SiteX,SiteY,SiteZ;
 | 
|---|
| 706 | MAT3x3 SiteMatrix;
 | 
|---|
| 707 | double *Azimuth,*Elevation;
 | 
|---|
| 708 | {
 | 
|---|
| 709 |     double x,y,z;
 | 
|---|
| 710 | 
 | 
|---|
| 711 |     GetTopocentric(SatX,SatY,SatZ,SiteX,SiteY,SiteZ,SiteMatrix,&x,&y,&z);
 | 
|---|
| 712 | 
 | 
|---|
| 713 |     *Elevation = atan(z/sqrt(SQR(x) + SQR(y)));
 | 
|---|
| 714 | 
 | 
|---|
| 715 |     *Azimuth = PI - atan2(y,x);
 | 
|---|
| 716 | 
 | 
|---|
| 717 |     if (*Azimuth < 0)
 | 
|---|
| 718 |         *Azimuth += PI;
 | 
|---|
| 719 | }
 | 
|---|
| 720 | 
 | 
|---|
| 721 | static int
 | 
|---|
| 722 | Eclipsed(SatX,SatY,SatZ,SatRadius,CrntTime)
 | 
|---|
| 723 | double SatX,SatY,SatZ,SatRadius,CrntTime;
 | 
|---|
| 724 | {
 | 
|---|
| 725 |     double MeanAnomaly,TrueAnomaly;
 | 
|---|
| 726 |     double SunX,SunY,SunZ,SunRad;
 | 
|---|
| 727 |     double vx,vy,vz;
 | 
|---|
| 728 |     double CosTheta;
 | 
|---|
| 729 | 
 | 
|---|
| 730 |     MeanAnomaly = SunMeanAnomaly+ (CrntTime-SunEpochTime)*SunMeanMotion*PI2;
 | 
|---|
| 731 |     TrueAnomaly = Kepler(MeanAnomaly,SunEccentricity);
 | 
|---|
| 732 | 
 | 
|---|
| 733 |     GetSatPosition(SunEpochTime,SunRAAN,SunArgPerigee,SunSemiMajorAxis,
 | 
|---|
| 734 |                 SunInclination,SunEccentricity,0.0,0.0,CrntTime,
 | 
|---|
| 735 |                 TrueAnomaly,&SunX,&SunY,&SunZ,&SunRad,&vx,&vy,&vz);
 | 
|---|
| 736 | 
 | 
|---|
| 737 |     CosTheta = (SunX*SatX + SunY*SatY + SunZ*SatZ)/(SunRad*SatRadius)
 | 
|---|
| 738 |                  *CosPenumbra + (SatRadius/EarthRadius)*SinPenumbra;
 | 
|---|
| 739 | 
 | 
|---|
| 740 |     if (CosTheta < 0)
 | 
|---|
| 741 |         if (CosTheta < -sqrt(SQR(SatRadius)-SQR(EarthRadius))/SatRadius
 | 
|---|
| 742 |                         *CosPenumbra + (SatRadius/EarthRadius)*SinPenumbra)
 | 
|---|
| 743 |           
 | 
|---|
| 744 |             return 1;
 | 
|---|
| 745 |     return 0;
 | 
|---|
| 746 | }
 | 
|---|
| 747 | 
 | 
|---|
| 748 | /* Initialize the Sun's keplerian elements for a given epoch.
 | 
|---|
| 749 |    Formulas are from "Explanatory Supplement to the Astronomical Ephemeris".
 | 
|---|
| 750 |    Also init the sidereal reference                             */
 | 
|---|
| 751 | 
 | 
|---|
| 752 | static void
 | 
|---|
| 753 | InitOrbitRoutines(EpochDay, AtEod)
 | 
|---|
| 754 | double EpochDay;
 | 
|---|
| 755 | int AtEod;
 | 
|---|
| 756 | {
 | 
|---|
| 757 |     double T,T2,T3,Omega;
 | 
|---|
| 758 |     int n;
 | 
|---|
| 759 |     double SunTrueAnomaly,SunDistance;
 | 
|---|
| 760 | 
 | 
|---|
| 761 |     T = (floor(EpochDay)-0.5)/36525;
 | 
|---|
| 762 |     T2 = T*T;
 | 
|---|
| 763 |     T3 = T2*T;
 | 
|---|
| 764 | 
 | 
|---|
| 765 |     SidDay = floor(EpochDay);
 | 
|---|
| 766 | 
 | 
|---|
| 767 |     SidReference = (6.6460656 + 2400.051262*T + 0.00002581*T2)/24;
 | 
|---|
| 768 |     SidReference -= floor(SidReference);
 | 
|---|
| 769 | 
 | 
|---|
| 770 |     /* Omega is used to correct for the nutation and the abberation */
 | 
|---|
| 771 |     Omega = AtEod ? (259.18 - 1934.142*T) * RadiansPerDegree : 0.0;
 | 
|---|
| 772 |     n = (int)(Omega / PI2);
 | 
|---|
| 773 |     Omega -= n*PI2;
 | 
|---|
| 774 | 
 | 
|---|
| 775 |     SunEpochTime = EpochDay;
 | 
|---|
| 776 |     SunRAAN = 0;
 | 
|---|
| 777 | 
 | 
|---|
| 778 |     SunInclination = (23.452294 - 0.0130125*T - 0.00000164*T2
 | 
|---|
| 779 |                     + 0.000000503*T3 +0.00256*cos(Omega)) * RadiansPerDegree;
 | 
|---|
| 780 |     SunEccentricity = (0.01675104 - 0.00004180*T - 0.000000126*T2);
 | 
|---|
| 781 |     SunArgPerigee = (281.220833 + 1.719175*T + 0.0004527*T2
 | 
|---|
| 782 |                         + 0.0000033*T3) * RadiansPerDegree;
 | 
|---|
| 783 |     SunMeanAnomaly = (358.475845 + 35999.04975*T - 0.00015*T2
 | 
|---|
| 784 |                         - 0.00000333333*T3) * RadiansPerDegree;
 | 
|---|
| 785 |     n = (int)(SunMeanAnomaly / PI2);
 | 
|---|
| 786 |     SunMeanAnomaly -= n*PI2;
 | 
|---|
| 787 | 
 | 
|---|
| 788 |     SunMeanMotion = 1/(365.24219879 - 0.00000614*T);
 | 
|---|
| 789 | 
 | 
|---|
| 790 |     SunTrueAnomaly = Kepler(SunMeanAnomaly,SunEccentricity);
 | 
|---|
| 791 |     SunDistance = SunSemiMajorAxis*(1-SQR(SunEccentricity))
 | 
|---|
| 792 |                         / (1+SunEccentricity*cos(SunTrueAnomaly));
 | 
|---|
| 793 | 
 | 
|---|
| 794 |     SinPenumbra = (SunRadius-EarthRadius)/SunDistance;
 | 
|---|
| 795 |     CosPenumbra = sqrt(1-SQR(SinPenumbra));
 | 
|---|
| 796 | }
 | 
|---|
| 797 | 
 | 
|---|
| 798 | /* For RCS Only -- Do Not Edit */
 | 
|---|
| 799 | static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: earthsat.c,v $ $Date: 2001-10-22 12:08:27 $ $Revision: 1.2 $ $Name: not supported by cvs2svn $"};
 | 
|---|