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