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