[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;
|
---|
| 239 | aa_hadec (lat, (double)op->s_alt, (double)op->s_az, &ha, &dec);
|
---|
| 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 */
|
---|
[3111] | 786 | static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: earthsat.c,v $ $Date: 2006-11-22 13:53:29 $ $Revision: 1.7 $ $Name: not supported by cvs2svn $"};
|
---|