DESERT 3.6.0
Loading...
Searching...
No Matches
uwphysicaldb.cpp
Go to the documentation of this file.
1//
2// Copyright (c) 2017 Regents of the SIGNET lab, University of Padova.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution.
13// 3. Neither the name of the University of Padova (SIGNET lab) nor the
14// names of its contributors may be used to endorse or promote products
15// derived from this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
39#include "uwphysicaldb.h"
40#include "rng.h"
41#include <climits>
42
43static class UnderwaterPhysicaldbClass : public TclClass
44{
45public:
47 : TclClass("Module/UW/PHYSICALDB")
48 {
49 }
50 TclObject *
51 create(int, const char *const *)
52 {
53 return (new UnderwaterPhysicaldb);
54 }
56
58 : path_(nullptr),
59 interference_(nullptr),
60 snr({}),
61 overlap({}),
62 sir({}),
63 range({}),
64 type_of_node({}),
65 range_nums({}),
66 country(nullptr),
67 modulation(nullptr),
68 interf_val({0.0,0.0}),
69 token_separator(0),
70 osstream(0)
71
72{
73 bind_error("token_separator_", &token_separator);
74 path_ = "";
75 token_separator = '\t';
76}
77
78int
79UnderwaterPhysicaldb::command(int argc, const char *const *argv)
80{
81 if (argc == 3) {
82 if (strcasecmp(argv[1], "addr") == 0) {
83 ipAddr_ = static_cast<uint8_t>(atoi(argv[2]));
84 if (ipAddr_ == 0) {
85 fprintf(stderr, "0 is not a valid IP address");
86 return TCL_ERROR;
87 }
88 return TCL_OK;
89 } else if (strcasecmp(argv[1], "setCountry") == 0) {
90 country = ((char *) argv[2]);
91 return TCL_OK;
92 } else if (strcasecmp(argv[1], "setModulation") == 0) {
93 modulation = ((char *) argv[2]);
94 return TCL_OK;
95 } else if (strcasecmp(argv[1], "addSnr") == 0) {
96 snr.insert(snr.end(), strtod(argv[2], NULL));
97 return TCL_OK;
98 } else if (strcasecmp(argv[1], "addSir") == 0) {
99 sir.insert(sir.end(), strtod(argv[2], NULL));
100 return TCL_OK;
101 } else if (strcasecmp(argv[1], "addOverlap") == 0) {
102 overlap.insert(overlap.end(), strtod(argv[2], NULL));
103 return TCL_OK;
104 } else if (strcasecmp(argv[1], "setPath") == 0) {
105 path_ = (char *) (argv[2]);
106 return TCL_OK;
107 } else if (strcasecmp(argv[1], "setInterference") == 0) {
109 dynamic_cast<uwinterference *>(TclObject::lookup(argv[2]));
110 if (!interference_)
111 return TCL_ERROR;
112 return TCL_OK;
113 }
114 } else if (argc == 4) {
115 if (strcasecmp(argv[1], "addRange") == 0) {
116 uint8_t node_id_ = atoi(argv[2]);
117 double range_ = atof(argv[3]);
118 std::map<uint8_t, std::set<double> >::iterator it =
119 range.find(node_id_);
120 if (it == range.end()) {
121 std::set<double> tmp_set_;
122 tmp_set_.insert(range_);
123 range.insert(
124 pair<uint8_t, std::set<double> >(node_id_, tmp_set_));
125 } else {
126 it->second.insert(range_);
127 }
128 return TCL_OK;
129 } else if (strcasecmp(argv[1], "addTypeOfNode") == 0) {
130 uint8_t node_id_ = atoi(argv[2]);
131 string node_type_ = (char *) (argv[3]);
132 std::map<uint8_t, string>::iterator it =
133 type_of_node.find(node_id_);
134 if (it == type_of_node.end()) {
135 type_of_node.insert(pair<double, string>(node_id_, node_type_));
136 return TCL_OK;
137 } else if (it != type_of_node.end() && it->second != node_type_) {
138 type_of_node.erase(it);
139 type_of_node.insert(pair<double, string>(node_id_, node_type_));
140 return TCL_OK;
141 } else {
142 std::fprintf(stderr,
143 "You added the same node with the same type twice.");
144 return TCL_ERROR;
145 }
146 } else if (strcasecmp(argv[1], "addRangeNum") == 0) {
147 string pathtype_ = (char *) (argv[2]);
148 uint8_t rangenum_ = atoi(argv[3]);
149 std::map<string, uint8_t>::iterator it = range_nums.find(pathtype_);
150 if (it == range_nums.end()) {
151 range_nums.insert(pair<string, uint8_t>(pathtype_, rangenum_));
152 return TCL_OK;
153 } else if (it != range_nums.end() && it->second != rangenum_) {
154 range_nums.erase(it);
155 range_nums.insert(pair<string, uint8_t>(pathtype_, rangenum_));
156 return TCL_OK;
157 } else {
158 std::fprintf(stderr, "You added the same range_num already");
159 return TCL_ERROR;
160 }
161 }
162 }
163 return UnderwaterPhysical::command(argc, argv);
164} /* UnderwaterPhysicaldb::command */
165
166void
168{
169 hdr_cmn *ch = HDR_CMN(p);
170 hdr_MPhy *ph = HDR_MPHY(p);
171
172 if (ch->direction() == hdr_cmn::UP) {
173 ph->dstSpectralMask = getRxSpectralMask(p);
174 ph->dstPosition = getPosition();
175 ph->dstAntenna = getRxAntenna(p);
176
177 assert(ph->dstSpectralMask);
178 assert(ph->dstPosition);
179
180 ph->Pr = getRxPower(p);
181
182 p->txinfo_.RxPr = 0;
183 p->txinfo_.CPThresh = 0;
184
185 if (ph->Pr > 0) {
186 ph->Pn = getNoisePower(p);
187
188 if (interference_) {
190 }
191
192 ph->rxtime = NOW;
193 ph->worth_tracing = true;
194
195 if (isOn == true) {
196 PacketEvent *pe = new PacketEvent(p);
197 Scheduler::instance().schedule(&rxtimer, pe, ph->duration);
198
199 startRx(p);
200 } else {
201 Packet::free(p);
202 }
203 } else {
204 Packet::free(p);
205 }
206 } else { // Direction DOWN
207 assert(isOn);
208
209 ph->Pr = 0;
210 ph->Pn = 0;
211 ph->Pi = 0;
212 ph->txtime = NOW;
213 ph->rxtime = ph->txtime;
214
215 ph->worth_tracing = false;
216
217 ph->srcSpectralMask = getTxSpectralMask(p);
218 ph->srcAntenna = getTxAntenna(p);
219 ph->srcPosition = getPosition();
220 ph->dstSpectralMask = 0;
221 ph->dstPosition = 0;
222 ph->dstAntenna = 0;
223 ph->modulationType = getModulationType(p);
224 ph->duration = getTxDuration(p);
225
226 ph->Pt = getTxPower(p);
227
228 assert(ph->srcSpectralMask);
229 assert(ph->srcPosition);
230 assert(ph->duration > 0);
231 assert(ph->Pt > 0);
232
233 ch->prev_hop_ =
234 ipAddr_; // Must be added to ensure compatibility with uw-al
235
236 PacketEvent *pe = new PacketEvent(p->copy());
237 Scheduler::instance().schedule(&txtimer, pe, ph->duration);
238
239 startTx(p);
240 }
241}
242
243void
245{
246 hdr_cmn *ch = HDR_CMN(p);
247 hdr_MPhy *ph = HDR_MPHY(p);
248
249 if (PktRx != 0) {
250 if (PktRx == p) {
251 double per_ni; // packet error rate due to noise and/or interference
252 double per_n; // packet error rate due to noise only
253
254 int nbits = ch->size() * 8;
255 double x = RNG::defaultrng()->uniform_double();
256 per_n = getPERfromSNR(ph->Pr / ph->Pn, nbits, p);
257 bool error_n = x <= per_n;
258 bool error_ni = 0;
259
260 if (!error_n) {
261 double recv_power = ph->Pr;
262 double duration = ph->duration;
263 double endrx_time = ph->rxtime + duration;
264 if (interference_) {
265 double interference_power_ =
267 double interference_start_time_ =
269 if (interference_power_ > 0) {
270 interf_val.first = recv_power / interference_power_;
271 } else {
272 interf_val.first = recv_power;
273 }
274 assert(duration > 0);
275 interf_val.second =
276 ((endrx_time - interference_start_time_) /
277 (duration));
278 per_ni = this->getPERfromSIR(
279 interf_val.first, interf_val.second);
280 // std::cout << "\33[31;40m" << per_ni <<
281 // "\33[0m" << std::endl;
282 x = RNG::defaultrng()->uniform_double();
283 error_ni = x <= per_ni;
284 } else {
285 std::cerr << "No interference model provided!" << std::endl;
286 interf_val.first = 0;
287 interf_val.second = 0;
288 exit(1);
289 }
290 }
291
292 if (time_ready_to_end_rx_ > Scheduler::instance().clock()) {
293 Rx_Time_ = Rx_Time_ + ph->duration - time_ready_to_end_rx_ +
294 Scheduler::instance().clock();
295 } else {
296 Rx_Time_ += ph->duration;
297 }
299 Scheduler::instance().clock() + ph->duration;
300 Energy_Rx_ += consumedEnergyRx(ph->duration);
301
302 ch->error() = error_ni || error_n;
303
304 if (error_n) {
305 incrErrorPktsNoise();
306 } else if (error_ni) {
307 incrErrorPktsInterf();
308 }
309 sendUp(p);
310 PktRx = 0; // We can now sync onto another packet
311 } else {
312 dropPacket(p);
313 }
314 } else {
315 dropPacket(p);
316 }
317} /* UnderwaterPhysicaldb::endRx */
318
319double
321 const double &_snr, const int &_nbits, const Packet *p)
322{
323 hdr_cmn *ch = HDR_CMN(p);
324 hdr_MPhy *ph = HDR_MPHY(p);
325 // hdr_uwip* iph = HDR_UWIP(p);
326
327 // Type of node.
328 std::map<uint8_t, string>::const_iterator it =
329 type_of_node.find(ch->prev_hop_);
330 assert(it != type_of_node.end());
331 const string type_prev_ = it->second;
332 it = type_of_node.find(ipAddr_);
333 assert(it != type_of_node.end());
334 const string type_me_ = it->second;
335 string type_ = type_prev_ + type_me_;
336 string type_reversed_ = type_me_ + type_prev_;
337
338 // Modification to allow LUT use when type-pairs are missing
339 std::map<string, uint8_t>::const_iterator it_r = range_nums.find(type_);
340 std::map<string, uint8_t>::const_iterator it_rr =
341 range_nums.find(type_reversed_);
342 if ((it_r != range_nums.end() && it_r->second == 0) ||
343 (it_rr != range_nums.end() && it_rr->second == 0)) {
344 if (country == "NO") {
345 if (type_ == "AA") {
346 type_ = "AG";
347 } else {
348 type_ = "BG";
349 }
350 } else if (country == "SE") {
351 if ((type_ == "BG") || (type_ == "GB") || (type_ == "GG")) {
352 type_ = "BB";
353 } else {
354 type_ = "AB";
355 }
356 } else if (country == "NL") {
357 if ((type_ == "AB") || (type_ == "BA")) {
358 type_ = "AG";
359 } else {
360 type_ = "GG";
361 }
362 } else if (country == "IT") {
363 type_ = "BB";
364 }
365 }
366
367 // Nearest neighbor range.
368 const double x_ = (ph->srcPosition)->getX();
369 const double y_ = (ph->srcPosition)->getY();
370 const double z_ = (ph->srcPosition)->getZ();
371 const double x_dst_ = (ph->dstPosition)->getX();
372 const double y_dst_ = (ph->dstPosition)->getY();
373 const double z_dst_ = (ph->dstPosition)->getZ();
374 const double distance_ = sqrt((x_ - x_dst_) * (x_ - x_dst_) +
375 (y_ - y_dst_) * (y_ - y_dst_) + (z_ - z_dst_) * (z_ - z_dst_));
376 const double distance_miles_ = this->fromKmToMiles(distance_ / 1000);
377
378 std::map<uint8_t, std::set<double> >::const_iterator it2 =
379 range.find(ch->prev_hop_);
380 double nn_range_;
381 if (it2 != range.end()) {
382 nn_range_ = this->getNearestNeighbor(it2->second, distance_miles_);
383 } else {
384 // if (ch->direction() == 1) {
385 // std::cout << "\33[31;40m" << "DIR: UP" << "\33[0m" <<
386 // std::endl;
387 // } else if (ch->direction() == -1) {
388 // std::cout << "\33[31;40m" << "DIR: DOWN" << "\33[0m" <<
389 // std::endl;
390 // }
391 // std::cout << "\33[32;40m" << "ME:" <<
392 // static_cast<int>(ipAddr_);
393 // std::cout << "\33[33;40m" << " NXT:" <<
394 // static_cast<int>(ch->next_hop_);
395 // std::cout << "\33[34;40m" << " PRV:" <<
396 // static_cast<int>(ch->prev_hop_);
397 // std::cout << "\33[35;40m" << " DST:" <<
398 // static_cast<int>(iph->daddr());
399 // std::cout << "\33[36;40m" << " SRC:" <<
400 // static_cast<int>(iph->saddr());
401 // std::cout << "\33[0m" << std::endl;
402 // std::cout << "\33[31;40m" << "TPE:" << type_ << "\33[0m" <<
403 // std::endl;
404 return 1;
405 // std::cerr << "Empty range table" << std::endl;
406 // exit(1);
407 }
408
409 // File's name.
410 osstream.clear();
411 osstream.str("");
412 osstream << path_ << country << "_" << modulation << "_" << type_ << "_"
413 << nn_range_;
414 const string file_name_ = osstream.str();
415
416 // Nearest neighbor snr.
417 const double nn_snr_ = this->getNearestNeighbor(snr, 10 * log10(_snr));
418
419 // Open the file and get the per that corresponds to the nn_snr_ value.
420 const double per_ = this->retrievePerFromFile(file_name_, nn_snr_);
421
422 return per_;
423} /* UnderwaterPhysicaldb::getPERfromSNR */
424
425double
426UnderwaterPhysicaldb::getPERfromSIR(const double &_sir, const double &_overlap)
427{
428
429 // Nearest neighbor Overlap.
430 const double nn_overlap_ = this->getNearestNeighbor(
431 overlap, _overlap * 100); // From [0; 1] to [0; 100] scale.
432
433 // File's name.
434 osstream.clear();
435 osstream.str("");
436 osstream << path_ << "SIR"
437 << "_" << modulation << "_" << nn_overlap_;
438 const string file_name_ = osstream.str();
439
440 // Nearest neighbor SIR.
441 const double nn_sir_ = this->getNearestNeighbor(sir, _sir);
442
443 // Open the file and get the per that corresponds to the nn_snr_ value.
444 const double per_ = this->retrievePerFromFile(file_name_, nn_sir_);
445
446 return per_;
447} /* UnderwaterPhysicaldb::getPERfromSNR */
448
449double
451 const std::set<double> &_set, const double &_value)
452{
453 // Check if the value to search for is smaller than the min or greater than
454 // the max.
455 std::set<double>::iterator it_ = _set.begin();
456 if (_value <= *it_) {
457 return *it_;
458 }
459 it_ = --_set.end();
460 if (_value >= *it_) {
461 return *it_;
462 } else {
463 for (std::set<double>::const_iterator it_ = _set.begin();
464 it_ != _set.end();
465 it_++) {
466 std::set<double>::const_iterator it_next_ = it_;
467 it_next_++;
468 if (_value >= *it_next_) {
469 continue;
470 } else {
471 if (abs(_value - *it_) <= abs(_value - *it_next_)) {
472 return *it_;
473 } else {
474 return *it_next_;
475 }
476 }
477 }
478 return 0;
479 }
480} /* UnderwaterPhysicaldb::findNearestNeightbor */
481
482const double
484 const std::string &_file_name, const double &_snr) const
485{
486 std::ifstream input_file_;
487 std::string line_;
488 std::string token_;
489
490 // Convert the file name to a char*.
491 char *tmp_ = new char[_file_name.length() + 1];
492 strcpy(tmp_, _file_name.c_str());
493 if (tmp_ == NULL) {
494 fprintf(stderr, "Empty string for the file name");
495 }
496
497 // Open the file, scan for the line and get the per.
498 input_file_.open(tmp_);
499 if (input_file_.is_open()) {
500 while (std::getline(input_file_, line_)) {
501 std::istringstream iss_(line_);
502 getline(iss_, token_, token_separator);
503 std::stringstream ss_(token_);
504 double token_double_;
505 ss_ >> token_double_;
506 if (token_double_ == _snr) {
507 getline(iss_, token_, token_separator);
508 delete[] tmp_;
509 std::stringstream ss_(token_);
510 ss_ >> token_double_;
511 return token_double_;
512 }
513 }
514 } else {
515 cerr << "Impossible to open file " << _file_name << endl;
516 exit(1);
517 }
518 delete[] tmp_;
519 return (-INT_MAX);
520}
virtual int command(int, const char *const *) override
TCL command interpreter.
double Energy_Rx_
Energy (in Joule) spent by the node in transmission.
Definition uwphysical.h:426
virtual void startRx(Packet *p) override
Handles the start of a reception.
double time_ready_to_end_rx_
Used to keep track of the rx time.
Definition uwphysical.h:420
virtual double consumedEnergyRx(const double &_duration) const
Compute the energy (in Joule) spent by the modem in reception.
Definition uwphysical.h:192
double Rx_Time_
Time (in seconds) spent by the node in reception.
Definition uwphysical.h:423
TclObject * create(int, const char *const *)
UnderwaterPhysicaldb()
Constructor of UnderwaterMPhyBpskDb class.
virtual double getPERfromSIR(const double &, const double &)
Packet error rate based on Overlap and SIR.
string modulation
Name of the Modulation.
virtual void recv(Packet *)
recv method.
char token_separator
Token used to parse the elements in a line of the database.
std::pair< double, double > interf_val
(SIR, Overlap)
virtual double getNearestNeighbor(const std::set< double > &, const double &)
Nearest neighbor of a value contained in a set.
virtual double getPERfromSNR(const double &, const int &, const Packet *)
Packet error rate based on SNR.
std::set< double > overlap
Set of the available Overlaps.
uwinterference * interference_
Interference Model.
virtual void endRx(Packet *p)
Handles the end of a packet reception.
uint8_t ipAddr_
IP of the node.
string country
Name of the Country.
std::map< string, uint8_t > range_nums
Set of the number of ranges for a given pathtype, e.g "AA".
virtual int command(int, const char *const *)
TCL command interpreter.
std::set< double > snr
Set of the available SNRs.
char * path_
Name of the trace file writter for the current node.
virtual const double retrievePerFromFile(const std::string &, const double &) const
ostringstream osstream
const double fromKmToMiles(const double &_km) const
Converts from kilometers to miles.
std::map< uint8_t, std::set< double > > range
Set of the available Ranges.
std::map< uint8_t, string > type_of_node
Set of the available type of nodes.
std::set< double > sir
Set of the available SIRs.
virtual void addToInterference(Packet *p)
Add a packet to the interference calculation.
virtual double getInterferencePower(Packet *p)
Compute the average interference power for the given packet.
double getInitialInterferenceTime()
Get the timestamp of the begin of reception of the first interferer packet.
UnderwaterPhysicaldbClass class_UnderwaterPhysicaldb
Definition of UnderwaterPhysicaldb class.