lora-adr-component.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 University of Padova
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Matteo Perin <matteo.perin.2@studenti.unipd.it
19  *
20  * Modified by: Bastien Tauran <bastien.tauran@viveris.fr>
21  */
22 
23 #include "lora-adr-component.h"
24 
25 #include <ns3/log.h>
26 
27 namespace ns3
28 {
29 
31 // LinkAdrRequest commands management //
33 
34 NS_LOG_COMPONENT_DEFINE("LoraAdrComponent");
35 
36 NS_OBJECT_ENSURE_REGISTERED(LoraAdrComponent);
37 
38 TypeId
40 {
41  static TypeId tid =
42  TypeId("ns3::LoraAdrComponent")
43  .AddConstructor<LoraAdrComponent>()
44  .SetParent<LoraNetworkControllerComponent>()
45  .AddAttribute("MultipleGwCombiningMethod",
46  "Whether to average the received power of gateways or to use the maximum",
47  EnumValue(LoraAdrComponent::AVERAGE),
48  MakeEnumAccessor(&LoraAdrComponent::tpAveraging),
49  MakeEnumChecker(LoraAdrComponent::AVERAGE,
50  "avg",
52  "max",
54  "min"))
55  .AddAttribute("MultiplePacketsCombiningMethod",
56  "Whether to average SNRs from multiple packets or to use the maximum",
57  EnumValue(LoraAdrComponent::AVERAGE),
58  MakeEnumAccessor(&LoraAdrComponent::historyAveraging),
59  MakeEnumChecker(LoraAdrComponent::AVERAGE,
60  "avg",
62  "max",
64  "min"))
65  .AddAttribute("HistoryRange",
66  "Number of packets to use for averaging",
67  IntegerValue(4),
68  MakeIntegerAccessor(&LoraAdrComponent::historyRange),
69  MakeIntegerChecker<int>(0, 100))
70  .AddAttribute("ChangeTransmissionPower",
71  "Whether to toggle the transmission power or not",
72  BooleanValue(true),
73  MakeBooleanAccessor(&LoraAdrComponent::m_toggleTxPower),
74  MakeBooleanChecker());
75  return tid;
76 }
77 
79 {
80 }
81 
83 {
84 }
85 
86 void
87 LoraAdrComponent::OnReceivedPacket(Ptr<const Packet> packet,
88  Ptr<LoraEndDeviceStatus> status,
89  Ptr<LoraNetworkStatus> networkStatus)
90 {
91  NS_LOG_FUNCTION(this->GetTypeId() << packet << networkStatus);
92 
93  // We will only act just before reply, when all Gateways will have received
94  // the packet, since we need their respective received power.
95 }
96 
97 void
98 LoraAdrComponent::BeforeSendingReply(Ptr<LoraEndDeviceStatus> status,
99  Ptr<LoraNetworkStatus> networkStatus)
100 {
101  NS_LOG_FUNCTION(this << status << networkStatus);
102 
103  Ptr<Packet> myPacket = status->GetLastPacketReceivedFromDevice()->Copy();
104  LorawanMacHeader mHdr;
105  LoraFrameHeader fHdr;
106  fHdr.SetAsUplink();
107  myPacket->RemoveHeader(mHdr);
108  myPacket->RemoveHeader(fHdr);
109 
110  // Execute the ADR algotithm only if the request bit is set
111  if (fHdr.GetAdr())
112  {
113  if (int(status->GetReceivedPacketList().size()) < historyRange)
114  {
115  NS_LOG_ERROR("Not enough packets received by this device ("
116  << status->GetReceivedPacketList().size()
117  << ") for the algorithm to work (need " << historyRange << ")");
118  }
119  else
120  {
121  NS_LOG_DEBUG("New ADR request");
122 
123  // Get the SF used by the device
124  uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
125 
126  // Get the device transmission power (dBm)
127  uint8_t transmissionPower = status->GetMac()->GetTransmissionPower();
128 
129  // New parameters for the end-device
130  uint8_t newDataRate;
131  uint8_t newTxPower;
132 
133  // ADR Algorithm
134  AdrImplementation(&newDataRate, &newTxPower, status);
135 
136  // Change the power back to the default if we don't want to change it
137  if (!m_toggleTxPower)
138  {
139  newTxPower = transmissionPower;
140  }
141 
142  if (newDataRate != SfToDr(spreadingFactor) || newTxPower != transmissionPower)
143  {
144  // Create a list with mandatory channel indexes
145  int channels[] = {0, 1, 2};
146  std::list<int> enabledChannels(channels, channels + sizeof(channels) / sizeof(int));
147 
148  // Repetitions Setting
149  const int rep = 1;
150 
151  NS_LOG_DEBUG("Sending LinkAdrReq with DR = " << (unsigned)newDataRate
152  << " and TP = " << (unsigned)newTxPower
153  << " dBm");
154 
155  status->m_reply.frameHeader.AddLinkAdrReq(newDataRate,
156  GetTxPowerIndex(newTxPower),
157  enabledChannels,
158  rep);
159  status->m_reply.frameHeader.SetAsDownlink();
160  status->m_reply.macHeader.SetMType(LorawanMacHeader::UNCONFIRMED_DATA_DOWN);
161 
162  status->m_reply.needsReply = true;
163  }
164  else
165  {
166  NS_LOG_DEBUG("Skipped request");
167  }
168  }
169  }
170  else
171  {
172  // Do nothing
173  }
174 }
175 
176 void
177 LoraAdrComponent::OnFailedReply(Ptr<LoraEndDeviceStatus> status,
178  Ptr<LoraNetworkStatus> networkStatus)
179 {
180  NS_LOG_FUNCTION(this->GetTypeId() << networkStatus);
181 }
182 
183 void
185  uint8_t* newTxPower,
186  Ptr<LoraEndDeviceStatus> status)
187 {
188  // Compute the maximum or median SNR, based on the boolean value historyAveraging
189  double m_SNR = 0;
190  switch (historyAveraging)
191  {
193  m_SNR = GetAverageSNR(status->GetReceivedPacketList(), historyRange);
194  break;
196  m_SNR = GetMaxSNR(status->GetReceivedPacketList(), historyRange);
197  break;
199  m_SNR = GetMinSNR(status->GetReceivedPacketList(), historyRange);
200  }
201 
202  NS_LOG_DEBUG("m_SNR = " << m_SNR);
203 
204  // Get the SF used by the device
205  uint8_t spreadingFactor = status->GetFirstReceiveWindowSpreadingFactor();
206 
207  NS_LOG_DEBUG("SF = " << (unsigned)spreadingFactor);
208 
209  // Get the device data rate and use it to get the SNR demodulation treshold
210  double req_SNR = treshold[SfToDr(spreadingFactor)];
211 
212  NS_LOG_DEBUG("Required SNR = " << req_SNR);
213 
214  // Get the device transmission power (dBm)
215  double transmissionPower = status->GetMac()->GetTransmissionPower();
216 
217  NS_LOG_DEBUG("Transmission Power = " << transmissionPower);
218 
219  // Compute the SNR margin taking into consideration the SNR of
220  // previously received packets
221  double margin_SNR = m_SNR - req_SNR;
222 
223  NS_LOG_DEBUG("Margin = " << margin_SNR);
224 
225  // Number of steps to decrement the SF (thereby increasing the Data Rate)
226  // and the TP.
227  int steps = std::floor(margin_SNR / 3);
228 
229  NS_LOG_DEBUG("steps = " << steps);
230 
231  // If the number of steps is positive (margin_SNR is positive, so its
232  // decimal value is high) increment the data rate, if there are some
233  // leftover steps after reaching the maximum possible data rate
234  //(corresponding to the minimum SF) decrement the transmission power as
235  // well for the number of steps left.
236  // If, on the other hand, the number of steps is negative (margin_SNR is
237  // negative, so its decimal value is low) increase the transmission power
238  //(note that the SF is not incremented as this particular algorithm
239  // expects the node itself to raise its SF whenever necessary).
240  while (steps > 0 && spreadingFactor > min_spreadingFactor)
241  {
242  spreadingFactor--;
243  steps--;
244  NS_LOG_DEBUG("Decreased SF by 1");
245  }
246  while (steps > 0 && transmissionPower > min_transmissionPower)
247  {
248  transmissionPower -= 2;
249  steps--;
250  NS_LOG_DEBUG("Decreased Ptx by 2");
251  }
252  while (steps < 0 && transmissionPower < max_transmissionPower)
253  {
254  transmissionPower += 2;
255  steps++;
256  NS_LOG_DEBUG("Increased Ptx by 2");
257  }
258 
259  *newDataRate = SfToDr(spreadingFactor);
260  *newTxPower = transmissionPower;
261 }
262 
263 uint8_t
265 {
266  switch (sf)
267  {
268  case 12:
269  return 0;
270  break;
271  case 11:
272  return 1;
273  break;
274  case 10:
275  return 2;
276  break;
277  case 9:
278  return 3;
279  break;
280  case 8:
281  return 4;
282  break;
283  default:
284  return 5;
285  break;
286  }
287 }
288 
289 double
290 LoraAdrComponent::RxPowerToSNR(double transmissionPower)
291 {
292  // The following conversion ignores interfering packets
293  return transmissionPower + 174 - 10 * log10(B) - NF;
294 }
295 
296 // Get the maximum received power (it considers the values in dB!)
297 double
299 {
300  LoraEndDeviceStatus::GatewayList::iterator it = gwList.begin();
301  double min = it->second.rxPower;
302 
303  for (; it != gwList.end(); it++)
304  {
305  if (it->second.rxPower < min)
306  {
307  min = it->second.rxPower;
308  }
309  }
310 
311  return min;
312 }
313 
314 // Get the maximum received power (it considers the values in dB!)
315 double
317 {
318  LoraEndDeviceStatus::GatewayList::iterator it = gwList.begin();
319  double max = it->second.rxPower;
320 
321  for (; it != gwList.end(); it++)
322  {
323  if (it->second.rxPower > max)
324  {
325  max = it->second.rxPower;
326  }
327  }
328 
329  return max;
330 }
331 
332 // Get the maximum received power
333 double
335 {
336  double sum = 0;
337 
338  for (LoraEndDeviceStatus::GatewayList::iterator it = gwList.begin(); it != gwList.end(); it++)
339  {
340  NS_LOG_DEBUG("Gateway at " << it->first << " has TP " << it->second.rxPower);
341  sum += it->second.rxPower;
342  }
343 
344  double average = sum / gwList.size();
345 
346  NS_LOG_DEBUG("TP (average) = " << average);
347 
348  return average;
349 }
350 
351 double
353 {
354  switch (tpAveraging)
355  {
357  return GetAverageTxFromGateways(gwList);
359  return GetMaxTxFromGateways(gwList);
361  return GetMinTxFromGateways(gwList);
362  default:
363  return -1;
364  }
365 }
366 
367 // TODO Make this more elegant
368 double
370 {
371  double m_SNR;
372 
373  // Take elements from the list starting at the end
374  auto it = packetList.rbegin();
375  double min = RxPowerToSNR(GetReceivedPower(it->second.gwList));
376 
377  for (int i = 0; i < historyRange; i++, it++)
378  {
379  m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
380 
381  NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
382  NS_LOG_DEBUG("m_SNR = " << m_SNR);
383 
384  if (m_SNR < min)
385  {
386  min = m_SNR;
387  }
388  }
389 
390  NS_LOG_DEBUG("SNR (min) = " << min);
391 
392  return min;
393 }
394 
395 double
397 {
398  double m_SNR;
399 
400  // Take elements from the list starting at the end
401  auto it = packetList.rbegin();
402  double max = RxPowerToSNR(GetReceivedPower(it->second.gwList));
403 
404  for (int i = 0; i < historyRange; i++, it++)
405  {
406  m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
407 
408  NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
409  NS_LOG_DEBUG("m_SNR = " << m_SNR);
410 
411  if (m_SNR > max)
412  {
413  max = m_SNR;
414  }
415  }
416 
417  NS_LOG_DEBUG("SNR (max) = " << max);
418 
419  return max;
420 }
421 
422 double
424  int historyRange)
425 {
426  double sum = 0;
427  double m_SNR;
428 
429  // Take elements from the list starting at the end
430  auto it = packetList.rbegin();
431  for (int i = 0; i < historyRange; i++, it++)
432  {
433  m_SNR = RxPowerToSNR(GetReceivedPower(it->second.gwList));
434 
435  NS_LOG_DEBUG("Received power: " << GetReceivedPower(it->second.gwList));
436  NS_LOG_DEBUG("m_SNR = " << m_SNR);
437 
438  sum += m_SNR;
439  }
440 
441  double average = sum / historyRange;
442 
443  NS_LOG_DEBUG("SNR (average) = " << average);
444 
445  return average;
446 }
447 
448 int
450 {
451  if (txPower >= 16)
452  {
453  return 0;
454  }
455  else if (txPower >= 14)
456  {
457  return 1;
458  }
459  else if (txPower >= 12)
460  {
461  return 2;
462  }
463  else if (txPower >= 10)
464  {
465  return 3;
466  }
467  else if (txPower >= 8)
468  {
469  return 4;
470  }
471  else if (txPower >= 6)
472  {
473  return 5;
474  }
475  else if (txPower >= 4)
476  {
477  return 6;
478  }
479  else
480  {
481  return 7;
482  }
483 }
484 } // namespace ns3
enum CombiningMethod tpAveraging
uint8_t SfToDr(uint8_t sf)
double GetMinSNR(LoraEndDeviceStatus::ReceivedPacketList packetList, int historyRange)
double GetAverageSNR(LoraEndDeviceStatus::ReceivedPacketList packetList, int historyRange)
enum CombiningMethod historyAveraging
void OnFailedReply(Ptr< LoraEndDeviceStatus > status, Ptr< LoraNetworkStatus > networkStatus)
Method that is called when a packet cannot be sent in the downlink.
double RxPowerToSNR(double transmissionPower)
void OnReceivedPacket(Ptr< const Packet > packet, Ptr< LoraEndDeviceStatus > status, Ptr< LoraNetworkStatus > networkStatus)
Method that is called when a new packet is received by the NetworkServer.
static TypeId GetTypeId(void)
double GetMinTxFromGateways(LoraEndDeviceStatus::GatewayList gwList)
void AdrImplementation(uint8_t *newDataRate, uint8_t *newTxPower, Ptr< LoraEndDeviceStatus > status)
double GetAverageTxFromGateways(LoraEndDeviceStatus::GatewayList gwList)
void BeforeSendingReply(Ptr< LoraEndDeviceStatus > status, Ptr< LoraNetworkStatus > networkStatus)
double GetMaxSNR(LoraEndDeviceStatus::ReceivedPacketList packetList, int historyRange)
int GetTxPowerIndex(int txPower)
double GetMaxTxFromGateways(LoraEndDeviceStatus::GatewayList gwList)
double GetReceivedPower(LoraEndDeviceStatus::GatewayList gwList)
std::list< std::pair< Ptr< const Packet >, ReceivedPacketInfo > > ReceivedPacketList
std::map< Address, PacketInfoPerGw > GatewayList
This class represents the Frame header (FHDR) used in a LoraWAN network.
void SetAsUplink(void)
State that this is an uplink message.
bool GetAdr(void) const
Get the Adr value.
This class represents the Mac header of a LoRaWAN packet.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.