Added Tle class
parent
eea38304c1
commit
a118a86fe1
|
@ -78,12 +78,14 @@
|
|||
<ClCompile Include="Globals.cpp" />
|
||||
<ClCompile Include="Julian.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="Tle.cpp" />
|
||||
<ClCompile Include="Vector.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Coord.h" />
|
||||
<ClInclude Include="Globals.h" />
|
||||
<ClInclude Include="Julian.h" />
|
||||
<ClInclude Include="Tle.h" />
|
||||
<ClInclude Include="Vector.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Tle.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Coord.h">
|
||||
|
@ -44,5 +47,8 @@
|
|||
<ClInclude Include="Globals.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Tle.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,289 @@
|
|||
#include "Tle.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
Tle::Tle(const std::string& name, const std::string& line_one, const std::string& line_two) {
|
||||
name_ = name;
|
||||
line_one_ = line_one;
|
||||
line_two_ = line_two;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
Tle::Tle(const Tle& tle) {
|
||||
name_ = tle.name_;
|
||||
line_one_ = tle.line_one_;
|
||||
line_two_ = tle.line_two_;
|
||||
date_ = tle.date_;
|
||||
|
||||
for (int fld = FLD_FIRST; fld < FLD_LAST; fld++) {
|
||||
fields_[fld] = tle.fields_[fld];
|
||||
}
|
||||
}
|
||||
|
||||
Tle::~Tle() {
|
||||
}
|
||||
|
||||
double Tle::GetField(TleField fld, TleUnits units) const {
|
||||
assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
|
||||
assert((U_FIRST <= units) && (units < U_LAST));
|
||||
|
||||
double value = fields_[fld].second;
|
||||
double converted = 0.0;
|
||||
|
||||
switch (fld) {
|
||||
case FLD_I:
|
||||
case FLD_RAAN:
|
||||
case FLD_ARGPER:
|
||||
case FLD_M:
|
||||
{
|
||||
/*
|
||||
* native format is degrees
|
||||
*/
|
||||
if (units == U_RAD)
|
||||
converted = Globals::Deg2Rad(value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
converted = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
/*
|
||||
* get field represented as a string
|
||||
*/
|
||||
std::string Tle::GetFieldString(TleField fld, bool append_units) const {
|
||||
assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
|
||||
|
||||
std::string str = fields_[fld].first;
|
||||
|
||||
if (append_units)
|
||||
str += GetUnits(fld);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the units for a field
|
||||
*/
|
||||
std::string Tle::GetUnits(TleField field) const {
|
||||
static const std::string strDegrees = " degrees";
|
||||
static const std::string strRevsPerDay = " revs / day";
|
||||
static const std::string strNull = "";
|
||||
|
||||
switch (field) {
|
||||
case FLD_I:
|
||||
case FLD_RAAN:
|
||||
case FLD_ARGPER:
|
||||
case FLD_M:
|
||||
return strDegrees;
|
||||
|
||||
case FLD_MMOTION:
|
||||
return strRevsPerDay;
|
||||
|
||||
default:
|
||||
return strNull;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* convert a raw string into an exponent string
|
||||
*/
|
||||
std::string Tle::ExpToDecimal(const std::string& str) {
|
||||
static const int kColumnSign = 0;
|
||||
static const int kLengthSign = 1;
|
||||
static const int kColumnMantissa = 1;
|
||||
static const int kLengthMantissa = 5;
|
||||
static const int kColumnExp = 6;
|
||||
static const int kLengthExp = 2;
|
||||
|
||||
assert(8 == str.length());
|
||||
|
||||
std::string value;
|
||||
value = str.substr(kColumnSign, kLengthSign);
|
||||
value += ".";
|
||||
value += str.substr(kColumnMantissa, kLengthMantissa);
|
||||
value += "e";
|
||||
value += str.substr(kColumnExp, kLengthExp);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* extract all variables
|
||||
*/
|
||||
void Tle::Initialize() {
|
||||
assert(!name_.empty());
|
||||
assert(!line_one_.empty());
|
||||
assert(!line_two_.empty());
|
||||
|
||||
/*
|
||||
* line 1
|
||||
*/
|
||||
|
||||
fields_[FLD_NORADNUM].first = line_one_.substr(TLE1_COL_SATNUM, TLE1_LEN_SATNUM);
|
||||
fields_[FLD_INTLDESC].first = line_one_.substr(TLE1_COL_INTLDESC_A, TLE1_LEN_INTLDESC_A +
|
||||
TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);
|
||||
fields_[FLD_EPOCHYEAR].first = line_one_.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A);
|
||||
|
||||
fields_[FLD_EPOCHDAY].first = line_one_.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B);
|
||||
|
||||
if (line_one_[TLE1_COL_MEANMOTIONDT] == '-') {
|
||||
// value is negative
|
||||
fields_[FLD_MMOTIONDT].first = "-0";
|
||||
} else
|
||||
fields_[FLD_MMOTIONDT].first = "0";
|
||||
|
||||
fields_[FLD_MMOTIONDT].first += line_one_.substr(TLE1_COL_MEANMOTIONDT + 1, TLE1_LEN_MEANMOTIONDT);
|
||||
|
||||
// decimal point assumed; exponential notation
|
||||
fields_[FLD_MMOTIONDT2].first = ExpToDecimal(line_one_.substr(TLE1_COL_MEANMOTIONDT2, TLE1_LEN_MEANMOTIONDT2));
|
||||
|
||||
// decimal point assumed; exponential notation
|
||||
fields_[FLD_BSTAR].first = ExpToDecimal(line_one_.substr(TLE1_COL_BSTAR, TLE1_LEN_BSTAR));
|
||||
|
||||
fields_[FLD_SET].first = line_one_.substr(TLE1_COL_ELNUM, TLE1_LEN_ELNUM);
|
||||
TrimLeft(fields_[FLD_SET].first);
|
||||
|
||||
/*
|
||||
* line 2
|
||||
*/
|
||||
|
||||
fields_[FLD_I].first = line_two_.substr(TLE2_COL_INCLINATION, TLE2_LEN_INCLINATION);
|
||||
TrimLeft(fields_[FLD_I].first);
|
||||
|
||||
fields_[FLD_RAAN].first = line_two_.substr(TLE2_COL_RAASCENDNODE, TLE2_LEN_RAASCENDNODE);
|
||||
TrimLeft(fields_[FLD_RAAN].first);
|
||||
|
||||
// decimal point is assumed
|
||||
fields_[FLD_E].first = "0.";
|
||||
fields_[FLD_E].first += line_two_.substr(TLE2_COL_ECCENTRICITY, TLE2_LEN_ECCENTRICITY);
|
||||
|
||||
fields_[FLD_ARGPER].first = line_two_.substr(TLE2_COL_ARGPERIGEE, TLE2_LEN_ARGPERIGEE);
|
||||
TrimLeft(fields_[FLD_ARGPER].first);
|
||||
|
||||
fields_[FLD_M].first = line_two_.substr(TLE2_COL_MEANANOMALY, TLE2_LEN_MEANANOMALY);
|
||||
TrimLeft(fields_[FLD_M].first);
|
||||
|
||||
fields_[FLD_MMOTION].first = line_two_.substr(TLE2_COL_MEANMOTION, TLE2_LEN_MEANMOTION);
|
||||
TrimLeft(fields_[FLD_MMOTION].first);
|
||||
|
||||
fields_[FLD_ORBITNUM].first = line_two_.substr(TLE2_COL_REVATEPOCH, TLE2_LEN_REVATEPOCH);
|
||||
TrimLeft(fields_[FLD_ORBITNUM].first);
|
||||
|
||||
// update double variables
|
||||
for (int fld = FLD_FIRST; fld < FLD_LAST; fld++) {
|
||||
fields_[fld].second = atof(fields_[fld].first.c_str());
|
||||
}
|
||||
|
||||
int epochYear = (int) GetField(Tle::FLD_EPOCHYEAR);
|
||||
double epochDay = GetField(Tle::FLD_EPOCHDAY);
|
||||
|
||||
if (epochYear < 57)
|
||||
epochYear += 2000;
|
||||
else
|
||||
epochYear += 1900;
|
||||
|
||||
date_ = Julian(epochYear, epochDay);
|
||||
}
|
||||
|
||||
/*
|
||||
* validate a line
|
||||
*/
|
||||
bool Tle::IsValidLine(std::string& str, TleLine line) {
|
||||
TrimLeft(str);
|
||||
TrimRight(str);
|
||||
|
||||
const std::string line1_validation = "1 NNNNNC NNNNAAAA NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN";
|
||||
const std::string line2_validation = "2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN";
|
||||
|
||||
if (Tle::LINE_ONE == line) {
|
||||
if (!ValidateLine(line1_validation, str))
|
||||
return false;
|
||||
} else if (Tle::LINE_TWO == line) {
|
||||
if (!ValidateLine(line2_validation, str))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Last char in string must be checksum
|
||||
// int chk = CheckSum(str);
|
||||
// if (chk != (str[TLE_LEN_LINE_DATA - 1] - '0'))
|
||||
// return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* validate line given a pattern
|
||||
*/
|
||||
bool Tle::ValidateLine(const std::string& pattern, const std::string& line) {
|
||||
assert(pattern.length() == line.length());
|
||||
|
||||
std::string::size_type pos = 0;
|
||||
|
||||
while (pos != line.length() - 1) {
|
||||
if (isdigit(pattern[pos]) || pattern[pos] == ' ' || pattern[pos] == '.') {
|
||||
if (pattern[pos] != line[pos])
|
||||
return false;
|
||||
} else if (pattern[pos] == 'N') {
|
||||
if (!isdigit(line[pos]) && line[pos] != ' ')
|
||||
return false;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute checksum
|
||||
*/
|
||||
int Tle::CheckSum(const std::string& str) {
|
||||
size_t len = str.size() - 1;
|
||||
int xsum = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char ch = str[i];
|
||||
if (isdigit(ch))
|
||||
xsum += (ch - '0');
|
||||
else if (ch == '-')
|
||||
xsum++;
|
||||
}
|
||||
|
||||
return (xsum % 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* trim left of string
|
||||
*/
|
||||
void Tle::TrimLeft(std::string& s) {
|
||||
if (!s.empty()) {
|
||||
std::string::size_type pos = s.find_first_not_of(' ');
|
||||
|
||||
if (pos != std::string::npos)
|
||||
s.erase(0, pos);
|
||||
else
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* trim right of string
|
||||
*/
|
||||
void Tle::TrimRight(std::string& s) {
|
||||
if (!s.empty()) {
|
||||
std::string::size_type pos = s.find_last_not_of(' ');
|
||||
|
||||
if (pos != std::string::npos)
|
||||
s.erase(pos + 1);
|
||||
else
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#ifndef TLE_H_
|
||||
#define TLE_H_
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Julian.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class Tle {
|
||||
public:
|
||||
Tle(const std::string& name, const std::string& line_one, const std::string& line_two);
|
||||
Tle(const Tle& tle);
|
||||
virtual ~Tle();
|
||||
|
||||
enum TleLine {
|
||||
LINE_ZERO,
|
||||
LINE_ONE,
|
||||
LINE_TWO
|
||||
};
|
||||
|
||||
enum TleField {
|
||||
FLD_FIRST,
|
||||
FLD_NORADNUM = FLD_FIRST,
|
||||
FLD_INTLDESC,
|
||||
FLD_SET, // Tle set number
|
||||
FLD_EPOCHYEAR, // Epoch: Last two digits of year
|
||||
FLD_EPOCHDAY, // Epoch: Fractional Julian Day of year
|
||||
FLD_ORBITNUM, // Orbit at epoch
|
||||
FLD_I, // Inclination
|
||||
FLD_RAAN, // R.A. ascending node
|
||||
FLD_E, // Eccentricity
|
||||
FLD_ARGPER, // Argument of perigee
|
||||
FLD_M, // Mean anomaly
|
||||
FLD_MMOTION, // Mean motion
|
||||
FLD_MMOTIONDT, // First time derivative of mean motion
|
||||
FLD_MMOTIONDT2, // Second time derivative of mean motion
|
||||
FLD_BSTAR, // BSTAR Drag
|
||||
FLD_LAST // MUST be last
|
||||
};
|
||||
|
||||
enum TleUnits {
|
||||
U_FIRST,
|
||||
U_RAD = U_FIRST, // radians
|
||||
U_DEG, // degrees
|
||||
U_NATIVE, // Tle format native units (no conversion)
|
||||
U_LAST // MUST be last
|
||||
};
|
||||
|
||||
/*
|
||||
* initialize from raw tle strings
|
||||
*/
|
||||
void Initialize();
|
||||
|
||||
/*
|
||||
* get field represented as a double
|
||||
*/
|
||||
double GetField(TleField fld, TleUnits unit = U_NATIVE) const;
|
||||
/*
|
||||
* get field represented as a string
|
||||
*/
|
||||
std::string GetFieldString(TleField fld, bool append_units) const;
|
||||
|
||||
/*
|
||||
* get epoch of tle
|
||||
*/
|
||||
Julian GetEpoch() const {
|
||||
return date_;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute checksum
|
||||
*/
|
||||
static int CheckSum(const std::string& str);
|
||||
static bool IsValidLine(std::string& str, TleLine line);
|
||||
static void TrimLeft(std::string& str);
|
||||
static void TrimRight(std::string& str);
|
||||
|
||||
std::string GetName() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string GetLine1() const {
|
||||
return line_one_;
|
||||
}
|
||||
|
||||
std::string GetLine2() const {
|
||||
return line_two_;
|
||||
}
|
||||
|
||||
double GetNoradNumber() const {
|
||||
return GetField(Tle::FLD_NORADNUM);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* get units for a field
|
||||
*/
|
||||
std::string GetUnits(TleField field) const;
|
||||
/*
|
||||
* get raw value for a field
|
||||
*/
|
||||
double GetFieldNumeric(TleField) const;
|
||||
/*
|
||||
* convert a raw string into an exponent string
|
||||
*/
|
||||
static std::string ExpToDecimal(const std::string&);
|
||||
/*
|
||||
* validate a line
|
||||
*/
|
||||
static bool ValidateLine(const std::string& pattern, const std::string& line);
|
||||
|
||||
/*
|
||||
* raw tle data
|
||||
*/
|
||||
std::string name_;
|
||||
std::string line_one_;
|
||||
std::string line_two_;
|
||||
|
||||
/*
|
||||
* epoch of tle
|
||||
*/
|
||||
Julian date_;
|
||||
|
||||
// array of tle values in native string and double form
|
||||
std::pair<std::string, double> fields_[FLD_LAST];
|
||||
|
||||
/*
|
||||
* name line
|
||||
*/
|
||||
static const unsigned int TLE_LEN_LINE_DATA = 69;
|
||||
static const unsigned int TLE_LEN_LINE_NAME = 22;
|
||||
|
||||
/*
|
||||
* line 1
|
||||
*/
|
||||
static const unsigned int TLE1_COL_SATNUM = 2;
|
||||
static const unsigned int TLE1_LEN_SATNUM = 5;
|
||||
static const unsigned int TLE1_COL_INTLDESC_A = 9;
|
||||
static const unsigned int TLE1_LEN_INTLDESC_A = 2;
|
||||
static const unsigned int TLE1_COL_INTLDESC_B = 11;
|
||||
static const unsigned int TLE1_LEN_INTLDESC_B = 3;
|
||||
static const unsigned int TLE1_COL_INTLDESC_C = 14;
|
||||
static const unsigned int TLE1_LEN_INTLDESC_C = 3;
|
||||
static const unsigned int TLE1_COL_EPOCH_A = 18;
|
||||
static const unsigned int TLE1_LEN_EPOCH_A = 2;
|
||||
static const unsigned int TLE1_COL_EPOCH_B = 20;
|
||||
static const unsigned int TLE1_LEN_EPOCH_B = 12;
|
||||
static const unsigned int TLE1_COL_MEANMOTIONDT = 33;
|
||||
static const unsigned int TLE1_LEN_MEANMOTIONDT = 10;
|
||||
static const unsigned int TLE1_COL_MEANMOTIONDT2 = 44;
|
||||
static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 8;
|
||||
static const unsigned int TLE1_COL_BSTAR = 53;
|
||||
static const unsigned int TLE1_LEN_BSTAR = 8;
|
||||
static const unsigned int TLE1_COL_EPHEMTYPE = 62;
|
||||
static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
|
||||
static const unsigned int TLE1_COL_ELNUM = 64;
|
||||
static const unsigned int TLE1_LEN_ELNUM = 4;
|
||||
|
||||
/*
|
||||
* line 2
|
||||
*/
|
||||
static const unsigned int TLE2_COL_SATNUM = 2;
|
||||
static const unsigned int TLE2_LEN_SATNUM = 5;
|
||||
static const unsigned int TLE2_COL_INCLINATION = 8;
|
||||
static const unsigned int TLE2_LEN_INCLINATION = 8;
|
||||
static const unsigned int TLE2_COL_RAASCENDNODE = 17;
|
||||
static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
|
||||
static const unsigned int TLE2_COL_ECCENTRICITY = 26;
|
||||
static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
|
||||
static const unsigned int TLE2_COL_ARGPERIGEE = 34;
|
||||
static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
|
||||
static const unsigned int TLE2_COL_MEANANOMALY = 43;
|
||||
static const unsigned int TLE2_LEN_MEANANOMALY = 8;
|
||||
static const unsigned int TLE2_COL_MEANMOTION = 52;
|
||||
static const unsigned int TLE2_LEN_MEANMOTION = 11;
|
||||
static const unsigned int TLE2_COL_REVATEPOCH = 63;
|
||||
static const unsigned int TLE2_LEN_REVATEPOCH = 5;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue