wifi: Add support for High Efficiency Resource Units

This commit is contained in:
Stefano Avallone
2018-11-19 14:54:01 +01:00
committed by Sébastien Deronne
parent 7bce530e71
commit 8205ef2df0
3 changed files with 527 additions and 0 deletions

352
src/wifi/model/he-ru.cc Normal file
View File

@@ -0,0 +1,352 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#include "he-ru.h"
#include "ns3/abort.h"
namespace ns3 {
const HeRu::SubcarrierGroups HeRu::m_heRuSubcarrierGroups =
{
// RUs in a 20 MHz HE PPDU (Table 28-6)
{ {20, HeRu::RU_26_TONE}, { /* 1 */ {{-121, -96}},
/* 2 */ {{-95, -70}},
/* 3 */ {{-68, -43}},
/* 4 */ {{-42, -17}},
/* 5 */ {{-16, -4}, {4, 16}},
/* 6 */ {{17, 42}},
/* 7 */ {{43, 68}},
/* 8 */ {{70, 95}},
/* 9 */ {{96, 121}} } },
{ {20, HeRu::RU_52_TONE}, { /* 1 */ {{-121, -70}},
/* 2 */ {{-68, -17}},
/* 3 */ {{17, 68}},
/* 4 */ {{70, 121}} } },
{ {20, HeRu::RU_106_TONE}, { /* 1 */ {{-122, -17}},
/* 2 */ {{17, 122}} } },
{ {20, HeRu::RU_242_TONE}, { /* 1 */ {{-122, -2}, {2, 122}} } },
// RUs in a 40 MHz HE PPDU (Table 28-7)
{ {40, HeRu::RU_26_TONE}, { /* 1 */ {{-243, -218}},
/* 2 */ {{-217, -192}},
/* 3 */ {{-189, -164}},
/* 4 */ {{-163, -138}},
/* 5 */ {{-136, -111}},
/* 6 */ {{-109, -84}},
/* 7 */ {{-83, -58}},
/* 8 */ {{-55, -30}},
/* 9 */ {{-29, -4}},
/* 10 */ {{4, 29}},
/* 11 */ {{30, 55}},
/* 12 */ {{58, 83}},
/* 13 */ {{84, 109}},
/* 14 */ {{111, 136}},
/* 15 */ {{138, 163}},
/* 16 */ {{164, 189}},
/* 17 */ {{192, 217}},
/* 18 */ {{218, 243}} } },
{ {40, HeRu::RU_52_TONE}, { /* 1 */ {{-243, -192}},
/* 2 */ {{-189, -138}},
/* 3 */ {{-109, -58}},
/* 4 */ {{-55, -4}},
/* 5 */ {{4, 55}},
/* 6 */ {{58, 109}},
/* 7 */ {{138, 189}},
/* 8 */ {{192, 243}} } },
{ {40, HeRu::RU_106_TONE}, { /* 1 */ {{-243, -138}},
/* 2 */ {{-109, -4}},
/* 3 */ {{4, 109}},
/* 4 */ {{138, 243}} } },
{ {40, HeRu::RU_242_TONE}, { /* 1 */ {{-244, -3}},
/* 2 */ {{3, 244}} } },
{ {40, HeRu::RU_484_TONE}, { /* 1 */ {{-244, -3}, {3, 244}} } },
// RUs in an 80 MHz HE PPDU (Table 28-8)
{ {80, HeRu::RU_26_TONE}, { /* 1 */ {{-499, -474}},
/* 2 */ {{-473, -448}},
/* 3 */ {{-445, -420}},
/* 4 */ {{-419, -394}},
/* 5 */ {{-392, -367}},
/* 6 */ {{-365, -340}},
/* 7 */ {{-339, -314}},
/* 8 */ {{-311, -286}},
/* 9 */ {{-285, -260}},
/* 10 */ {{-257, -232}},
/* 11 */ {{-231, -206}},
/* 12 */ {{-203, -178}},
/* 13 */ {{-177, -152}},
/* 14 */ {{-150, -125}},
/* 15 */ {{-123, -98}},
/* 16 */ {{-97, -72}},
/* 17 */ {{-69, -44}},
/* 18 */ {{-43, -18}},
/* 19 */ {{-16, -4}, {4, 16}},
/* 20 */ {{18, 43}},
/* 21 */ {{44, 69}},
/* 22 */ {{72, 97}},
/* 23 */ {{98, 123}},
/* 24 */ {{125, 150}},
/* 25 */ {{152, 177}},
/* 26 */ {{178, 203}},
/* 27 */ {{206, 231}},
/* 28 */ {{232, 257}},
/* 29 */ {{260, 285}},
/* 30 */ {{286, 311}},
/* 31 */ {{314, 339}},
/* 32 */ {{340, 365}},
/* 33 */ {{367, 392}},
/* 34 */ {{394, 419}},
/* 35 */ {{420, 445}},
/* 36 */ {{448, 473}},
/* 37 */ {{474, 499}} } },
{ {80, HeRu::RU_52_TONE}, { /* 1 */ {{-499, -448}},
/* 2 */ {{-445, -394}},
/* 3 */ {{-365, -314}},
/* 4 */ {{-311, -260}},
/* 5 */ {{-257, -206}},
/* 6 */ {{-203, -152}},
/* 7 */ {{-123, -72}},
/* 8 */ {{-69, -18}},
/* 9 */ {{18, 69}},
/* 10 */ {{72, 123}},
/* 11 */ {{152, 203}},
/* 12 */ {{206, 257}},
/* 13 */ {{260, 311}},
/* 14 */ {{314, 365}},
/* 15 */ {{394, 445}},
/* 16 */ {{448, 499}} } },
{ {80, HeRu::RU_106_TONE}, { /* 1 */ {{-499, -394}},
/* 2 */ {{-365, -260}},
/* 3 */ {{-257, -152}},
/* 4 */ {{-123, -18}},
/* 5 */ {{18, 123}},
/* 6 */ {{152, 257}},
/* 7 */ {{260, 365}},
/* 8 */ {{394, 499}} } },
{ {80, HeRu::RU_242_TONE}, { /* 1 */ {{-500, -259}},
/* 2 */ {{-258, -17}},
/* 3 */ {{17, 258}},
/* 4 */ {{259, 500}} } },
{ {80, HeRu::RU_484_TONE}, { /* 1 */ {{-500, -17}},
/* 2 */ {{17, 500}} } },
{ {80, HeRu::RU_996_TONE}, { /* 1 */ {{-500, -3}, {3, 500}} } }
};
std::size_t
HeRu::GetNRus (uint8_t bw, RuType ruType)
{
if (bw == 160 && ruType == RU_2x996_TONE)
{
return 1;
}
// if the bandwidth is 160MHz, search for the number of RUs available
// in 80MHz and double the result.
auto it = m_heRuSubcarrierGroups.find ({(bw == 160 ? 80 : bw), ruType});
if (it == m_heRuSubcarrierGroups.end ())
{
return 0;
}
return (bw == 160 ? 2 : 1) * it->second.size ();
}
HeRu::SubcarrierGroup
HeRu::GetSubcarrierGroup (uint8_t bw, RuType ruType, std::size_t index)
{
if (ruType == HeRu::RU_2x996_TONE) //handle special case of RU covering 160 MHz channel
{
NS_ABORT_MSG_IF (bw != 160, "2x996 tone RU can only be used on 160 MHz band");
return {{-1012, -3}, {3, 1012}};
}
// Determine the shift to apply to tone indices for 160 MHz channel (i.e. -1012 to 1012), since
// m_heRuSubcarrierGroups contains indices for primary 80 MHz subchannel (i.e. from -500 to 500).
// The index is used to that aim.
std::size_t indexInPrimary80MHz = index;
std::size_t numRus = GetNRus (bw, ruType);
int16_t shift = (bw == 160) ? -512 : 0;
if (bw == 160 && index > (numRus / 2))
{
// The provided index is that of the secondary 80 MHz subchannel
indexInPrimary80MHz = index - (numRus / 2);
shift = 512;
}
auto it = m_heRuSubcarrierGroups.find ({(bw == 160 ? 80 : bw), ruType});
NS_ABORT_MSG_IF (it == m_heRuSubcarrierGroups.end (), "RU not found");
NS_ABORT_MSG_IF (!indexInPrimary80MHz || indexInPrimary80MHz > it->second.size (), "RU index not available");
SubcarrierGroup group = it->second.at (indexInPrimary80MHz - 1);
if (bw == 160)
{
for (auto & range : group)
{
range.first += shift;
range.second += shift;
}
}
return group;
}
bool
HeRu::DoesOverlap (uint8_t bw, RuSpec ru, const std::vector<RuSpec> &v)
{
// A 2x996-tone RU spans 160 MHz, hence it overlaps with any other RU
if (bw == 160 && ru.ruType == RU_2x996_TONE && !v.empty ())
{
return true;
}
SubcarrierGroup groups = GetSubcarrierGroup (bw, ru.ruType, ru.index);
for (auto& p : v)
{
if (ru.primary80MHz != p.primary80MHz)
{
// the two RUs are located in distinct 80MHz bands
continue;
}
if (DoesOverlap (bw, p, groups))
{
return true;
}
}
return false;
}
bool
HeRu::DoesOverlap (uint8_t bw, RuSpec ru, const SubcarrierGroup &toneRanges)
{
for (const auto & range : toneRanges)
{
if (bw == 160 && ru.ruType == RU_2x996_TONE)
{
return true;
}
SubcarrierGroup rangesRu = GetSubcarrierGroup (bw, ru.ruType, ru.index);
for (auto& r : rangesRu)
{
if (range.second >= r.first && r.second >= range.first)
{
return true;
}
}
}
return false;
}
std::ostream& operator<< (std::ostream& os, const HeRu::RuType &ruType)
{
switch (ruType)
{
case HeRu::RU_26_TONE:
os << "26-tones";
break;
case HeRu::RU_52_TONE:
os << "52-tones";
break;
case HeRu::RU_106_TONE:
os << "106-tones";
break;
case HeRu::RU_242_TONE:
os << "242-tones";
break;
case HeRu::RU_484_TONE:
os << "484-tones";
break;
case HeRu::RU_996_TONE:
os << "996-tones";
break;
case HeRu::RU_2x996_TONE:
os << "2x996-tones";
break;
default:
NS_FATAL_ERROR ("Unknown RU type");
}
return os;
}
std::ostream& operator<< (std::ostream& os, const HeRu::RuSpec &ru)
{
os << "RU{" << ru.ruType << "/" << ru.index << "/" << (ru.primary80MHz ? "primary80MHz" : "secondary80MHz") << "}";
return os;
}
uint16_t
HeRu::GetBandwidth (RuType ruType)
{
switch (ruType)
{
case RU_26_TONE:
return 2;
case RU_52_TONE:
return 4;
case RU_106_TONE:
return 8;
case RU_242_TONE:
return 20;
case RU_484_TONE:
return 40;
case RU_996_TONE:
return 80;
case RU_2x996_TONE:
return 160;
default:
NS_ABORT_MSG ("RU type " << ruType << " not found");
return 0;
}
}
HeRu::RuType
HeRu::GetEqualSizedRusForStations (uint16_t bandwidth, std::size_t& nStations)
{
RuType ruType;
uint8_t nRusAssigned = 0;
// iterate over all the available RU types
for (auto& ru : m_heRuSubcarrierGroups)
{
if (ru.first.first == bandwidth && ru.second.size () <= nStations)
{
ruType = ru.first.second;
nRusAssigned = ru.second.size ();
break;
}
else if (bandwidth == 160 && ru.first.first == 80 && (2 * ru.second.size () <= nStations))
{
ruType = ru.first.second;
nRusAssigned = 2 * ru.second.size ();
break;
}
}
if (nRusAssigned == 0)
{
NS_ABORT_IF (bandwidth != 160 || nStations != 1);
nRusAssigned = 1;
ruType = RU_2x996_TONE;
}
nStations = nRusAssigned;
return ruType;
}
} //namespace ns3

