A Discrete-Event Network Simulator
API
he-ru.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018
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: Stefano Avallone <stavallo@unina.it>
19  */
20 
21 #include "he-ru.h"
22 #include "ns3/abort.h"
23 #include "ns3/assert.h"
24 
25 namespace ns3 {
26 
28 {
29  // RUs in a 20 MHz HE PPDU (Table 28-6)
30  { {20, HeRu::RU_26_TONE}, { /* 1 */ {{-121, -96}},
31  /* 2 */ {{-95, -70}},
32  /* 3 */ {{-68, -43}},
33  /* 4 */ {{-42, -17}},
34  /* 5 */ {{-16, -4}, {4, 16}},
35  /* 6 */ {{17, 42}},
36  /* 7 */ {{43, 68}},
37  /* 8 */ {{70, 95}},
38  /* 9 */ {{96, 121}} } },
39  { {20, HeRu::RU_52_TONE}, { /* 1 */ {{-121, -70}},
40  /* 2 */ {{-68, -17}},
41  /* 3 */ {{17, 68}},
42  /* 4 */ {{70, 121}} } },
43  { {20, HeRu::RU_106_TONE}, { /* 1 */ {{-122, -17}},
44  /* 2 */ {{17, 122}} } },
45  { {20, HeRu::RU_242_TONE}, { /* 1 */ {{-122, -2}, {2, 122}} } },
46  // RUs in a 40 MHz HE PPDU (Table 28-7)
47  { {40, HeRu::RU_26_TONE}, { /* 1 */ {{-243, -218}},
48  /* 2 */ {{-217, -192}},
49  /* 3 */ {{-189, -164}},
50  /* 4 */ {{-163, -138}},
51  /* 5 */ {{-136, -111}},
52  /* 6 */ {{-109, -84}},
53  /* 7 */ {{-83, -58}},
54  /* 8 */ {{-55, -30}},
55  /* 9 */ {{-29, -4}},
56  /* 10 */ {{4, 29}},
57  /* 11 */ {{30, 55}},
58  /* 12 */ {{58, 83}},
59  /* 13 */ {{84, 109}},
60  /* 14 */ {{111, 136}},
61  /* 15 */ {{138, 163}},
62  /* 16 */ {{164, 189}},
63  /* 17 */ {{192, 217}},
64  /* 18 */ {{218, 243}} } },
65  { {40, HeRu::RU_52_TONE}, { /* 1 */ {{-243, -192}},
66  /* 2 */ {{-189, -138}},
67  /* 3 */ {{-109, -58}},
68  /* 4 */ {{-55, -4}},
69  /* 5 */ {{4, 55}},
70  /* 6 */ {{58, 109}},
71  /* 7 */ {{138, 189}},
72  /* 8 */ {{192, 243}} } },
73  { {40, HeRu::RU_106_TONE}, { /* 1 */ {{-243, -138}},
74  /* 2 */ {{-109, -4}},
75  /* 3 */ {{4, 109}},
76  /* 4 */ {{138, 243}} } },
77  { {40, HeRu::RU_242_TONE}, { /* 1 */ {{-244, -3}},
78  /* 2 */ {{3, 244}} } },
79  { {40, HeRu::RU_484_TONE}, { /* 1 */ {{-244, -3}, {3, 244}} } },
80  // RUs in an 80 MHz HE PPDU (Table 28-8)
81  { {80, HeRu::RU_26_TONE}, { /* 1 */ {{-499, -474}},
82  /* 2 */ {{-473, -448}},
83  /* 3 */ {{-445, -420}},
84  /* 4 */ {{-419, -394}},
85  /* 5 */ {{-392, -367}},
86  /* 6 */ {{-365, -340}},
87  /* 7 */ {{-339, -314}},
88  /* 8 */ {{-311, -286}},
89  /* 9 */ {{-285, -260}},
90  /* 10 */ {{-257, -232}},
91  /* 11 */ {{-231, -206}},
92  /* 12 */ {{-203, -178}},
93  /* 13 */ {{-177, -152}},
94  /* 14 */ {{-150, -125}},
95  /* 15 */ {{-123, -98}},
96  /* 16 */ {{-97, -72}},
97  /* 17 */ {{-69, -44}},
98  /* 18 */ {{-43, -18}},
99  /* 19 */ {{-16, -4}, {4, 16}},
100  /* 20 */ {{18, 43}},
101  /* 21 */ {{44, 69}},
102  /* 22 */ {{72, 97}},
103  /* 23 */ {{98, 123}},
104  /* 24 */ {{125, 150}},
105  /* 25 */ {{152, 177}},
106  /* 26 */ {{178, 203}},
107  /* 27 */ {{206, 231}},
108  /* 28 */ {{232, 257}},
109  /* 29 */ {{260, 285}},
110  /* 30 */ {{286, 311}},
111  /* 31 */ {{314, 339}},
112  /* 32 */ {{340, 365}},
113  /* 33 */ {{367, 392}},
114  /* 34 */ {{394, 419}},
115  /* 35 */ {{420, 445}},
116  /* 36 */ {{448, 473}},
117  /* 37 */ {{474, 499}} } },
118  { {80, HeRu::RU_52_TONE}, { /* 1 */ {{-499, -448}},
119  /* 2 */ {{-445, -394}},
120  /* 3 */ {{-365, -314}},
121  /* 4 */ {{-311, -260}},
122  /* 5 */ {{-257, -206}},
123  /* 6 */ {{-203, -152}},
124  /* 7 */ {{-123, -72}},
125  /* 8 */ {{-69, -18}},
126  /* 9 */ {{18, 69}},
127  /* 10 */ {{72, 123}},
128  /* 11 */ {{152, 203}},
129  /* 12 */ {{206, 257}},
130  /* 13 */ {{260, 311}},
131  /* 14 */ {{314, 365}},
132  /* 15 */ {{394, 445}},
133  /* 16 */ {{448, 499}} } },
134  { {80, HeRu::RU_106_TONE}, { /* 1 */ {{-499, -394}},
135  /* 2 */ {{-365, -260}},
136  /* 3 */ {{-257, -152}},
137  /* 4 */ {{-123, -18}},
138  /* 5 */ {{18, 123}},
139  /* 6 */ {{152, 257}},
140  /* 7 */ {{260, 365}},
141  /* 8 */ {{394, 499}} } },
142  { {80, HeRu::RU_242_TONE}, { /* 1 */ {{-500, -259}},
143  /* 2 */ {{-258, -17}},
144  /* 3 */ {{17, 258}},
145  /* 4 */ {{259, 500}} } },
146  { {80, HeRu::RU_484_TONE}, { /* 1 */ {{-500, -17}},
147  /* 2 */ {{17, 500}} } },
148  { {80, HeRu::RU_996_TONE}, { /* 1 */ {{-500, -3}, {3, 500}} } }
149 };
150 
151 
153  : m_index (0) // indicates undefined RU
154 {
155 }
156 
157 HeRu::RuSpec::RuSpec (RuType ruType, std::size_t index, bool primary80MHz)
158  : m_ruType (ruType),
159  m_index (index),
160  m_primary80MHz (primary80MHz),
161  m_phyIndex (0)
162 {
163  NS_ABORT_MSG_IF (index == 0, "Index cannot be zero");
164 }
165 
168 {
169  NS_ABORT_MSG_IF (m_index == 0, "Undefined RU");
170  return m_ruType;
171 }
172 
173 std::size_t
175 {
176  NS_ABORT_MSG_IF (m_index == 0, "Undefined RU");
177  return m_index;
178 }
179 
180 bool
182 {
183  NS_ABORT_MSG_IF (m_index == 0, "Undefined RU");
184  return m_primary80MHz;
185 }
186 
187 void
188 HeRu::RuSpec::SetPhyIndex (uint16_t bw, uint8_t p20Index)
189 {
190  bool primary80IsLower80 = (p20Index < bw / 40);
191 
192  if (bw < 160
193  || m_ruType == HeRu::RU_2x996_TONE
194  || (primary80IsLower80 && m_primary80MHz)
195  || (!primary80IsLower80 && !m_primary80MHz))
196  {
197  m_phyIndex = m_index;
198  }
199  else
200  {
201  m_phyIndex = m_index + GetNRus (bw, m_ruType) / 2;
202  }
203 }
204 
205 bool
207 {
208  return (m_phyIndex != 0);
209 }
210 
211 std::size_t
213 {
214  NS_ABORT_MSG_IF (m_phyIndex == 0, "RU PHY index not set");
215  return m_phyIndex;
216 }
217 
218 std::size_t
219 HeRu::GetNRus (uint16_t bw, RuType ruType)
220 {
221  if (bw == 160 && ruType == RU_2x996_TONE)
222  {
223  return 1;
224  }
225 
226  // if the bandwidth is 160MHz, search for the number of RUs available
227  // in 80MHz and double the result.
228  auto it = m_heRuSubcarrierGroups.find ({(bw == 160 ? 80 : bw), ruType});
229 
230  if (it == m_heRuSubcarrierGroups.end ())
231  {
232  return 0;
233  }
234 
235  return (bw == 160 ? 2 : 1) * it->second.size ();
236 }
237 
238 std::vector<HeRu::RuSpec>
239 HeRu::GetRusOfType (uint16_t bw, HeRu::RuType ruType)
240 {
241  if (ruType == HeRu::RU_2x996_TONE)
242  {
243  NS_ASSERT (bw >= 160);
244  return {{ruType, 1, true}};
245  }
246 
247  std::vector<HeRu::RuSpec> ret;
248  std::vector<bool> primary80MHzSet {true};
249 
250  if (bw == 160)
251  {
252  primary80MHzSet.push_back (false);
253  bw = 80;
254  }
255 
256  for (auto primary80MHz : primary80MHzSet)
257  {
258  for (std::size_t ruIndex = 1; ruIndex <= HeRu::m_heRuSubcarrierGroups.at ({bw, ruType}).size (); ruIndex++)
259  {
260  ret.push_back ({ruType, ruIndex, primary80MHz});
261  }
262  }
263  return ret;
264 }
265 
266 std::vector<HeRu::RuSpec>
268 {
269  std::vector<std::size_t> indices;
270 
271  if (ruType == HeRu::RU_52_TONE || ruType == HeRu::RU_106_TONE)
272  {
273  if (bw == 20)
274  {
275  indices.push_back (5);
276  }
277  else if (bw == 40)
278  {
279  indices.insert (indices.end (), {5, 14});
280  }
281  else if (bw >= 80)
282  {
283  indices.insert (indices.end (), {5, 14, 19, 24, 33});
284  }
285  }
286  else if (ruType == HeRu::RU_242_TONE || ruType == HeRu::RU_484_TONE)
287  {
288  if (bw >= 80)
289  {
290  indices.push_back (19);
291  }
292  }
293 
294  std::vector<HeRu::RuSpec> ret;
295  std::vector<bool> primary80MHzSet {true};
296 
297  if (bw == 160)
298  {
299  primary80MHzSet.push_back (false);
300  }
301 
302  for (auto primary80MHz : primary80MHzSet)
303  {
304  for (const auto& index : indices)
305  {
306  ret.push_back ({HeRu::RU_26_TONE, index, primary80MHz});
307  }
308  }
309  return ret;
310 }
311 
313 HeRu::GetSubcarrierGroup (uint16_t bw, RuType ruType, std::size_t phyIndex)
314 {
315  if (ruType == HeRu::RU_2x996_TONE) //handle special case of RU covering 160 MHz channel
316  {
317  NS_ABORT_MSG_IF (bw != 160, "2x996 tone RU can only be used on 160 MHz band");
318  return {{-1012, -3}, {3, 1012}};
319  }
320 
321  // Determine the shift to apply to tone indices for 160 MHz channel (i.e. -1012 to 1012), since
322  // m_heRuSubcarrierGroups contains indices for lower 80 MHz subchannel (i.e. from -500 to 500).
323  // The phyIndex is used to that aim.
324  std::size_t indexInLower80MHz = phyIndex;
325  std::size_t numRus = GetNRus (bw, ruType);
326  int16_t shift = (bw == 160) ? -512 : 0;
327  if (bw == 160 && phyIndex > (numRus / 2))
328  {
329  // The provided index is that of the upper 80 MHz subchannel
330  indexInLower80MHz = phyIndex - (numRus / 2);
331  shift = 512;
332  }
333 
334  auto it = m_heRuSubcarrierGroups.find ({(bw == 160 ? 80 : bw), ruType});
335 
336  NS_ABORT_MSG_IF (it == m_heRuSubcarrierGroups.end (), "RU not found");
337  NS_ABORT_MSG_IF (indexInLower80MHz > it->second.size (), "RU index not available");
338 
339  SubcarrierGroup group = it->second.at (indexInLower80MHz - 1);
340  if (bw == 160)
341  {
342  for (auto & range : group)
343  {
344  range.first += shift;
345  range.second += shift;
346  }
347  }
348  return group;
349 }
350 
351 bool
352 HeRu::DoesOverlap (uint16_t bw, RuSpec ru, const std::vector<RuSpec> &v)
353 {
354  // A 2x996-tone RU spans 160 MHz, hence it overlaps with any other RU
355  if (bw == 160 && ru.GetRuType () == RU_2x996_TONE && !v.empty ())
356  {
357  return true;
358  }
359 
360  // This function may be called by the MAC layer, hence the PHY index may have
361  // not been set yet. Hence, we pass the "MAC" index to GetSubcarrierGroup instead
362  // of the PHY index. This is fine because we compare the primary 80 MHz bands of
363  // the two RUs below.
364  SubcarrierGroup rangesRu = GetSubcarrierGroup (bw, ru.GetRuType (), ru.GetIndex ());
365  for (auto& p : v)
366  {
367  if (ru.GetPrimary80MHz () != p.GetPrimary80MHz ())
368  {
369  // the two RUs are located in distinct 80MHz bands
370  continue;
371  }
372  for (const auto& rangeRu : rangesRu)
373  {
374  SubcarrierGroup rangesP = GetSubcarrierGroup (bw, p.GetRuType (), p.GetIndex ());
375  for (auto& rangeP : rangesP)
376  {
377  if (rangeP.second >= rangeRu.first && rangeRu.second >= rangeP.first)
378  {
379  return true;
380  }
381  }
382  }
383  }
384  return false;
385 }
386 
387 bool
388 HeRu::DoesOverlap (uint16_t bw, RuSpec ru, const SubcarrierGroup &toneRanges)
389 {
390  for (const auto & range : toneRanges)
391  {
392  if (bw == 160 && ru.GetRuType () == RU_2x996_TONE)
393  {
394  return true;
395  }
396 
397  SubcarrierGroup rangesRu = GetSubcarrierGroup (bw, ru.GetRuType (), ru.GetPhyIndex ());
398  for (auto& r : rangesRu)
399  {
400  if (range.second >= r.first && r.second >= range.first)
401  {
402  return true;
403  }
404  }
405  }
406  return false;
407 }
408 
410 HeRu::FindOverlappingRu (uint16_t bw, RuSpec referenceRu, RuType searchedRuType)
411 {
412  std::size_t numRus = HeRu::GetNRus (bw, searchedRuType);
413 
414  std::size_t numRusPer80Mhz;
415  std::vector<bool> primary80MhzFlags;
416  if (bw == 160)
417  {
418  primary80MhzFlags.push_back (true);
419  primary80MhzFlags.push_back (false);
420  numRusPer80Mhz = (searchedRuType == HeRu::RU_2x996_TONE ? 1 : numRus / 2);
421  }
422  else
423  {
424  primary80MhzFlags.push_back (referenceRu.GetPrimary80MHz ());
425  numRusPer80Mhz = numRus;
426  }
427 
428  for (const auto primary80MHz : primary80MhzFlags)
429  {
430  std::size_t index = 1;
431  for (std::size_t indexPer80Mhz = 1; indexPer80Mhz <= numRusPer80Mhz; ++indexPer80Mhz, ++index)
432  {
433  RuSpec searchedRu (searchedRuType, index, primary80MHz);
434  if (DoesOverlap (bw, referenceRu, {searchedRu}))
435  {
436  return searchedRu;
437  }
438  }
439  }
440  NS_ABORT_MSG ("The searched RU type " << searchedRuType << " was not found for bw=" << bw << " and referenceRu=" << referenceRu);
441  return HeRu::RuSpec ();
442 }
443 
444 std::ostream& operator<< (std::ostream& os, const HeRu::RuType &ruType)
445 {
446  switch (ruType)
447  {
448  case HeRu::RU_26_TONE:
449  os << "26-tones";
450  break;
451  case HeRu::RU_52_TONE:
452  os << "52-tones";
453  break;
454  case HeRu::RU_106_TONE:
455  os << "106-tones";
456  break;
457  case HeRu::RU_242_TONE:
458  os << "242-tones";
459  break;
460  case HeRu::RU_484_TONE:
461  os << "484-tones";
462  break;
463  case HeRu::RU_996_TONE:
464  os << "996-tones";
465  break;
466  case HeRu::RU_2x996_TONE:
467  os << "2x996-tones";
468  break;
469  default:
470  NS_FATAL_ERROR ("Unknown RU type");
471  }
472  return os;
473 }
474 
475 std::ostream& operator<< (std::ostream& os, const HeRu::RuSpec &ru)
476 {
477  os << "RU{" << ru.GetRuType () << "/" << ru.GetIndex () << "/" << (ru.GetPrimary80MHz () ? "primary80MHz" : "secondary80MHz");
478  if (ru.IsPhyIndexSet ())
479  {
480  os << "[" << ru.GetPhyIndex () << "]";
481  }
482  os << "}";
483  return os;
484 }
485 
486 uint16_t
488 {
489  switch (ruType)
490  {
491  case RU_26_TONE:
492  return 2;
493  case RU_52_TONE:
494  return 4;
495  case RU_106_TONE:
496  return 8;
497  case RU_242_TONE:
498  return 20;
499  case RU_484_TONE:
500  return 40;
501  case RU_996_TONE:
502  return 80;
503  case RU_2x996_TONE:
504  return 160;
505  default:
506  NS_ABORT_MSG ("RU type " << ruType << " not found");
507  return 0;
508  }
509 }
510 
512 HeRu::GetRuType (uint16_t bandwidth)
513 {
514  switch (bandwidth)
515  {
516  case 2:
517  return RU_26_TONE;
518  case 4:
519  return RU_52_TONE;
520  case 8:
521  return RU_106_TONE;
522  case 20:
523  return RU_242_TONE;
524  case 40:
525  return RU_484_TONE;
526  case 80:
527  return RU_996_TONE;
528  case 160:
529  return RU_2x996_TONE;
530  default:
531  NS_ABORT_MSG (bandwidth << " MHz bandwidth not found");
532  return RU_242_TONE;
533  }
534 }
535 
537 HeRu::GetEqualSizedRusForStations (uint16_t bandwidth, std::size_t& nStations,
538  std::size_t& nCentral26TonesRus)
539 {
540  RuType ruType;
541  uint8_t nRusAssigned = 0;
542 
543  // iterate over all the available RU types
544  for (auto& ru : m_heRuSubcarrierGroups)
545  {
546  if (ru.first.first == bandwidth && ru.second.size () <= nStations)
547  {
548  ruType = ru.first.second;
549  nRusAssigned = ru.second.size ();
550  break;
551  }
552  else if (bandwidth == 160 && ru.first.first == 80 && (2 * ru.second.size () <= nStations))
553  {
554  ruType = ru.first.second;
555  nRusAssigned = 2 * ru.second.size ();
556  break;
557  }
558  }
559  if (nRusAssigned == 0)
560  {
561  NS_ABORT_IF (bandwidth != 160 || nStations != 1);
562  nRusAssigned = 1;
563  ruType = RU_2x996_TONE;
564  }
565 
566  nStations = nRusAssigned;
567 
568  switch (ruType)
569  {
570  case RU_52_TONE:
571  case RU_106_TONE:
572  if (bandwidth == 20)
573  {
574  nCentral26TonesRus = 1;
575  }
576  else if (bandwidth == 40)
577  {
578  nCentral26TonesRus = 2;
579  }
580  else
581  {
582  nCentral26TonesRus = 5;
583  }
584  break;
585  case RU_242_TONE:
586  case RU_484_TONE:
587  nCentral26TonesRus = (bandwidth >= 80 ? 1 : 0);
588  break;
589  default:
590  nCentral26TonesRus = 0;
591  }
592 
593  if (bandwidth == 160)
594  {
595  nCentral26TonesRus *= 2;
596  }
597 
598  return ruType;
599 }
600 
601 
602 } //namespace ns3
std::vector< SubcarrierRange > SubcarrierGroup
a vector of subcarrier ranges defining a subcarrier group
Definition: he-ru.h:56
RuSpec()
Default constructor.
Definition: he-ru.cc:152
RU Specification.
Definition: he-ru.h:67
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#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
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
bool GetPrimary80MHz(void) const
Get the primary 80 MHz flag.
Definition: he-ru.cc:181
static bool DoesOverlap(uint16_t bw, RuSpec ru, const std::vector< RuSpec > &v)
Check whether the given RU overlaps with the given set of RUs.
Definition: he-ru.cc:352
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:137
static RuSpec FindOverlappingRu(uint16_t bw, RuSpec referenceRu, RuType searchedRuType)
Find the RU allocation of the given RU type overlapping the given reference RU allocation.
Definition: he-ru.cc:410
std::map< BwTonesPair, std::vector< SubcarrierGroup > > SubcarrierGroups
map (bandwidth, number of tones) pairs to the group of subcarrier ranges
Definition: he-ru.h:251
static uint16_t GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition: he-ru.cc:487
static const SubcarrierGroups m_heRuSubcarrierGroups
Subcarrier groups for all RUs (with indices being applicable to primary 80 MHz channel) ...
Definition: he-ru.h:254
void SetPhyIndex(uint16_t bw, uint8_t p20Index)
Set the RU PHY index.
Definition: he-ru.cc:188
static std::size_t GetNRus(uint16_t bw, RuType ruType)
Get the number of distinct RUs of the given type (number of tones) available in a HE PPDU of the give...
Definition: he-ru.cc:219
static RuType GetRuType(uint16_t bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition: he-ru.cc:512
static SubcarrierGroup GetSubcarrierGroup(uint16_t bw, RuType ruType, std::size_t phyIndex)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition: he-ru.cc:313
Every class exported by the ns3 library is enclosed in the ns3 namespace.
RuType GetRuType(void) const
Get the RU type.
Definition: he-ru.cc:167
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:41
static RuType GetEqualSizedRusForStations(uint16_t bandwidth, std::size_t &nStations, std::size_t &nCentral26TonesRus)
Given the channel bandwidth and the number of stations candidate for being assigned an RU...
Definition: he-ru.cc:537
static std::vector< HeRu::RuSpec > GetCentral26TonesRus(uint16_t bw, HeRu::RuType ruType)
Get the set of 26-tone RUs that can be additionally allocated if the given bandwidth is split in RUs ...
Definition: he-ru.cc:267
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:77
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
std::size_t GetIndex(void) const
Get the RU index.
Definition: he-ru.cc:174
bool IsPhyIndexSet(void) const
Return true if the RU PHY index has been set, false otherwise.
Definition: he-ru.cc:206
static std::vector< HeRu::RuSpec > GetRusOfType(uint16_t bw, HeRu::RuType ruType)
Get the set of distinct RUs of the given type (number of tones) available in a HE PPDU of the given b...
Definition: he-ru.cc:239
std::size_t GetPhyIndex(void) const
Get the RU PHY index.
Definition: he-ru.cc:212