/[PAMELA software]/YodaProfiler/src/sgp4.cpp
ViewVC logotype

Annotation of /YodaProfiler/src/sgp4.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations) (download)
Fri Oct 20 11:39:40 2006 UTC (18 years, 1 month ago) by mocchiut
Branch: MAIN
CVS Tags: v2r06, v2r05, v2r04, v2r01, v2r00, v2r03, v2r02
Create libsgp4.so shared lib; unified sgp4 code

1 mocchiut 1.1 //
2     // globals.cpp
3     //
4     #include <sgp4.h>
5    
6     //////////////////////////////////////////////////////////////////////////////
7     double sqr(const double x)
8     {
9     return (x * x);
10     }
11    
12     //////////////////////////////////////////////////////////////////////////////
13     double Fmod2p(const double arg)
14     {
15     double modu = fmod(arg, TWOPI);
16    
17     if (modu < 0.0)
18     modu += TWOPI;
19    
20     return modu;
21     }
22    
23     //////////////////////////////////////////////////////////////////////////////
24     // AcTan()
25     // ArcTangent of sin(x) / cos(x). The advantage of this function over arctan()
26     // is that it returns the correct quadrant of the angle.
27     double AcTan(const double sinx, const double cosx)
28     {
29     double ret;
30    
31     if (cosx == 0.0)
32     {
33     if (sinx > 0.0)
34     ret = PI / 2.0;
35     else
36     ret = 3.0 * PI / 2.0;
37     }
38     else
39     {
40     if (cosx > 0.0)
41     ret = atan(sinx / cosx);
42     else
43     ret = PI + atan(sinx / cosx);
44     }
45    
46     return ret;
47     }
48    
49     //////////////////////////////////////////////////////////////////////////////
50     double rad2deg(const double r)
51     {
52     const double DEG_PER_RAD = 180.0 / PI;
53     return r * DEG_PER_RAD;
54     }
55    
56     //////////////////////////////////////////////////////////////////////////////
57     double deg2rad(const double d)
58     {
59     const double RAD_PER_DEG = PI / 180.0;
60     return d * RAD_PER_DEG;
61     }
62    
63     //
64     // coord.cpp
65     //
66     // Copyright (c) 2003 Michael F. Henry
67     //
68    
69     //////////////////////////////////////////////////////////////////////
70     // cCoordGeo Class
71     //////////////////////////////////////////////////////////////////////
72    
73     cCoordGeo::cCoordGeo()
74     {
75     m_Lat = 0.0;
76     m_Lon = 0.0;
77     m_Alt = 0.0;
78     }
79    
80     //////////////////////////////////////////////////////////////////////
81     // cCoordTopo Class
82     //////////////////////////////////////////////////////////////////////
83    
84     cCoordTopo::cCoordTopo()
85     {
86     m_Az = 0.0;
87     m_El = 0.0;
88     m_Range = 0.0;
89     m_RangeRate = 0.0;
90    
91     }
92    
93    
94    
95     //
96     // cVector.cpp
97     //
98     // Copyright (c) 2001-2003 Michael F. Henry
99     //
100     //*****************************************************************************
101     // Multiply each component in the vector by 'factor'.
102     //*****************************************************************************
103     void cVector::Mul(double factor)
104     {
105     m_x *= factor;
106     m_y *= factor;
107     m_z *= factor;
108     m_w *= fabs(factor);
109     }
110    
111     //*****************************************************************************
112     // Subtract a vector from this one.
113     //*****************************************************************************
114     void cVector::Sub(const cVector& vec)
115     {
116     m_x -= vec.m_x;
117     m_y -= vec.m_y;
118     m_z -= vec.m_z;
119     m_w -= vec.m_w;
120     }
121    
122     //*****************************************************************************
123     // Calculate the angle between this vector and another
124     //*****************************************************************************
125     double cVector::Angle(const cVector& vec) const
126     {
127     return acos(Dot(vec) / (Magnitude() * vec.Magnitude()));
128     }
129    
130     //*****************************************************************************
131     //
132     //*****************************************************************************
133     double cVector::Magnitude() const
134     {
135     return sqrt((m_x * m_x) +
136     (m_y * m_y) +
137     (m_z * m_z));
138     }
139    
140     //*****************************************************************************
141     // Return the dot product
142     //*****************************************************************************
143     double cVector::Dot(const cVector& vec) const
144     {
145     return (m_x * vec.m_x) +
146     (m_y * vec.m_y) +
147     (m_z * vec.m_z);
148     }
149     //
150     // cJulian.cpp
151     //
152     // This class encapsulates Julian dates with the epoch of 12:00 noon (12:00 UT)
153     // on January 1, 4713 B.C. Some epoch dates:
154     // 01/01/1990 00:00 UTC - 2447892.5
155     // 01/01/1990 12:00 UTC - 2447893.0
156     // 01/01/2000 00:00 UTC - 2451544.5
157     // 01/01/2001 00:00 UTC - 2451910.5
158     //
159     // Note the Julian day begins at noon, which allows astronomers to have all
160     // the dates in a single observing session the same.
161     //
162     // References:
163     // "Astronomical Formulae for Calculators", Jean Meeus
164     // "Satellite Communications", Dennis Roddy, 2nd Edition, 1995.
165     //
166     // Copyright (c) 2003 Michael F. Henry
167     //
168     // mfh 12/24/2003
169     //
170    
171     //////////////////////////////////////////////////////////////////////////////
172     // Create a Julian date object from a time_t object. time_t objects store the
173     // number of seconds since midnight UTC January 1, 1970.
174     cJulian::cJulian(time_t time)
175     {
176     struct tm *ptm = gmtime(&time);
177     assert(ptm);
178    
179     int year = ptm->tm_year + 1900;
180     double day = ptm->tm_yday + 1 +
181     (ptm->tm_hour +
182     ((ptm->tm_min +
183     (ptm->tm_sec / 60.0)) / 60.0)) / 24.0;
184    
185     Initialize(year, day);
186     }
187    
188     //////////////////////////////////////////////////////////////////////////////
189     // Create a Julian date object from a year and day of year.
190     // Example parameters: year = 2001, day = 1.5 (Jan 1 12h)
191     cJulian::cJulian(int year, double day)
192     {
193     Initialize(year, day);
194     }
195    
196     //////////////////////////////////////////////////////////////////////////////
197     // Create a Julian date object.
198     cJulian::cJulian(int year, // i.e., 2004
199     int mon, // 1..12
200     int day, // 1..31
201     int hour, // 0..23
202     int min, // 0..59
203     double sec /* = 0.0 */) // 0..(59.999999...)
204    
205     {
206     // Calculate N, the day of the year (1..366)
207     int N;
208     int F1 = (int)((275.0 * mon) / 9.0);
209     int F2 = (int)((mon + 9.0) / 12.0);
210    
211     if (IsLeapYear(year))
212     {
213     // Leap year
214     N = F1 - F2 + day - 30;
215     }
216     else
217     {
218     // Common year
219     N = F1 - (2 * F2) + day - 30;
220     }
221    
222     double dblDay = N + (hour + (min + (sec / 60.0)) / 60.0) / 24.0;
223    
224     Initialize(year, dblDay);
225     }
226    
227     //////////////////////////////////////////////////////////////////////////////
228     void cJulian::Initialize(int year, double day)
229     {
230     // 1582 A.D.: 10 days removed from calendar
231     // 3000 A.D.: Arbitrary error checking limit
232     assert((year > 1582) && (year < 3000));
233     assert((day >= 0.0) && (day <= 366.5));
234    
235     // Now calculate Julian date
236    
237     year--;
238    
239     // Centuries are not leap years unless they divide by 400
240     int A = (year / 100);
241     int B = 2 - A + (A / 4);
242    
243     double NewYears = (int)(365.25 * year) +
244     (int)(30.6001 * 14) +
245     1720994.5 + B; // 1720994.5 = Oct 30, year -1
246    
247     m_Date = NewYears + day;
248     }
249    
250     //////////////////////////////////////////////////////////////////////////////
251     // getComponent()
252     // Return requested components of date.
253     // Year : Includes the century.
254     // Month: 1..12
255     // Day : 1..31 including fractional part
256     void cJulian::getComponent(int *pYear,
257     int *pMon /* = NULL */,
258     double *pDOM /* = NULL */) const
259     {
260     assert(pYear != NULL);
261    
262     double jdAdj = getDate() + 0.5;
263     int Z = (int)jdAdj; // integer part
264     double F = jdAdj - Z; // fractional part
265     double alpha = (int)((Z - 1867216.25) / 36524.25);
266     double A = Z + 1 + alpha - (int)(alpha / 4.0);
267     double B = A + 1524.0;
268     int C = (int)((B - 122.1) / 365.25);
269     int D = (int)(C * 365.25);
270     int E = (int)((B - D) / 30.6001);
271    
272     double DOM = B - D - (int)(E * 30.6001) + F;
273     int month = (E < 13.5) ? (E - 1) : (E - 13);
274     int year = (month > 2.5) ? (C - 4716) : (C - 4715);
275    
276     *pYear = year;
277    
278     if (pMon != NULL)
279     *pMon = month;
280    
281     if (pDOM != NULL)
282     *pDOM = DOM;
283     }
284    
285     //////////////////////////////////////////////////////////////////////////////
286     // toGMST()
287     // Calculate Greenwich Mean Sidereal Time for the Julian date. The return value
288     // is the angle, in radians, measuring eastward from the Vernal Equinox to the
289     // prime meridian. This angle is also referred to as "ThetaG" (Theta GMST).
290     //
291     // References:
292     // The 1992 Astronomical Almanac, page B6.
293     // Explanatory Supplement to the Astronomical Almanac, page 50.
294     // Orbital Coordinate Systems, Part III, Dr. T.S. Kelso, Satellite Times,
295     // Nov/Dec 1995
296     double cJulian::toGMST() const
297     {
298     const double UT = fmod(m_Date + 0.5, 1.0);
299     const double TU = (FromJan1_12h_2000() - UT) / 36525.0;
300    
301     double GMST = 24110.54841 + TU *
302     (8640184.812866 + TU * (0.093104 - TU * 6.2e-06));
303    
304     GMST = fmod(GMST + SEC_PER_DAY * OMEGA_E * UT, SEC_PER_DAY);
305    
306     if (GMST < 0.0)
307     GMST += SEC_PER_DAY; // "wrap" negative modulo value
308    
309     return (TWOPI * (GMST / SEC_PER_DAY));
310     }
311    
312     //////////////////////////////////////////////////////////////////////////////
313     // toLMST()
314     // Calculate Local Mean Sidereal Time for given longitude (for this date).
315     // The longitude is assumed to be in radians measured west from Greenwich.
316     // The return value is the angle, in radians, measuring eastward from the
317     // Vernal Equinox to the given longitude.
318     double cJulian::toLMST(double lon) const
319     {
320     return fmod(toGMST() + lon, TWOPI);
321     }
322    
323     //////////////////////////////////////////////////////////////////////////////
324     // toTime()
325     // Convert to type time_t
326     // Avoid using this function as it discards the fractional seconds of the
327     // time component.
328     time_t cJulian::toTime() const
329     {
330     int nYear;
331     int nMonth;
332     double dblDay;
333    
334     getComponent(&nYear, &nMonth, &dblDay);
335    
336     // dblDay is the fractional Julian Day (i.e., 29.5577).
337     // Save the whole number day in nDOM and convert dblDay to
338     // the fractional portion of day.
339     int nDOM = (int)dblDay;
340    
341     dblDay -= nDOM;
342    
343     const int SEC_PER_MIN = 60;
344     const int SEC_PER_HR = 60 * SEC_PER_MIN;
345     const int SEC_PER_DAY = 24 * SEC_PER_HR;
346    
347     int secs = (int)((dblDay * SEC_PER_DAY) + 0.5);
348    
349     // Create a "struct tm" type.
350     // NOTE:
351     // The "struct tm" type has a 1-second resolution. Any fractional
352     // component of the "seconds" time value is discarded.
353     struct tm tGMT;
354     memset(&tGMT, 0, sizeof(tGMT));
355    
356     tGMT.tm_year = nYear - 1900; // 2001 is 101
357     tGMT.tm_mon = nMonth - 1; // January is 0
358     tGMT.tm_mday = nDOM; // First day is 1
359     tGMT.tm_hour = secs / SEC_PER_HR;
360     tGMT.tm_min = (secs % SEC_PER_HR) / SEC_PER_MIN;
361     tGMT.tm_sec = (secs % SEC_PER_HR) % SEC_PER_MIN;
362     tGMT.tm_isdst = 0; // No conversion desired
363    
364     time_t tEpoch = mktime(&tGMT);
365    
366     if (tEpoch != -1)
367     {
368     // Valid time_t value returned from mktime().
369     // mktime() expects a local time which means that tEpoch now needs
370     // to be adjusted by the difference between this time zone and GMT.
371     tEpoch -= timezone;
372     }
373    
374     return tEpoch;
375     }
376     //
377     // cTle.cpp
378     // This class encapsulates a single set of standard NORAD two line elements.
379     //
380     // Copyright 1996-2005 Michael F. Henry
381     //
382     // Note: The column offsets are ZERO based.
383    
384     // Name
385     const int TLE_LEN_LINE_DATA = 69; const int TLE_LEN_LINE_NAME = 22;
386    
387     // Line 1
388     const int TLE1_COL_SATNUM = 2; const int TLE1_LEN_SATNUM = 5;
389     const int TLE1_COL_INTLDESC_A = 9; const int TLE1_LEN_INTLDESC_A = 2;
390     const int TLE1_COL_INTLDESC_B = 11; const int TLE1_LEN_INTLDESC_B = 3;
391     const int TLE1_COL_INTLDESC_C = 14; const int TLE1_LEN_INTLDESC_C = 3;
392     const int TLE1_COL_EPOCH_A = 18; const int TLE1_LEN_EPOCH_A = 2;
393     const int TLE1_COL_EPOCH_B = 20; const int TLE1_LEN_EPOCH_B = 12;
394     const int TLE1_COL_MEANMOTIONDT = 33; const int TLE1_LEN_MEANMOTIONDT = 10;
395     const int TLE1_COL_MEANMOTIONDT2 = 44; const int TLE1_LEN_MEANMOTIONDT2 = 8;
396     const int TLE1_COL_BSTAR = 53; const int TLE1_LEN_BSTAR = 8;
397     const int TLE1_COL_EPHEMTYPE = 62; const int TLE1_LEN_EPHEMTYPE = 1;
398     const int TLE1_COL_ELNUM = 64; const int TLE1_LEN_ELNUM = 4;
399    
400     // Line 2
401     const int TLE2_COL_SATNUM = 2; const int TLE2_LEN_SATNUM = 5;
402     const int TLE2_COL_INCLINATION = 8; const int TLE2_LEN_INCLINATION = 8;
403     const int TLE2_COL_RAASCENDNODE = 17; const int TLE2_LEN_RAASCENDNODE = 8;
404     const int TLE2_COL_ECCENTRICITY = 26; const int TLE2_LEN_ECCENTRICITY = 7;
405     const int TLE2_COL_ARGPERIGEE = 34; const int TLE2_LEN_ARGPERIGEE = 8;
406     const int TLE2_COL_MEANANOMALY = 43; const int TLE2_LEN_MEANANOMALY = 8;
407     const int TLE2_COL_MEANMOTION = 52; const int TLE2_LEN_MEANMOTION = 11;
408     const int TLE2_COL_REVATEPOCH = 63; const int TLE2_LEN_REVATEPOCH = 5;
409    
410     /////////////////////////////////////////////////////////////////////////////
411     cTle::cTle(string& strName, string& strLine1, string& strLine2)
412     {
413     m_strName = strName;
414     m_strLine1 = strLine1;
415     m_strLine2 = strLine2;
416    
417     Initialize();
418     }
419    
420     /////////////////////////////////////////////////////////////////////////////
421     cTle::cTle(const cTle &tle)
422     {
423     m_strName = tle.m_strName;
424     m_strLine1 = tle.m_strLine1;
425     m_strLine2 = tle.m_strLine2;
426    
427     for (int fld = FLD_FIRST; fld < FLD_LAST; fld++)
428     {
429     m_Field[fld] = tle.m_Field[fld];
430     }
431    
432     m_mapCache = tle.m_mapCache;
433     }
434    
435     /////////////////////////////////////////////////////////////////////////////
436     cTle::~cTle()
437     {
438     }
439    
440     /////////////////////////////////////////////////////////////////////////////
441     // getField()
442     // Return requested field as a double (function return value) or as a text
443     // string (*pstr) in the units requested (eUnit). Set 'bStrUnits' to true
444     // to have units appended to text string.
445     //
446     // Note: numeric return values are cached; asking for the same field more
447     // than once incurs minimal overhead.
448     double cTle::getField(eField fld,
449     eUnits units, /* = U_NATIVE */
450     string *pstr /* = NULL */,
451     bool bStrUnits /* = false */) const
452     {
453     assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
454     assert((U_FIRST <= units) && (units < U_LAST));
455    
456     if (pstr)
457     {
458     // Return requested field in string form.
459     *pstr = m_Field[fld];
460    
461     if (bStrUnits)
462     *pstr += getUnits(fld);
463    
464     return 0.0;
465     }
466     else
467     {
468     // Return requested field in floating-point form.
469     // Return cache contents if it exists, else populate cache
470     FldKey key = Key(units, fld);
471    
472     if (m_mapCache.find(key) == m_mapCache.end())
473     {
474     // Value not in cache; add it
475     double valNative = atof(m_Field[fld].c_str());
476     double valConv = ConvertUnits(valNative, fld, units);
477     m_mapCache[key] = valConv;
478    
479     return valConv;
480     }
481     else
482     {
483     // return cached value
484     return m_mapCache[key];
485     }
486     }
487     }
488    
489     //////////////////////////////////////////////////////////////////////////////
490     // Convert the given field into the requested units. It is assumed that
491     // the value being converted is in the TLE format's "native" form.
492     double cTle::ConvertUnits(double valNative, // value to convert
493     eField fld, // what field the value is
494     eUnits units) // what units to convert to
495     {
496     switch (fld)
497     {
498     case FLD_I:
499     case FLD_RAAN:
500     case FLD_ARGPER:
501     case FLD_M:
502     {
503     // The native TLE format is DEGREES
504     if (units == U_RAD)
505     return valNative * RADS_PER_DEG;
506     }
507    
508     case FLD_NORADNUM:
509     case FLD_INTLDESC:
510     case FLD_SET:
511     case FLD_EPOCHYEAR:
512     case FLD_EPOCHDAY:
513     case FLD_ORBITNUM:
514     case FLD_E:
515     case FLD_MMOTION:
516     case FLD_MMOTIONDT:
517     case FLD_MMOTIONDT2:
518     case FLD_BSTAR:
519     case FLD_LAST:
520     { // do nothing
521    
522     }
523    
524     }
525    
526     return valNative; // return value in unconverted native format
527     }
528    
529     //////////////////////////////////////////////////////////////////////////////
530     string cTle::getUnits(eField fld) const
531     {
532     static const string strDegrees = " degrees";
533     static const string strRevsPerDay = " revs / day";
534     static const string strNull;
535    
536     switch (fld)
537     {
538     case FLD_I:
539     case FLD_RAAN:
540     case FLD_ARGPER:
541     case FLD_M:
542     return strDegrees;
543    
544     case FLD_MMOTION:
545     return strRevsPerDay;
546    
547     default:
548     return strNull;
549     }
550     }
551    
552     /////////////////////////////////////////////////////////////////////////////
553     // ExpToDecimal()
554     // Converts TLE-style exponential notation of the form [ |-]00000[+|-]0 to
555     // decimal notation. Assumes implied decimal point to the left of the first
556     // number in the string, i.e.,
557     // " 12345-3" = 0.00012345
558     // "-23429-5" = -0.0000023429
559     // " 40436+1" = 4.0436
560     string cTle::ExpToDecimal(const string &str)
561     {
562     const int COL_EXP_SIGN = 6;
563     const int LEN_EXP = 2;
564    
565     const int LEN_BUFREAL = 32; // max length of buffer to hold floating point
566     // representation of input string.
567     int nMan;
568     int nExp;
569    
570     // sscanf(%d) will read up to the exponent sign
571     sscanf(str.c_str(), "%d", &nMan);
572    
573     double dblMan = nMan;
574     bool bNeg = (nMan < 0);
575    
576     if (bNeg)
577     dblMan *= -1;
578    
579     // Move decimal place to left of first digit
580     while (dblMan >= 1.0)
581     dblMan /= 10.0;
582    
583     if (bNeg)
584     dblMan *= -1;
585    
586     // now read exponent
587     sscanf(str.substr(COL_EXP_SIGN, LEN_EXP).c_str(), "%d", &nExp);
588    
589     double dblVal = dblMan * pow(10.0, nExp);
590     char szVal[LEN_BUFREAL];
591    
592     snprintf(szVal, sizeof(szVal), "%.9f", dblVal);
593    
594     string strVal = szVal;
595    
596     return strVal;
597    
598     } // ExpToDecimal()
599    
600     /////////////////////////////////////////////////////////////////////////////
601     // Initialize()
602     // Initialize the string array.
603     void cTle::Initialize()
604     {
605     // Have we already been initialized?
606     if (m_Field[FLD_NORADNUM].size())
607     return;
608    
609     assert(!m_strName.empty());
610     assert(!m_strLine1.empty());
611     assert(!m_strLine2.empty());
612    
613     m_Field[FLD_NORADNUM] = m_strLine1.substr(TLE1_COL_SATNUM, TLE1_LEN_SATNUM);
614     m_Field[FLD_INTLDESC] = m_strLine1.substr(TLE1_COL_INTLDESC_A,
615     TLE1_LEN_INTLDESC_A +
616     TLE1_LEN_INTLDESC_B +
617     TLE1_LEN_INTLDESC_C);
618     m_Field[FLD_EPOCHYEAR] =
619     m_strLine1.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A);
620    
621     m_Field[FLD_EPOCHDAY] =
622     m_strLine1.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B);
623    
624     if (m_strLine1[TLE1_COL_MEANMOTIONDT] == '-')
625     {
626     // value is negative
627     m_Field[FLD_MMOTIONDT] = "-0";
628     }
629     else
630     m_Field[FLD_MMOTIONDT] = "0";
631    
632     m_Field[FLD_MMOTIONDT] += m_strLine1.substr(TLE1_COL_MEANMOTIONDT + 1,
633     TLE1_LEN_MEANMOTIONDT);
634    
635     // decimal point assumed; exponential notation
636     m_Field[FLD_MMOTIONDT2] = ExpToDecimal(
637     m_strLine1.substr(TLE1_COL_MEANMOTIONDT2,
638     TLE1_LEN_MEANMOTIONDT2));
639     // decimal point assumed; exponential notation
640     m_Field[FLD_BSTAR] = ExpToDecimal(m_strLine1.substr(TLE1_COL_BSTAR,
641     TLE1_LEN_BSTAR));
642     //TLE1_COL_EPHEMTYPE
643     //TLE1_LEN_EPHEMTYPE
644     m_Field[FLD_SET] = m_strLine1.substr(TLE1_COL_ELNUM, TLE1_LEN_ELNUM);
645    
646     TrimLeft(m_Field[FLD_SET]);
647    
648     //TLE2_COL_SATNUM
649     //TLE2_LEN_SATNUM
650    
651     m_Field[FLD_I] = m_strLine2.substr(TLE2_COL_INCLINATION,
652     TLE2_LEN_INCLINATION);
653     TrimLeft(m_Field[FLD_I]);
654    
655     m_Field[FLD_RAAN] = m_strLine2.substr(TLE2_COL_RAASCENDNODE,
656     TLE2_LEN_RAASCENDNODE);
657     TrimLeft(m_Field[FLD_RAAN]);
658    
659     // decimal point is assumed
660     m_Field[FLD_E] = "0.";
661     m_Field[FLD_E] += m_strLine2.substr(TLE2_COL_ECCENTRICITY,
662     TLE2_LEN_ECCENTRICITY);
663    
664     m_Field[FLD_ARGPER] = m_strLine2.substr(TLE2_COL_ARGPERIGEE,
665     TLE2_LEN_ARGPERIGEE);
666     TrimLeft(m_Field[FLD_ARGPER]);
667    
668     m_Field[FLD_M] = m_strLine2.substr(TLE2_COL_MEANANOMALY,
669     TLE2_LEN_MEANANOMALY);
670     TrimLeft(m_Field[FLD_M]);
671    
672     m_Field[FLD_MMOTION] = m_strLine2.substr(TLE2_COL_MEANMOTION,
673     TLE2_LEN_MEANMOTION);
674     TrimLeft(m_Field[FLD_MMOTION]);
675    
676     m_Field[FLD_ORBITNUM] = m_strLine2.substr(TLE2_COL_REVATEPOCH,
677     TLE2_LEN_REVATEPOCH);
678     TrimLeft(m_Field[FLD_ORBITNUM]);
679    
680     } // InitStrVars()
681    
682     /////////////////////////////////////////////////////////////////////////////
683     // IsTleFormat()
684     // Returns true if "str" is a valid data line of a two-line element set,
685     // else false.
686     //
687     // To be valid a line must:
688     // Have as the first character the line number
689     // Have as the second character a blank
690     // Be TLE_LEN_LINE_DATA characters long
691     // Have a valid checksum (note: no longer required as of 12/96)
692     //
693     bool cTle::IsValidLine(string& str, eTleLine line)
694     {
695     TrimLeft(str);
696     TrimRight(str);
697    
698     size_t nLen = str.size();
699    
700     if (nLen != (uint)TLE_LEN_LINE_DATA)
701     return false;
702    
703     // First char in string must be line number
704     if ((str[0] - '0') != line)
705     return false;
706    
707     // Second char in string must be blank
708     if (str[1] != ' ')
709     return false;
710    
711     /*
712     NOTE: 12/96
713     The requirement that the last char in the line data must be a valid
714     checksum is too restrictive.
715    
716     // Last char in string must be checksum
717     int nSum = CheckSum(str);
718    
719     if (nSum != (str[TLE_LEN_LINE_DATA - 1] - '0'))
720     return false;
721     */
722    
723     return true;
724    
725     } // IsTleFormat()
726    
727     /////////////////////////////////////////////////////////////////////////////
728     // CheckSum()
729     // Calculate the check sum for a given line of TLE data, the last character
730     // of which is the current checksum. (Although there is no check here,
731     // the current checksum should match the one we calculate.)
732     // The checksum algorithm:
733     // Each number in the data line is summed, modulo 10.
734     // Non-numeric characters are zero, except minus signs, which are 1.
735     //
736     int cTle::CheckSum(const string& str)
737     {
738     // The length is "- 1" because we don't include the current (existing)
739     // checksum character in the checksum calculation.
740     size_t len = str.size() - 1;
741     int xsum = 0;
742    
743     for (size_t i = 0; i < len; i++)
744     {
745     char ch = str[i];
746     if (isdigit(ch))
747     xsum += (ch - '0');
748     else if (ch == '-')
749     xsum++;
750     }
751    
752     return (xsum % 10);
753    
754     } // CheckSum()
755    
756     /////////////////////////////////////////////////////////////////////////////
757     void cTle::TrimLeft(string& s)
758     {
759     while (s[0] == ' ')
760     s.erase(0, 1);
761     }
762    
763     /////////////////////////////////////////////////////////////////////////////
764     void cTle::TrimRight(string& s)
765     {
766     while (s[s.size() - 1] == ' ')
767     s.erase(s.size() - 1);
768     }
769    
770     //
771     // cEci.cpp
772     //
773     // Copyright (c) 2002-2003 Michael F. Henry
774     //
775     //////////////////////////////////////////////////////////////////////
776     // cEci Class
777     //////////////////////////////////////////////////////////////////////
778     cEci::cEci(const cVector &pos,
779     const cVector &vel,
780     const cJulian &date,
781     bool IsAeUnits /* = true */)
782     {
783     m_pos = pos;
784     m_vel = vel;
785     m_date = date;
786     m_VecUnits = (IsAeUnits ? UNITS_AE : UNITS_NONE);
787     }
788    
789     //////////////////////////////////////////////////////////////////////
790     // cEci(cCoordGeo&, cJulian&)
791     // Calculate the ECI coordinates of the location "geo" at time "date".
792     // Assumes geo coordinates are km-based.
793     // Assumes the earth is an oblate spheroid as defined in WGS '72.
794     // Reference: The 1992 Astronomical Almanac, page K11
795     // Reference: www.celestrak.com (Dr. TS Kelso)
796     cEci::cEci(const cCoordGeo &geo, const cJulian &date)
797     {
798     m_VecUnits = UNITS_KM;
799    
800     double mfactor = TWOPI * (OMEGA_E / SEC_PER_DAY);
801     double lat = geo.m_Lat;
802     double lon = geo.m_Lon;
803     double alt = geo.m_Alt;
804    
805     // Calculate Local Mean Sidereal Time (theta)
806     double theta = date.toLMST(lon);
807     double c = 1.0 / sqrt(1.0 + F * (F - 2.0) * sqr(sin(lat)));
808     double s = sqr(1.0 - F) * c;
809     double achcp = (XKMPER_WGS72 * c + alt) * cos(lat);
810    
811     m_date = date;
812    
813     m_pos.m_x = achcp * cos(theta); // km
814     m_pos.m_y = achcp * sin(theta); // km
815     m_pos.m_z = (XKMPER_WGS72 * s + alt) * sin(lat); // km
816     m_pos.m_w = sqrt(sqr(m_pos.m_x) +
817     sqr(m_pos.m_y) +
818     sqr(m_pos.m_z)); // range, km
819    
820     m_vel.m_x = -mfactor * m_pos.m_y; // km / sec
821     m_vel.m_y = mfactor * m_pos.m_x;
822     m_vel.m_z = 0.0;
823     m_vel.m_w = sqrt(sqr(m_vel.m_x) + // range rate km/sec^2
824     sqr(m_vel.m_y));
825     }
826    
827     //////////////////////////////////////////////////////////////////////////////
828     // toGeo()
829     // Return the corresponding geodetic position (based on the current ECI
830     // coordinates/Julian date).
831     // Assumes the earth is an oblate spheroid as defined in WGS '72.
832     // Side effects: Converts the position and velocity vectors to km-based units.
833     // Reference: The 1992 Astronomical Almanac, page K12.
834     // Reference: www.celestrak.com (Dr. TS Kelso)
835     cCoordGeo cEci::toGeo()
836     {
837     ae2km(); // Vectors must be in kilometer-based units
838    
839     double theta = AcTan(m_pos.m_y, m_pos.m_x);
840     double lon = fmod(theta - m_date.toGMST(), TWOPI);
841    
842     if (lon < 0.0)
843     lon += TWOPI; // "wrap" negative modulo
844    
845     double r = sqrt(sqr(m_pos.m_x) + sqr(m_pos.m_y));
846     double e2 = F * (2.0 - F);
847     double lat = AcTan(m_pos.m_z, r);
848    
849     const double delta = 1.0e-07;
850     double phi;
851     double c;
852    
853     do
854     {
855     phi = lat;
856     c = 1.0 / sqrt(1.0 - e2 * sqr(sin(phi)));
857     lat = AcTan(m_pos.m_z + XKMPER_WGS72 * c * e2 * sin(phi), r);
858     }
859     while (fabs(lat - phi) > delta);
860    
861     double alt = r / cos(lat) - XKMPER_WGS72 * c;
862    
863     return cCoordGeo(lat, lon, alt); // radians, radians, kilometers
864     }
865    
866     //////////////////////////////////////////////////////////////////////////////
867     // ae2km()
868     // Convert the position and velocity vector units from AE-based units
869     // to kilometer based units.
870     void cEci::ae2km()
871     {
872     if (UnitsAreAe())
873     {
874     MulPos(XKMPER_WGS72 / AE); // km
875     MulVel((XKMPER_WGS72 / AE) * (MIN_PER_DAY / 86400)); // km/sec
876     m_VecUnits = UNITS_KM;
877     }
878     }

  ViewVC Help
Powered by ViewVC 1.1.23