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