DESERT 3.5.1
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
41static class UnderwaterPhysicaldbClass : public TclClass
42{
43public:
45 : TclClass("Module/UW/PHYSICALDB")
46 {
47 }
48 TclObject *
49 create(int, const char *const *)
50 {
51 return (new UnderwaterPhysicaldb);
52 }
54
56 : path_(nullptr),
57 interference_(nullptr),
58 snr({}),
59 overlap({}),
60 sir({}),
61 range({}),
62 type_of_node({}),
63 range_nums({}),
64 country(nullptr),
65 modulation(nullptr),
66 interf_val({0.0,0.0}),
67 token_separator(0),
68 osstream(0)
69
70{
71 bind_error("token_separator_", &token_separator);
72 path_ = "";
73 token_separator = '\t';
74}
75
76int
77UnderwaterPhysicaldb::command(int argc, const char *const *argv)
78{
79 if (argc == 3) {
80 if (strcasecmp(argv[1], "addr") == 0) {
81 ipAddr_ = static_cast<uint8_t>(atoi(argv[2]));
82 if (ipAddr_ == 0) {
83 fprintf(stderr, "0 is not a valid IP address");
84 return TCL_ERROR;
85 }
86 return TCL_OK;
87 } else if (strcasecmp(argv[1], "setCountry") == 0) {
88 country = ((char *) argv[2]);
89 return TCL_OK;
90 } else if (strcasecmp(argv[1], "setModulation") == 0) {
91 modulation = ((char *) argv[2]);
92 return TCL_OK;
93 } else if (strcasecmp(argv[1], "addSnr") == 0) {
94 snr.insert(snr.end(), strtod(argv[2], NULL));
95 return TCL_OK;
96 } else if (strcasecmp(argv[1], "addSir") == 0) {
97 sir.insert(sir.end(), strtod(argv[2], NULL));
98 return TCL_OK;
99 } else if (strcasecmp(argv[1], "addOverlap") == 0) {
100 overlap.insert(overlap.end(), strtod(argv[2], NULL));
101 return TCL_OK;
102 } else if (strcasecmp(argv[1], "setPath") == 0) {
103 path_ = (char *) (argv[2]);
104 return TCL_OK;
105 } else if (strcasecmp(argv[1], "setInterference") == 0) {
107 dynamic_cast<uwinterference *>(TclObject::lookup(argv[2]));
108 if (!interference_)
109 return TCL_ERROR;
110 return TCL_OK;
111 }
112 } else if (argc == 4) {
113 if (strcasecmp(argv[1], "addRange") == 0) {
114 uint8_t node_id_ = atoi(argv[2]);
115 double range_ = atof(argv[3]);
116 std::map<uint8_t, std::set<double> >::iterator it =
117 range.find(node_id_);
118 if (it == range.end()) {
119 std::set<double> tmp_set_;
120 tmp_set_.insert(range_);
121 range.insert(
122 pair<uint8_t, std::set<double> >(node_id_, tmp_set_));
123 } else {
124 it->second.insert(range_);
125 }
126 return TCL_OK;
127 } else if (strcasecmp(argv[1], "addTypeOfNode") == 0) {
128 uint8_t node_id_ = atoi(argv[2]);
129 string node_type_ = (char *) (argv[3]);
130 std::map<uint8_t, string>::iterator it =
131 type_of_node.find(node_id_);
132 if (it == type_of_node.end()) {
133 type_of_node.insert(pair<double, string>(node_id_, node_type_));
134 return TCL_OK;
135 } else if (it != type_of_node.end() && it->second != node_type_) {
136 type_of_node.erase(it);
137 type_of_node.insert(pair<double, string>(node_id_, node_type_));
138 return TCL_OK;
139 } else {
140 std::fprintf(stderr,
141 "You added the same node with the same type twice.");
142 return TCL_ERROR;
143 }
144 } else if (strcasecmp(argv[1], "addRangeNum") == 0) {
145 string pathtype_ = (char *) (argv[2]);
146 uint8_t rangenum_ = atoi(argv[3]);
147 std::map<string, uint8_t>::iterator it = range_nums.find(pathtype_);
148 if (it == range_nums.end()) {
149 range_nums.insert(pair<string, uint8_t>(pathtype_, rangenum_));
150 return TCL_OK;
151 } else if (it != range_nums.end() && it->second != rangenum_) {
152 range_nums.erase(it);
153 range_nums.insert(pair<string, uint8_t>(pathtype_, rangenum_));
154 return TCL_OK;
155 } else {
156 std::fprintf(stderr, "You added the same range_num already");
157 return TCL_ERROR;
158 }
159 }
160 }
161 return UnderwaterPhysical::command(argc, argv);
162} /* UnderwaterPhysicaldb::command */
163
164void
166{
167 hdr_cmn *ch = HDR_CMN(p);
168 hdr_MPhy *ph = HDR_MPHY(p);
169
170 if (ch->direction() == hdr_cmn::UP) {
171 ph->dstSpectralMask = getRxSpectralMask(p);
172 ph->dstPosition = getPosition();
173 ph->dstAntenna = getRxAntenna(p);
174
175 assert(ph->dstSpectralMask);
176 assert(ph->dstPosition);
177
178 ph->Pr = getRxPower(p);
179
180 p->txinfo_.RxPr = 0;
181 p->txinfo_.CPThresh = 0;
182
183 if (ph->Pr > 0) {
184 ph->Pn = getNoisePower(p);
185
186 if (interference_) {
188 }
189
190 ph->rxtime = NOW;
191 ph->worth_tracing = true;
192
193 if (isOn == true) {
194 PacketEvent *pe = new PacketEvent(p);
195 Scheduler::instance().schedule(&rxtimer, pe, ph->duration);
196
197 startRx(p);
198 } else {
199 Packet::free(p);
200 }
201 } else {
202 Packet::free(p);
203 }
204 } else { // Direction DOWN
205 assert(isOn);
206
207 ph->Pr = 0;
208 ph->Pn = 0;
209 ph->Pi = 0;
210 ph->txtime = NOW;
211 ph->rxtime = ph->txtime;
212
213 ph->worth_tracing = false;
214
215 ph->srcSpectralMask = getTxSpectralMask(p);
216 ph->srcAntenna = getTxAntenna(p);
217 ph->srcPosition = getPosition();
218 ph->dstSpectralMask = 0;
219 ph->dstPosition = 0;
220 ph->dstAntenna = 0;
221 ph->modulationType = getModulationType(p);
222 ph->duration = getTxDuration(p);
223
224 ph->Pt = getTxPower(p);
225
226 assert(ph->srcSpectralMask);
227 assert(ph->srcPosition);
228 assert(ph->duration > 0);
229 assert(ph->Pt > 0);
230
231 ch->prev_hop_ =
232 ipAddr_; // Must be added to ensure compatibility with uw-al
233
234 PacketEvent *pe = new PacketEvent(p->copy());
235 Scheduler::instance().schedule(&txtimer, pe, ph->duration);
236
237 startTx(p);
238 }
239}
240
241void
243{
244 hdr_cmn *ch = HDR_CMN(p);
245 hdr_MPhy *ph = HDR_MPHY(p);
246
247 if (PktRx != 0) {
248 if (PktRx == p) {
249 double per_ni; // packet error rate due to noise and/or interference
250 double per_n; // packet error rate due to noise only
251
252 int nbits = ch->size() * 8;
253 double x = RNG::defaultrng()->uniform_double();
254 per_n = getPERfromSNR(ph->Pr / ph->Pn, nbits, p);
255 bool error_n = x <= per_n;
256 bool error_ni = 0;
257
258 if (!error_n) {
259 double recv_power = ph->Pr;
260 double duration = ph->duration;
261 double endrx_time = ph->rxtime + duration;
262 if (interference_) {
263 double interference_power_ =
265 double interference_start_time_ =
267 if (interference_power_ > 0) {
268 interf_val.first = recv_power / interference_power_;
269 } else {
270 interf_val.first = recv_power;
271 }
272 assert(duration > 0);
273 interf_val.second =
274 ((endrx_time - interference_start_time_) /
275 (duration));
276 per_ni = this->getPERfromSIR(
277 interf_val.first, interf_val.second);
278 // std::cout << "\33[31;40m" << per_ni <<
279 // "\33[0m" << std::endl;
280 x = RNG::defaultrng()->uniform_double();
281 error_ni = x <= per_ni;
282 } else {
283 std::cerr << "No interference model provided!" << std::endl;
284 interf_val.first = 0;
285 interf_val.second = 0;
286 exit(1);
287 }
288 }
289
290 if (time_ready_to_end_rx_ > Scheduler::instance().clock()) {
291 Rx_Time_ = Rx_Time_ + ph->duration - time_ready_to_end_rx_ +
292 Scheduler::instance().clock();
293 } else {
294 Rx_Time_ += ph->duration;
295 }
297 Scheduler::instance().clock() + ph->duration;
298 Energy_Rx_ += consumedEnergyRx(ph->duration);
299
300 ch->error() = error_ni || error_n;
301
302 if (error_n) {
303 incrErrorPktsNoise();
304 } else if (error_ni) {
305 incrErrorPktsInterf();
306 }
307 sendUp(p);
308 PktRx = 0; // We can now sync onto another packet
309 } else {
310 dropPacket(p);
311 }
312 } else {
313 dropPacket(p);
314 }
315} /* UnderwaterPhysicaldb::endRx */
316
317double
319 const double &_snr, const int &_nbits, const Packet *p)
320{
321 hdr_cmn *ch = HDR_CMN(p);
322 hdr_MPhy *ph = HDR_MPHY(p);
323 // hdr_uwip* iph = HDR_UWIP(p);
324
325 // Type of node.
326 std::map<uint8_t, string>::const_iterator it =
327 type_of_node.find(ch->prev_hop_);
328 assert(it != type_of_node.end());
329 const string type_prev_ = it->second;
330 it = type_of_node.find(ipAddr_);
331 assert(it != type_of_node.end());
332 const string type_me_ = it->second;
333 string type_ = type_prev_ + type_me_;
334 string type_reversed_ = type_me_ + type_prev_;
335
336 // Modification to allow LUT use when type-pairs are missing
337 std::map<string, uint8_t>::const_iterator it_r = range_nums.find(type_);
338 std::map<string, uint8_t>::const_iterator it_rr =
339 range_nums.find(type_reversed_);
340 if ((it_r != range_nums.end() && it_r->second == 0) ||
341 (it_rr != range_nums.end() && it_rr->second == 0)) {
342 if (country == "NO") {
343 if (type_ == "AA") {
344 type_ = "AG";
345 } else {
346 type_ = "BG";
347 }
348 } else if (country == "SE") {
349 if ((type_ == "BG") || (type_ == "GB") || (type_ == "GG")) {
350 type_ = "BB";
351 } else {
352 type_ = "AB";
353 }
354 } else if (country == "NL") {
355 if ((type_ == "AB") || (type_ == "BA")) {
356 type_ = "AG";
357 } else {
358 type_ = "GG";
359 }
360 } else if (country == "IT") {
361 type_ = "BB";
362 }
363 }
364
365 // Nearest neighbor range.
366 const double x_ = (ph->srcPosition)->getX();
367 const double y_ = (ph->srcPosition)->getY();
368 const double z_ = (ph->srcPosition)->getZ();
369 const double x_dst_ = (ph->dstPosition)->getX();
370 const double y_dst_ = (ph->dstPosition)->getY();
371 const double z_dst_ = (ph->dstPosition)->getZ();
372 const double distance_ = sqrt((x_ - x_dst_) * (x_ - x_dst_) +
373 (y_ - y_dst_) * (y_ - y_dst_) + (z_ - z_dst_) * (z_ - z_dst_));
374 const double distance_miles_ = this->fromKmToMiles(distance_ / 1000);
375
376 std::map<uint8_t, std::set<double> >::const_iterator it2 =
377 range.find(ch->prev_hop_);
378 double nn_range_;
379 if (it2 != range.end()) {
380 nn_range_ = this->getNearestNeighbor(it2->second, distance_miles_);
381 } else {
382 // if (ch->direction() == 1) {
383 // std::cout << "\33[31;40m" << "DIR: UP" << "\33[0m" <<
384 // std::endl;
385 // } else if (ch->direction() == -1) {
386 // std::cout << "\33[31;40m" << "DIR: DOWN" << "\33[0m" <<
387 // std::endl;
388 // }
389 // std::cout << "\33[32;40m" << "ME:" <<
390 // static_cast<int>(ipAddr_);
391 // std::cout << "\33[33;40m" << " NXT:" <<
392 // static_cast<int>(ch->next_hop_);
393 // std::cout << "\33[34;40m" << " PRV:" <<
394 // static_cast<int>(ch->prev_hop_);
395 // std::cout << "\33[35;40m" << " DST:" <<
396 // static_cast<int>(iph->daddr());
397 // std::cout << "\33[36;40m" << " SRC:" <<
398 // static_cast<int>(iph->saddr());
399 // std::cout << "\33[0m" << std::endl;
400 // std::cout << "\33[31;40m" << "TPE:" << type_ << "\33[0m" <<
401 // std::endl;
402 return 1;
403 // std::cerr << "Empty range table" << std::endl;
404 // exit(1);
405 }
406
407 // File's name.
408 osstream.clear();
409 osstream.str("");
410 osstream << path_ << country << "_" << modulation << "_" << type_ << "_"
411 << nn_range_;
412 const string file_name_ = osstream.str();
413
414 // Nearest neighbor snr.
415 const double nn_snr_ = this->getNearestNeighbor(snr, 10 * log10(_snr));
416
417 // Open the file and get the per that corresponds to the nn_snr_ value.
418 const double per_ = this->retrievePerFromFile(file_name_, nn_snr_);
419
420 return per_;
421} /* UnderwaterPhysicaldb::getPERfromSNR */
422
423double
424UnderwaterPhysicaldb::getPERfromSIR(const double &_sir, const double &_overlap)
425{
426
427 // Nearest neighbor Overlap.
428 const double nn_overlap_ = this->getNearestNeighbor(
429 overlap, _overlap * 100); // From [0; 1] to [0; 100] scale.
430
431 // File's name.
432 osstream.clear();
433 osstream.str("");
434 osstream << path_ << "SIR"
435 << "_" << modulation << "_" << nn_overlap_;
436 const string file_name_ = osstream.str();
437
438 // Nearest neighbor SIR.
439 const double nn_sir_ = this->getNearestNeighbor(sir, _sir);
440
441 // Open the file and get the per that corresponds to the nn_snr_ value.
442 const double per_ = this->retrievePerFromFile(file_name_, nn_sir_);
443
444 return per_;
445} /* UnderwaterPhysicaldb::getPERfromSNR */
446
447double
449 const std::set<double> &_set, const double &_value)
450{
451 // Check if the value to search for is smaller than the min or greater than
452 // the max.
453 std::set<double>::iterator it_ = _set.begin();
454 if (_value <= *it_) {
455 return *it_;
456 }
457 it_ = --_set.end();
458 if (_value >= *it_) {
459 return *it_;
460 } else {
461 for (std::set<double>::const_iterator it_ = _set.begin();
462 it_ != _set.end();
463 it_++) {
464 std::set<double>::const_iterator it_next_ = it_;
465 it_next_++;
466 if (_value >= *it_next_) {
467 continue;
468 } else {
469 if (abs(_value - *it_) <= abs(_value - *it_next_)) {
470 return *it_;
471 } else {
472 return *it_next_;
473 }
474 }
475 }
476 return 0;
477 }
478} /* UnderwaterPhysicaldb::findNearestNeightbor */
479
480const double
482 const std::string &_file_name, const double &_snr) const
483{
484 std::ifstream input_file_;
485 std::string line_;
486 std::string token_;
487
488 // Convert the file name to a char*.
489 char *tmp_ = new char[_file_name.length() + 1];
490 strcpy(tmp_, _file_name.c_str());
491 if (tmp_ == NULL) {
492 fprintf(stderr, "Empty string for the file name");
493 }
494
495 // Open the file, scan for the line and get the per.
496 input_file_.open(tmp_);
497 if (input_file_.is_open()) {
498 while (std::getline(input_file_, line_)) {
499 std::istringstream iss_(line_);
500 getline(iss_, token_, token_separator);
501 std::stringstream ss_(token_);
502 double token_double_;
503 ss_ >> token_double_;
504 if (token_double_ == _snr) {
505 getline(iss_, token_, token_separator);
506 delete[] tmp_;
507 std::stringstream ss_(token_);
508 ss_ >> token_double_;
509 return token_double_;
510 }
511 }
512 } else {
513 cerr << "Impossible to open file " << _file_name << endl;
514 exit(1);
515 }
516 delete[] tmp_;
517 return (-INT_MAX);
518}
virtual double consumedEnergyRx(const double &_duration)
Compute the energy (in Joule) spent by the modem in reception.
Definition uwphysical.h:200
double Energy_Rx_
Energy (in Joule) spent by the node in transmission.
Definition uwphysical.h:441
virtual void startRx(Packet *p)
Handles the start of a reception.
double time_ready_to_end_rx_
Used to keep track of the arrival time.
Definition uwphysical.h:430
double Rx_Time_
Time (in seconds) spent by the node in reception.
Definition uwphysical.h:435
virtual int command(int, const char *const *)
TCL command interpreter.
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.