1 |
//
|
2 |
// cOrbit.cpp
|
3 |
//
|
4 |
// Copyright (c) 2002-2003 Michael F. Henry
|
5 |
//
|
6 |
// mfh 11/15/2003
|
7 |
//
|
8 |
#include "stdafx.h"
|
9 |
|
10 |
#include "cOrbit.h"
|
11 |
#include "math.h"
|
12 |
#include "time.h"
|
13 |
#include "cVector.h"
|
14 |
#include "cEci.h"
|
15 |
#include "coord.h"
|
16 |
#include "cJulian.h"
|
17 |
#include "cNoradSGP4.h"
|
18 |
#include "cNoradSDP4.h"
|
19 |
|
20 |
//////////////////////////////////////////////////////////////////////
|
21 |
cOrbit::cOrbit(const cTle &tle) :
|
22 |
m_tle(tle),
|
23 |
m_pNoradModel(NULL)
|
24 |
{
|
25 |
m_tle.Initialize();
|
26 |
|
27 |
int epochYear = (int)m_tle.getField(cTle::FLD_EPOCHYEAR);
|
28 |
double epochDay = m_tle.getField(cTle::FLD_EPOCHDAY );
|
29 |
|
30 |
if (epochYear < 57)
|
31 |
epochYear += 2000;
|
32 |
else
|
33 |
epochYear += 1900;
|
34 |
|
35 |
m_jdEpoch = cJulian(epochYear, epochDay);
|
36 |
|
37 |
m_secPeriod = -1.0;
|
38 |
|
39 |
// Recover the original mean motion and semimajor axis from the
|
40 |
// input elements.
|
41 |
double mm = mnMotion();
|
42 |
double rpmin = mm * 2 * PI / MIN_PER_DAY; // rads per minute
|
43 |
|
44 |
double a1 = pow(XKE / rpmin, TWOTHRD);
|
45 |
double e = Eccentricity();
|
46 |
double i = Inclination();
|
47 |
double temp = (1.5 * CK2 * (3.0 * sqr(cos(i)) - 1.0) /
|
48 |
pow(1.0 - e * e, 1.5));
|
49 |
double delta1 = temp / (a1 * a1);
|
50 |
double a0 = a1 *
|
51 |
(1.0 - delta1 *
|
52 |
((1.0 / 3.0) + delta1 *
|
53 |
(1.0 + 134.0 / 81.0 * delta1)));
|
54 |
|
55 |
double delta0 = temp / (a0 * a0);
|
56 |
|
57 |
m_mnMotionRec = rpmin / (1.0 + delta0);
|
58 |
m_aeAxisSemiMinorRec = a0 / (1.0 - delta0);
|
59 |
m_aeAxisSemiMajorRec = m_aeAxisSemiMinorRec / sqrt(1.0 - (e * e));
|
60 |
m_kmPerigeeRec = XKMPER_WGS72 * (m_aeAxisSemiMajorRec * (1.0 - e) - AE);
|
61 |
m_kmApogeeRec = XKMPER_WGS72 * (m_aeAxisSemiMajorRec * (1.0 + e) - AE);
|
62 |
|
63 |
if (2.0 * PI / m_mnMotionRec >= 225.0)
|
64 |
{
|
65 |
// SDP4 - period >= 225 minutes.
|
66 |
m_pNoradModel = new cNoradSDP4(*this);
|
67 |
}
|
68 |
else
|
69 |
{
|
70 |
// SGP4 - period < 225 minutes
|
71 |
m_pNoradModel = new cNoradSGP4(*this);
|
72 |
}
|
73 |
}
|
74 |
|
75 |
/////////////////////////////////////////////////////////////////////////////
|
76 |
cOrbit::~cOrbit()
|
77 |
{
|
78 |
delete m_pNoradModel;
|
79 |
}
|
80 |
|
81 |
//////////////////////////////////////////////////////////////////////////////
|
82 |
// Return the period in seconds
|
83 |
double cOrbit::Period() const
|
84 |
{
|
85 |
if (m_secPeriod < 0.0)
|
86 |
{
|
87 |
// Calculate the period using the recovered mean motion.
|
88 |
if (m_mnMotionRec == 0)
|
89 |
m_secPeriod = 0.0;
|
90 |
else
|
91 |
m_secPeriod = (2 * PI) / m_mnMotionRec * 60.0;
|
92 |
}
|
93 |
|
94 |
return m_secPeriod;
|
95 |
}
|
96 |
|
97 |
//////////////////////////////////////////////////////////////////////////////
|
98 |
// Returns elapsed number of seconds from epoch to given time.
|
99 |
// Note: "Predicted" TLEs can have epochs in the future.
|
100 |
double cOrbit::TPlusEpoch(const cJulian &gmt) const
|
101 |
{
|
102 |
return gmt.spanSec(Epoch());
|
103 |
}
|
104 |
|
105 |
//////////////////////////////////////////////////////////////////////////////
|
106 |
// Returns the mean anomaly in radians at given GMT.
|
107 |
// At epoch, the mean anomaly is given by the elements data.
|
108 |
double cOrbit::mnAnomaly(cJulian gmt) const
|
109 |
{
|
110 |
double span = TPlusEpoch(gmt);
|
111 |
double P = Period();
|
112 |
|
113 |
assert(P != 0.0);
|
114 |
|
115 |
return fmod(mnAnomaly() + (TWOPI * (span / P)), TWOPI);
|
116 |
}
|
117 |
|
118 |
//////////////////////////////////////////////////////////////////////////////
|
119 |
// getPosition()
|
120 |
// This procedure returns the ECI position and velocity for the satellite
|
121 |
// at "tsince" minutes from the (GMT) TLE epoch. The vectors returned in
|
122 |
// the ECI object are kilometer-based.
|
123 |
// tsince - Time in minutes since the TLE epoch (GMT).
|
124 |
bool cOrbit::getPosition(double tsince, cEci *pEci) const
|
125 |
{
|
126 |
bool rc;
|
127 |
|
128 |
rc = m_pNoradModel->getPosition(tsince, *pEci);
|
129 |
|
130 |
pEci->ae2km();
|
131 |
|
132 |
return rc;
|
133 |
}
|
134 |
|
135 |
//////////////////////////////////////////////////////////////////////////////
|
136 |
// SatName()
|
137 |
// Return the name of the satellite. If requested, the NORAD number is
|
138 |
// appended to the end of the name, i.e., "ISS (ZARYA) #25544".
|
139 |
// The name of the satellite with the NORAD number appended is important
|
140 |
// because many satellites, especially debris, have the same name and
|
141 |
// would otherwise appear to be the same satellite in ouput data.
|
142 |
string cOrbit::SatName(bool fAppendId /* = false */) const
|
143 |
{
|
144 |
string str = m_tle.getName();
|
145 |
|
146 |
if (fAppendId)
|
147 |
{
|
148 |
string strId;
|
149 |
|
150 |
m_tle.getField(cTle::FLD_NORADNUM, cTle::U_NATIVE, &strId);
|
151 |
str = str + " #" + strId;
|
152 |
}
|
153 |
|
154 |
return str;
|
155 |
}
|
156 |
|