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 * 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: Matteo Perin <matteo.perin.2@studenti.unipd.it
18 */
19
20#include "adr-component.h"
21
22namespace ns3
23{
24namespace lorawan
25{
26
27////////////////////////////////////////
28// LinkAdrRequest commands management //
29////////////////////////////////////////
30
31NS_LOG_COMPONENT_DEFINE("AdrComponent");
32
33NS_OBJECT_ENSURE_REGISTERED(AdrComponent);
34
35TypeId
37{
38 static TypeId tid =
39 TypeId("ns3::AdrComponent")
40 .SetGroupName("lorawan")
42 .SetParent<NetworkControllerComponent>()
43 .AddAttribute("MultipleGwCombiningMethod",
44 "Whether to average the received power of gateways or to use the maximum",
46 MakeEnumAccessor<CombiningMethod>(&AdrComponent::tpAveraging),
48 "avg",
50 "max",
52 "min"))
53 .AddAttribute("MultiplePacketsCombiningMethod",
54 "Whether to average SNRs from multiple packets or to use the maximum",
56 MakeEnumAccessor<CombiningMethod>(&AdrComponent::historyAveraging),
58 "avg",
60 "max",
62 "min"))
63 .AddAttribute("HistoryRange",
64 "Number of packets to use for averaging",
65 IntegerValue(4),
67 MakeIntegerChecker<int>(0, 100))
68 .AddAttribute("ChangeTransmissionPower",
69 "Whether to toggle the transmission power or not",
70 BooleanValue(true),
73 return tid;
74}
75
77{
78}
79
81{
82}
83
84void
87 Ptr<NetworkStatus> networkStatus)
88{
89 NS_LOG_FUNCTION(this->GetTypeId() << packet << networkStatus);
90
91 // We will only act just before reply, when all Gateways will have received
92 // the packet, since we need their respective received power.
93}
94
95void
97{
98 NS_LOG_FUNCTION(this << status << networkStatus);
99
100 Ptr<Packet> myPacket = status->GetLastPacketReceivedFromDevice()->Copy();
101 LorawanMacHeader mHdr;
102 LoraFrameHeader fHdr;
103 fHdr.SetAsUplink();
104 myPacket->RemoveHeader(mHdr);
105 myPacket->RemoveHeader(fHdr);
106
107 // Execute the Adaptive Data Rate (ADR) algorithm only if the request bit is set
108 if (fHdr.GetAdr())
109 {
110 if (int(status->GetReceivedPacketList().size()) < historyRange)
111 {
112 NS_LOG_ERROR("Not enough packets received by this device ("
113 << status->GetReceivedPacketList().size()
114 << ") for the algorithm to work (need " << historyRange << ")");
115 }
116 else
117 {
118 NS_LOG_DEBUG("New Adaptive Data Rate (ADR) request");
119
120 // Get the spreading factor used by the device
121 uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
122
123 // Get the device transmission power (dBm)
124 uint8_t transmissionPower = status->GetMac()->GetTransmissionPower();
125
126 // New parameters for the end-device
127 uint8_t newDataRate;
128 uint8_t newTxPower;
129
130 // Adaptive Data Rate (ADR) Algorithm
131 AdrImplementation(&newDataRate, &newTxPower, status);
132
133 // Change the power back to the default if we don't want to change it
134 if (!m_toggleTxPower)
135 {
136 newTxPower = transmissionPower;
137 }
138
139 if (newDataRate != SfToDr(spreadingFactor) || newTxPower != transmissionPower)
140 {
141 // Create a list with mandatory channel indexes
142 int channels[] = {0, 1, 2};
143 std::list<int> enabledChannels(channels, channels + sizeof(channels) / sizeof(int));
144
145 // Repetitions Setting
146 const int rep = 1;
147
148 NS_LOG_DEBUG("Sending LinkAdrReq with DR = " << (unsigned)newDataRate
149 << " and TP = " << (unsigned)newTxPower
150 << " dBm");
151
152 status->m_reply.frameHeader.AddLinkAdrReq(newDataRate,
153 GetTxPowerIndex(newTxPower),
154 enabledChannels,
155 rep);
156 status->m_reply.frameHeader.SetAsDownlink();
157 status->m_reply.macHeader.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN);
158
159 status->m_reply.needsReply = true;
160 }
161 else
162 {
163 NS_LOG_DEBUG("Skipped request");
164 }
165 }
166 }
167 else
168 {
169 // Do nothing
170 }
171}
172
173void
175{
176 NS_LOG_FUNCTION(this->GetTypeId() << networkStatus);
177}
178
179void
181 uint8_t* newTxPower,
183{
184 // Compute the maximum or median SNR, based on the boolean value historyAveraging
185 double m_SNR = 0;
186 switch (historyAveraging)
187 {
189 m_SNR = GetAverageSNR(status->GetReceivedPacketList(), historyRange);
190 break;
192 m_SNR = GetMaxSNR(status->GetReceivedPacketList(), historyRange);
193 break;
195 m_SNR = GetMinSNR(status->GetReceivedPacketList(), historyRange);
196 }
197
198 NS_LOG_DEBUG("m_SNR = " << m_SNR);
199
200 // Get the spreading factor used by the device
201 uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
202
203 NS_LOG_DEBUG("SF = " << (unsigned)spreadingFactor);
204
205 // Get the device data rate and use it to get the SNR demodulation threshold
206 double req_SNR = threshold[SfToDr(spreadingFactor)];
207
208 NS_LOG_DEBUG("Required SNR = " << req_SNR);
209
210 // Get the device transmission power (dBm)
211 double transmissionPower = status->GetMac()->GetTransmissionPower();
212
213 NS_LOG_DEBUG("Transmission Power = " << transmissionPower);
214
215 // Compute the SNR margin taking into consideration the SNR of
216 // previously received packets
217 double margin_SNR = m_SNR - req_SNR;
218
219 NS_LOG_DEBUG("Margin = " << margin_SNR);
220
221 // Number of steps to decrement the spreading factor (thereby increasing the data rate)
222 // and the TP.
223 int steps = std::floor(margin_SNR / 3);
224
225 NS_LOG_DEBUG("steps = " << steps);
226
227 // If the number of steps is positive (margin_SNR is positive, so its
228 // decimal value is high) increment the data rate, if there are some
229 // leftover steps after reaching the maximum possible data rate
230 //(corresponding to the minimum spreading factor) decrement the transmission power as
231 // well for the number of steps left.
232 // If, on the other hand, the number of steps is negative (margin_SNR is
233 // negative, so its decimal value is low) increase the transmission power
234 //(note that the spreading factor is not incremented as this particular algorithm
235 // expects the node itself to raise its spreading factor whenever necessary).
236 while (steps > 0 && spreadingFactor > min_spreadingFactor)
237 {
238 spreadingFactor--;
239 steps--;
240 NS_LOG_DEBUG("Decreased SF by 1");
241 }
242 while (steps > 0 && transmissionPower > min_transmissionPower)
243 {
244 transmissionPower -= 2;
245 steps--;
246 NS_LOG_DEBUG("Decreased Ptx by 2");
247 }
248 while (steps < 0 && transmissionPower < max_transmissionPower)
249 {
250 transmissionPower += 2;
251 steps++;
252 NS_LOG_DEBUG("Increased Ptx by 2");
253 }
254
255 *newDataRate = SfToDr(spreadingFactor);
256 *newTxPower = transmissionPower;
257}
258
259uint8_t
261{
262 switch (sf)
263 {
264 case 12:
265 return 0;
266 break;
267 case 11:
268 return 1;
269 break;
270 case 10:
271 return 2;
272 break;
273 case 9:
274 return 3;
275 break;
276 case 8:
277 return 4;
278 break;
279 default:
280 return 5;
281 break;
282 }
283}
284
285double
286AdrComponent::RxPowerToSNR(double transmissionPower) const
287{
288 // The following conversion ignores interfering packets
289 return transmissionPower + 174 - 10 * log10(B) - NF;
290}
291
292// Get the maximum received power (it considers the values in dB!)
293double
295{
296 auto it = gwList.begin();
297 double min = it->second.rxPower;
298
299 for (; it != gwList.end(); it++)
300 {
301 if (it->second.rxPower < min)
302 {
303 min = it->second.rxPower;
304 }
305 }
306
307 return min;
308}
309
310// Get the maximum received power (it considers the values in dB!)
311double
313{
314 auto it = gwList.begin();
315 double max = it->second.rxPower;
316
317 for (; it != gwList.end(); it++)
318 {
319 if (it->second.rxPower > max)
320 {
321 max = it->second.rxPower;
322 }
323 }
324
325 return max;
326}
327
328// Get the maximum received power
329double
331{
332 double sum = 0;
333
334 for (auto it = gwList.begin(); it != gwList.end(); it++)
335 {
336 NS_LOG_DEBUG("Gateway at " << it->first << " has TP " << it->second.rxPower);
337 sum += it->second.rxPower;
338 }
339
340 double average = sum / gwList.size();
341
342 NS_LOG_DEBUG("TP (average) = " << average);
343
344 return average;
345}
346
347double
349{
350 switch (tpAveraging)
351 {
353 return GetAverageTxFromGateways(gwList);
355 return GetMaxTxFromGateways(gwList);
357 return GetMinTxFromGateways(gwList);
358 default:
359 return -1;
360 }
361}
362
363// TODO Make this more elegant
364double
366{
367 double m_SNR;
368
369 // Take elements from the list starting at the end
370 auto it = packetList.rbegin();
371 double min = RxPowerToSNR(GetReceivedPower(it->second.gwList));
372
373 for (int i = 0; i < historyRange; i++, it++)
374 {
375 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
376
377 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
378 NS_LOG_DEBUG("m_SNR = " << m_SNR);
379
380 if (m_SNR < min)
381 {
382 min = m_SNR;
383 }
384 }
385
386 NS_LOG_DEBUG("SNR (min) = " << min);
387
388 return min;
389}
390
391double
393{
394 double m_SNR;
395
396 // Take elements from the list starting at the end
397 auto it = packetList.rbegin();
398 double max = RxPowerToSNR(GetReceivedPower(it->second.gwList));
399
400 for (int i = 0; i < historyRange; i++, it++)
401 {
402 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
403
404 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
405 NS_LOG_DEBUG("m_SNR = " << m_SNR);
406
407 if (m_SNR > max)
408 {
409 max = m_SNR;
410 }
411 }
412
413 NS_LOG_DEBUG("SNR (max) = " << max);
414
415 return max;
416}
417
418double
420{
421 double sum = 0;
422 double m_SNR;
423
424 // Take elements from the list starting at the end
425 auto it = packetList.rbegin();
426 for (int i = 0; i < historyRange; i++, it++)
427 {
428 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
429
430 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
431 NS_LOG_DEBUG("m_SNR = " << m_SNR);
432
433 sum += m_SNR;
434 }
435
436 double average = sum / historyRange;
437
438 NS_LOG_DEBUG("SNR (average) = " << average);
439
440 return average;
441}
442
443int
445{
446 if (txPower >= 16)
447 {
448 return 0;
449 }
450 else if (txPower >= 14)
451 {
452 return 1;
453 }
454 else if (txPower >= 12)
455 {
456 return 2;
457 }
458 else if (txPower >= 10)
459 {
460 return 3;
461 }
462 else if (txPower >= 8)
463 {
464 return 4;
465 }
466 else if (txPower >= 6)
467 {
468 return 5;
469 }
470 else if (txPower >= 4)
471 {
472 return 6;
473 }
474 else
475 {
476 return 7;
477 }
478}
479} // namespace lorawan
480} // namespace ns3
Hold variables of type enum.
Definition: enum.h:62
Hold a signed integer type.
Definition: integer.h:45
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
a unique identifier for an interface.
Definition: type-id.h:59
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition: type-id.h:651
TypeId SetGroupName(std::string groupName)
Set the group name.
Definition: type-id.cc:940
LinkAdrRequest commands management.
Definition: adr-component.h:41
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:254
#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(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:46
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Definition: integer.h:46
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:189
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81