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 double transmissionPowerDbm = status->GetMac()->GetTransmissionPowerDbm();
114
115 // New parameters for the end-device
116 uint8_t newDataRate;
117 double newTxPowerDbm;
118
119 // Adaptive Data Rate (ADR) Algorithm
120 AdrImplementation(&newDataRate, &newTxPowerDbm, status);
121
122 // Change the power back to the default if we don't want to change it
123 if (!m_toggleTxPower)
124 {
125 newTxPowerDbm = transmissionPowerDbm;
126 }
127
128 if (newDataRate != SfToDr(spreadingFactor) || newTxPowerDbm != transmissionPowerDbm)
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 = "
138 << (unsigned)newDataRate << " and TP = " << newTxPowerDbm << "dBm");
139
140 status->m_reply.frameHeader.AddLinkAdrReq(newDataRate,
141 GetTxPowerIndex(newTxPowerDbm),
142 enabledChannels,
143 rep);
144 status->m_reply.frameHeader.SetAsDownlink();
145 status->m_reply.macHeader.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN);
146
147 status->m_reply.needsReply = true;
148 }
149 else
150 {
151 NS_LOG_DEBUG("Skipped request");
152 }
153 }
154 }
155 else
156 {
157 // Do nothing
158 }
159}
160
161void
163{
164 NS_LOG_FUNCTION(this->GetTypeId() << networkStatus);
165}
166
167void
169 double* newTxPower,
171{
172 // Compute the maximum or median SNR, based on the boolean value historyAveraging
173 double m_SNR = 0;
174 switch (historyAveraging)
175 {
177 m_SNR = GetAverageSNR(status->GetReceivedPacketList(), historyRange);
178 break;
180 m_SNR = GetMaxSNR(status->GetReceivedPacketList(), historyRange);
181 break;
183 m_SNR = GetMinSNR(status->GetReceivedPacketList(), historyRange);
184 }
185
186 NS_LOG_DEBUG("m_SNR = " << m_SNR);
187
188 // Get the spreading factor used by the device
189 uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
190
191 NS_LOG_DEBUG("SF = " << (unsigned)spreadingFactor);
192
193 // Get the device data rate and use it to get the SNR demodulation threshold
194 double req_SNR = threshold[SfToDr(spreadingFactor)];
195
196 NS_LOG_DEBUG("Required SNR = " << req_SNR);
197
198 // Get the device transmission power (dBm)
199 double transmissionPower = status->GetMac()->GetTransmissionPowerDbm();
200
201 NS_LOG_DEBUG("Transmission Power = " << transmissionPower);
202
203 // Compute the SNR margin taking into consideration the SNR of
204 // previously received packets
205 double margin_SNR = m_SNR - req_SNR;
206
207 NS_LOG_DEBUG("Margin = " << margin_SNR);
208
209 // Number of steps to decrement the spreading factor (thereby increasing the data rate)
210 // and the TP.
211 int steps = std::floor(margin_SNR / 3);
212
213 NS_LOG_DEBUG("steps = " << steps);
214
215 // If the number of steps is positive (margin_SNR is positive, so its
216 // decimal value is high) increment the data rate, if there are some
217 // leftover steps after reaching the maximum possible data rate
218 //(corresponding to the minimum spreading factor) decrement the transmission power as
219 // well for the number of steps left.
220 // If, on the other hand, the number of steps is negative (margin_SNR is
221 // negative, so its decimal value is low) increase the transmission power
222 //(note that the spreading factor is not incremented as this particular algorithm
223 // expects the node itself to raise its spreading factor whenever necessary).
224 while (steps > 0 && spreadingFactor > min_spreadingFactor)
225 {
226 spreadingFactor--;
227 steps--;
228 NS_LOG_DEBUG("Decreased SF by 1");
229 }
230 while (steps > 0 && transmissionPower > min_transmissionPower)
231 {
232 transmissionPower -= 2;
233 steps--;
234 NS_LOG_DEBUG("Decreased Ptx by 2");
235 }
236 while (steps < 0 && transmissionPower < max_transmissionPower)
237 {
238 transmissionPower += 2;
239 steps++;
240 NS_LOG_DEBUG("Increased Ptx by 2");
241 }
242
243 *newDataRate = SfToDr(spreadingFactor);
244 *newTxPower = transmissionPower;
245}
246
247uint8_t
249{
250 switch (sf)
251 {
252 case 12:
253 return 0;
254 break;
255 case 11:
256 return 1;
257 break;
258 case 10:
259 return 2;
260 break;
261 case 9:
262 return 3;
263 break;
264 case 8:
265 return 4;
266 break;
267 default:
268 return 5;
269 break;
270 }
271}
272
273double
274AdrComponent::RxPowerToSNR(double transmissionPower) const
275{
276 // The following conversion ignores interfering packets
277 return transmissionPower + 174 - 10 * log10(B) - NF;
278}
279
280// Get the maximum received power (it considers the values in dB!)
281double
283{
284 auto it = gwList.begin();
285 double min = it->second.rxPower;
286
287 for (; it != gwList.end(); it++)
288 {
289 if (it->second.rxPower < min)
290 {
291 min = it->second.rxPower;
292 }
293 }
294
295 return min;
296}
297
298// Get the maximum received power (it considers the values in dB!)
299double
301{
302 auto it = gwList.begin();
303 double max = it->second.rxPower;
304
305 for (; it != gwList.end(); it++)
306 {
307 if (it->second.rxPower > max)
308 {
309 max = it->second.rxPower;
310 }
311 }
312
313 return max;
314}
315
316// Get the maximum received power
317double
319{
320 double sum = 0;
321
322 for (auto it = gwList.begin(); it != gwList.end(); it++)
323 {
324 NS_LOG_DEBUG("Gateway at " << it->first << " has TP " << it->second.rxPower);
325 sum += it->second.rxPower;
326 }
327
328 double average = sum / gwList.size();
329
330 NS_LOG_DEBUG("TP (average) = " << average);
331
332 return average;
333}
334
335double
337{
338 switch (tpAveraging)
339 {
341 return GetAverageTxFromGateways(gwList);
343 return GetMaxTxFromGateways(gwList);
345 return GetMinTxFromGateways(gwList);
346 default:
347 return -1;
348 }
349}
350
351// TODO Make this more elegant
352double
354{
355 double m_SNR;
356
357 // Take elements from the list starting at the end
358 auto it = packetList.rbegin();
359 double min = RxPowerToSNR(GetReceivedPower(it->second.gwList));
360
361 for (int i = 0; i < historyRange; i++, it++)
362 {
363 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
364
365 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
366 NS_LOG_DEBUG("m_SNR = " << m_SNR);
367
368 if (m_SNR < min)
369 {
370 min = m_SNR;
371 }
372 }
373
374 NS_LOG_DEBUG("SNR (min) = " << min);
375
376 return min;
377}
378
379double
381{
382 double m_SNR;
383
384 // Take elements from the list starting at the end
385 auto it = packetList.rbegin();
386 double max = RxPowerToSNR(GetReceivedPower(it->second.gwList));
387
388 for (int i = 0; i < historyRange; i++, it++)
389 {
390 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
391
392 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
393 NS_LOG_DEBUG("m_SNR = " << m_SNR);
394
395 if (m_SNR > max)
396 {
397 max = m_SNR;
398 }
399 }
400
401 NS_LOG_DEBUG("SNR (max) = " << max);
402
403 return max;
404}
405
406double
408{
409 double sum = 0;
410 double m_SNR;
411
412 // Take elements from the list starting at the end
413 auto it = packetList.rbegin();
414 for (int i = 0; i < historyRange; i++, it++)
415 {
416 m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
417
418 NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
419 NS_LOG_DEBUG("m_SNR = " << m_SNR);
420
421 sum += m_SNR;
422 }
423
424 double average = sum / historyRange;
425
426 NS_LOG_DEBUG("SNR (average) = " << average);
427
428 return average;
429}
430
431uint8_t
433{
434 NS_ASSERT_MSG(txPower >= 0 && txPower <= 14, "TxPower dBm value out of supported range");
435 NS_ASSERT_MSG(fmod(txPower, 2) == 0, "Invalid TxPower value");
436 return 7 - txPower / 2;
437}
438} // namespace lorawan
439} // 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:49
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition type-id.h:694
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 AdrImplementation(uint8_t *newDataRate, double *newTxPower, Ptr< EndDeviceStatus > status)
Implementation of the default Adaptive Data Rate (ADR) procedure.
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)
uint8_t GetTxPowerIndex(double txPower)
Get the LoRaWAN protocol TxPower parameter from the Equivalent Radiated Power (ERP) in dBm.
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.
static TypeId GetTypeId()
Register this type.
const int B
Bandwidth (Hz)
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_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#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