A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lora-interference-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 University of Padova
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Davide Magrin <magrinda@dei.unipd.it>
18 */
19
21
22#include "ns3/enum.h"
23#include "ns3/log.h"
24
25#include <limits>
26
27namespace ns3
28{
29namespace lorawan
30{
31
32NS_LOG_COMPONENT_DEFINE("LoraInterferenceHelper");
33
34/***************************************
35 * LoraInterferenceHelper::Event *
36 ***************************************/
37
38// Event Constructor
40 double rxPowerdBm,
41 uint8_t spreadingFactor,
42 Ptr<Packet> packet,
43 double frequencyMHz)
44 : m_startTime(Simulator::Now()),
45 m_endTime(m_startTime + duration),
46 m_sf(spreadingFactor),
47 m_rxPowerdBm(rxPowerdBm),
48 m_packet(packet),
49 m_frequencyMHz(frequencyMHz)
50{
51 // NS_LOG_FUNCTION_NOARGS ();
52}
53
54// Event Destructor
56{
57 // NS_LOG_FUNCTION_NOARGS ();
58}
59
60// Getters
61Time
63{
64 return m_startTime;
65}
66
67Time
69{
70 return m_endTime;
71}
72
73Time
75{
76 return m_endTime - m_startTime;
77}
78
79double
81{
82 return m_rxPowerdBm;
83}
84
85uint8_t
87{
88 return m_sf;
89}
90
93{
94 return m_packet;
95}
96
97double
99{
100 return m_frequencyMHz;
101}
102
103void
104LoraInterferenceHelper::Event::Print(std::ostream& stream) const
105{
106 stream << "(" << m_startTime.GetSeconds() << " s - " << m_endTime.GetSeconds() << " s), SF"
107 << unsigned(m_sf) << ", " << m_rxPowerdBm << " dBm, " << m_frequencyMHz << " MHz";
108}
109
110std::ostream&
111operator<<(std::ostream& os, const LoraInterferenceHelper::Event& event)
112{
113 event.Print(os);
114
115 return os;
116}
117
118/****************************
119 * LoraInterferenceHelper *
120 ****************************/
121// This collision matrix can be used for comparisons with the performance of Aloha
122// systems, where collisions imply the loss of both packets.
123double inf = std::numeric_limits<double>::max();
124std::vector<std::vector<double>> LoraInterferenceHelper::collisionSnirAloha = {
125 // 7 8 9 10 11 12
126 {inf, -inf, -inf, -inf, -inf, -inf}, // SF7
127 {-inf, inf, -inf, -inf, -inf, -inf}, // SF8
128 {-inf, -inf, inf, -inf, -inf, -inf}, // SF9
129 {-inf, -inf, -inf, inf, -inf, -inf}, // SF10
130 {-inf, -inf, -inf, -inf, inf, -inf}, // SF11
131 {-inf, -inf, -inf, -inf, -inf, inf} // SF12
132};
133
134// LoRa Collision Matrix (Goursaud)
135// Values are inverted w.r.t. the paper since here we interpret this as an
136// _isolation_ matrix instead of a cochannel _rejection_ matrix like in
137// Goursaud's paper.
138std::vector<std::vector<double>> LoraInterferenceHelper::collisionSnirGoursaud = {
139 // SF7 SF8 SF9 SF10 SF11 SF12
140 {6, -16, -18, -19, -19, -20}, // SF7
141 {-24, 6, -20, -22, -22, -22}, // SF8
142 {-27, -27, 6, -23, -25, -25}, // SF9
143 {-30, -30, -30, 6, -26, -28}, // SF10
144 {-33, -33, -33, -33, 6, -29}, // SF11
145 {-36, -36, -36, -36, -36, 6} // SF12
146};
147
150
152
153void
156{
157 switch (collisionMatrix)
158 {
160 NS_LOG_DEBUG("Setting the ALOHA collision matrix");
162 break;
164 NS_LOG_DEBUG("Setting the GOURSAUD collision matrix");
166 break;
167 }
168}
169
170TypeId
172{
173 static TypeId tid =
174 TypeId("ns3::LoraInterferenceHelper").SetParent<Object>().SetGroupName("lorawan");
175
176 return tid;
177}
178
181{
182 NS_LOG_FUNCTION(this);
183
185}
186
188{
189 NS_LOG_FUNCTION(this);
190}
191
193
196 double rxPower,
197 uint8_t spreadingFactor,
198 Ptr<Packet> packet,
199 double frequencyMHz)
200{
201 NS_LOG_FUNCTION(this << duration.GetSeconds() << rxPower << unsigned(spreadingFactor) << packet
202 << frequencyMHz);
203
204 // Create an event based on the parameters
206 Create<LoraInterferenceHelper::Event>(duration,
207 rxPower,
208 spreadingFactor,
209 packet,
210 frequencyMHz);
211
212 // Add the event to the list
213 m_events.push_back(event);
214
215 // Clean the event list
216 if (m_events.size() > 100)
217 {
219 }
220
221 return event;
222}
223
224void
226{
227 NS_LOG_FUNCTION(this);
228
229 // Cycle the events, and clean up if an event is old.
230 for (auto it = m_events.begin(); it != m_events.end();)
231 {
232 if ((*it)->GetEndTime() + oldEventThreshold < Simulator::Now())
233 {
234 it = m_events.erase(it);
235 }
236 else
237 {
238 it++;
239 }
240 }
241}
242
243std::list<Ptr<LoraInterferenceHelper::Event>>
245{
246 return m_events;
247}
248
249void
251{
253
254 stream << "Currently registered events:" << std::endl;
255
256 for (auto it = m_events.begin(); it != m_events.end(); it++)
257 {
258 (*it)->Print(stream);
259 stream << std::endl;
260 }
261}
262
263uint8_t
265{
266 NS_LOG_FUNCTION(this << event);
267
268 NS_LOG_INFO("Current number of events in LoraInterferenceHelper: " << m_events.size());
269
270 // We want to see the interference affecting this event: cycle through events
271 // that overlap with this one and see whether it survives the interference or
272 // not.
273
274 // Gather information about the event
275 double rxPowerDbm = event->GetRxPowerdBm();
276 uint8_t sf = event->GetSpreadingFactor();
277 double frequency = event->GetFrequency();
278
279 // Handy information about the time frame when the packet was received
280 Time now = Simulator::Now();
281 Time duration = event->GetDuration();
282 Time packetStartTime = now - duration;
283
284 // Get the list of interfering events
285 std::list<Ptr<LoraInterferenceHelper::Event>>::iterator it;
286
287 // Energy for interferers of various SFs
288 std::vector<double> cumulativeInterferenceEnergy(6, 0);
289
290 // Cycle over the events
291 for (it = m_events.begin(); it != m_events.end();)
292 {
293 // Pointer to the current interferer
294 Ptr<LoraInterferenceHelper::Event> interferer = *it;
295
296 // Only consider the current event if the channel is the same: we
297 // assume there's no interchannel interference. Also skip the current
298 // event if it's the same that we want to analyze.
299 if (!(interferer->GetFrequency() == frequency) || interferer == event)
300 {
301 NS_LOG_DEBUG("Different channel or same event");
302 it++;
303 continue; // Continues from the first line inside the for cycle
304 }
305
306 NS_LOG_DEBUG("Interferer on same channel");
307
308 // Gather information about this interferer
309 uint8_t interfererSf = interferer->GetSpreadingFactor();
310 double interfererPower = interferer->GetRxPowerdBm();
311 Time interfererStartTime = interferer->GetStartTime();
312 Time interfererEndTime = interferer->GetEndTime();
313
314 NS_LOG_INFO("Found an interferer: sf = " << unsigned(interfererSf)
315 << ", power = " << interfererPower
316 << ", start time = " << interfererStartTime
317 << ", end time = " << interfererEndTime);
318
319 // Compute the fraction of time the two events are overlapping
320 Time overlap = GetOverlapTime(event, interferer);
321
322 NS_LOG_DEBUG("The two events overlap for " << overlap.GetSeconds() << " s.");
323
324 // Compute the equivalent energy of the interference
325 // Power [mW] = 10^(Power[dBm]/10)
326 // Power [W] = Power [mW] / 1000
327 double interfererPowerW = pow(10, interfererPower / 10) / 1000;
328 // Energy [J] = Time [s] * Power [W]
329 double interferenceEnergy = overlap.GetSeconds() * interfererPowerW;
330 cumulativeInterferenceEnergy.at(unsigned(interfererSf) - 7) += interferenceEnergy;
331 NS_LOG_DEBUG("Interferer power in W: " << interfererPowerW);
332 NS_LOG_DEBUG("Interference energy: " << interferenceEnergy);
333 it++;
334 }
335
336 // For each spreading factor, check if there was destructive interference
337 for (auto currentSf = uint8_t(7); currentSf <= uint8_t(12); currentSf++)
338 {
339 NS_LOG_DEBUG("Cumulative Interference Energy: "
340 << cumulativeInterferenceEnergy.at(unsigned(currentSf) - 7));
341
342 // Use the computed cumulativeInterferenceEnergy to determine whether the
343 // interference with this spreading factor destroys the packet
344 double signalPowerW = pow(10, rxPowerDbm / 10) / 1000;
345 double signalEnergy = duration.GetSeconds() * signalPowerW;
346 NS_LOG_DEBUG("Signal power in W: " << signalPowerW);
347 NS_LOG_DEBUG("Signal energy: " << signalEnergy);
348
349 // Check whether the packet survives the interference of this spreading factor
350 double snirIsolation = m_collisionSnir[unsigned(sf) - 7][unsigned(currentSf) - 7];
351 NS_LOG_DEBUG("The needed isolation to survive is " << snirIsolation << " dB");
352 double snir =
353 10 * log10(signalEnergy / cumulativeInterferenceEnergy.at(unsigned(currentSf) - 7));
354 NS_LOG_DEBUG("The current SNIR is " << snir << " dB");
355
356 if (snir >= snirIsolation)
357 {
358 // Move on and check the rest of the interferers
359 NS_LOG_DEBUG("Packet survived interference with SF " << currentSf);
360 }
361 else
362 {
363 NS_LOG_DEBUG("Packet destroyed by interference with SF" << unsigned(currentSf));
364
365 return currentSf;
366 }
367 }
368 // If we get to here, it means that the packet survived all interference
369 NS_LOG_DEBUG("Packet survived all interference");
370
371 // Since the packet was not destroyed, we return 0.
372 return uint8_t(0);
373}
374
375void
377{
379
380 m_events.clear();
381}
382
383Time
386{
388
389 // Create the value we will return later
390 Time overlap;
391
392 // Get handy values
393 Time s1 = event1->GetStartTime(); // Start times
394 Time s2 = event2->GetStartTime();
395 Time e1 = event1->GetEndTime(); // End times
396 Time e2 = event2->GetEndTime();
397
398 // Non-overlapping events
399 if (e1 <= s2 || e2 <= s1)
400 {
401 overlap = Seconds(0);
402 }
403 // event1 before event2
404 else if (s1 < s2)
405 {
406 if (e2 < e1)
407 {
408 overlap = e2 - s2;
409 }
410 else
411 {
412 overlap = e1 - s2;
413 }
414 }
415 // event2 before event1 or they start at the same time (s1 = s2)
416 else
417 {
418 if (e1 < e2)
419 {
420 overlap = e1 - s1;
421 }
422 else
423 {
424 overlap = e2 - s1;
425 }
426 }
427
428 return overlap;
429}
430} // namespace lorawan
431} // namespace ns3
432
433/*
434 ----------------------------------------------------------------------------
435
436 // Event1 starts before Event2
437 if (s1 < s2)
438 {
439 // Non-overlapping events
440 if (e1 < s2)
441 {
442 overlap = Seconds (0);
443 }
444 // event1 contains event2
445 else if (e1 >= e2)
446 {
447 overlap = e2 - s2;
448 }
449 // Partially overlapping events
450 else
451 {
452 overlap = e1 - s2;
453 }
454 }
455 // Event2 starts before Event1
456 else
457 {
458 // Non-overlapping events
459 if (e2 < s1)
460 {
461 overlap = Seconds (0);
462 }
463 // event2 contains event1
464 else if (e2 >= e1)
465 {
466 overlap = e1 - s1;
467 }
468 // Partially overlapping events
469 else
470 {
471 overlap = e2 - s1;
472 }
473 }
474 return overlap;
475 }
476 }
477 }
478*/
A base class which provides memory management and object aggregation.
Definition: object.h:89
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Control the scheduling of simulation events.
Definition: simulator.h:68
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
A class representing a signal in time.
double GetRxPowerdBm() const
Get the power of the event.
Time GetStartTime() const
Get the starting time of the event.
double GetFrequency() const
Get the frequency this event was on.
Time GetEndTime() const
Get the ending time of the event.
uint8_t GetSpreadingFactor() const
Get the spreading factor used by this signal.
Time GetDuration() const
Get the duration of the event.
Event(Time duration, double rxPowerdBm, uint8_t spreadingFactor, Ptr< Packet > packet, double frequencyMHz)
Construct a new interference signal Event object.
Ptr< Packet > GetPacket() const
Get the packet this event was generated for.
void Print(std::ostream &stream) const
Print the current event in a human readable form.
Helper for LoraPhy that manages interference calculations.
Ptr< LoraInterferenceHelper::Event > Add(Time duration, double rxPower, uint8_t spreadingFactor, Ptr< Packet > packet, double frequencyMHz)
Add an event to the InterferenceHelper.
static std::vector< std::vector< double > > collisionSnirGoursaud
GOURSAUD collision matrix.
static Time oldEventThreshold
The threshold after which an event is considered old and removed from the list.
Time GetOverlapTime(Ptr< LoraInterferenceHelper::Event > event1, Ptr< LoraInterferenceHelper::Event > event2)
Compute the time duration in which two given events are overlapping.
CollisionMatrix
Enumeration of types of collision matrices.
void CleanOldEvents()
Delete old events in this LoraInterferenceHelper.
void ClearAllEvents()
Delete all events in the LoraInterferenceHelper.
static CollisionMatrix collisionMatrix
Collision matrix type set by the constructor.
static std::vector< std::vector< double > > collisionSnirAloha
ALOHA collision matrix.
static TypeId GetTypeId()
Register this type.
std::vector< std::vector< double > > m_collisionSnir
The matrix containing information about how packets survive interference.
void SetCollisionMatrix(enum CollisionMatrix collisionMatrix)
Set the collision matrix.
uint8_t IsDestroyedByInterference(Ptr< LoraInterferenceHelper::Event > event)
Determine whether the event was destroyed by interference or not.
void PrintEvents(std::ostream &stream)
Print the events that are saved in this helper in a human readable format.
std::list< Ptr< LoraInterferenceHelper::Event > > GetInterferers()
Get a list of the interferers currently registered at this InterferenceHelper.
std::list< Ptr< LoraInterferenceHelper::Event > > m_events
List of the events this LoraInterferenceHelper is keeping track of.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
std::ostream & operator<<(std::ostream &os, const EndDeviceStatus &status)
Every class exported by the ns3 library is enclosed in the ns3 namespace.