A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
adr-component.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 University of Padova
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Matteo Perin <matteo.perin.2@studenti.unipd.it
7 */
8
9#include "adr-component.h"
10
11namespace ns3
12{
13namespace lorawan
14{
15
16////////////////////////////////////////
17// LinkAdrRequest commands management //
18////////////////////////////////////////
19
20NS_LOG_COMPONENT_DEFINE("AdrComponent");
21
22NS_OBJECT_ENSURE_REGISTERED(AdrComponent);
23
24TypeId
26{
27 static TypeId tid =
28 TypeId("ns3::AdrComponent")
29 .SetGroupName("lorawan")
31 .SetParent<NetworkControllerComponent>()
32 .AddAttribute("MultipleGwCombiningMethod",
33 "Whether to average the received power of gateways or to use the maximum",
37 "avg",
39 "max",
41 "min"))
42 .AddAttribute("MultiplePacketsCombiningMethod",
43 "Whether to average SNRs from multiple packets or to use the maximum",
47 "avg",
49 "max",
51 "min"))
52 .AddAttribute("HistoryRange",
53 "Number of packets to use for averaging",
54 IntegerValue(4),
57 .AddAttribute("ChangeTransmissionPower",
58 "Whether to toggle the transmission power or not",
59 BooleanValue(true),
62 return tid;
63}
64
68
72
73void
76 Ptr<NetworkStatus> networkStatus)
77{
78 NS_LOG_FUNCTION(this->GetTypeId() << packet << networkStatus);
79
80 // We will only act just before reply, when all Gateways will have received
81 // the packet, since we need their respective received power.
82}
83
84void
86{
87 NS_LOG_FUNCTION(this << status << networkStatus);
88
89 Ptr<Packet> myPacket = status->GetLastPacketReceivedFromDevice()->Copy();
91 LoraFrameHeader fHdr;
92 fHdr.SetAsUplink();
93 myPacket->RemoveHeader(mHdr);
94 myPacket->RemoveHeader(fHdr);
95
96 // Execute the Adaptive Data Rate (ADR) algorithm only if the request bit is set
97 if (fHdr.GetAdr())
98 {
99 if (int(status->GetReceivedPacketList().size()) < historyRange)
100 {
101 NS_LOG_ERROR("Not enough packets received by this device ("
102 << status->GetReceivedPacketList().size()
103 << ") for the algorithm to work (need " << historyRange << ")");
104 }
105 else
106 {
107 NS_LOG_DEBUG("New Adaptive Data Rate (ADR) request");
108
109 // Get the spreading factor used by the device
110 uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
111
112 // Get the device transmission power (dBm)
113 uint8_t transmissionPower = status->GetMac()->GetTransmissionPower();
114
115 // New parameters for the end-device
116 uint8_t newDataRate;
117 uint8_t newTxPower;
118
119 // Adaptive Data Rate (ADR) Algorithm
120 AdrImplementation(&newDataRate, &newTxPower, status);
121
122 // Change the power back to the default if we don't want to change it
123 if (!m_toggleTxPower)
124 {
125 newTxPower = transmissionPower;
126 }
127
128 if (newDataRate != SfToDr(spreadingFactor) || newTxPower != transmissionPower)
129 {
130 // Create a list with mandatory channel indexes
131 int channels[] = {0, 1, 2};
132 std::list<int> enabledChannels(channels, channels + sizeof(channels) / sizeof(int));
133
134 // Repetitions Setting
135 const int rep = 1;
136
137 NS_LOG_DEBUG("Sending LinkAdrReq with DR = " << (unsigned)newDataRate
138 << " and TP = " << (unsigned)newTxPower
139 << " dBm");
140
141 status->m_reply.frameHeader.AddLinkAdrReq(newDataRate,
142 GetTxPowerIndex(newTxPower),
143 enabledChannels,
144 rep);
145 status->m_reply.frameHeader.SetAsDownlink();
146 status->m_reply.macHeader.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN);
147
148 status->m_reply.needsReply = true;
149 }
150 else
151 {
152 NS_LOG_DEBUG("Skipped request");
153 }
154 }
155 }
156 else
157 {
158 // Do nothing
159 }
160}
161
162void
164{
165 NS_LOG_FUNCTION(this->GetTypeId() << networkStatus);
166}
167
168void
170 uint8_t* newTxPower,
172{
173 // Compute the maximum or median SNR, based on the boolean value historyAveraging
174 double m_SNR = 0;
175 switch (historyAveraging)
176 {
178 m_SNR = GetAverageSNR(status->GetReceivedPacketList(), historyRange);
179 break;
181 m_SNR = GetMaxSNR(status->GetReceivedPacketList(), historyRange);
182 break;
184 m_SNR = GetMinSNR(status->GetReceivedPacketList(), historyRange);
185 }
186
187 NS_LOG_DEBUG("m_SNR = " << m_SNR);
188
189 // Get the spreading factor used by the device
190 uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
191
192 NS_LOG_DEBUG("SF = " << (unsigned)spreadingFactor);
193
194 // Get the device data rate and use it to get the SNR demodulation threshold
195 double req_SNR = threshold[SfToDr(spreadingFactor)];
196
197 NS_LOG_DEBUG("Required SNR = " << req_SNR);
198
199 // Get the device transmission power (dBm)
200 double transmissionPower = status->GetMac()->GetTransmissionPower();
201
202 NS_LOG_DEBUG("Transmission Power = " << transmissionPower);
203
204 // Compute the SNR margin taking into consideration the SNR of
205 // previously received packets
206 double margin_SNR = m_SNR - req_SNR;
207
208 NS_LOG_DEBUG("Margin = " << margin_SNR);
209
210 // Number of steps to decrement the spreading factor (thereby increasing the data rate)
211 // and the TP.
212 int steps = std::floor(margin_SNR / 3);
213
214 NS_LOG_DEBUG("steps = " << steps);
215
216 // If the number of steps is positive (margin_SNR is positive, so its
217 // decimal value is high) increment the data rate, if there are some
218 // leftover steps after reaching the maximum possible data rate
219 //(corresponding to the minimum spreading factor) decrement the transmission power as
220 // well for the number of steps left.
221 // If, on the other hand, the number of steps is negative (margin_SNR is
222 // negative, so its decimal value is low) increase the transmission power
223 //(note that the spreading factor is not incremented as this particular algorithm
224 // expects the node itself to raise its spreading factor whenever necessary).
225 while (steps > 0 && spreadingFactor > min_spreadingFactor)
226 {
227 spreadingFactor--;
228 steps--;
229 NS_LOG_DEBUG("Decreased SF by 1");
230 }
231 while (steps > 0 && transmissionPower > min_transmissionPower)
232 {
233 transmissionPower -= 2;
234 steps--;
235 NS_LOG_DEBUG("Decreased Ptx by 2");
236 }
237 while (steps < 0 && transmissionPower < max_transmissionPower)
238 {
239 transmissionPower += 2;
240 steps++;
241 NS_LOG_DEBUG("Increased Ptx by 2");
242 }
243
244 *newDataRate = SfToDr(spreadingFactor);
245 *newTxPower = transmissionPower;
246}
247
248uint8_t
250{
251 switch (sf)
252 {
253 case 12:
254 return 0;
255 break;
256 case 11:
257 return 1;
258 break;
259 case 10:
260 return 2;
261 break;
262 case 9:
263 return 3;
264 break;
265 case 8:
266 return 4;
267 break;
268 default:
269 return 5;
270 break;
271 }
272}
273
274double
275AdrComponent::RxPowerToSNR(double transmissionPower) const
276{
277 // The following conversion ignores interfering packets
278 return transmissionPower + 174 - 10 * log10(B) - NF;
279}
280
281// Get the maximum received power (it considers the values in dB!)
282double
284{
285 auto it = gwList.begin();
286 double min = it->second.rxPower;
287
288 for (; it != gwList.end(); it++)
289 {
290 if (it->second.rxPower < min)
291 {
292 min = it->second.rxPower;
293 }
294 }
295
296 return min;
297}
298
299// Get the maximum received power (it considers the values in dB!)
300double
302{
303 auto it = gwList.begin();
304 double max = it->second.rxPower;
305
306 for (; it != gwList.end(); it++)
307 {
308 if (it->second.rxPower > max)
309 {
310 max = it->second.rxPower;
311 }
312 }
313
314 return max;
315}
316
317// Get the maximum received power
318double
320{
321 double sum = 0;
322
323 for (auto it = gwList.begin(); it != gwList.end(); it++)
324 {
325 NS_LOG_DEBUG("Gateway at " << it->first << " has TP " << it->second.rxPower);
326 sum += it->second.rxPower;
327 }
328
329 double average = sum / gwList.size();
330
331 NS_LOG_DEBUG("TP (average) = " << average);
332
333 return average;
334}
335
336double
338{
339 switch (tpAveraging)
340 {
342 return GetAverageTxFromGateways(gwList);
344 return GetMaxTxFromGateways(gwList);
346 return GetMinTxFromGateways(gwList);
347 default:
348 return -1;
349 }
350}
351
352// TODO Make this more elegant
353double
355{
356 double m_SNR;
357
358 // Take elements from the list starting at the end
359 auto it = packetList.rbegin();
360 double min = RxPowerToSNR(GetReceivedPower(it->second.gwList));
361
362 for (int i = 0; i < historyRange; i++, it++)
363 {
364 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
365
366 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
367 NS_LOG_DEBUG("m_SNR = " << m_SNR);
368
369 if (m_SNR < min)
370 {
371 min = m_SNR;
372 }
373 }
374
375 NS_LOG_DEBUG("SNR (min) = " << min);
376
377 return min;
378}
379
380double
382{
383 double m_SNR;
384
385 // Take elements from the list starting at the end
386 auto it = packetList.rbegin();
387 double max = RxPowerToSNR(GetReceivedPower(it->second.gwList));
388
389 for (int i = 0; i < historyRange; i++, it++)
390 {
391 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
392
393 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
394 NS_LOG_DEBUG("m_SNR = " << m_SNR);
395
396 if (m_SNR > max)
397 {
398 max = m_SNR;
399 }
400 }
401
402 NS_LOG_DEBUG("SNR (max) = " << max);
403
404 return max;
405}
406
407double
409{
410 double sum = 0;
411 double m_SNR;
412
413 // Take elements from the list starting at the end
414 auto it = packetList.rbegin();
415 for (int i = 0; i < historyRange; i++, it++)
416 {
417 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
418
419 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
420 NS_LOG_DEBUG("m_SNR = " << m_SNR);
421
422 sum += m_SNR;
423 }
424
425 double average = sum / historyRange;
426
427 NS_LOG_DEBUG("SNR (average) = " << average);
428
429 return average;
430}
431
432int
434{
435 if (txPower >= 16)
436 {
437 return 0;
438 }
439 else if (txPower >= 14)
440 {
441 return 1;
442 }
443 else if (txPower >= 12)
444 {
445 return 2;
446 }
447 else if (txPower >= 10)
448 {
449 return 3;
450 }
451 else if (txPower >= 8)
452 {
453 return 4;
454 }
455 else if (txPower >= 6)
456 {
457 return 5;
458 }
459 else if (txPower >= 4)
460 {
461 return 6;
462 }
463 else
464 {
465 return 7;
466 }
467}
468} // namespace lorawan
469} // namespace ns3
Hold variables of type enum.
Definition enum.h:52
Hold a signed integer type.
Definition integer.h:34
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:48
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition type-id.h:670
TypeId SetGroupName(std::string groupName)
Set the group name.
Definition type-id.cc:1009
LinkAdrRequest commands management.
double GetAverageSNR(EndDeviceStatus::ReceivedPacketList packetList, int historyRange)
Get the average Signal to Noise Ratio (SNR) of the received packet history.
enum CombiningMethod historyAveraging
Received SNR history policy.
double GetMinSNR(EndDeviceStatus::ReceivedPacketList packetList, int historyRange)
Get the min Signal to Noise Ratio (SNR) of the receive packet history.
void OnReceivedPacket(Ptr< const Packet > packet, Ptr< EndDeviceStatus > status, Ptr< NetworkStatus > networkStatus) override
Function called as a new uplink packet is received by the NetworkServer application.
double threshold[6]
Vector containing the required SNR for the 6 allowed spreading factor levels ranging from 7 to 12 (th...
void OnFailedReply(Ptr< EndDeviceStatus > status, Ptr< NetworkStatus > networkStatus) override
Method that is called when a packet cannot be sent in the downlink.
AdrComponent()
Default constructor.
void BeforeSendingReply(Ptr< EndDeviceStatus > status, Ptr< NetworkStatus > networkStatus) override
Function called as a downlink reply is about to leave the NetworkServer application.
const int NF
Noise Figure (dB)
double GetMinTxFromGateways(EndDeviceStatus::GatewayList gwList)
Get the min RSSI (dBm) among gateways receiving the same transmission.
int historyRange
Number of previous packets to consider.
const int min_spreadingFactor
Spreading factor lower limit.
double GetMaxTxFromGateways(EndDeviceStatus::GatewayList gwList)
Get the max RSSI (dBm) among gateways receiving the same transmission.
enum CombiningMethod tpAveraging
TX power from gateways policy.
bool m_toggleTxPower
Whether to control transmission power of end devices or not.
double GetReceivedPower(EndDeviceStatus::GatewayList gwList)
Get RSSI metric for a transmission according to chosen gateway aggregation policy.
~AdrComponent() override
Destructor.
void AdrImplementation(uint8_t *newDataRate, uint8_t *newTxPower, Ptr< EndDeviceStatus > status)
Implementation of the default Adaptive Data Rate (ADR) procedure.
static TypeId GetTypeId()
Register this type.
const int B
Bandwidth (Hz)
int GetTxPowerIndex(int txPower)
Get the LoRaWAN protocol TXPower configuration index from the Equivalent Isotropically Radiated Power...
double GetMaxSNR(EndDeviceStatus::ReceivedPacketList packetList, int historyRange)
Get the max Signal to Noise Ratio (SNR) of the receive packet history.
double RxPowerToSNR(double transmissionPower) const
Convert reception power values [dBm] to Signal to Noise Ratio (SNR) values [dB].
double GetAverageTxFromGateways(EndDeviceStatus::GatewayList gwList)
Get the average RSSI (dBm) of gateways receiving the same transmission.
const int min_transmissionPower
Minimum transmission power (dBm) (Europe)
uint8_t SfToDr(uint8_t sf)
Convert spreading factor values [7:12] to respective data rate values [0:5].
const int max_transmissionPower
Maximum transmission power (dBm) (Europe)
std::list< std::pair< Ptr< const Packet >, ReceivedPacketInfo > > ReceivedPacketList
typedef of a list of packets paired to their reception info.
std::map< Address, PacketInfoPerGw > GatewayList
typedef of a list of gateways with relative reception information.
This class represents the Frame header (FHDR) used in a LoraWAN network.
bool GetAdr() const
Get the value of the ADR bit field.
void SetAsUplink()
State that this is an uplink message.
This class represents the Mac header of a LoRaWAN packet.
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeIntegerChecker()
Definition integer.h:99
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Definition integer.h:35
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition enum.h:221