173
src/wifi/model/he-ru.h Normal file
View File

@@ -0,0 +1,173 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#ifndef HE_RU_H
#define HE_RU_H
#include <map>
#include <vector>
#include <cstdint>
#include <ostream>
namespace ns3 {
/**
* This class stores the subcarrier groups of all the available HE RUs.
*/
class HeRu
{
public:
/**
* The different HE Resource Unit (RU) types.
*/
enum RuType
{
RU_26_TONE = 0,
RU_52_TONE,
RU_106_TONE,
RU_242_TONE,
RU_484_TONE,
RU_996_TONE,
RU_2x996_TONE
};
/// (lowest index, highest index) pair defining a subcarrier range
typedef std::pair<int16_t, int16_t> SubcarrierRange;
/// a vector of subcarrier ranges defining a subcarrier group
typedef std::vector<SubcarrierRange> SubcarrierGroup;
/**
* RU Specification. Stores the information carried by the RU Allocation
* subfield of the User Info field of Trigger frames. Note that primary80MHz
* must be true if ruType is RU_2x996_TONE.
*/
typedef struct
{
bool primary80MHz; //!< true if the RU is allocated in the primary 80MHz channel
RuType ruType; //!< RU type
std::size_t index; //!< index (starting at 1)
} RuSpec;
/**
* Get the number of distinct RUs of the given type (number of tones)
* available in a HE PPDU of the given bandwidth.
*
* \param bw the bandwidth (MHz) of the HE PPDU (20, 40, 80, 160)
* \param ruType the RU type (number of tones)
* \return the number of distinct RUs available
*/
static std::size_t GetNRus (uint8_t bw, RuType ruType);
/**
* Get the subcarrier group of the RU having the given index among all the
* RUs of the given type (number of tones) available in a HE PPDU of the
* given bandwidth. A subcarrier group is defined as one or more pairs
* indicating the lowest frequency index and the highest frequency index.
* Note that for channel width of 160 MHz the returned range is relative to
* the 160 MHz channel (i.e. -1012 to 1012). The index parameter is used to
* distinguish between primary and secondary 80 MHz subchannels.
*
* \param bw the bandwidth (MHz) of the HE PPDU (20, 40, 80, 160)
* \param ruType the RU type (number of tones)
* \param index the index (starting at 1) of the RU
* \return the subcarrier range of the specified RU
*/
static SubcarrierGroup GetSubcarrierGroup (uint8_t bw, RuType ruType, std::size_t index);
/**
* Check whether the given RU overlaps with the given set of RUs.
* Note that for channel width of 160 MHz the returned range is relative to
* the 160 MHz channel (i.e. -1012 to 1012).
*
* \param bw the bandwidth (MHz) of the HE PPDU (20, 40, 80, 160)
* \param ru the given RU allocation
* \param v the given set of RUs
* \return true if the given RU overlaps with the given set of RUs.
*/
static bool DoesOverlap (uint8_t bw, RuSpec ru, const std::vector<RuSpec> &v);
/**
* Check whether the given RU overlaps with the given tone ranges.
* Note that for channel width of 160 MHz the returned range is relative to
* the 160 MHz channel (i.e. -1012 to 1012).
*
* \param bw the bandwidth (MHz) of the HE PPDU (20, 40, 80, 160)
* \param ru the given RU allocation
* \param toneRanges the given set of tone ranges
* \return true if the given RU overlaps with the given set of tone ranges.
*/
static bool DoesOverlap (uint8_t bw, RuSpec ru, const SubcarrierGroup &toneRanges);
/**
* Get the approximate bandwidth occupied by a RU.
*
* \param ruType the RU type
* \return the approximate bandwidth (in MHz) occupied by the RU
*/
static uint16_t GetBandwidth (RuType ruType);
/**
* Given the channel bandwidth and the number of stations candidate for being
* assigned an RU, maximize the number of candidate stations that can be assigned
* an RU subject to the constraint that all the stations must be assigned an RU
* of the same size (in terms of number of tones).
*
* \param bandwidth the channel bandwidth in MHz
* \param nStations the number of candidate stations. On return, it is set to
* the number of stations that are assigned an RU
* \return the RU type
*/
static RuType GetEqualSizedRusForStations (uint16_t bandwidth, std::size_t& nStations);
/// (bandwidth, number of tones) pair
typedef std::pair<uint8_t, RuType> BwTonesPair;
/// map (bandwidth, number of tones) pairs to the group of subcarrier ranges
typedef std::map<BwTonesPair, std::vector<SubcarrierGroup> > SubcarrierGroups;
//!< Subcarrier groups for all RUs (with indices being applicable to primary 80 MHz channel)
static const SubcarrierGroups m_heRuSubcarrierGroups;
};
/**
* \brief Stream insertion operator.
*
* \param os the stream
* \param ruType the RU type
* \returns a reference to the stream
*/
std::ostream& operator<< (std::ostream& os, const HeRu::RuType &ruType);
/**
* \brief Stream insertion operator.
*
* \param os the stream
* \param ru the RU
* \returns a reference to the stream
*/
std::ostream& operator<< (std::ostream& os, const HeRu::RuSpec &ru);
} //namespace ns3
#endif /* HE_RU_H */

View File

@@ -101,6 +101,7 @@ def build(bld):
'model/constant-obss-pd-algorithm.cc',
'model/wifi-ack-policy-selector.cc',
'model/constant-wifi-ack-policy-selector.cc',
'model/he-ru.cc',
'helper/wifi-radio-energy-model-helper.cc',
'helper/athstats-helper.cc',
'helper/wifi-helper.cc',
@@ -239,6 +240,7 @@ def build(bld):
'model/constant-obss-pd-algorithm.h',
'model/wifi-ack-policy-selector.h',
'model/constant-wifi-ack-policy-selector.h',
'model/he-ru.h',
'model/reference/error-rate-tables.h',
'helper/wifi-radio-energy-model-helper.h',
'helper/athstats-helper.h',