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