Loading...
Searching...
No Matches
satellite-sgp4ext.cc
Go to the documentation of this file.
1/* ----------------------------------------------------------------
2 *
3 * sgp4ext.h
4 *
5 * this file contains extra routines needed for the main test program for sgp4.
6 * these routines are derived from the astro libraries.
7 *
8 * companion code for
9 * fundamentals of astrodynamics and applications
10 * 2007
11 * by david vallado
12 *
13 * (w) 719-573-2600, email dvallado@agi.com
14 *
15 * current :
16 * 20 apr 07 david vallado
17 * misc documentation updates
18 * changes :
19 * 14 aug 06 david vallado
20 * original baseline
21 *
22 * code from https://gitlab.inesctec.pt/pmms/ns3-satellite
23 * ---------------------------------------------------------------- */
24
25#include "satellite-sgp4ext.h"
26
27#include <stdint.h>
28
29double
30sgn(double x)
31{
32 if (x < 0.0)
33 {
34 return -1.0;
35 }
36 else
37 {
38 return 1.0;
39 }
40} // end sgn
41
42/* -----------------------------------------------------------------------------
43 *
44 * function mag
45 *
46 * this procedure finds the magnitude of a vector. the tolerance is set to
47 * 0.000001, thus the 1.0e-12 for the squared test of underflows.
48 *
49 * author : david vallado 719-573-2600 1 mar 2001
50 *
51 * inputs description range / units
52 * vec - vector
53 *
54 * outputs :
55 * vec - answer stored in fourth component
56 *
57 * locals :
58 * none.
59 *
60 * coupling :
61 * none.
62 * --------------------------------------------------------------------------- */
63
64double
65mag(double x[3])
66{
67 return sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
68} // end mag
69
70/* -----------------------------------------------------------------------------
71*
72* procedure cross
73*
74* this procedure crosses two vectors.
75*
76* author : david vallado 719-573-2600 1 mar 2001
77*
78* inputs description range / units
79* vec1 - vector number 1
80* vec2 - vector number 2
81*
82* outputs :
83* outvec - vector result of a x b
84*
85* locals :
86* none.
87*
88* coupling :
89* mag magnitude of a vector
90 ---------------------------------------------------------------------------- */
91
92void
93cross(double vec1[3], double vec2[3], double outvec[3])
94{
95 outvec[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
96 outvec[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
97 outvec[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
98} // end cross
99
100/* -----------------------------------------------------------------------------
101 *
102 * function dot
103 *
104 * this function finds the dot product of two vectors.
105 *
106 * author : david vallado 719-573-2600 1 mar 2001
107 *
108 * inputs description range / units
109 * vec1 - vector number 1
110 * vec2 - vector number 2
111 *
112 * outputs :
113 * dot - result
114 *
115 * locals :
116 * none.
117 *
118 * coupling :
119 * none.
120 *
121 * --------------------------------------------------------------------------- */
122
123double
124dot(double x[3], double y[3])
125{
126 return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
127} // end dot
128
129/* -----------------------------------------------------------------------------
130 *
131 * procedure angle
132 *
133 * this procedure calculates the angle between two vectors. the output is
134 * set to 999999.1 to indicate an undefined value. be sure to check for
135 * this at the output phase.
136 *
137 * author : david vallado 719-573-2600 1 mar 2001
138 *
139 * inputs description range / units
140 * vec1 - vector number 1
141 * vec2 - vector number 2
142 *
143 * outputs :
144 * theta - angle between the two vectors -pi to pi
145 *
146 * locals :
147 * temp - temporary real variable
148 *
149 * coupling :
150 * dot dot product of two vectors
151 * --------------------------------------------------------------------------- */
152
153double
154angle(double vec1[3], double vec2[3])
155{
156 double small, undefined, magv1, magv2, temp;
157 small = 0.00000001;
158 undefined = 999999.1;
159
160 magv1 = mag(vec1);
161 magv2 = mag(vec2);
162
163 if (magv1 * magv2 > small * small)
164 {
165 temp = dot(vec1, vec2) / (magv1 * magv2);
166 if (fabs(temp) > 1.0)
167 {
168 temp = sgn(temp) * 1.0;
169 }
170 return acos(temp);
171 }
172 else
173 {
174 return undefined;
175 }
176} // end angle
177
178/* -----------------------------------------------------------------------------
179 *
180 * function asinh
181 *
182 * this function evaluates the inverse hyperbolic sine function.
183 *
184 * author : david vallado 719-573-2600 1 mar 2001
185 *
186 * inputs description range / units
187 * xval - angle value any real
188 *
189 * outputs :
190 * arcsinh - result any real
191 *
192 * locals :
193 * none.
194 *
195 * coupling :
196 * none.
197 *
198 * --------------------------------------------------------------------------- */
199
200// double asinh (double xval)
201//{
202// return log( xval + sqrt( xval*xval + 1.0 ) );
203// } // end asinh
204
205/* -----------------------------------------------------------------------------
206 *
207 * function newtonnu
208 *
209 * this function solves keplers equation when the true anomaly is known.
210 * the mean and eccentric, parabolic, or hyperbolic anomaly is also found.
211 * the parabolic limit at 168ø is arbitrary. the hyperbolic anomaly is also
212 * limited. the hyperbolic sine is used because it's not double valued.
213 *
214 * author : david vallado 719-573-2600 27 may 2002
215 *
216 * revisions
217 * vallado - fix small 24 sep 2002
218 *
219 * inputs description range / units
220 * ecc - eccentricity 0.0 to
221 * nu - true anomaly -2pi to 2pi rad
222 *
223 * outputs :
224 * e0 - eccentric anomaly 0.0 to 2pi rad 153.02 ø
225 * m - mean anomaly 0.0 to 2pi rad 151.7425 ø
226 *
227 * locals :
228 * e1 - eccentric anomaly, next value rad
229 * sine - sine of e
230 * cose - cosine of e
231 * ktr - index
232 *
233 * coupling :
234 * asinh - arc hyperbolic sine
235 *
236 * references :
237 * vallado 2007, 85, alg 5
238 * --------------------------------------------------------------------------- */
239
240void
241newtonnu(double ecc, double nu, double& e0, double& m)
242{
243 double small, sine, cose;
244
245 // --------------------- implementation ---------------------
246 e0 = 999999.9;
247 m = 999999.9;
248 small = 0.00000001;
249
250 // --------------------------- circular ------------------------
251 if (fabs(ecc) < small)
252 {
253 m = nu;
254 e0 = nu;
255 }
256 else
257 // ---------------------- elliptical -----------------------
258 if (ecc < 1.0 - small)
259 {
260 sine = (sqrt(1.0 - ecc * ecc) * sin(nu)) / (1.0 + ecc * cos(nu));
261 cose = (ecc + cos(nu)) / (1.0 + ecc * cos(nu));
262 e0 = atan2(sine, cose);
263 m = e0 - ecc * sin(e0);
264 }
265 else
266 // -------------------- hyperbolic --------------------
267 if (ecc > 1.0 + small)
268 {
269 if ((ecc > 1.0) && (fabs(nu) + 0.00001 < pi - acos(1.0 / ecc)))
270 {
271 sine = (sqrt(ecc * ecc - 1.0) * sin(nu)) / (1.0 + ecc * cos(nu));
272 e0 = asinh(sine);
273 m = ecc * sinh(e0) - e0;
274 }
275 }
276 else
277 // ----------------- parabolic ---------------------
278 if (fabs(nu) < 168.0 * pi / 180.0)
279 {
280 e0 = tan(nu * 0.5);
281 m = e0 + (e0 * e0 * e0) / 3.0;
282 }
283
284 if (ecc < 1.0)
285 {
286 m = fmod(m, 2.0 * pi);
287 if (m < 0.0)
288 {
289 m = m + 2.0 * pi;
290 }
291 e0 = fmod(e0, 2.0 * pi);
292 }
293} // end newtonnu
294
295/* -----------------------------------------------------------------------------
296 *
297 * function rv2coe
298 *
299 * this function finds the classical orbital elements given the geocentric
300 * equatorial position and velocity vectors.
301 *
302 * author : david vallado 719-573-2600 21 jun 2002
303 *
304 * revisions
305 * vallado - fix special cases 5 sep 2002
306 * vallado - delete extra check in inclination code 16 oct 2002
307 * vallado - add constant file use 29 jun 2003
308 * vallado - add mu 2 apr 2007
309 *
310 * inputs description range / units
311 * r - ijk position vector km
312 * v - ijk velocity vector km / s
313 * mu - gravitational parameter km3 / s2
314 *
315 * outputs :
316 * p - semilatus rectum km
317 * a - semimajor axis km
318 * ecc - eccentricity
319 * incl - inclination 0.0 to pi rad
320 * omega - longitude of ascending node 0.0 to 2pi rad
321 * argp - argument of perigee 0.0 to 2pi rad
322 * nu - true anomaly 0.0 to 2pi rad
323 * m - mean anomaly 0.0 to 2pi rad
324 * arglat - argument of latitude (ci) 0.0 to 2pi rad
325 * truelon - true longitude (ce) 0.0 to 2pi rad
326 * lonper - longitude of periapsis (ee) 0.0 to 2pi rad
327 *
328 * locals :
329 * hbar - angular momentum h vector km2 / s
330 * ebar - eccentricity e vector
331 * nbar - line of nodes n vector
332 * c1 - v**2 - u/r
333 * rdotv - r dot v
334 * hk - hk unit vector
335 * sme - specfic mechanical energy km2 / s2
336 * i - index
337 * e - eccentric, parabolic,
338 * hyperbolic anomaly rad
339 * temp - temporary variable
340 * typeorbit - type of orbit ee, ei, ce, ci
341 *
342 * coupling :
343 * mag - magnitude of a vector
344 * cross - cross product of two vectors
345 * angle - find the angle between two vectors
346 * newtonnu - find the mean anomaly
347 *
348 * references :
349 * vallado 2007, 126, alg 9, ex 2-5
350 * --------------------------------------------------------------------------- */
351
352void
353rv2coe(double r[3],
354 double v[3],
355 double mu,
356 double& p,
357 double& a,
358 double& ecc,
359 double& incl,
360 double& omega,
361 double& argp,
362 double& nu,
363 double& m,
364 double& arglat,
365 double& truelon,
366 double& lonper)
367{
368 double undefined, small, hbar[3], nbar[3], magr, magv, magn, ebar[3], sme, rdotv, infinite,
369 temp, c1, hk, twopi, magh, halfpi, e;
370
371 int i;
372 char typeorbit[3];
373
374 twopi = 2.0 * pi;
375 halfpi = 0.5 * pi;
376 small = 0.00000001;
377 undefined = 999999.1;
378 infinite = 999999.9;
379
380 // ------------------------- implementation -----------------
381 magr = mag(r);
382 magv = mag(v);
383
384 // ------------------ find h n and e vectors ----------------
385 cross(r, v, hbar);
386 magh = mag(hbar);
387 if (magh > small)
388 {
389 nbar[0] = -hbar[1];
390 nbar[1] = hbar[0];
391 nbar[2] = 0.0;
392 magn = mag(nbar);
393 c1 = magv * magv - mu / magr;
394 rdotv = dot(r, v);
395 for (i = 0; i <= 2; i++)
396 {
397 ebar[i] = (c1 * r[i] - rdotv * v[i]) / mu;
398 }
399 ecc = mag(ebar);
400
401 // ------------ find a e and semi-latus rectum ----------
402 sme = (magv * magv * 0.5) - (mu / magr);
403 if (fabs(sme) > small)
404 {
405 a = -mu / (2.0 * sme);
406 }
407 else
408 {
409 a = infinite;
410 }
411 p = magh * magh / mu;
412
413 // ----------------- find inclination -------------------
414 hk = hbar[2] / magh;
415 incl = acos(hk);
416
417 // -------- determine type of orbit for later use --------
418 // ------ elliptical, parabolic, hyperbolic inclined -------
419 strcpy(typeorbit, "ei");
420 if (ecc < small)
421 {
422 // ---------------- circular equatorial ---------------
423 if ((incl < small) | (fabs(incl - pi) < small))
424 {
425 strcpy(typeorbit, "ce");
426 }
427 else
428 {
429 // -------------- circular inclined ---------------
430 strcpy(typeorbit, "ci");
431 }
432 }
433 else
434 {
435 // - elliptical, parabolic, hyperbolic equatorial --
436 if ((incl < small) | (fabs(incl - pi) < small))
437 {
438 strcpy(typeorbit, "ee");
439 }
440 }
441
442 // ---------- find longitude of ascending node ------------
443 if (magn > small)
444 {
445 temp = nbar[0] / magn;
446 if (fabs(temp) > 1.0)
447 {
448 temp = sgn(temp);
449 }
450 omega = acos(temp);
451 if (nbar[1] < 0.0)
452 {
453 omega = twopi - omega;
454 }
455 }
456 else
457 {
458 omega = undefined;
459 }
460
461 // ---------------- find argument of perigee ---------------
462 if (strcmp(typeorbit, "ei") == 0)
463 {
464 argp = angle(nbar, ebar);
465 if (ebar[2] < 0.0)
466 {
467 argp = twopi - argp;
468 }
469 }
470 else
471 {
472 argp = undefined;
473 }
474
475 // ------------ find true anomaly at epoch -------------
476 if (typeorbit[0] == 'e')
477 {
478 nu = angle(ebar, r);
479 if (rdotv < 0.0)
480 {
481 nu = twopi - nu;
482 }
483 }
484 else
485 {
486 nu = undefined;
487 }
488
489 // ---- find argument of latitude - circular inclined -----
490 if (strcmp(typeorbit, "ci") == 0)
491 {
492 arglat = angle(nbar, r);
493 if (r[2] < 0.0)
494 {
495 arglat = twopi - arglat;
496 }
497 m = arglat;
498 }
499 else
500 {
501 arglat = undefined;
502 }
503
504 // -- find longitude of perigee - elliptical equatorial ----
505 if ((ecc > small) && (strcmp(typeorbit, "ee") == 0))
506 {
507 temp = ebar[0] / ecc;
508 if (fabs(temp) > 1.0)
509 {
510 temp = sgn(temp);
511 }
512 lonper = acos(temp);
513 if (ebar[1] < 0.0)
514 {
515 lonper = twopi - lonper;
516 }
517 if (incl > halfpi)
518 {
519 lonper = twopi - lonper;
520 }
521 }
522 else
523 {
524 lonper = undefined;
525 }
526
527 // -------- find true longitude - circular equatorial ------
528 if ((magr > small) && (strcmp(typeorbit, "ce") == 0))
529 {
530 temp = r[0] / magr;
531 if (fabs(temp) > 1.0)
532 {
533 temp = sgn(temp);
534 }
535 truelon = acos(temp);
536 if (r[1] < 0.0)
537 {
538 truelon = twopi - truelon;
539 }
540 if (incl > halfpi)
541 {
542 truelon = twopi - truelon;
543 }
544 m = truelon;
545 }
546 else
547 {
548 truelon = undefined;
549 }
550
551 // ------------ find mean anomaly for all orbits -----------
552 if (typeorbit[0] == 'e')
553 {
554 newtonnu(ecc, nu, e, m);
555 }
556 }
557 else
558 {
559 p = undefined;
560 a = undefined;
561 ecc = undefined;
562 incl = undefined;
563 omega = undefined;
564 argp = undefined;
565 nu = undefined;
566 m = undefined;
567 arglat = undefined;
568 truelon = undefined;
569 lonper = undefined;
570 }
571} // end rv2coe
572
573/* -----------------------------------------------------------------------------
574 *
575 * procedure jday
576 *
577 * this procedure finds the julian date given the year, month, day, and time.
578 * the julian date is defined by each elapsed day since noon, jan 1, 4713 bc.
579 *
580 * algorithm : calculate the answer in one step for efficiency
581 *
582 * author : david vallado 719-573-2600 1 mar 2001
583 *
584 * inputs description range / units
585 * year - year 1900 .. 2100
586 * mon - month 1 .. 12
587 * day - day 1 .. 28,29,30,31
588 * hr - universal time hour 0 .. 23
589 * min - universal time min 0 .. 59
590 * sec - universal time sec 0.0 .. 59.999
591 *
592 * outputs :
593 * jd - julian date days from 4713 bc
594 *
595 * locals :
596 * none.
597 *
598 * coupling :
599 * none.
600 *
601 * references :
602 * vallado 2007, 189, alg 14, ex 3-14
603 *
604 * --------------------------------------------------------------------------- */
605
606void
607jday(int year, int mon, int day, int hr, int minute, double sec, double& jd)
608{
609 jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25) +
610 floor(275 * mon / 9.0) + day + 1721013.5 +
611 ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days
612} // end jday
613
614/* -----------------------------------------------------------------------------
615 *
616 * procedure days2mdhms
617 *
618 * this procedure converts the day of the year, days, to the equivalent month
619 * day, hour, minute and second.
620 *
621 * algorithm : set up array for the number of days per month
622 * find leap year - use 1900 because 2000 is a leap year
623 * loop through a temp value while the value is < the days
624 * perform int conversions to the correct day and month
625 * convert remainder into h m s using type conversions
626 *
627 * author : david vallado 719-573-2600 1 mar 2001
628 *
629 * inputs description range / units
630 * year - year 1900 .. 2100
631 * days - julian day of the year 0.0 .. 366.0
632 *
633 * outputs :
634 * mon - month 1 .. 12
635 * day - day 1 .. 28,29,30,31
636 * hr - hour 0 .. 23
637 * min - minute 0 .. 59
638 * sec - second 0.0 .. 59.999
639 *
640 * locals :
641 * dayofyr - day of year
642 * temp - temporary extended values
643 * inttemp - temporary int value
644 * i - index
645 * lmonth[12] - int array containing the number of days per month
646 *
647 * coupling :
648 * none.
649 * --------------------------------------------------------------------------- */
650
651void
652days2mdhms(int year, double days, int& mon, int& day, int& hr, int& minute, double& sec)
653{
654 int i, inttemp, dayofyr;
655 double temp;
656 int lmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
657
658 dayofyr = (int)floor(days);
659 /* ----------------- find month and day of month ---------------- */
660 if ((year % 4) == 0)
661 {
662 lmonth[1] = 29;
663 }
664
665 i = 1;
666 inttemp = 0;
667 while ((dayofyr > inttemp + lmonth[i - 1]) && (i < 12))
668 {
669 inttemp = inttemp + lmonth[i - 1];
670 i++;
671 }
672 mon = i;
673 day = dayofyr - inttemp;
674
675 /* ----------------- find hours minutes and seconds ------------- */
676 temp = (days - dayofyr) * 24.0;
677 hr = (int)floor(temp);
678 temp = (temp - hr) * 60.0;
679 minute = (int)floor(temp);
680 sec = (temp - minute) * 60.0;
681} // end days2mdhms
682
683/* -----------------------------------------------------------------------------
684 *
685 * procedure invjday
686 *
687 * this procedure finds the year, month, day, hour, minute and second
688 * given the julian date. tu can be ut1, tdt, tdb, etc.
689 *
690 * algorithm : set up starting values
691 * find leap year - use 1900 because 2000 is a leap year
692 * find the elapsed days through the year in a loop
693 * call routine to find each individual value
694 *
695 * author : david vallado 719-573-2600 1 mar 2001
696 *
697 * inputs description range / units
698 * jd - julian date days from 4713 bc
699 *
700 * outputs :
701 * year - year 1900 .. 2100
702 * mon - month 1 .. 12
703 * day - day 1 .. 28,29,30,31
704 * hr - hour 0 .. 23
705 * min - minute 0 .. 59
706 * sec - second 0.0 .. 59.999
707 *
708 * locals :
709 * days - day of year plus fractional
710 * portion of a day days
711 * tu - julian centuries from 0 h
712 * jan 0, 1900
713 * temp - temporary double values
714 * leapyrs - number of leap years from 1900
715 *
716 * coupling :
717 * days2mdhms - finds month, day, hour, minute and second given days and year
718 *
719 * references :
720 * vallado 2007, 208, alg 22, ex 3-13
721 * --------------------------------------------------------------------------- */
722
723void
724invjday(double jd, int& year, int& mon, int& day, int& hr, int& minute, double& sec)
725{
726 int leapyrs;
727 double days, tu, temp;
728
729 /* --------------- find year and days of the year --------------- */
730 temp = jd - 2415019.5;
731 tu = temp / 365.25;
732 year = 1900 + (int)floor(tu);
733 leapyrs = (int)floor((year - 1901) * 0.25);
734
735 // optional nudge by 8.64x10-7 sec to get even outputs
736 days = temp - ((year - 1900) * 365.0 + leapyrs) + 0.00000000001;
737
738 /* ------------ check for case of beginning of a year ----------- */
739 if (days < 1.0)
740 {
741 year = year - 1;
742 leapyrs = (int)floor((year - 1901) * 0.25);
743 days = temp - ((year - 1900) * 365.0 + leapyrs);
744 }
745
746 /* ----------------- find remaing data ------------------------- */
747 days2mdhms(year, days, mon, day, hr, minute, sec);
748 sec = sec - 0.00000086400;
749} // end invjday
void invjday(double jd, int &year, int &mon, int &day, int &hr, int &minute, double &sec)
void cross(double vec1[3], double vec2[3], double outvec[3])
double sgn(double x)
void days2mdhms(int year, double days, int &mon, int &day, int &hr, int &minute, double &sec)
void newtonnu(double ecc, double nu, double &e0, double &m)
double angle(double vec1[3], double vec2[3])
void rv2coe(double r[3], double v[3], double mu, double &p, double &a, double &ecc, double &incl, double &omega, double &argp, double &nu, double &m, double &arglat, double &truelon, double &lonper)
double dot(double x[3], double y[3])
double mag(double x[3])
void jday(int year, int mon, int day, int hr, int minute, double sec, double &jd)
#define pi