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 <cmath>
30 #include <fstream>
31 #include <iostream>
32 #include <limits>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 NS_LOG_COMPONENT_DEFINE("SatAntennaGainPattern");
40 
41 namespace ns3
42 {
43 
44 const std::string SatAntennaGainPattern::m_nanStringArray[4] = {"nan", "NaN", "Nan", "NAN"};
45 
46 NS_OBJECT_ENSURE_REGISTERED(SatAntennaGainPattern);
47 
48 TypeId
50 {
51  static TypeId tid =
52  TypeId("ns3::SatAntennaGainPattern")
53  .SetParent<Object>()
54  .AddConstructor<SatAntennaGainPattern>()
55  .AddAttribute(
56  "MinAcceptableAntennaGainDb",
57  "Minimum acceptable antenna gain in dBs",
58  DoubleValue(48.0),
60  MakeDoubleChecker<double>());
61  return tid;
62 }
63 
64 TypeId
66 {
67  return GetTypeId();
68 }
69 
71  : m_antennaPattern(),
72  m_validPositions(),
73  m_minAcceptableAntennaGainInDb(40.0),
74  m_uniformRandomVariable(),
75  m_latitudes(),
76  m_longitudes(),
77  m_minLat(0.0),
78  m_minLon(0.0),
79  m_maxLat(0.0),
80  m_maxLon(0.0),
81  m_latInterval(0.0),
82  m_lonInterval(0.0),
83  m_latDefaultSatellite(0.0),
84  m_lonDefaultSatellite(0.0),
85  m_nanStrings()
86 {
87  // Do nothing here
88 }
89 
91  GeoCoordinate defaultSatellitePosition)
92  : m_nanStrings(m_nanStringArray,
93  m_nanStringArray + (sizeof m_nanStringArray / sizeof m_nanStringArray[0]))
94 {
95  // Attributes are needed already in construction phase:
96  // - ConstructSelf call in constructor
97  // - GetInstanceTypeId is needed to be implemented
98  ObjectBase::ConstructSelf(AttributeConstructionList());
99 
100  m_latDefaultSatellite = defaultSatellitePosition.GetLatitude();
101  m_lonDefaultSatellite = defaultSatellitePosition.GetLongitude();
102 
103  ReadAntennaPatternFromFile(filePathName);
104  m_uniformRandomVariable = CreateObject<UniformRandomVariable>();
105 }
106 
107 void
109 {
110  NS_LOG_FUNCTION(this << filePathName);
111 
112  // READ FROM THE SPECIFIED INPUT FILE
113  std::ifstream* ifs = new std::ifstream(filePathName.c_str(), std::ifstream::in);
114 
115  if (!ifs->is_open())
116  {
117  // script might be launched by test.py, try a different base path
118  delete ifs;
119  filePathName = "../../" + filePathName;
120  ifs = new std::ifstream(filePathName.c_str(), std::ifstream::in);
121 
122  if (!ifs->is_open())
123  {
124  NS_FATAL_ERROR("The file " << filePathName << " is not found.");
125  }
126  }
127 
128  // Row vector containing all the gain values for a certain latitude
129  std::vector<double> rowVector;
130 
131  // Start conditions
132  double lat, lon, gainDouble;
133  std::string gainString;
134  bool firstRowDone(false);
135 
136  double bestGain = -100;
137 
138  // Read a row
139  *ifs >> lat >> lon >> gainString;
140 
141  while (ifs->good())
142  {
143  // Validity of latitude and longitude
144  if (lat < -90.0 || lat > 90.0 || lon < -180.0 || lon > 180.0)
145  {
146  NS_FATAL_ERROR("SatAntennaGainPattern::ReadAntennaPatternFromFile - unvalid latitude: "
147  << lat << " or longitude. " << lon);
148  }
149 
150  // The antenna gain value is read to a string, so that we may check
151  // that whether the value is NaN. If not, then the number is just converted
152  // to a double.
153  if (find(m_nanStrings.begin(), m_nanStrings.end(), gainString) != m_nanStrings.end())
154  {
155  gainDouble = NAN;
156  }
157  else
158  {
159  gainDouble = atof(gainString.c_str());
160 
161  // Add the position to valid positions vector if the gain is
162  // above a specified threshold.
163  if (gainDouble >= m_minAcceptableAntennaGainInDb)
164  {
165  m_validPositions.push_back(std::make_pair(lat, lon));
166  }
167  }
168 
169  // Collect the valid latitude values
170  if (!m_latitudes.empty())
171  {
172  if (m_latitudes.back() != lat)
173  {
174  firstRowDone = true;
175  m_latInterval = lat - m_latitudes.back();
176  m_latitudes.push_back(lat);
177  }
178  }
179  else
180  {
181  m_latitudes.push_back(lat);
182  }
183 
184  // Collect the valid longitude values
185  if (!m_longitudes.empty())
186  {
187  if (!firstRowDone && m_longitudes.back() != lon)
188  {
189  m_lonInterval = lon - m_longitudes.back();
190  m_longitudes.push_back(lon);
191  }
192  }
193  else
194  {
195  m_longitudes.push_back(lon);
196  }
197 
198  if (gainDouble > bestGain)
199  {
200  bestGain = gainDouble;
201  m_centerLatitude = lat;
202  m_centerLongitude = lon;
203  }
204 
205  // If this is the first gain entry
206  if (rowVector.empty())
207  {
208  m_minLat = lat;
209  m_minLon = lon;
210  rowVector.push_back(gainDouble);
211  }
212  // We are still in the same row (= latitude)
213  else if (lat == m_maxLat)
214  {
215  rowVector.push_back(gainDouble);
216  }
217  // Latitude changed
218  // - Store the vector
219  // - Clean-up
220  // - Start from another row
221  else
222  {
223  m_antennaPattern.push_back(rowVector);
224  rowVector.clear();
225  rowVector.push_back(gainDouble);
226  }
227 
228  // Update the maximum values
229  m_maxLat = lat;
230  m_maxLon = lon;
231 
232  // get next row
233  *ifs >> lat >> lon >> gainString;
234  }
235 
236  // At this point, the last row should not be stored, since the storing
237  // happens every time the row changes. I.e. the last row is stored here!
238  NS_ASSERT(rowVector.size() == m_longitudes.size());
239 
240  m_antennaPattern.push_back(rowVector);
241  rowVector.clear();
242 
243  ifs->close();
244  delete ifs;
245 }
246 
247 void
249  double& lonOffset,
250  Ptr<SatMobilityModel> mobility) const
251 {
252  NS_LOG_FUNCTION(this);
253 
254  if (!mobility)
255  {
256  NS_FATAL_ERROR("SatAntennaGainPattern::GetSatelliteOffset - Called without initializing "
257  "satellite position first");
258  }
259 
260  GeoCoordinate satellite = mobility->GetGeoPosition();
261 
262  latOffset = m_latDefaultSatellite - satellite.GetLatitude();
263  lonOffset = m_lonDefaultSatellite - satellite.GetLongitude();
264 
265  NS_LOG_DEBUG(this << " Satellite offset (moved from the beginning of the simulation): "
266  << latOffset << " / " << lonOffset);
267 }
268 
269 double
270 SatAntennaGainPattern::GetCenterLatitude(Ptr<SatMobilityModel> mobility) const
271 {
272  NS_LOG_FUNCTION(this);
273 
274  if (!mobility)
275  {
276  NS_FATAL_ERROR("SatAntennaGainPattern::GetCenterLatitude - Called without initializing "
277  "satellite position first");
278  }
279 
280  GeoCoordinate satellite = mobility->GetGeoPosition();
281  double latOffset = m_latDefaultSatellite - satellite.GetLatitude();
282 
283  return m_centerLatitude - latOffset;
284 }
285 
286 double
287 SatAntennaGainPattern::GetCenterLongitude(Ptr<SatMobilityModel> mobility) const
288 {
289  NS_LOG_FUNCTION(this);
290 
291  if (!mobility)
292  {
293  NS_FATAL_ERROR("SatAntennaGainPattern::GetCenterLongitude - Called without initializing "
294  "satellite position first");
295  }
296 
297  GeoCoordinate satellite = mobility->GetGeoPosition();
298  double lonOffset = m_lonDefaultSatellite - satellite.GetLongitude();
299 
300  return m_centerLongitude - lonOffset;
301 }
302 
304 SatAntennaGainPattern::GetValidRandomPosition(Ptr<SatMobilityModel> mobility) const
305 {
306  NS_LOG_FUNCTION(this << mobility);
307 
308  double satLatOffset, satLonOffset;
309  GetSatelliteOffset(satLatOffset, satLonOffset, mobility);
310 
311  uint32_t numPosGridPoints = m_validPositions.size();
312  uint32_t ind(0);
313  std::pair<double, double> lowerLeftCoord;
314 
315  while (1)
316  {
317  // Get random position (=lower left corner of a grid) from the valid ones
318  ind = m_uniformRandomVariable->GetInteger(0, numPosGridPoints - 1);
319  lowerLeftCoord = m_validPositions[ind];
320 
321  // Test if the three other corners for interpolation are found.
322  // If they do not, loop again to find another position.
323 
324  std::pair<double, double> testPos;
325 
326  // Upper left corner
327  testPos.first = lowerLeftCoord.first + m_latInterval;
328  testPos.second = lowerLeftCoord.second;
329  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
330  m_validPositions.end())
331  {
332  continue;
333  }
334 
335  // Upper right corner
336  testPos.second = lowerLeftCoord.second + m_lonInterval;
337  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
338  m_validPositions.end())
339  {
340  continue;
341  }
342 
343  // Lower right corner
344  testPos.first = lowerLeftCoord.first;
345  if (find(m_validPositions.begin(), m_validPositions.end(), testPos) ==
346  m_validPositions.end())
347  {
348  continue;
349  }
350 
351  // None of the previous checks triggered, thus we have a valid position.
352  break;
353  }
354 
355  // Pick a random position within a grid square
356  double latOffset = m_uniformRandomVariable->GetValue(0.0, m_latInterval - 0.001);
357  double lonOffset = m_uniformRandomVariable->GetValue(0.0, m_lonInterval - 0.001);
358 
359  double latitude = lowerLeftCoord.first + latOffset - satLatOffset;
360  double longitude = lowerLeftCoord.second + lonOffset - satLonOffset;
361 
362  GeoCoordinate coord(latitude, longitude, 0.0, true);
363 
364  return coord;
365 }
366 
367 bool
369  TracedCallback<double> cb,
370  Ptr<SatMobilityModel> mobility) const
371 {
372  NS_LOG_FUNCTION(this << coord.GetLatitude() << coord.GetLongitude());
373 
374  double antennaGain = SatUtils::LinearToDb(GetAntennaGain_lin(coord, mobility));
375  cb(antennaGain);
376  return antennaGain >= m_minAcceptableAntennaGainInDb;
377 }
378 
379 double
380 SatAntennaGainPattern::GetAntennaGain_lin(GeoCoordinate coord, Ptr<SatMobilityModel> mobility) const
381 {
382  NS_LOG_FUNCTION(this << coord.GetLatitude() << coord.GetLongitude());
383 
384  double satLatOffset, satLonOffset;
385  GetSatelliteOffset(satLatOffset, satLonOffset, mobility);
386 
387  // Get the requested position {latitude, longitude}
388  double latitude = coord.GetLatitude() + satLatOffset;
389  double longitude = coord.GetLongitude() + satLonOffset;
390 
391  // Given {latitude, longitude} has to be inside the min/max latitude/longitude values
392  if (m_minLat > latitude || latitude > m_maxLat || m_minLon > longitude || longitude > m_maxLon)
393  {
394  NS_LOG_WARN("Given latitude and longitude out of range!");
395  return std::numeric_limits<double>::quiet_NaN();
396  }
397 
398  // Calculate the minimum grid point {minLatIndex, minLonIndex} for the given {latitude,
399  // longitude} point
400  uint32_t minLatIndex = (uint32_t)(std::floor(std::abs(latitude - m_minLat) / m_latInterval));
401  uint32_t minLonIndex = (uint32_t)(std::floor(std::abs(longitude - m_minLon) / m_lonInterval));
402 
403  // All the values within the grid box has to be valid! If UT is placed (or
404  // is moving outside) the valid simulation area, the simulation will crash
405  // to a fatal error.
406  if (std::isnan(m_antennaPattern[minLatIndex][minLonIndex]) ||
407  std::isnan(m_antennaPattern[minLatIndex][minLonIndex + 1]) ||
408  std::isnan(m_antennaPattern[minLatIndex + 1][minLonIndex]) ||
409  std::isnan(m_antennaPattern[minLatIndex + 1][minLonIndex + 1]))
410  {
411  NS_LOG_WARN(this << ", some value(s) of the interpolated grid point(s) is/are NAN!");
412  return std::numeric_limits<double>::quiet_NaN();
413  }
414 
422  // Longitude direction with latitude minLatIndex
423  double upperLonShare = (m_longitudes[minLonIndex + 1] - longitude) / m_lonInterval;
424  double lowerLonShare = (longitude - m_longitudes[minLonIndex]) / m_lonInterval;
425 
426  // Change the gains to linear values , because the interpolation is done in linear domain.
427  double G11 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex][minLonIndex]);
428  double G12 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex][minLonIndex + 1]);
429  double G21 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex + 1][minLonIndex]);
430  double G22 = SatUtils::DbToLinear(m_antennaPattern[minLatIndex + 1][minLonIndex + 1]);
431 
432  // Longitude direction with latitude minLatIndex
433  double valLatLower = upperLonShare * G11 + lowerLonShare * G12;
434 
435  // Longitude direction with latitude minLatIndex+1
436  double valLatUpper = upperLonShare * G21 + lowerLonShare * G22;
437 
438  // Latitude direction with longitude "longitude"
439  double gain = ((m_latitudes[minLatIndex + 1] - latitude) / m_latInterval) * valLatLower +
440  ((latitude - m_latitudes[minLatIndex]) / m_latInterval) * valLatUpper;
441 
442  /*
443  std::cout << "minLonIndex = " << minLonIndex <<
444  ", minLatIndex = " << minLatIndex <<
445  ", m_lonInterval = " << m_lonInterval <<
446  ", m_LatInterval = " << m_latInterval <<
447  ", x1 = " << m_longitudes[minLonIndex] <<
448  ", y1 = " << m_latitudes[minLatIndex] <<
449  ", x2 = " << m_longitudes[minLonIndex+1] <<
450  ", y2 = " << m_latitudes[minLatIndex+1] <<
451  ", G(x1, y1) = " << m_antennaPattern[minLatIndex][minLonIndex] <<
452  ", G(x1, y2) = " << m_antennaPattern[minLatIndex+1][minLonIndex] <<
453  ", G(x2, y1) = " << m_antennaPattern[minLatIndex][minLonIndex+1] <<
454  ", G(x2, y2) = " << m_antennaPattern[minLatIndex+1][minLonIndex+1] <<
455  ", x = " << longitude <<
456  ", y = " << latitude <<
457  ", interpolated gain: " << gain << std::endl;
458  */
459  return gain;
460 }
461 
462 } // 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.
double m_centerLatitude
Latitude with best gain.
void GetSatelliteOffset(double &latOffset, double &lonOffset, Ptr< SatMobilityModel > mobility) const
virtual TypeId GetInstanceTypeId(void) const
Get the type ID of instance.
double GetCenterLongitude(Ptr< SatMobilityModel > mobility) const
Get latitude of this beam with best gain, based on satellite given in mobility model.
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_centerLongitude
Longitude with best gain.
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 GetCenterLatitude(Ptr< SatMobilityModel > mobility) const
Get latitude of this beam with best gain, based on satellite given in mobility model.
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.