satellite-antenna-gain-pattern.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 Magister Solutions Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Jani Puttonen <jani.puttonen@magister.fi>
19  */
20 
22 
23 #include "satellite-utils.h"
24 
25 #include "ns3/double.h"
26 #include "ns3/log.h"
27 
28 #include <algorithm>
29 #include <stdlib.h>
30 
31 NS_LOG_COMPONENT_DEFINE("SatAntennaGainPattern");
32 
33 namespace ns3
34 {
35 
36 const std::string SatAntennaGainPattern::m_nanStringArray[4] = {"nan", "NaN", "Nan", "NAN"};
37 
38 NS_OBJECT_ENSURE_REGISTERED(SatAntennaGainPattern);
39 
40 TypeId
42 {
43  static TypeId tid =
44  TypeId("ns3::SatAntennaGainPattern")
45  .SetParent<Object>()
46  .AddConstructor<SatAntennaGainPattern>()
47  .AddAttribute(
48  "MinAcceptableAntennaGainDb",
49  "Minimum acceptable antenna gain in dBs",
50  DoubleValue(48.0),
52  MakeDoubleChecker<double>());
53  return tid;
54 }
55 
56 TypeId
58 {
59  return GetTypeId();
60 }
61 
63  : m_antennaPattern(),
64  m_validPositions(),
65  m_minAcceptableAntennaGainInDb(40.0),
66  m_uniformRandomVariable(),
67  m_latitudes(),
68  m_longitudes(),
69  m_minLat(0.0),
70  m_minLon(0.0),
71  m_maxLat(0.0),
72  m_maxLon(0.0),
73  m_latInterval(0.0),
74  m_lonInterval(0.0),
75  m_latDefaultSatellite(0.0),
76  m_lonDefaultSatellite(0.0),
77  m_nanStrings()
78 {
79  // Do nothing here
80 }
81 
83  GeoCoordinate defaultSatellitePosition)
84  : m_nanStrings(m_nanStringArray,
85  m_nanStringArray + (sizeof m_nanStringArray / sizeof m_nanStringArray[0]))
86 {
87  // Attributes are needed already in construction phase:
88  // - ConstructSelf call in constructor
89  // - GetInstanceTypeId is needed to be implemented
90  ObjectBase::ConstructSelf(AttributeConstructionList());
91 
92  m_latDefaultSatellite = defaultSatellitePosition.GetLatitude();
93  m_lonDefaultSatellite = defaultSatellitePosition.GetLongitude();
94 
95  ReadAntennaPatternFromFile(filePathName);
96  m_uniformRandomVariable = CreateObject<UniformRandomVariable>();
97 }
98 
99 void
101 {
102  NS_LOG_FUNCTION(this << filePathName);
103 
104  // READ FROM THE SPECIFIED INPUT FILE
105  std::ifstream* ifs = new std::ifstream(filePathName.c_str(), std::ifstream::in);
106 
107  if (!ifs->is_open())
108  {
109  // script might be launched by test.py, try a different base path
110  delete ifs;
111  filePathName = "../../" + filePathName;
112  ifs = new std::ifstream(filePathName.c_str(), std::ifstream::in);
113 
114  if (!ifs->is_open())
115  {
116  NS_FATAL_ERROR("The file " << filePathName << " is not found.");
117  }
118  }
119 
120  // Row vector containing all the gain values for a certain latitude
121  std::vector<double> rowVector;
122 
123  // Start conditions
124  double lat, lon, gainDouble;
125  std::string gainString;
126  bool firstRowDone(false);
127 
128  // Read a row
129  *ifs >> lat >> lon >> gainString;
130 
131  while (ifs->good())
132  {
133  // Validity of latitude and longitude
134  if (lat < -90.0 || lat > 90.0 || lon < -180.0 || lon > 180.0)
135  {
136  NS_FATAL_ERROR("SatAntennaGainPattern::ReadAntennaPatternFromFile - unvalid latitude: "
137  << lat << " or longitude. " << lon);
138  }
139 
140  // The antenna gain value is read to a string, so that we may check
141  // that whether the value is NaN. If not, then the number is just converted
142  // to a double.
143  if (find(m_nanStrings.begin(), m_nanStrings.end(), gainString) != m_nanStrings.end())
144  {
145  gainDouble = NAN;
146  }
147  else
148  {
149  gainDouble = atof(gainString.c_str());
150 
151  // Add the position to valid positions vector if the gain is
152  // above a specified threshold.
153  if (gainDouble >= m_minAcceptableAntennaGainInDb)
154  {
155  m_validPositions.push_back(std::make_pair(lat, lon));
156  }
157  }
158 
159  // Collect the valid latitude values
160  if (!m_latitudes.empty())
161  {
162  if (m_latitudes.back() != lat)
163  {
164  firstRowDone = true;
165  m_latInterval = lat - m_latitudes.back();
166  m_latitudes.push_back(lat);
167  }
168  }
169  else
170  {
171  m_latitudes.push_back(lat);
172  }
173 
174  // Collect the valid longitude values
175  if (!m_longitudes.empty())
176  {
177  if (!firstRowDone && m_longitudes.back() != lon)
178  {
179  m_lonInterval = lon - m_longitudes.back();
180  m_longitudes.push_back(lon);
181  }
182  }
183  else
184  {
185  m_longitudes.push_back(lon);
186  }
187 
188  // If this is the first gain entry
189  if (rowVector.empty())
190  {
191  m_minLat = lat;
192  m_minLon = lon;
193  rowVector.push_back(gainDouble);
194  }
195  // We are still in the same row (= latitude)
196  else if (lat == m_maxLat)
197  {
198  rowVector.push_back(gainDouble);
199  }
200  // Latitude changed
201  // - Store the vector
202  // - Clean-up
203  // - Start from another row
204  else
205  {
206  m_antennaPattern.push_back(rowVector);
207  rowVector.clear();
208  rowVector.push_back(gainDouble);
209  }
210 
211  // Update the maximum values
212  m_maxLat = lat;
213  m_maxLon = lon;
214 
215  // get next row
216  *ifs >> lat >> lon >> gainString;
217  }
218 
219  // At this point, the last row should not be stored, since the storing
220  // happens every time the row changes. I.e. the last row is stored here!
221  NS_ASSERT(rowVector.size() == m_longitudes.size());
222 
223  m_antennaPattern.push_back(rowVector);
224  rowVector.clear();
225 
226  ifs->close();
227  delete ifs;
228 }
229 
230 void
232  double& lonOffset,
233  Ptr<SatMobilityModel> mobility) const
234 {
235  NS_LOG_FUNCTION(this);
236 
237  if (!mobility)
238  {
239  NS_FATAL_ERROR("SatAntennaGainPattern::GetSatelliteOffset - Called without initializing "
240  "satellite position first");
241  }
242 
243  GeoCoordinate satellite = mobility->GetGeoPosition();
244 
245  latOffset = m_latDefaultSatellite - satellite.GetLatitude();
246  lonOffset = m_lonDefaultSatellite - satellite.GetLongitude();
247 
248  NS_LOG_DEBUG(this << " Satellite offset (moved from the beginning of the simulation): "
249  << latOffset << " / " << lonOffset);
250 }
251 
253 SatAntennaGainPattern::GetValidRandomPosition(Ptr<SatMobilityModel> mobility) const
254 {
255  NS_LOG_FUNCTION(this << mobility);
256 
257  double satLatOffset, satLonOffset;
258  GetSatelliteOffset(satLatOffset, satLonOffset, mobility);
259 
260  uint32_t numPosGridPoints = m_validPositions.size();
261  uint32_t ind(0);
262  std::pair<double, double> lowerLeftCoord;
263 
264  while (1)
265  {
266  // Get random position (=lower left corner of a grid) from the valid ones
267  ind = m_uniformRandomVariable->GetInteger(0, numPosGridPoints - 1);
268  lowerLeftCoord = m_validPositions[ind];
269 
270  // Test if the three other corners for interpolation are found.
271  // If they do not, loop again to find another position.
272 
273  std::pair<double, double> testPos;
274 
275  // Upper left corner
276  testPos.first = lowerLeftCoord.first + m_latInterval;
277  testPos.second = lowerLeftCoord.second;
278  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
279  m_validPositions.end())
280  {
281  continue;
282  }
283 
284  // Upper right corner
285  testPos.second = lowerLeftCoord.second + m_lonInterval;
286  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
287  m_validPositions.end())
288  {
289  continue;
290  }
291 
292  // Lower right corner
293  testPos.first = lowerLeftCoord.first;
294  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
295  m_validPositions.end())
296  {
297  continue;
298  }
299 
300  // None of the previous checks triggered, thus we have a valid position.
301  break;
302  }
303 
304  // Pick a random position within a grid square
305  double latOffset = m_uniformRandomVariable->GetValue(0.0, m_latInterval - 0.001);
306  double lonOffset = m_uniformRandomVariable->GetValue(0.0, m_lonInterval - 0.001);
307 
308  double latitude = lowerLeftCoord.first + latOffset - satLatOffset;
309  double longitude = lowerLeftCoord.second + lonOffset - satLonOffset;
310 
311  GeoCoordinate coord(latitude, longitude, 0.0, true);
312 
313  return coord;
314 }
315 
316 bool
318  TracedCallback<double> cb,
319  Ptr<SatMobilityModel> mobility) const
320 {
321  NS_LOG_FUNCTION(this << coord.GetLatitude() << coord.GetLongitude());
322 
323  double antennaGain = SatUtils::LinearToDb(GetAntennaGain_lin(coord, mobility));
324  cb(antennaGain);
325  return antennaGain >= m_minAcceptableAntennaGainInDb;
326 }
327 
328 double
329 SatAntennaGainPattern::GetAntennaGain_lin(GeoCoordinate coord, Ptr<SatMobilityModel> mobility) const
330 {
331  NS_LOG_FUNCTION(this << coord.GetLatitude() << coord.GetLongitude());
332 
333  double satLatOffset, satLonOffset;
334  GetSatelliteOffset(satLatOffset, satLonOffset, mobility);
335 
336  // Get the requested position {latitude, longitude}
337  double latitude = coord.GetLatitude() + satLatOffset;
338  double longitude = coord.GetLongitude() + satLonOffset;
339 
340  // Given {latitude, longitude} has to be inside the min/max latitude/longitude values
341  if (m_minLat > latitude || latitude > m_maxLat || m_minLon > longitude || longitude > m_maxLon)
342  {
343  NS_LOG_WARN("Given latitude and longitude out of range!");
344  return std::numeric_limits<double>::quiet_NaN();
345  }
346 
347  // Calculate the minimum grid point {minLatIndex, minLonIndex} for the given {latitude,
348  // longitude} point
349  uint32_t minLatIndex = (uint32_t)(std::floor(std::abs(latitude - m_minLat) / m_latInterval));
350  uint32_t minLonIndex = (uint32_t)(std::floor(std::abs(longitude - m_minLon) / m_lonInterval));
351 
352  // All the values within the grid box has to be valid! If UT is placed (or
353  // is moving outside) the valid simulation area, the simulation will crash
354  // to a fatal error.
355  if (std::isnan(m_antennaPattern[minLatIndex][minLonIndex]) ||
356  std::isnan(m_antennaPattern[minLatIndex][minLonIndex + 1]) ||
357  std::isnan(m_antennaPattern[minLatIndex + 1][minLonIndex]) ||
358  std::isnan(m_antennaPattern[minLatIndex + 1][minLonIndex + 1]))
359  {
360  NS_LOG_WARN(this << ", some value(s) of the interpolated grid point(s) is/are NAN!");
361  return std::numeric_limits<double>::quiet_NaN();
362  }
363 
371  // Longitude direction with latitude minLatIndex
372  double upperLonShare = (m_longitudes[minLonIndex + 1] - longitude) / m_lonInterval;
373  double lowerLonShare = (longitude - m_longitudes[minLonIndex]) / m_lonInterval;
374 
375  // Change the gains to linear values , because the interpolation is done in linear domain.
376  double G11 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex][minLonIndex]);
377  double G12 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex][minLonIndex + 1]);
378  double G21 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex + 1][minLonIndex]);
379  double G22 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex + 1][minLonIndex + 1]);
380 
381  // Longitude direction with latitude minLatIndex
382  double valLatLower = upperLonShare * G11 + lowerLonShare * G12;
383 
384  // Longitude direction with latitude minLatIndex+1
385  double valLatUpper = upperLonShare * G21 + lowerLonShare * G22;
386 
387  // Latitude direction with longitude "longitude"
388  double gain = ((m_latitudes[minLatIndex + 1] - latitude) / m_latInterval) * valLatLower +
389  ((latitude - m_latitudes[minLatIndex]) / m_latInterval) * valLatUpper;
390 
391  /*
392  std::cout << "minLonIndex = " << minLonIndex <<
393  ", minLatIndex = " << minLatIndex <<
394  ", m_lonInterval = " << m_lonInterval <<
395  ", m_LatInterval = " << m_latInterval <<
396  ", x1 = " << m_longitudes[minLonIndex] <<
397  ", y1 = " << m_latitudes[minLatIndex] <<
398  ", x2 = " << m_longitudes[minLonIndex+1] <<
399  ", y2 = " << m_latitudes[minLatIndex+1] <<
400  ", G(x1, y1) = " << m_antennaPattern[minLatIndex][minLonIndex] <<
401  ", G(x1, y2) = " << m_antennaPattern[minLatIndex+1][minLonIndex] <<
402  ", G(x2, y1) = " << m_antennaPattern[minLatIndex][minLonIndex+1] <<
403  ", G(x2, y2) = " << m_antennaPattern[minLatIndex+1][minLonIndex+1] <<
404  ", x = " << longitude <<
405  ", y = " << latitude <<
406  ", interpolated gain: " << gain << std::endl;
407  */
408  return gain;
409 }
410 
411 } // namespace ns3
GeoCoordinate class is used to store and operate with geodetic coordinates.
double GetLatitude() const
Gets latitude value of coordinate.
double GetLongitude() const
Gets longitude value of coordinate.
void GetSatelliteOffset(double &latOffset, double &lonOffset, Ptr< SatMobilityModel > mobility) const
virtual TypeId GetInstanceTypeId(void) const
Get the type ID of instance.
double GetAntennaGain_lin(GeoCoordinate coord, Ptr< SatMobilityModel > mobility) const
Calculate the antenna gain value for a certain {latitude, longitude} point.
Ptr< UniformRandomVariable > m_uniformRandomVariable
Uniform random variable used for beam selection.
GeoCoordinate GetValidRandomPosition(Ptr< SatMobilityModel > mobility) const
Get a valid random position under this spot-beam coverage.
double m_lonInterval
Interval between longitudes, must be constant.
static const std::string m_nanStringArray[4]
Valid Not-a-Number (NaN) strings.
double m_minLon
Minimum longitude value of the antenna gain pattern.
std::vector< double > m_latitudes
All valid latitudes from the file.
double m_maxLat
Maximum latitude value of the antenna gain pattern.
double m_lonDefaultSatellite
Longitude of default satellite for antenna gain pattern.
bool IsValidPosition(GeoCoordinate coord, TracedCallback< double > cb, Ptr< SatMobilityModel > mobility) const
Check if a given position is under this spot-beam coverage.
double m_minAcceptableAntennaGainInDb
Minimum acceptable antenna gain for a serving spot-beam.
std::vector< std::string > m_nanStrings
double m_latDefaultSatellite
Latitude of default satellite for antenna gain pattern.
double m_maxLon
Minimum longitude value of the antenna gain pattern.
double m_minLat
Minimum latitude value of the antenna gain pattern.
void ReadAntennaPatternFromFile(std::string filePathName)
Read the antenna gain pattern from a file.
std::vector< std::pair< double, double > > m_validPositions
Container for valid positions.
std::vector< double > m_longitudes
All valid latitudes from the file.
std::vector< std::vector< double > > m_antennaPattern
Container for the antenna pattern from one spot-beam.
static TypeId GetTypeId(void)
Get the type ID.
double m_latInterval
Interval between latitudes, must be constant.
static T DbToLinear(T db)
Converts decibels to linear.
static T LinearToDb(T linear)
Converts linear to decibels.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.