satellite-sgp4-mobility-model.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2016 INESC TEC
4  * Copyright (c) 2021 CNES
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Code from https://gitlab.inesctec.pt/pmms/ns3-satellite
20  *
21  * Author: Pedro Silva <pmms@inesctec.pt>
22  * Author: Bastien Tauran <bastien.tauran@viveris.fr>
23  */
24 
26 
27 #include "vector-extensions.h"
28 
29 #include <ns3/boolean.h>
30 #include <ns3/log.h>
31 #include <ns3/simulator.h>
32 #include <ns3/string.h>
33 
34 #include <string>
35 #include <utility>
36 
37 NS_LOG_COMPONENT_DEFINE("SatSGP4MobilityModel");
38 
39 namespace ns3
40 {
41 
42 NS_OBJECT_ENSURE_REGISTERED(SatSGP4MobilityModel);
43 
44 const gravconsttype SatSGP4MobilityModel::WGeoSys = wgs72; // recommended for SGP4/SDP4
45 const uint32_t SatSGP4MobilityModel::TleSatInfoWidth = 69;
46 
47 TypeId
49 {
50  static TypeId tid =
51  TypeId("ns3::SatSGP4MobilityModel")
52  .SetParent<SatMobilityModel>()
53  .AddConstructor<SatSGP4MobilityModel>()
54  .AddAttribute("UpdatePositionEachRequest",
55  "Compute position each time a packet is transmitted",
56  BooleanValue(true),
58  MakeBooleanChecker())
59  .AddAttribute(
60  "UpdatePositionPeriod",
61  "Period of satellite position refresh, if UpdatePositionEachRequest is false",
62  TimeValue(Seconds(1)),
64  MakeTimeChecker());
65  return tid;
66 }
67 
68 TypeId
70 {
71  return GetTypeId();
72 }
73 
75  : m_startStr("1992-01-01 00:00:00"),
76  m_timeLastUpdate(Time::Min())
77 {
78  NS_LOG_FUNCTION(this);
79 
80  ObjectBase::ConstructSelf(AttributeConstructionList());
82 }
83 
85 {
86 }
87 
88 void
90 {
91  NS_LOG_FUNCTION(this << startStr);
92 
93  m_startStr = startStr;
95 }
96 
99 {
100  NS_LOG_FUNCTION(this);
101 
102  return m_start;
103 }
104 
105 void
107 {
108  NS_LOG_FUNCTION(this << t);
109 
110  m_start = t;
111 }
112 
113 Vector3D
115 {
116  NS_LOG_FUNCTION(this);
117 
118  JulianDate cur = m_start + Simulator::Now();
119 
120  double r[3], v[3];
121  double delta = (cur - GetTleEpoch()).GetMinutes();
122 
123  if (!IsInitialized())
124  return Vector3D();
125 
126  sgp4(WGeoSys, m_sgp4_record, delta, r, v);
127 
128  if (m_sgp4_record.error != 0)
129  return Vector3D();
130 
131  // velocity vector is in km/s so it needs to be converted to m/s
132  return 1000 * rvTemeTovItrf(Vector3D(r[0], r[1], r[2]), Vector3D(v[0], v[1], v[2]), cur);
133 }
134 
135 Vector
137 {
138  NS_LOG_FUNCTION(this);
139 
140  return DoGetGeoPosition().ToVector();
141 }
142 
143 void
144 SatSGP4MobilityModel::DoSetPosition(const Vector& position)
145 {
146  NS_LOG_FUNCTION(this << position);
147 
148  DoSetGeoPosition(GeoCoordinate(position));
149 }
150 
153 {
154  NS_LOG_FUNCTION(this);
155 
156  if ((m_updatePositionEachRequest == false) &&
157  (Simulator::Now() < m_timeLastUpdate + m_updatePositionPeriod))
158  {
159  return m_lastPosition;
160  }
161 
162  m_timeLastUpdate = Simulator::Now();
164 
165  double r[3], v[3];
166  double delta = (cur - GetTleEpoch()).GetMinutes();
167 
168  if (!IsInitialized())
169  return Vector3D();
170 
171  sgp4(WGeoSys, m_sgp4_record, delta, r, v);
172 
173  if (m_sgp4_record.error != 0)
174  return Vector3D();
175 
176  // vector r is in km so it needs to be converted to meters
177  m_lastPosition = rTemeTorItrf(Vector3D(r[0], r[1], r[2]), cur) * 1000;
178 
179  return m_lastPosition;
180 }
181 
182 void
184 {
185  NS_LOG_FUNCTION(this << position);
186 
187  m_lastPosition = position;
189 }
190 
191 bool
193 {
194  NS_LOG_FUNCTION(this);
195 
196  return ((m_sgp4_record.jdsatepoch > 0) && (m_tle1 != "") && (m_tle2 != ""));
197 }
198 
201 {
202  NS_LOG_FUNCTION(this);
203 
204  if (IsInitialized())
206 
207  return JulianDate();
208 }
209 
210 void
211 SatSGP4MobilityModel::SetTleInfo(const std::string& tle)
212 {
213  NS_LOG_FUNCTION(this << tle);
214 
215  uint32_t delimPos = tle.find("\n");
216  const std::string line1 = tle.substr(0, delimPos);
217  const std::string line2 = tle.substr(delimPos + 1, tle.size() - delimPos);
218 
219  double start, stop, delta;
220  char l1[TleSatInfoWidth + 1], l2[TleSatInfoWidth + 1];
221  double r[3], v[3];
222 
223  NS_ASSERT_MSG(line1.size() == TleSatInfoWidth && line2.size() == TleSatInfoWidth,
224  "Two-Line Element info lines must be of length" << TleSatInfoWidth << "!");
225 
226  m_tle1 = std::string(line1.c_str());
227  m_tle2 = std::string(line2.c_str());
228 
229  memcpy(l1, line1.c_str(), sizeof(l1));
230  memcpy(l2, line2.c_str(), sizeof(l2));
231 
232  // 'c' => catalog mode run
233  // 'e' => epoch time (relative to TLE lines)
234  // 'i' => improved mode of operation
235  twoline2rv(l1, l2, 'c', 'e', 'i', WGeoSys, start, stop, delta, m_sgp4_record);
236 
237  // call propagator to check if it has been properly initialized
238  sgp4(WGeoSys, m_sgp4_record, 0, r, v);
239 
240  if (m_start > GetTleEpoch() + Years(1))
241  {
242  NS_FATAL_ERROR("Simulation start date "
243  << (m_start - GetTleEpoch()).GetDays()
244  << " after TLE epoch. TLE are only valid for a few days");
245  }
246 
247  if (m_sgp4_record.error != 0)
248  {
249  NS_FATAL_ERROR("Error while loading TLE file");
250  }
251 
253 }
254 
255 Vector3D
256 SatSGP4MobilityModel::rTemeTorItrf(const Vector3D& rteme, const JulianDate& t)
257 {
258  Matrix pmt = PefToItrf(t); // PEF->ITRF matrix transposed
259  Matrix tmt = TemeToPef(t); // TEME->PEF matrix
260 
261  return pmt * (tmt * rteme);
262 }
263 
264 Vector3D
266  const Vector3D& vteme,
267  const JulianDate& t)
268 {
269  Matrix pmt = PefToItrf(t); // PEF->ITRF matrix transposed
270  Matrix tmt = TemeToPef(t); // TEME->PEF matrix
271  Vector3D w(0.0, 0.0, t.GetOmegaEarth());
272 
273  return pmt * ((tmt * vteme) - CrossProduct(w, tmt * rteme));
274 }
275 
278 {
279  std::pair<double, double> eop = t.GetPolarMotion();
280 
281  const double &xp = eop.first, &yp = eop.second;
282  const double cosxp = cos(xp), cosyp = cos(yp);
283  const double sinxp = sin(xp), sinyp = sin(yp);
284 
285  // [from AIAA-2006-6753 Report, Page 32, Appendix C - TEME Coordinate System]
286  //
287  // Matrix(ITRF<->PEF) = ROT1(yp)*ROT2(xp) [using c for cos, and s for sin]
288  //
289  // | 1 0 0 |*| c(xp) 0 -s(xp) |=| c(xp) 0 -s(xp) |
290  // | 0 c(yp) s(yp) | | 0 1 0 | | s(yp)*s(xp) c(yp) s(yp)*c(xp) |
291  // | 0 -s(yp) c(yp) | | s(xp) 0 c(xp) | | c(yp)*s(xp) -s(yp) c(yp)*c(xp) |
292  //
293 
294  // we return the transpose because it is what's needed
295  return Matrix(cosxp,
296  sinyp * sinxp,
297  cosyp * sinxp,
298  0,
299  cosyp,
300  -sinyp,
301  -sinxp,
302  sinyp * cosxp,
303  cosyp * cosxp);
304 }
305 
308 {
309  const double gmst = t.GetGmst();
310  const double cosg = cos(gmst), sing = sin(gmst);
311 
312  // [from AIAA-2006-6753 Report, Page 32, Appendix C - TEME Coordinate System]
313  //
314  // rPEF = ROT3(gmst)*rTEME
315  //
316  // | cos(gmst) sin(gmst) 0 |
317  // | -sin(gmst) cos(gmst) 0 |
318  // | 0 0 1 |
319  //
320 
321  return Matrix(cosg, sing, 0, -sing, cosg, 0, 0, 0, 1);
322 }
323 
325  double c01,
326  double c02,
327  double c10,
328  double c11,
329  double c12,
330  double c20,
331  double c21,
332  double c22)
333 {
334  m[0][0] = c00;
335  m[0][1] = c01;
336  m[0][2] = c02;
337  m[1][0] = c10;
338  m[1][1] = c11;
339  m[1][2] = c12;
340  m[2][0] = c20;
341  m[2][1] = c21;
342  m[2][2] = c22;
343 }
344 
345 Vector3D
347 {
348  return Vector3D(m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
349  m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
350  m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
351 }
352 
353 } // namespace ns3
GeoCoordinate class is used to store and operate with geodetic coordinates.
Vector ToVector() const
Converts Geodetic coordinates to Cartesian coordinates.
Class to handle Julian days and provide respective Earth Orientation Parameters (EOP).
Definition: julian-date.h:79
double GetGmst(void) const
Retrieve the Greenwich Mean Sidereal Time.
Definition: julian-date.cc:187
double GetOmegaEarth(void) const
Retrieve Earth's angular velocity.
Definition: julian-date.cc:174
std::pair< double, double > GetPolarMotion(void) const
Retrieve the polar motion cofficients measured/predicted.
Definition: julian-date.cc:161
Keep track of the current position and velocity of an object in satellite network.
void NotifyGeoCourseChange(void) const
std::string m_startStr
Simulation absolute start time in string format.
virtual void DoSetGeoPosition(const GeoCoordinate &position)
static const gravconsttype WGeoSys
World Geodetic System (WGS) constants to be used by SGP4/SDP4 models.
JulianDate GetStartTime() const
Get the time instant considered as the simulation start.
virtual void DoSetPosition(const Vector &position)
static const uint32_t TleSatInfoWidth
Satellite's information line size defined by TLE data format.
GeoCoordinate m_lastPosition
Last saved satellite position.
void SetStartTime(const JulianDate &t)
Set the time instant considered as the simulation start.
static Matrix PefToItrf(const JulianDate &t)
Retrieve the matrix for converting from PEF to ITRF at a given time.
Time m_updatePositionPeriod
Period of satellite position refresh, if UpdatePositionEachRequest is false.
JulianDate GetTleEpoch(void) const
Retrieve the TLE epoch time.
bool m_updatePositionEachRequest
Compute position each time a packet is transmitted.
elsetrec m_sgp4_record
SGP4/SDP4 record.
static Vector3D rvTemeTovItrf(const Vector3D &rteme, const Vector3D &vteme, const JulianDate &t)
Retrieve the satellite's velocity vector in ITRF coordinates.
static Matrix TemeToPef(const JulianDate &t)
Retrieve the matrix for converting from TEME to PEF at a given time.
Time m_timeLastUpdate
Last position update time.
std::string m_tle2
satellite's TLE data.
static TypeId GetTypeId(void)
Get the type ID.
static Vector3D rTemeTorItrf(const Vector3D &rteme, const JulianDate &t)
Retrieve the satellite's position vector in ITRF coordinates.
void SetStartDate(std::string startStr)
Set the simulation absolute start time in string format.
virtual GeoCoordinate DoGetGeoPosition() const
bool IsInitialized(void) const
Check if the satellite has already been initialized.
void SetTleInfo(const std::string &tle)
Set satellite's TLE information required for its initialization.
JulianDate m_start
Simulation absolute start time.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
Vector3D CrossProduct(const Vector3D &v1, const Vector3D &v2)
Cross product of two Vector3D objects.
void twoline2rv(char longstr1[130], char longstr2[130], char typerun, char typeinput, char opsmode, gravconsttype whichconst, double &startmfe, double &stopmfe, double &deltamin, elsetrec &satrec)
bool sgp4(gravconsttype whichconst, elsetrec &satrec, double tsince, double r[3], double v[3])
gravconsttype
@ wgs72
double jdsatepoch
Matrix data structure to make coordinate conversion code clearer and less verbose.
Vector3D operator*(const Vector3D &v) const