A Discrete-Event Network Simulator
API
wifi-mode.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2006,2007 INRIA
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  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  * Sébastien Deronne <sebastien.deronne@gmail.com>
20  */
21 
22 #include "wifi-mode.h"
23 #include "wifi-tx-vector.h"
24 #include "ns3/simulator.h"
25 #include "ns3/assert.h"
26 #include "ns3/log.h"
27 #include <cmath>
28 
29 namespace ns3 {
30 
40 bool operator == (const WifiMode &a, const WifiMode &b)
41 {
42  return a.GetUid () == b.GetUid ();
43 }
52 std::ostream & operator << (std::ostream & os, const WifiMode &mode)
53 {
54  os << mode.GetUniqueName ();
55  return os;
56 }
65 std::istream & operator >> (std::istream &is, WifiMode &mode)
66 {
67  std::string str;
68  is >> str;
69  mode = WifiModeFactory::GetFactory ()->Search (str);
70  return is;
71 }
72 
73 uint64_t
74 WifiMode::GetPhyRate (uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const
75 {
76  //TODO: nss > 4 not supported yet
77  NS_ASSERT (nss <= 4);
78  uint32_t dataRate, phyRate;
79  dataRate = GetDataRate (channelWidth, isShortGuardInterval, nss);
80  switch (GetCodeRate ())
81  {
82  case WIFI_CODE_RATE_5_6:
83  phyRate = dataRate * 6 / 5;
84  break;
85  case WIFI_CODE_RATE_3_4:
86  phyRate = dataRate * 4 / 3;
87  break;
88  case WIFI_CODE_RATE_2_3:
89  phyRate = dataRate * 3 / 2;
90  break;
91  case WIFI_CODE_RATE_1_2:
92  phyRate = dataRate * 2 / 1;
93  break;
95  default:
96  phyRate = dataRate;
97  break;
98  }
99  return phyRate;
100 }
101 
102 uint64_t
104 {
105  return GetPhyRate (txVector.GetChannelWidth (), txVector.IsShortGuardInterval (), txVector.GetNss ());
106 }
107 
108 uint64_t
109 WifiMode::GetDataRate (uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const
110 {
111  //TODO: nss > 4 not supported yet
112  NS_ASSERT (nss <= 4);
114  uint64_t dataRate = 0;
115  uint32_t usableSubCarriers = 0;
116  double symbolRate = 0;
117  double codingRate = 0;
118  uint32_t numberOfBitsPerSubcarrier = log2 (GetConstellationSize ());
119  if (item->modClass == WIFI_MOD_CLASS_DSSS)
120  {
121  dataRate = ((11000000 / 11) * numberOfBitsPerSubcarrier);
122  }
123  else if (item->modClass == WIFI_MOD_CLASS_HR_DSSS)
124  {
125  dataRate = ((11000000 / 8) * numberOfBitsPerSubcarrier);
126  }
127  else if (item->modClass == WIFI_MOD_CLASS_OFDM || item->modClass == WIFI_MOD_CLASS_ERP_OFDM)
128  {
129  usableSubCarriers = 48;
130  switch (channelWidth)
131  {
132  case 20:
133  default:
134  symbolRate = (1 / 4.0) * 1e6;
135  break;
136  case 10:
137  symbolRate = (1 / 8.0) * 1e6;
138  break;
139  case 5:
140  symbolRate = (1 / 16.0) * 1e6;
141  break;
142  }
143 
144  switch (GetCodeRate ())
145  {
146  case WIFI_CODE_RATE_3_4:
147  codingRate = (3.0 / 4.0);
148  break;
149  case WIFI_CODE_RATE_2_3:
150  codingRate = (2.0 / 3.0);
151  break;
152  case WIFI_CODE_RATE_1_2:
153  codingRate = (1.0 / 2.0);
154  break;
156  default:
157  NS_FATAL_ERROR ("trying to get datarate for a mcs without any coding rate defined");
158  break;
159  }
160 
161  dataRate = lrint (ceil (symbolRate * usableSubCarriers * numberOfBitsPerSubcarrier * codingRate));
162  }
163  else if (item->modClass == WIFI_MOD_CLASS_HT || item->modClass == WIFI_MOD_CLASS_VHT)
164  {
165  if (item->modClass == WIFI_MOD_CLASS_VHT && item->mcsValue == 9 && nss != 3)
166  {
167  NS_ASSERT_MSG (channelWidth != 20, "VHT MCS 9 forbidden at 20 MHz (only allowed when NSS = 3)");
168  }
169  if (item->modClass == WIFI_MOD_CLASS_VHT && item->mcsValue == 6 && nss == 3)
170  {
171  NS_ASSERT_MSG (channelWidth != 80, "VHT MCS 6 forbidden at 80 MHz when NSS = 3");
172  }
173 
174  if (!isShortGuardInterval)
175  {
176  symbolRate = (1 / 4.0) * 1e6;
177  }
178  else
179  {
180  symbolRate = (1 / 3.6) * 1e6;
181  }
182 
183  switch (channelWidth)
184  {
185  case 20:
186  default:
187  usableSubCarriers = 52;
188  break;
189  case 40:
190  usableSubCarriers = 108;
191  break;
192  case 80:
193  usableSubCarriers = 234;
194  break;
195  case 160:
196  usableSubCarriers = 468;
197  break;
198  }
199 
200  switch (GetCodeRate ())
201  {
202  case WIFI_CODE_RATE_5_6:
203  codingRate = (5.0 / 6.0);
204  break;
205  case WIFI_CODE_RATE_3_4:
206  codingRate = (3.0 / 4.0);
207  break;
208  case WIFI_CODE_RATE_2_3:
209  codingRate = (2.0 / 3.0);
210  break;
211  case WIFI_CODE_RATE_1_2:
212  codingRate = (1.0 / 2.0);
213  break;
215  default:
216  NS_FATAL_ERROR ("trying to get datarate for a mcs without any coding rate defined with nss: " << (uint16_t) nss);
217  break;
218  }
219 
220  dataRate = lrint (ceil (symbolRate * usableSubCarriers * numberOfBitsPerSubcarrier * codingRate));
221  }
222  else
223  {
224  NS_ASSERT ("undefined datarate for the modulation class!");
225  }
226  dataRate *= nss; // number of spatial streams
227  return dataRate;
228 }
229 
230 uint64_t
232 {
233  return GetDataRate (txVector.GetChannelWidth (), txVector.IsShortGuardInterval (), txVector.GetNss ());
234 }
235 
236 enum WifiCodeRate
238 {
240  if (item->modClass == WIFI_MOD_CLASS_HT)
241  {
242  switch (item->mcsValue % 8)
243  {
244  case 0:
245  case 1:
246  case 3:
247  return WIFI_CODE_RATE_1_2;
248  case 2:
249  case 4:
250  case 6:
251  return WIFI_CODE_RATE_3_4;
252  case 5:
253  return WIFI_CODE_RATE_2_3;
254  case 7:
255  return WIFI_CODE_RATE_5_6;
256  default:
258  }
259  }
260  else if (item->modClass == WIFI_MOD_CLASS_VHT)
261  {
262  switch (item->mcsValue)
263  {
264  case 0:
265  case 1:
266  case 3:
267  return WIFI_CODE_RATE_1_2;
268  case 2:
269  case 4:
270  case 6:
271  case 8:
272  return WIFI_CODE_RATE_3_4;
273  case 5:
274  return WIFI_CODE_RATE_2_3;
275  case 7:
276  case 9:
277  return WIFI_CODE_RATE_5_6;
278  default:
280  }
281  }
282  else
283  {
284  return item->codingRate;
285  }
286 }
287 
288 uint16_t
290 {
292  if (item->modClass == WIFI_MOD_CLASS_HT)
293  {
294  switch (item->mcsValue % 8)
295  {
296  case 0:
297  return 2;
298  case 1:
299  case 2:
300  return 4;
301  case 3:
302  case 4:
303  return 16;
304  case 5:
305  case 6:
306  case 7:
307  return 64;
308  default:
309  return 0;
310  }
311  }
312  else if (item->modClass == WIFI_MOD_CLASS_VHT)
313  {
314  switch (item->mcsValue)
315  {
316  case 0:
317  return 2;
318  case 1:
319  case 2:
320  return 4;
321  case 3:
322  case 4:
323  return 16;
324  case 5:
325  case 6:
326  case 7:
327  return 64;
328  case 8:
329  case 9:
330  return 256;
331  default:
332  return 0;
333  }
334  }
335  else
336  {
337  return item->constellationSize;
338  }
339 }
340 
341 std::string
343 {
344  //needed for ostream printing of the invalid mode
346  return item->uniqueUid;
347 }
348 
349 bool
351 {
353  return item->isMandatory;
354 }
355 
356 uint8_t
358 {
360  if (item->modClass == WIFI_MOD_CLASS_HT || item->modClass == WIFI_MOD_CLASS_VHT)
361  {
362  return item->mcsValue;
363  }
364  else
365  {
366  //We should not go here!
367  NS_ASSERT (false);
368  return 0;
369  }
370 }
371 
372 uint32_t
373 WifiMode::GetUid (void) const
374 {
375  return m_uid;
376 }
377 
380 {
382  return item->modClass;
383 }
384 
385 uint64_t
387 {
388  uint64_t dataRate;
390  if (item->modClass == WIFI_MOD_CLASS_HT || item->modClass == WIFI_MOD_CLASS_VHT)
391  {
392  WifiCodeRate codeRate = GetCodeRate();
393  switch(GetConstellationSize())
394  {
395  case 2:
396  if (codeRate == WIFI_CODE_RATE_1_2)
397  dataRate = 6000000;
398  else if (codeRate == WIFI_CODE_RATE_3_4)
399  dataRate = 9000000;
400  else
401  NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
402  break;
403  case 4:
404  if (codeRate == WIFI_CODE_RATE_1_2)
405  dataRate = 12000000;
406  else if (codeRate == WIFI_CODE_RATE_3_4)
407  dataRate = 18000000;
408  else
409  NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
410  break;
411  case 16:
412  if (codeRate == WIFI_CODE_RATE_1_2)
413  dataRate = 24000000;
414  else if (codeRate == WIFI_CODE_RATE_3_4)
415  dataRate = 36000000;
416  else
417  NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
418  break;
419  case 64:
420  if (codeRate == WIFI_CODE_RATE_1_2 || codeRate == WIFI_CODE_RATE_2_3)
421  dataRate = 48000000;
422  else if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
423  dataRate = 54000000;
424  else
425  NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
426  break;
427  case 256:
428  if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
429  dataRate = 54000000;
430  else
431  NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
432  break;
433  default:
434  NS_FATAL_ERROR ("Wrong constellation size");
435  }
436  }
437  else
438  {
439  NS_FATAL_ERROR ("Trying to get reference rate for a non-HT rate");
440  }
441  return dataRate;
442 }
443 
444 bool
446 {
447  WifiCodeRate codeRate = mode.GetCodeRate ();
448  switch (GetCodeRate ())
449  {
450  case WIFI_CODE_RATE_1_2:
451  return false; //This is the smallest code rate.
452  case WIFI_CODE_RATE_2_3:
453  return (codeRate == WIFI_CODE_RATE_1_2);
454  case WIFI_CODE_RATE_3_4:
455  return (codeRate == WIFI_CODE_RATE_1_2 || codeRate == WIFI_CODE_RATE_2_3);
456  case WIFI_CODE_RATE_5_6:
457  return (codeRate == WIFI_CODE_RATE_1_2 || codeRate == WIFI_CODE_RATE_2_3 || codeRate == WIFI_CODE_RATE_3_4);
458  default:
459  NS_FATAL_ERROR ("Wifi Code Rate not defined");
460  return false;
461  }
462 }
463 
464 bool
466 {
468  switch(item->modClass)
469  {
470  case WIFI_MOD_CLASS_DSSS:
472  {
473  return (GetConstellationSize () > mode.GetConstellationSize ());
474  }
475  else
476  {
477  return false;
478  }
481  {
482  return true;
483  }
484  else
485  {
486  return (GetConstellationSize () > mode.GetConstellationSize ());
487  }
489  case WIFI_MOD_CLASS_OFDM:
490  case WIFI_MOD_CLASS_HT:
491  case WIFI_MOD_CLASS_VHT:
493  {
494  return true;
495  }
496  else if (mode.GetModulationClass () == WIFI_MOD_CLASS_HR_DSSS)
497  {
498  return (mode.GetConstellationSize () > GetConstellationSize ());
499  }
500  else
501  {
503  {
504  return true;
505  }
506  else if (GetConstellationSize () == mode.GetConstellationSize ())
507  {
508  return IsHigherCodeRate (mode);
509  }
510  else
511  {
512  return false;
513  }
514  }
515  default:
516  NS_FATAL_ERROR ("Modulation class not defined");
517  return false;
518  }
519 }
520 
522  : m_uid (0)
523 {
524 }
525 
526 WifiMode::WifiMode (uint32_t uid)
527  : m_uid (uid)
528 {
529 }
530 
531 WifiMode::WifiMode (std::string name)
532 {
533  *this = WifiModeFactory::GetFactory ()->Search (name);
534 }
535 
537 
539 {
540 }
541 
542 WifiMode
543 WifiModeFactory::CreateWifiMode (std::string uniqueName,
544  enum WifiModulationClass modClass,
545  bool isMandatory,
546  enum WifiCodeRate codingRate,
547  uint16_t constellationSize)
548 {
549  WifiModeFactory *factory = GetFactory ();
550  uint32_t uid = factory->AllocateUid (uniqueName);
551  WifiModeItem *item = factory->Get (uid);
552  item->uniqueUid = uniqueName;
553  item->modClass = modClass;
554  //The modulation class for this WifiMode must be valid.
555  NS_ASSERT (modClass != WIFI_MOD_CLASS_UNKNOWN);
556  item->codingRate = codingRate;
557 
558  //Check for compatibility between modulation class and coding
559  //rate. If modulation class is DSSS then coding rate must be
560  //undefined, and vice versa. I could have done this with an
561  //assertion, but it seems better to always give the error (i.e.,
562  //not only in non-optimised builds) and the cycles that extra test
563  //here costs are only suffered at simulation setup.
564  if ((codingRate == WIFI_CODE_RATE_UNDEFINED) && modClass != WIFI_MOD_CLASS_DSSS && modClass != WIFI_MOD_CLASS_HR_DSSS)
565  {
566  NS_FATAL_ERROR ("Error in creation of WifiMode named " << uniqueName << std::endl
567  << "Code rate must be WIFI_CODE_RATE_UNDEFINED iff Modulation Class is WIFI_MOD_CLASS_DSSS or WIFI_MOD_CLASS_HR_DSSS");
568  }
569 
570  item->constellationSize = constellationSize;
571  item->isMandatory = isMandatory;
572 
573  NS_ASSERT (modClass != WIFI_MOD_CLASS_HT && modClass != WIFI_MOD_CLASS_VHT);
574  //fill unused mcs item with a dummy value
575  item->mcsValue = 0;
576 
577  return WifiMode (uid);
578 }
579 
580 WifiMode
581 WifiModeFactory::CreateWifiMcs (std::string uniqueName,
582  uint8_t mcsValue,
583  enum WifiModulationClass modClass)
584 {
585  WifiModeFactory *factory = GetFactory ();
586  uint32_t uid = factory->AllocateUid (uniqueName);
587  WifiModeItem *item = factory->Get (uid);
588  item->uniqueUid = uniqueName;
589  item->modClass = modClass;
590 
591  //The modulation class must be either HT or VHT
592  NS_ASSERT (modClass == WIFI_MOD_CLASS_HT || modClass == WIFI_MOD_CLASS_VHT);
593 
594  item->mcsValue = mcsValue;
595  //fill unused items with dummy values
596  item->constellationSize = 0;
598  item->isMandatory = false;
599 
600  return WifiMode (uid);
601 }
602 
603 WifiMode
604 WifiModeFactory::Search (std::string name)
605 {
606  WifiModeItemList::const_iterator i;
607  uint32_t j = 0;
608  for (i = m_itemList.begin (); i != m_itemList.end (); i++)
609  {
610  if (i->uniqueUid == name)
611  {
612  return WifiMode (j);
613  }
614  j++;
615  }
616 
617  //If we get here then a matching WifiMode was not found above. This
618  //is a fatal problem, but we try to be helpful by displaying the
619  //list of WifiModes that are supported.
620  NS_LOG_UNCOND ("Could not find match for WifiMode named \""
621  << name << "\". Valid options are:");
622  for (i = m_itemList.begin (); i != m_itemList.end (); i++)
623  {
624  NS_LOG_UNCOND (" " << i->uniqueUid);
625  }
626  //Empty fatal error to die. We've already unconditionally logged
627  //the helpful information.
628  NS_FATAL_ERROR ("");
629 
630  //This next line is unreachable because of the fatal error
631  //immediately above, and that is fortunate, because we have no idea
632  //what is in WifiMode (0), but we do know it is not what our caller
633  //has requested by name. It's here only because it's the safest
634  //thing that'll give valid code.
635  return WifiMode (0);
636 }
637 
638 uint32_t
639 WifiModeFactory::AllocateUid (std::string uniqueUid)
640 {
641  uint32_t j = 0;
642  for (WifiModeItemList::const_iterator i = m_itemList.begin ();
643  i != m_itemList.end (); i++)
644  {
645  if (i->uniqueUid == uniqueUid)
646  {
647  return j;
648  }
649  j++;
650  }
651  uint32_t uid = m_itemList.size ();
652  m_itemList.push_back (WifiModeItem ());
653  return uid;
654 }
655 
657 WifiModeFactory::Get (uint32_t uid)
658 {
659  NS_ASSERT (uid < m_itemList.size ());
660  return &m_itemList[uid];
661 }
662 
665 {
666  static bool isFirstTime = true;
667  static WifiModeFactory factory;
668  if (isFirstTime)
669  {
670  uint32_t uid = factory.AllocateUid ("Invalid-WifiMode");
671  WifiModeItem *item = factory.Get (uid);
672  item->uniqueUid = "Invalid-WifiMode";
674  item->constellationSize = 0;
676  item->isMandatory = false;
677  item->mcsValue = 0;
678  isFirstTime = false;
679  }
680  return &factory;
681 }
682 
683 } //namespace ns3
std::istream & operator>>(std::istream &is, Angles &a)
initialize a struct Angles from input
Definition: angles.cc:48
WifiMode()
Create an invalid WifiMode.
Definition: wifi-mode.cc:521
ERP-OFDM PHY (19.5)
Definition: wifi-mode.h:58
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiCodeRate
This enumeration defines the various convolutional coding rates used for the OFDM transmission modes ...
Definition: wifi-mode.h:74
#define ATTRIBUTE_HELPER_CPP(type)
Define the attribute value, accessor and checkers for class type.
enum WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:379
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
bool IsShortGuardInterval(void) const
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
VHT PHY (Clause 22)
Definition: wifi-mode.h:64
HR/DSSS PHY (Clause 18)
Definition: wifi-mode.h:52
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:99
bool IsMandatory(void) const
Definition: wifi-mode.cc:350
static WifiMode CreateWifiMcs(std::string uniqueName, uint8_t mcsValue, enum WifiModulationClass modClass)
Definition: wifi-mode.cc:581
Modulation class unknown or unspecified.
Definition: wifi-mode.h:44
WifiModeItem * Get(uint32_t uid)
Return a WifiModeItem at the given uid index.
Definition: wifi-mode.cc:657
uint64_t GetPhyRate(uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const
Definition: wifi-mode.cc:74
uint16_t GetConstellationSize(void) const
Definition: wifi-mode.cc:289
bool IsHigherDataRate(WifiMode mode) const
Definition: wifi-mode.cc:465
uint32_t m_uid
Definition: wifi-mode.h:219
enum WifiCodeRate GetCodeRate(void) const
Definition: wifi-mode.cc:237
uint32_t GetChannelWidth(void) const
HT PHY (Clause 20)
Definition: wifi-mode.h:62
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:357
std::string GetUniqueName(void) const
Definition: wifi-mode.cc:342
WifiModeItemList m_itemList
Definition: wifi-mode.h:342
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
Every class exported by the ns3 library is enclosed in the ns3 namespace.
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionaly.
uint64_t GetDataRate(uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const
Definition: wifi-mode.cc:109
friend class WifiMode
Definition: wifi-mode.h:287
uint64_t GetNonHtReferenceRate(void) const
Definition: wifi-mode.cc:386
static WifiMode CreateWifiMode(std::string uniqueName, enum WifiModulationClass modClass, bool isMandatory, enum WifiCodeRate codingRate, uint16_t constellationSize)
Definition: wifi-mode.cc:543
#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:90
No explicit coding (e.g., DSSS rates)
Definition: wifi-mode.h:77
create WifiMode class instances and keep track of them.
Definition: wifi-mode.h:246
uint8_t GetNss(void) const
WifiModulationClass
This enumeration defines the modulation classes per (Table 9-4 "Modulation classes"; IEEE 802...
Definition: wifi-mode.h:40
bool IsHigherCodeRate(WifiMode mode) const
Definition: wifi-mode.cc:445
OFDM PHY (Clause 17)
Definition: wifi-mode.h:60
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.cc:95
static WifiModeFactory * GetFactory()
Return a WifiModeFactory.
Definition: wifi-mode.cc:664
uint32_t AllocateUid(std::string uniqueUid)
Allocate a WifiModeItem from a given uniqueUid.
Definition: wifi-mode.cc:639
enum WifiModulationClass modClass
Definition: wifi-mode.h:306
uint32_t GetUid(void) const
Definition: wifi-mode.cc:373
WifiMode Search(std::string name)
Search and return WifiMode from a given name.
Definition: wifi-mode.cc:604
This is the data associated to a unique WifiMode.
Definition: wifi-mode.h:303
DSSS PHY (Clause 15)
Definition: wifi-mode.h:50