File indexing completed on 2024-03-24 03:51:10
0001 /* ---------------------------------------------------------------- 0002 * 0003 * sgp4ext.cpp 0004 * 0005 * this file contains extra routines needed for the main test program for sgp4. 0006 * these routines are derived from the astro libraries. 0007 * 0008 * companion code for 0009 * fundamentals of astrodynamics and applications 0010 * 2007 0011 * by david vallado 0012 * 0013 * (w) 719-573-2600, email dvallado@agi.com 0014 * 0015 * current : 0016 * 7 may 08 david vallado 0017 * fix sgn 0018 * changes : 0019 * 2 apr 07 david vallado 0020 * fix jday floor and str lengths 0021 * updates for constants 0022 * 14 aug 06 david vallado 0023 * original baseline 0024 * ---------------------------------------------------------------- */ 0025 0026 #include "sgp4ext.h" 0027 0028 0029 double sgn 0030 ( 0031 double x 0032 ) 0033 { 0034 if (x < 0.0) 0035 { 0036 return -1.0; 0037 } 0038 else 0039 { 0040 return 1.0; 0041 } 0042 0043 } // end sgn 0044 0045 /* ----------------------------------------------------------------------------- 0046 * 0047 * function mag 0048 * 0049 * this procedure finds the magnitude of a vector. the tolerance is set to 0050 * 0.000001, thus the 1.0e-12 for the squared test of underflows. 0051 * 0052 * author : david vallado 719-573-2600 1 mar 2001 0053 * 0054 * inputs description range / units 0055 * vec - vector 0056 * 0057 * outputs : 0058 * vec - answer stored in fourth component 0059 * 0060 * locals : 0061 * none. 0062 * 0063 * coupling : 0064 * none. 0065 * --------------------------------------------------------------------------- */ 0066 0067 double mag 0068 ( 0069 double x[3] 0070 ) 0071 { 0072 return sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); 0073 } // end mag 0074 0075 /* ----------------------------------------------------------------------------- 0076 * 0077 * procedure cross 0078 * 0079 * this procedure crosses two vectors. 0080 * 0081 * author : david vallado 719-573-2600 1 mar 2001 0082 * 0083 * inputs description range / units 0084 * vec1 - vector number 1 0085 * vec2 - vector number 2 0086 * 0087 * outputs : 0088 * outvec - vector result of a x b 0089 * 0090 * locals : 0091 * none. 0092 * 0093 * coupling : 0094 * mag magnitude of a vector 0095 ---------------------------------------------------------------------------- */ 0096 0097 void cross 0098 ( 0099 double vec1[3], double vec2[3], double outvec[3] 0100 ) 0101 { 0102 outvec[0]= vec1[1]*vec2[2] - vec1[2]*vec2[1]; 0103 outvec[1]= vec1[2]*vec2[0] - vec1[0]*vec2[2]; 0104 outvec[2]= vec1[0]*vec2[1] - vec1[1]*vec2[0]; 0105 } // end cross 0106 0107 0108 /* ----------------------------------------------------------------------------- 0109 * 0110 * function dot 0111 * 0112 * this function finds the dot product of two vectors. 0113 * 0114 * author : david vallado 719-573-2600 1 mar 2001 0115 * 0116 * inputs description range / units 0117 * vec1 - vector number 1 0118 * vec2 - vector number 2 0119 * 0120 * outputs : 0121 * dot - result 0122 * 0123 * locals : 0124 * none. 0125 * 0126 * coupling : 0127 * none. 0128 * 0129 * --------------------------------------------------------------------------- */ 0130 0131 double dot 0132 ( 0133 double x[3], double y[3] 0134 ) 0135 { 0136 return (x[0]*y[0] + x[1]*y[1] + x[2]*y[2]); 0137 } // end dot 0138 0139 /* ----------------------------------------------------------------------------- 0140 * 0141 * procedure angle 0142 * 0143 * this procedure calculates the angle between two vectors. the output is 0144 * set to 999999.1 to indicate an undefined value. be sure to check for 0145 * this at the output phase. 0146 * 0147 * author : david vallado 719-573-2600 1 mar 2001 0148 * 0149 * inputs description range / units 0150 * vec1 - vector number 1 0151 * vec2 - vector number 2 0152 * 0153 * outputs : 0154 * theta - angle between the two vectors -pi to pi 0155 * 0156 * locals : 0157 * temp - temporary real variable 0158 * 0159 * coupling : 0160 * dot dot product of two vectors 0161 * --------------------------------------------------------------------------- */ 0162 0163 double angle 0164 ( 0165 double vec1[3], 0166 double vec2[3] 0167 ) 0168 { 0169 double small, undefined, magv1, magv2, temp; 0170 small = 0.00000001; 0171 undefined = 999999.1; 0172 0173 magv1 = mag(vec1); 0174 magv2 = mag(vec2); 0175 0176 if (magv1*magv2 > small*small) 0177 { 0178 temp= dot(vec1,vec2) / (magv1*magv2); 0179 if (fabs( temp ) > 1.0) 0180 temp= sgn(temp) * 1.0; 0181 return acos( temp ); 0182 } 0183 else 0184 return undefined; 0185 } // end angle 0186 0187 0188 /* ----------------------------------------------------------------------------- 0189 * 0190 * function newtonnu 0191 * 0192 * this function solves keplers equation when the true anomaly is known. 0193 * the mean and eccentric, parabolic, or hyperbolic anomaly is also found. 0194 * the parabolic limit at 168ø is arbitrary. the hyperbolic anomaly is also 0195 * limited. the hyperbolic sine is used because it's not double valued. 0196 * 0197 * author : david vallado 719-573-2600 27 may 2002 0198 * 0199 * revisions 0200 * vallado - fix small 24 sep 2002 0201 * 0202 * inputs description range / units 0203 * ecc - eccentricity 0.0 to 0204 * nu - true anomaly -2pi to 2pi rad 0205 * 0206 * outputs : 0207 * e0 - eccentric anomaly 0.0 to 2pi rad 153.02 ø 0208 * m - mean anomaly 0.0 to 2pi rad 151.7425 ø 0209 * 0210 * locals : 0211 * e1 - eccentric anomaly, next value rad 0212 * sine - sine of e 0213 * cose - cosine of e 0214 * ktr - index 0215 * 0216 * coupling : 0217 * asinh - arc hyperbolic sine 0218 * 0219 * references : 0220 * vallado 2007, 85, alg 5 0221 * --------------------------------------------------------------------------- */ 0222 0223 void newtonnu 0224 ( 0225 double ecc, double nu, 0226 double& e0, double& m 0227 ) 0228 { 0229 double small, sine, cose; 0230 0231 // --------------------- implementation --------------------- 0232 e0= 999999.9; 0233 m = 999999.9; 0234 small = 0.00000001; 0235 0236 // --------------------------- circular ------------------------ 0237 if ( fabs( ecc ) < small ) 0238 { 0239 m = nu; 0240 e0= nu; 0241 } 0242 else 0243 // ---------------------- elliptical ----------------------- 0244 if ( ecc < 1.0-small ) 0245 { 0246 sine= ( sqrt( 1.0 -ecc*ecc ) * sin(nu) ) / ( 1.0 +ecc*cos(nu) ); 0247 cose= ( ecc + cos(nu) ) / ( 1.0 + ecc*cos(nu) ); 0248 e0 = atan2( sine,cose ); 0249 m = e0 - ecc*sin(e0); 0250 } 0251 else 0252 // -------------------- hyperbolic -------------------- 0253 if ( ecc > 1.0 + small ) 0254 { 0255 if ((ecc > 1.0 ) && (fabs(nu)+0.00001 < M_PI-acos(1.0 /ecc))) 0256 { 0257 sine= ( sqrt( ecc*ecc-1.0 ) * sin(nu) ) / ( 1.0 + ecc*cos(nu) ); 0258 e0 = asinh( sine ); 0259 m = ecc*sinh(e0) - e0; 0260 } 0261 } 0262 else 0263 // ----------------- parabolic --------------------- 0264 if ( fabs(nu) < 168.0*M_PI/180.0 ) 0265 { 0266 e0= tan( nu*0.5 ); 0267 m = e0 + (e0*e0*e0)/3.0; 0268 } 0269 0270 if ( ecc < 1.0 ) 0271 { 0272 m = fmod( m,2.0 *M_PI ); 0273 if ( m < 0.0 ) 0274 m = m + 2.0 *M_PI; 0275 e0 = fmod( e0,2.0 *M_PI ); 0276 } 0277 } // end newtonnu 0278 0279 0280 /* ----------------------------------------------------------------------------- 0281 * 0282 * function rv2coe 0283 * 0284 * this function finds the classical orbital elements given the geocentric 0285 * equatorial position and velocity vectors. 0286 * 0287 * author : david vallado 719-573-2600 21 jun 2002 0288 * 0289 * revisions 0290 * vallado - fix special cases 5 sep 2002 0291 * vallado - delete extra check in inclination code 16 oct 2002 0292 * vallado - add constant file use 29 jun 2003 0293 * vallado - add mu 2 apr 2007 0294 * 0295 * inputs description range / units 0296 * r - ijk position vector km 0297 * v - ijk velocity vector km / s 0298 * mu - gravitational parameter km3 / s2 0299 * 0300 * outputs : 0301 * p - semilatus rectum km 0302 * a - semimajor axis km 0303 * ecc - eccentricity 0304 * incl - inclination 0.0 to pi rad 0305 * omega - longitude of ascending node 0.0 to 2pi rad 0306 * argp - argument of perigee 0.0 to 2pi rad 0307 * nu - true anomaly 0.0 to 2pi rad 0308 * m - mean anomaly 0.0 to 2pi rad 0309 * arglat - argument of latitude (ci) 0.0 to 2pi rad 0310 * truelon - true longitude (ce) 0.0 to 2pi rad 0311 * lonper - longitude of periapsis (ee) 0.0 to 2pi rad 0312 * 0313 * locals : 0314 * hbar - angular momentum h vector km2 / s 0315 * ebar - eccentricity e vector 0316 * nbar - line of nodes n vector 0317 * c1 - v**2 - u/r 0318 * rdotv - r dot v 0319 * hk - hk unit vector 0320 * sme - specific mechanical energy km2 / s2 0321 * i - index 0322 * e - eccentric, parabolic, 0323 * hyperbolic anomaly rad 0324 * temp - temporary variable 0325 * typeorbit - type of orbit ee, ei, ce, ci 0326 * 0327 * coupling : 0328 * mag - magnitude of a vector 0329 * cross - cross product of two vectors 0330 * angle - find the angle between two vectors 0331 * newtonnu - find the mean anomaly 0332 * 0333 * references : 0334 * vallado 2007, 126, alg 9, ex 2-5 0335 * --------------------------------------------------------------------------- */ 0336 0337 void rv2coe 0338 ( 0339 double r[3], double v[3], double mu, 0340 double& p, double& a, double& ecc, double& incl, double& omega, double& argp, 0341 double& nu, double& m, double& arglat, double& truelon, double& lonper 0342 ) 0343 { 0344 double undefined, small, hbar[3], nbar[3], magr, magv, magn, ebar[3], sme, 0345 rdotv, infinite, temp, c1, hk, twopi, magh, halfpi, e; 0346 0347 int i; 0348 char typeorbit[3]; 0349 0350 twopi = 2.0 * M_PI; 0351 halfpi = 0.5 * M_PI; 0352 small = 0.00000001; 0353 undefined = 999999.1; 0354 infinite = 999999.9; 0355 0356 // ------------------------- implementation ----------------- 0357 magr = mag( r ); 0358 magv = mag( v ); 0359 0360 // ------------------ find h n and e vectors ---------------- 0361 cross( r,v, hbar ); 0362 magh = mag( hbar ); 0363 if ( magh > small ) 0364 { 0365 nbar[0]= -hbar[1]; 0366 nbar[1]= hbar[0]; 0367 nbar[2]= 0.0; 0368 magn = mag( nbar ); 0369 c1 = magv*magv - mu /magr; 0370 rdotv = dot( r,v ); 0371 for (i= 0; i <= 2; i++) 0372 ebar[i]= (c1*r[i] - rdotv*v[i])/mu; 0373 ecc = mag( ebar ); 0374 0375 // ------------ find a e and semi-latus rectum ---------- 0376 sme= ( magv*magv*0.5 ) - ( mu /magr ); 0377 if ( fabs( sme ) > small ) 0378 a= -mu / (2.0 *sme); 0379 else 0380 a= infinite; 0381 p = magh*magh/mu; 0382 0383 // ----------------- find inclination ------------------- 0384 hk= hbar[2]/magh; 0385 incl= acos( hk ); 0386 0387 // -------- determine type of orbit for later use -------- 0388 // ------ elliptical, parabolic, hyperbolic inclined ------- 0389 strcpy(typeorbit,"ei"); 0390 if ( ecc < small ) 0391 { 0392 // ---------------- circular equatorial --------------- 0393 if ((incl<small) | (fabs(incl-M_PI)<small)) 0394 strcpy(typeorbit,"ce"); 0395 else 0396 // -------------- circular inclined --------------- 0397 strcpy(typeorbit,"ci"); 0398 } 0399 else 0400 { 0401 // - elliptical, parabolic, hyperbolic equatorial -- 0402 if ((incl<small) | (fabs(incl-M_PI)<small)) 0403 strcpy(typeorbit,"ee"); 0404 } 0405 0406 // ---------- find longitude of ascending node ------------ 0407 if ( magn > small ) 0408 { 0409 temp= nbar[0] / magn; 0410 if ( fabs(temp) > 1.0 ) 0411 temp= sgn(temp); 0412 omega= acos( temp ); 0413 if ( nbar[1] < 0.0 ) 0414 omega= twopi - omega; 0415 } 0416 else 0417 omega= undefined; 0418 0419 // ---------------- find argument of perigee --------------- 0420 if ( strcmp(typeorbit,"ei") == 0 ) 0421 { 0422 argp = angle( nbar,ebar); 0423 if ( ebar[2] < 0.0 ) 0424 argp= twopi - argp; 0425 } 0426 else 0427 argp= undefined; 0428 0429 // ------------ find true anomaly at epoch ------------- 0430 if ( typeorbit[0] == 'e' ) 0431 { 0432 nu = angle( ebar,r); 0433 if ( rdotv < 0.0 ) 0434 nu= twopi - nu; 0435 } 0436 else 0437 nu= undefined; 0438 0439 // ---- find argument of latitude - circular inclined ----- 0440 if ( strcmp(typeorbit,"ci") == 0 ) 0441 { 0442 arglat = angle( nbar,r ); 0443 if ( r[2] < 0.0 ) 0444 arglat= twopi - arglat; 0445 m = arglat; 0446 } 0447 else 0448 arglat= undefined; 0449 0450 // -- find longitude of perigee - elliptical equatorial ---- 0451 if (( ecc>small ) && (strcmp(typeorbit,"ee") == 0)) 0452 { 0453 temp= ebar[0]/ecc; 0454 if ( fabs(temp) > 1.0 ) 0455 temp= sgn(temp); 0456 lonper= acos( temp ); 0457 if ( ebar[1] < 0.0 ) 0458 lonper= twopi - lonper; 0459 if ( incl > halfpi ) 0460 lonper= twopi - lonper; 0461 } 0462 else 0463 lonper= undefined; 0464 0465 // -------- find true longitude - circular equatorial ------ 0466 if (( magr>small ) && ( strcmp(typeorbit,"ce") == 0 )) 0467 { 0468 temp= r[0]/magr; 0469 if ( fabs(temp) > 1.0 ) 0470 temp= sgn(temp); 0471 truelon= acos( temp ); 0472 if ( r[1] < 0.0 ) 0473 truelon= twopi - truelon; 0474 if ( incl > halfpi ) 0475 truelon= twopi - truelon; 0476 m = truelon; 0477 } 0478 else 0479 truelon= undefined; 0480 0481 // ------------ find mean anomaly for all orbits ----------- 0482 if ( typeorbit[0] == 'e' ) 0483 newtonnu(ecc,nu, e, m); 0484 } 0485 else 0486 { 0487 p = undefined; 0488 a = undefined; 0489 ecc = undefined; 0490 incl = undefined; 0491 omega= undefined; 0492 argp = undefined; 0493 nu = undefined; 0494 m = undefined; 0495 arglat = undefined; 0496 truelon= undefined; 0497 lonper = undefined; 0498 } 0499 } // end rv2coe 0500 0501 /* ----------------------------------------------------------------------------- 0502 * 0503 * procedure jday 0504 * 0505 * this procedure finds the julian date given the year, month, day, and time. 0506 * the julian date is defined by each elapsed day since noon, jan 1, 4713 bc. 0507 * 0508 * algorithm : calculate the answer in one step for efficiency 0509 * 0510 * author : david vallado 719-573-2600 1 mar 2001 0511 * 0512 * inputs description range / units 0513 * year - year 1900 .. 2100 0514 * mon - month 1 .. 12 0515 * day - day 1 .. 28,29,30,31 0516 * hr - universal time hour 0 .. 23 0517 * min - universal time min 0 .. 59 0518 * sec - universal time sec 0.0 .. 59.999 0519 * 0520 * outputs : 0521 * jd - julian date days from 4713 bc 0522 * 0523 * locals : 0524 * none. 0525 * 0526 * coupling : 0527 * none. 0528 * 0529 * references : 0530 * vallado 2007, 189, alg 14, ex 3-14 0531 * 0532 * --------------------------------------------------------------------------- */ 0533 0534 void jday 0535 ( 0536 int year, int mon, int day, int hr, int minute, double sec, 0537 double& jd 0538 ) 0539 { 0540 jd = 367.0 * year - 0541 floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25) + 0542 floor( 275 * mon / 9.0 ) + 0543 day + 1721013.5 + 0544 ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days 0545 // - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5; 0546 } // end jday 0547 0548 /* ----------------------------------------------------------------------------- 0549 * 0550 * procedure days2mdhms 0551 * 0552 * this procedure converts the day of the year, days, to the equivalent month 0553 * day, hour, minute and second. 0554 * 0555 * algorithm : set up array for the number of days per month 0556 * find leap year - use 1900 because 2000 is a leap year 0557 * loop through a temp value while the value is < the days 0558 * perform int conversions to the correct day and month 0559 * convert remainder into h m s using type conversions 0560 * 0561 * author : david vallado 719-573-2600 1 mar 2001 0562 * 0563 * inputs description range / units 0564 * year - year 1900 .. 2100 0565 * days - julian day of the year 0.0 .. 366.0 0566 * 0567 * outputs : 0568 * mon - month 1 .. 12 0569 * day - day 1 .. 28,29,30,31 0570 * hr - hour 0 .. 23 0571 * min - minute 0 .. 59 0572 * sec - second 0.0 .. 59.999 0573 * 0574 * locals : 0575 * dayofyr - day of year 0576 * temp - temporary extended values 0577 * inttemp - temporary int value 0578 * i - index 0579 * lmonth[12] - int array containing the number of days per month 0580 * 0581 * coupling : 0582 * none. 0583 * --------------------------------------------------------------------------- */ 0584 0585 void days2mdhms 0586 ( 0587 int year, double days, 0588 int& mon, int& day, int& hr, int& minute, double& sec 0589 ) 0590 { 0591 int i, inttemp, dayofyr; 0592 double temp; 0593 int lmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 0594 0595 dayofyr = (int)floor(days); 0596 /* ----------------- find month and day of month ---------------- */ 0597 if ( (year % 4) == 0 ) 0598 lmonth[1] = 29; 0599 0600 i = 1; 0601 inttemp = 0; 0602 while ((dayofyr > inttemp + lmonth[i-1]) && (i < 12)) 0603 { 0604 inttemp = inttemp + lmonth[i-1]; 0605 i++; 0606 } 0607 mon = i; 0608 day = dayofyr - inttemp; 0609 0610 /* ----------------- find hours minutes and seconds ------------- */ 0611 temp = (days - dayofyr) * 24.0; 0612 hr = (int)floor(temp); 0613 temp = (temp - hr) * 60.0; 0614 minute = (int)floor(temp); 0615 sec = (temp - minute) * 60.0; 0616 } // end days2mdhms 0617 0618 /* ----------------------------------------------------------------------------- 0619 * 0620 * procedure invjday 0621 * 0622 * this procedure finds the year, month, day, hour, minute and second 0623 * given the julian date. tu can be ut1, tdt, tdb, etc. 0624 * 0625 * algorithm : set up starting values 0626 * find leap year - use 1900 because 2000 is a leap year 0627 * find the elapsed days through the year in a loop 0628 * call routine to find each individual value 0629 * 0630 * author : david vallado 719-573-2600 1 mar 2001 0631 * 0632 * inputs description range / units 0633 * jd - julian date days from 4713 bc 0634 * 0635 * outputs : 0636 * year - year 1900 .. 2100 0637 * mon - month 1 .. 12 0638 * day - day 1 .. 28,29,30,31 0639 * hr - hour 0 .. 23 0640 * min - minute 0 .. 59 0641 * sec - second 0.0 .. 59.999 0642 * 0643 * locals : 0644 * days - day of year plus fractional 0645 * portion of a day days 0646 * tu - julian centuries from 0 h 0647 * jan 0, 1900 0648 * temp - temporary double values 0649 * leapyrs - number of leap years from 1900 0650 * 0651 * coupling : 0652 * days2mdhms - finds month, day, hour, minute and second given days and year 0653 * 0654 * references : 0655 * vallado 2007, 208, alg 22, ex 3-13 0656 * --------------------------------------------------------------------------- */ 0657 0658 void invjday 0659 ( 0660 double jd, 0661 int& year, int& mon, int& day, 0662 int& hr, int& minute, double& sec 0663 ) 0664 { 0665 int leapyrs; 0666 double days, tu, temp; 0667 0668 /* --------------- find year and days of the year --------------- */ 0669 temp = jd - 2415019.5; 0670 tu = temp / 365.25; 0671 year = 1900 + (int)floor(tu); 0672 leapyrs = (int)floor((year - 1901) * 0.25); 0673 0674 // optional nudge by 8.64x10-7 sec to get even outputs 0675 days = temp - ((year - 1900) * 365.0 + leapyrs) + 0.00000000001; 0676 0677 /* ------------ check for case of beginning of a year ----------- */ 0678 if (days < 1.0) 0679 { 0680 year = year - 1; 0681 leapyrs = (int)floor((year - 1901) * 0.25); 0682 days = temp - ((year - 1900) * 365.0 + leapyrs); 0683 } 0684 0685 /* ----------------- find residual data ------------------------- */ 0686 days2mdhms(year, days, mon, day, hr, minute, sec); 0687 sec = sec - 0.00000086400; 0688 } // end invjday 0689 0690 0691 0692 0693