wifi: Add MIMO support in minstrel-ht
Two other changes included: 1) model was not setting the calculated rate in GetRtsTxVector, and 2) change behavior so that by default (when VHT is supported) use only VHT rates
This commit is contained in:
@@ -25,8 +25,8 @@
|
||||
* 1) By default, Minstrel applies the multi-rate retry (the core of Minstrel
|
||||
* algorithm). Otherwise, please use ConstantRateWifiManager instead.
|
||||
*
|
||||
* 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
|
||||
* to sample all rates in all groups at least once and to avoid many
|
||||
* 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
|
||||
* to sample all rates in all groups at least once and to avoid many
|
||||
* consecutive samplings.
|
||||
*
|
||||
* 3) Sample rate is tried only once, at first place of the MRR chain.
|
||||
@@ -128,7 +128,7 @@ MinstrelHtWifiManager::GetTypeId (void)
|
||||
MakeUintegerChecker <uint32_t> ())
|
||||
.AddAttribute ("UseVhtOnly",
|
||||
"Use only VHT MCSs (and not HT) when VHT is available",
|
||||
BooleanValue (false),
|
||||
BooleanValue (true),
|
||||
MakeBooleanAccessor (&MinstrelHtWifiManager::m_useVhtOnly),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("PrintStats",
|
||||
@@ -185,72 +185,127 @@ void
|
||||
MinstrelHtWifiManager::SetupPhy (Ptr<WifiPhy> phy)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << phy);
|
||||
// Setup phy for legacy manager.
|
||||
m_legacyManager->SetupPhy (phy);
|
||||
WifiRemoteStationManager::SetupPhy (phy);
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelHtWifiManager::DoInitialize ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
/**
|
||||
* Here we initialize m_minstrelGroups with all the groups the device
|
||||
* would support. Then, after all initializations are finished, we
|
||||
* check actual support for each receiving station.
|
||||
* Here we initialize m_minstrelGroups with all the possible groups.
|
||||
* If a group is not supported by the device, then it is marked as not supported.
|
||||
* Then, after all initializations are finished, we check actual support for each receiving station.
|
||||
*/
|
||||
|
||||
// Check if the device supports HT or VHT
|
||||
if (HasHtSupported () || HasVhtSupported ())
|
||||
{
|
||||
m_numGroups = MAX_SUPPORTED_STREAMS * MAX_HT_STREAM_GROUPS;
|
||||
m_numRates = MAX_HT_GROUP_RATES;
|
||||
|
||||
if (HasVhtSupported ())
|
||||
{
|
||||
m_numGroups = MAX_SUPPORTED_STREAMS * MAX_VHT_STREAM_GROUPS;
|
||||
m_numRates = MAX_HT_GROUP_RATES + MAX_VHT_GROUP_RATES;
|
||||
m_maxChWidth = MAX_VHT_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_numGroups = MAX_SUPPORTED_STREAMS * MAX_HT_STREAM_GROUPS;
|
||||
m_numRates = MAX_HT_GROUP_RATES;
|
||||
m_maxChWidth = MAX_HT_WIDTH;
|
||||
m_numGroups += MAX_SUPPORTED_STREAMS * MAX_VHT_STREAM_GROUPS;
|
||||
m_numRates = MAX_VHT_GROUP_RATES;
|
||||
}
|
||||
|
||||
// Initialize the groups array.
|
||||
/**
|
||||
* Initialize the groups array.
|
||||
* The HT groups come first, then the VHT ones.
|
||||
* Minstrel maintains different types of indexes:
|
||||
* - A global continuous index, which identifies all rates within all groups, in [0, m_numGroups * m_numRates]
|
||||
* - A groupId, which indexes a group in the array, in [0, m_numGroups]
|
||||
* - A rateId, which identifies a rate within a group, in [0, m_numRates]
|
||||
* - A deviceIndex, which indexes a MCS in the phy MCS array.
|
||||
* - A mcsIndex, which indexes a MCS in the wifi-remote-station-manager supported MCSs array.
|
||||
*/
|
||||
NS_LOG_DEBUG ("Initialize MCS Groups:");
|
||||
m_minstrelGroups = MinstrelMcsGroups (m_numGroups);
|
||||
for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
|
||||
|
||||
// Initialize all HT groups
|
||||
for (uint32_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
|
||||
{
|
||||
for (uint8_t sgi = 0; sgi <= 1; sgi++)
|
||||
{
|
||||
for (uint32_t chWidth = 20; chWidth <= m_maxChWidth; chWidth *= 2)
|
||||
for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
|
||||
{
|
||||
uint32_t groupId = GetGroupId (streams, sgi, chWidth);
|
||||
uint32_t groupId = GetHtGroupId (streams, sgi, chWidth);
|
||||
|
||||
m_minstrelGroups[groupId].streams = streams;
|
||||
m_minstrelGroups[groupId].sgi = sgi;
|
||||
m_minstrelGroups[groupId].chWidth = chWidth;
|
||||
m_minstrelGroups[groupId].isVht = false;
|
||||
m_minstrelGroups[groupId].isSupported = false;
|
||||
|
||||
for (uint8_t i = 0; i < m_numRates; i++)
|
||||
// Check capabilities of the device
|
||||
if (!(!GetPhy ()->GetGuardInterval () && m_minstrelGroups[groupId].sgi) ///Is SGI supported by the transmitter?
|
||||
&& (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth) ///Is channel width supported by the transmitter?
|
||||
&& (GetPhy ()->GetNumberOfTransmitAntennas () >= m_minstrelGroups[groupId].streams)) ///Are streams supported by the transmitter?
|
||||
{
|
||||
// Check for invalid VHT MCSs and do not add time to array.
|
||||
WifiMode mode = phy->GetMcs (i);
|
||||
if (IsValidMcs (phy, streams, chWidth, mode))
|
||||
m_minstrelGroups[groupId].isSupported = true;
|
||||
|
||||
// Calculate tx time for all rates of the group
|
||||
WifiModeList htMcsList = GetHtDeviceMcsList ();
|
||||
for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
|
||||
{
|
||||
// Check if the group corresponds to a VHT MCS.
|
||||
if (streams > 4 || chWidth > MAX_HT_WIDTH || i > (MAX_HT_GROUP_RATES - 1)) //TODO change 4 for a constant
|
||||
uint32_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
|
||||
WifiMode mode = htMcsList[deviceIndex];
|
||||
AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
|
||||
AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
|
||||
}
|
||||
NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << (uint32_t)streams << "," << (uint32_t)sgi << "," << chWidth << ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasVhtSupported ())
|
||||
{
|
||||
// Initialize all VHT groups
|
||||
for (uint32_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
|
||||
{
|
||||
for (uint8_t sgi = 0; sgi <= 1; sgi++)
|
||||
{
|
||||
for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
|
||||
{
|
||||
uint32_t groupId = GetVhtGroupId (streams, sgi, chWidth);
|
||||
|
||||
m_minstrelGroups[groupId].streams = streams;
|
||||
m_minstrelGroups[groupId].sgi = sgi;
|
||||
m_minstrelGroups[groupId].chWidth = chWidth;
|
||||
m_minstrelGroups[groupId].isVht = true;
|
||||
m_minstrelGroups[groupId].isSupported = false;
|
||||
|
||||
// Check capabilities of the device
|
||||
if (!(!GetPhy ()->GetGuardInterval () && m_minstrelGroups[groupId].sgi) ///Is SGI supported by the transmitter?
|
||||
&& (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth) ///Is channel width supported by the transmitter?
|
||||
&& (GetPhy ()->GetNumberOfTransmitAntennas () >= m_minstrelGroups[groupId].streams)) ///Are streams supported by the transmitter?
|
||||
{
|
||||
m_minstrelGroups[groupId].isSupported = true;
|
||||
|
||||
// Calculate tx time for all rates of the group
|
||||
WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
|
||||
for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
|
||||
{
|
||||
m_minstrelGroups[groupId].isVht = true;
|
||||
WifiMode mode = vhtMcsList[i];
|
||||
// Check for invalid VHT MCSs and do not add time to array.
|
||||
if (IsValidMcs (GetPhy (), streams, chWidth, mode))
|
||||
{
|
||||
AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
|
||||
AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minstrelGroups[groupId].isVht = false;
|
||||
}
|
||||
AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (phy, streams, sgi, chWidth, mode));
|
||||
AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (phy, streams, sgi, chWidth, mode));
|
||||
NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << (uint32_t)streams << "," << (uint32_t)sgi << "," << chWidth << ")");
|
||||
}
|
||||
}
|
||||
NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << (uint32_t)streams << "," << (uint32_t)sgi << "," << chWidth << ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup phy for legacy manager.
|
||||
m_legacyManager->SetupPhy (phy);
|
||||
WifiRemoteStationManager::SetupPhy (phy);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -439,8 +494,8 @@ MinstrelHtWifiManager::CheckInit (MinstrelHtWifiRemoteStation *station)
|
||||
NS_LOG_DEBUG ("HT station " << station);
|
||||
station->m_isHt = true;
|
||||
station->m_nModes = GetNMcsSupported (station);
|
||||
station->m_sampleTable = SampleRate (station->m_nModes, std::vector<uint32_t> (m_nSampleCol));
|
||||
m_legacyManager->InitSampleTable (station);
|
||||
station->m_sampleTable = SampleRate (m_numRates, std::vector<uint32_t> (m_nSampleCol));
|
||||
InitSampleTable (station);
|
||||
RateInit (station);
|
||||
std::ostringstream tmp;
|
||||
tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
|
||||
@@ -859,8 +914,9 @@ MinstrelHtWifiManager::DoGetDataTxVector (WifiRemoteStation *st)
|
||||
|
||||
uint32_t rateId = GetRateId (station->m_txrate);
|
||||
uint32_t groupId = GetGroupId (station->m_txrate);
|
||||
uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
|
||||
|
||||
NS_LOG_DEBUG ("DoGetDataMode rateId= " << rateId << " groupId= " << groupId << " mode= " << GetMcsSupported (station, rateId));
|
||||
NS_LOG_DEBUG ("DoGetDataMode rateId= " << rateId << " groupId= " << groupId << " mode= " << GetMcsSupported (station, mcsIndex));
|
||||
|
||||
McsGroup group = m_minstrelGroups[groupId];
|
||||
|
||||
@@ -871,14 +927,13 @@ MinstrelHtWifiManager::DoGetDataTxVector (WifiRemoteStation *st)
|
||||
" Station capabilities: (" << GetNumberOfSupportedRxAntennas (station) << "," << GetShortGuardInterval (station) << "," << GetChannelWidth (station) << ")");
|
||||
}
|
||||
|
||||
|
||||
uint64_t dataRate = GetMcsSupported (station, rateId).GetDataRate (group.chWidth, group.sgi, group.streams);
|
||||
uint64_t dataRate = GetMcsSupported (station, mcsIndex).GetDataRate (group.chWidth, group.sgi, group.streams);
|
||||
if (!station->m_isSampling)
|
||||
{
|
||||
m_rateChange (dataRate, station->m_state->m_address);
|
||||
}
|
||||
|
||||
return WifiTxVector (GetMcsSupported (station, rateId), GetDefaultTxPowerLevel (), GetLongRetryCount (station),
|
||||
return WifiTxVector (GetMcsSupported (station, mcsIndex), GetDefaultTxPowerLevel (), GetLongRetryCount (station),
|
||||
group.sgi, group.streams, GetNess (station), group.chWidth, !station->m_isSampling, GetStbc (station));
|
||||
}
|
||||
}
|
||||
@@ -916,8 +971,12 @@ MinstrelHtWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
|
||||
*/
|
||||
|
||||
// As we are in Minstrel HT, assume the last rate was an HT rate.
|
||||
WifiMode lastRate = GetMcsSupported (station, GetRateId (station->m_txrate));
|
||||
uint8_t streams = m_minstrelGroups[GetGroupId (station->m_txrate)].streams;
|
||||
uint32_t rateId = GetRateId (station->m_txrate);
|
||||
uint32_t groupId = GetGroupId (station->m_txrate);
|
||||
uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
|
||||
|
||||
WifiMode lastRate = GetMcsSupported (station, mcsIndex);
|
||||
uint8_t streams = m_minstrelGroups[groupId].streams;
|
||||
uint64_t lastDataRate = lastRate.GetNonHtReferenceRate (streams);
|
||||
uint32_t nBasicRates = GetNBasicModes ();
|
||||
|
||||
@@ -951,7 +1010,7 @@ MinstrelHtWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
|
||||
|
||||
NS_ASSERT (rateFound);
|
||||
|
||||
return WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station),
|
||||
return WifiTxVector (rtsRate, GetDefaultTxPowerLevel (), GetShortRetryCount (station),
|
||||
false, 1, 0, GetChannelWidth (station), GetAggregation (station), false);
|
||||
}
|
||||
}
|
||||
@@ -1059,7 +1118,7 @@ MinstrelHtWifiManager::SetNextSample (MinstrelHtWifiRemoteStation *station)
|
||||
uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
|
||||
uint8_t col = station->m_groupsTable[sampleGroup].m_col;
|
||||
|
||||
if (index >= station->m_nModes)
|
||||
if (index >= m_numRates)
|
||||
{
|
||||
station->m_groupsTable[station->m_sampleGroup].m_index = 0;
|
||||
station->m_groupsTable[station->m_sampleGroup].m_col++;
|
||||
@@ -1084,6 +1143,7 @@ MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
|
||||
return station->m_maxTpRate;
|
||||
}
|
||||
|
||||
// If we have waited enough, then sample.
|
||||
if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
|
||||
{
|
||||
//SAMPLING
|
||||
@@ -1092,14 +1152,12 @@ MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
|
||||
uint32_t sampleIdx = GetNextSample (station);
|
||||
NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
|
||||
|
||||
|
||||
//Evaluate if the sampling rate selected should be used.
|
||||
uint32_t sampleGroupId = GetGroupId (sampleIdx);
|
||||
uint32_t sampleRateId = GetRateId (sampleIdx);
|
||||
McsGroup sampleGroup = m_minstrelGroups[sampleGroupId];
|
||||
HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
|
||||
|
||||
if (sampleRateInfo.supported)
|
||||
// If the rate selected is not supported, then don't sample.
|
||||
if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
|
||||
{
|
||||
/**
|
||||
* Sampling might add some overhead to the frame.
|
||||
@@ -1108,8 +1166,11 @@ MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
|
||||
* Also do not sample if the probability is already higher than 95%
|
||||
* to avoid wasting airtime.
|
||||
*/
|
||||
HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
|
||||
|
||||
NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
|
||||
" SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
|
||||
|
||||
if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
|
||||
&& sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
|
||||
{
|
||||
@@ -1176,14 +1237,6 @@ MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
|
||||
NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
|
||||
return station->m_maxTpRate;
|
||||
}
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetIndex (uint32_t groupid, uint32_t mcsIndex)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << groupid << mcsIndex);
|
||||
uint32_t index;
|
||||
index = groupid * m_numRates + mcsIndex;
|
||||
return index;
|
||||
}
|
||||
void
|
||||
MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
|
||||
{
|
||||
@@ -1206,12 +1259,10 @@ MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
|
||||
station->m_ampduPacketCount = 0;
|
||||
}
|
||||
|
||||
uint32_t index;
|
||||
|
||||
/* Initialize global rate indexes */
|
||||
station->m_maxTpRate = 0;
|
||||
station->m_maxTpRate2 = 0;
|
||||
station->m_maxProbRate = 0;
|
||||
station->m_maxTpRate = GetLowestIndex (station);
|
||||
station->m_maxTpRate2 = GetLowestIndex (station);
|
||||
station->m_maxProbRate = GetLowestIndex (station);
|
||||
|
||||
/// Update throughput and EWMA for each rate inside each group.
|
||||
for (uint32_t j = 0; j < m_numGroups; j++)
|
||||
@@ -1221,16 +1272,17 @@ MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
|
||||
station->m_sampleCount++;
|
||||
|
||||
/* (re)Initialize group rate indexes */
|
||||
station->m_groupsTable[j].m_maxTpRate = 0;
|
||||
station->m_groupsTable[j].m_maxTpRate2 = 0;
|
||||
station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
|
||||
station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
|
||||
station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
|
||||
|
||||
for (uint32_t i = 0; i < station->m_nModes; i++)
|
||||
for (uint32_t i = 0; i < m_numRates; i++)
|
||||
{
|
||||
if (station->m_groupsTable[j].m_ratesTable[i].supported)
|
||||
{
|
||||
station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
|
||||
|
||||
NS_LOG_DEBUG (i << " " << GetMcsSupported (station, i) <<
|
||||
NS_LOG_DEBUG (i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
|
||||
"\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
|
||||
"\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
|
||||
|
||||
@@ -1279,9 +1331,8 @@ MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
|
||||
|
||||
if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
|
||||
{
|
||||
index = GetIndex (j, i);
|
||||
SetBestStationThRates (station, index);
|
||||
SetBestProbabilityRate (station, index);
|
||||
SetBestStationThRates (station, GetIndex (j, i));
|
||||
SetBestProbabilityRate (station, GetIndex (j, i));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1462,62 +1513,70 @@ MinstrelHtWifiManager::RateInit (MinstrelHtWifiRemoteStation *station)
|
||||
station->m_groupsTable = McsGroupData (m_numGroups);
|
||||
|
||||
/**
|
||||
* Initialize groups supported by both transmitter and receiver.
|
||||
* Remember that we check again the transmitter because of late
|
||||
* initialization of some parameters.
|
||||
* Initialize groups supported by the receiver.
|
||||
*/
|
||||
NS_LOG_DEBUG ("Supported groups by station:");
|
||||
for (uint32_t j = 0; j < m_numGroups; j++)
|
||||
for (uint32_t groupId = 0; groupId < m_numGroups; groupId++)
|
||||
{
|
||||
station->m_groupsTable[j].m_supported = false;
|
||||
if (m_minstrelGroups[j].isVht || (!m_minstrelGroups[j].isVht && !m_useVhtOnly)) ///If it is an HT MCS, check if VHT only is disabled
|
||||
if (m_minstrelGroups[groupId].isSupported)
|
||||
{
|
||||
if (!(!GetPhy ()->GetGuardInterval () && m_minstrelGroups[j].sgi) ///Is SGI supported by the transmitter?
|
||||
&& (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[j].chWidth) ///Is channel width supported by the transmitter?
|
||||
&& (GetPhy ()->GetNumberOfTransmitAntennas () >= m_minstrelGroups[j].streams)) ///Are streams supported by the transmitter?
|
||||
station->m_groupsTable[groupId].m_supported = false;
|
||||
if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht) ///Is VHT supported by the receiver?
|
||||
&& (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly) ///If it is an HT MCS, check if VHT only is disabled
|
||||
&& !(!GetShortGuardInterval (station) && m_minstrelGroups[groupId].sgi) ///Is SGI supported by the receiver?
|
||||
&& (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth) ///Is channel width supported by the receiver?
|
||||
&& (GetNumberOfSupportedRxAntennas (station) >= m_minstrelGroups[groupId].streams)) ///Are streams supported by the receiver?
|
||||
{
|
||||
if (!(!GetVhtSupported (station) && m_minstrelGroups[j].isVht) ///Is VHT supported by the receiver?
|
||||
&& !(!GetShortGuardInterval (station) && m_minstrelGroups[j].sgi) ///Is SGI supported by the receiver?
|
||||
&& (GetChannelWidth (station) >= m_minstrelGroups[j].chWidth) ///Is channel width supported by the receiver?
|
||||
&& (GetNumberOfSupportedRxAntennas (station) >= m_minstrelGroups[j].streams)) ///Are streams supported by the receiver?
|
||||
NS_LOG_DEBUG ("Group " << groupId << ": (" << (uint32_t)m_minstrelGroups[groupId].streams <<
|
||||
"," << (uint32_t)m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
|
||||
|
||||
station->m_groupsTable[groupId].m_supported = true; ///Group supported.
|
||||
station->m_groupsTable[groupId].m_col = 0;
|
||||
station->m_groupsTable[groupId].m_index = 0;
|
||||
|
||||
station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates); ///Create the rate list for the group.
|
||||
for (uint32_t i = 0; i < m_numRates; i++)
|
||||
{
|
||||
NS_LOG_DEBUG ("Group " << j << ": (" << (uint32_t)m_minstrelGroups[j].streams <<
|
||||
"," << (uint32_t)m_minstrelGroups[j].sgi << "," << m_minstrelGroups[j].chWidth << ")");
|
||||
station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
|
||||
}
|
||||
|
||||
station->m_groupsTable[j].m_supported = true; ///Group supported.
|
||||
// Initialize all modes supported by the remote station that belong to the current group.
|
||||
for (uint32_t i = 0; i < station->m_nModes; i++)
|
||||
{
|
||||
WifiMode mode = GetMcsSupported (station, i);
|
||||
|
||||
station->m_groupsTable[j].m_ratesTable = HtMinstrelRate (station->m_nModes);
|
||||
station->m_groupsTable[j].m_col = 0;
|
||||
station->m_groupsTable[j].m_index = 0;
|
||||
|
||||
// Initialize all modes supported by the group.
|
||||
for (uint32_t i = 0; i < station->m_nModes; i++)
|
||||
///Use the McsValue as the index in the rate table.
|
||||
///This way, MCSs not supported are not initialized.
|
||||
uint32_t rateId = mode.GetMcsValue ();
|
||||
if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
NS_LOG_DEBUG ("Mode " << i << ": " << GetMcsSupported (station,i));
|
||||
///Check for invalid VHT MCS
|
||||
if (IsValidMcs (GetPhy (), m_minstrelGroups[j].streams,
|
||||
m_minstrelGroups[j].chWidth, GetMcsSupported (station,i)))
|
||||
{
|
||||
station->m_groupsTable[j].m_ratesTable[i].supported = true;
|
||||
station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].prob = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].ewmaProb = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].successHist = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].attemptHist = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].throughput = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].perfectTxTime = GetFirstMpduTxTime (j, GetMcsSupported (station,i));
|
||||
station->m_groupsTable[j].m_ratesTable[i].retryCount = 0;
|
||||
station->m_groupsTable[j].m_ratesTable[i].adjustedRetryCount = 0;
|
||||
CalculateRetransmits (station, j, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
station->m_groupsTable[j].m_ratesTable[i].supported = false;
|
||||
}
|
||||
rateId %= MAX_HT_GROUP_RATES;
|
||||
}
|
||||
|
||||
if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT ///If it is a VHT MCS only add to a VHT group.
|
||||
&& IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode)) ///Check validity of the VHT MCS
|
||||
|| (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT ///If it is a HT MCS only add to a HT group.
|
||||
&& mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8) ///Check if the HT MCS corresponds to groups number of streams.
|
||||
&& mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
|
||||
{
|
||||
NS_LOG_DEBUG ("Mode " << i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
|
||||
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i; ///Mapping between rateId and operationalMcsSet
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
|
||||
CalculateRetransmits (station, groupId, rateId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1561,8 +1620,8 @@ MinstrelHtWifiManager::CalculateRetransmits (MinstrelHtWifiRemoteStation *statio
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
|
||||
station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
|
||||
|
||||
dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station,rateId)) +
|
||||
GetMpduTxTime (groupId, GetMcsSupported (station, rateId)) * (station->m_avgAmpduLen - 1);
|
||||
dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
|
||||
GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
|
||||
|
||||
/* Contention time for first 2 tries */
|
||||
cwTime = (cw / 2) * slotTime;
|
||||
@@ -1603,6 +1662,38 @@ MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, doub
|
||||
return sqrt (tmp);
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelHtWifiManager::InitSampleTable (MinstrelHtWifiRemoteStation *station)
|
||||
{
|
||||
NS_LOG_DEBUG ("InitSampleTable=" << this);
|
||||
|
||||
station->m_col = station->m_index = 0;
|
||||
|
||||
//for off-setting to make rates fall between 0 and nModes
|
||||
uint32_t numSampleRates = m_numRates;
|
||||
|
||||
uint32_t newIndex;
|
||||
for (uint32_t col = 0; col < m_nSampleCol; col++)
|
||||
{
|
||||
for (uint32_t i = 0; i < numSampleRates; i++ )
|
||||
{
|
||||
/**
|
||||
* The next two lines basically tries to generate a random number
|
||||
* between 0 and the number of available rates
|
||||
*/
|
||||
int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
|
||||
newIndex = (i + uv) % numSampleRates;
|
||||
|
||||
//this loop is used for filling in other uninitialized places
|
||||
while (station->m_sampleTable[newIndex][col] != 0)
|
||||
{
|
||||
newIndex = (newIndex + 1) % m_numRates;
|
||||
}
|
||||
station->m_sampleTable[newIndex][col] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelHtWifiManager::PrintTable (MinstrelHtWifiRemoteStation *station)
|
||||
{
|
||||
@@ -1626,7 +1717,7 @@ MinstrelHtWifiManager::PrintTable (MinstrelHtWifiRemoteStation *station)
|
||||
void
|
||||
MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint32_t groupId, std::ofstream &of)
|
||||
{
|
||||
uint32_t numRates = station->m_nModes;
|
||||
uint32_t numRates = m_numRates;
|
||||
McsGroup group = m_minstrelGroups[groupId];
|
||||
Time txTime;
|
||||
char giMode;
|
||||
@@ -1693,7 +1784,7 @@ MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint32_t
|
||||
of << " " << std::setw (3) << idx << " ";
|
||||
|
||||
/* tx_time[rate(i)] in usec */
|
||||
txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
|
||||
txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
|
||||
of << std::setw (6) << txTime.GetMicroSeconds () << " ";
|
||||
|
||||
of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
|
||||
@@ -1709,7 +1800,14 @@ MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint32_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetIndex (uint32_t groupId, uint32_t rateId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << groupId << rateId);
|
||||
uint32_t index;
|
||||
index = groupId * m_numRates + rateId;
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetRateId (uint32_t index)
|
||||
@@ -1730,11 +1828,11 @@ MinstrelHtWifiManager::GetGroupId (uint32_t index)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetGroupId (uint8_t txstreams, uint8_t sgi, uint32_t chWidth)
|
||||
MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint32_t chWidth)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << (int)txstreams << (int)sgi << chWidth);
|
||||
|
||||
return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 160 ? 3 : chWidth == 80 ? 2 : chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
|
||||
return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -1742,7 +1840,73 @@ MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint32_t c
|
||||
{
|
||||
NS_LOG_FUNCTION (this << (int)txstreams << (int)sgi << chWidth);
|
||||
|
||||
return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 160 ? 3 : chWidth == 80 ? 2 : chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
|
||||
return MAX_HT_STREAM_GROUPS * MAX_SUPPORTED_STREAMS + MAX_SUPPORTED_STREAMS * 2 * (chWidth == 160 ? 3 : chWidth == 80 ? 2 : chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetLowestIndex (MinstrelHtWifiRemoteStation *station)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << station);
|
||||
|
||||
uint32_t groupId = 0;
|
||||
uint32_t rateId = 0;
|
||||
while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
|
||||
{
|
||||
groupId++;
|
||||
}
|
||||
while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
|
||||
{
|
||||
rateId++;
|
||||
}
|
||||
NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
|
||||
return GetIndex (groupId, rateId);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelHtWifiManager::GetLowestIndex (MinstrelHtWifiRemoteStation *station, uint32_t groupId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << station);
|
||||
|
||||
uint32_t rateId = 0;
|
||||
while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
|
||||
{
|
||||
rateId++;
|
||||
}
|
||||
NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
|
||||
return GetIndex (groupId, rateId);
|
||||
}
|
||||
|
||||
|
||||
WifiModeList
|
||||
MinstrelHtWifiManager::GetVhtDeviceMcsList (void) const
|
||||
{
|
||||
WifiModeList vhtMcsList;
|
||||
Ptr<WifiPhy> phy = GetPhy ();
|
||||
for (uint32_t i = 0; i < phy->GetNMcs (); i++)
|
||||
{
|
||||
WifiMode mode = phy->GetMcs (i);
|
||||
if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
|
||||
{
|
||||
vhtMcsList.push_back (mode);
|
||||
}
|
||||
}
|
||||
return vhtMcsList;
|
||||
}
|
||||
|
||||
WifiModeList
|
||||
MinstrelHtWifiManager::GetHtDeviceMcsList (void) const
|
||||
{
|
||||
WifiModeList htMcsList;
|
||||
Ptr<WifiPhy> phy = GetPhy ();
|
||||
for (uint32_t i = 0; i < phy->GetNMcs (); i++)
|
||||
{
|
||||
WifiMode mode = phy->GetMcs (i);
|
||||
if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
htMcsList.push_back (mode);
|
||||
}
|
||||
}
|
||||
return htMcsList;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -55,8 +55,9 @@ struct McsGroup
|
||||
uint8_t sgi;
|
||||
uint32_t chWidth;
|
||||
bool isVht;
|
||||
bool isSupported;
|
||||
|
||||
// To accurately account for TX times, we separate the TX time of the first
|
||||
// To accurately account for TX times, we separate the TX time of the first
|
||||
// MPDU in an A-MPDU from the rest of the MPDUs.
|
||||
TxTime ratesTxTimeTable;
|
||||
TxTime ratesFirstMpduTxTimeTable;
|
||||
@@ -82,6 +83,8 @@ struct HtRateInfo
|
||||
|
||||
bool supported; //!< If the rate is supported.
|
||||
|
||||
uint32_t mcsIndex; //!< The index in the operationalMcsSet of the WifiRemoteStationManager.
|
||||
|
||||
uint32_t retryCount; //!< Retry limit.
|
||||
uint32_t adjustedRetryCount; //!< Adjust the retry limit for this rate.
|
||||
uint32_t numRateAttempt; //!< Number of transmission attempts so far.
|
||||
@@ -149,7 +152,7 @@ typedef std::vector<std::vector<uint32_t> > HtSampleRate;
|
||||
* Constants for maximum values.
|
||||
*/
|
||||
|
||||
static const uint8_t MAX_SUPPORTED_STREAMS = 2; //!< Maximal number of streams supported by the phy layer.
|
||||
static const uint8_t MAX_SUPPORTED_STREAMS = 4; //!< Maximal number of streams supported by the phy layer.
|
||||
static const uint8_t MAX_HT_STREAM_GROUPS = 4; //!< Maximal number of groups per stream in HT (2 possible channel widths and 2 possible SGI configurations).
|
||||
static const uint8_t MAX_VHT_STREAM_GROUPS = 8; //!< Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible SGI configurations).
|
||||
static const uint8_t MAX_HT_GROUP_RATES = 8; //!< Number of rates (or MCS) per HT group.
|
||||
@@ -196,6 +199,7 @@ public:
|
||||
|
||||
private:
|
||||
// Overriden from base class.
|
||||
virtual void DoInitialize (void);
|
||||
virtual WifiRemoteStation * DoCreateStation (void) const;
|
||||
virtual void DoReportRxOk (WifiRemoteStation *station,
|
||||
double rxSnr, WifiMode txMode);
|
||||
@@ -319,21 +323,33 @@ private:
|
||||
* global index and vice versa.
|
||||
*/
|
||||
|
||||
/// Return the rate index inside a group.
|
||||
uint32_t GetRateId (uint32_t index);
|
||||
/// Return the rateId inside a group, from the global index.
|
||||
uint32_t GetRateId (uint32_t index);
|
||||
|
||||
/// Return the group id from global index.
|
||||
/// Return the groupId from the global index.
|
||||
uint32_t GetGroupId (uint32_t index);
|
||||
|
||||
/// Returns the global index corresponding to the MCS inside a group.
|
||||
uint32_t GetIndex (uint32_t groupid, uint32_t mcsIndex);
|
||||
/// Returns the global index corresponding to the groupId and rateId.
|
||||
uint32_t GetIndex (uint32_t groupId, uint32_t rateId);
|
||||
|
||||
/// Calculates the group id from the number of streams, if using sgi and the channel width used.
|
||||
uint32_t GetGroupId (uint8_t txstreams, uint8_t sgi, uint32_t chWidth);
|
||||
/// Returns the groupId of a HT MCS with the given number of streams, if using sgi and the channel width used.
|
||||
uint32_t GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint32_t chWidth);
|
||||
|
||||
/// Calculates the group id from the number of streams, if using sgi and the channel width used.
|
||||
/// Returns the groupId of a VHT MCS with the given number of streams, if using sgi and the channel width used.
|
||||
uint32_t GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint32_t chWidth);
|
||||
|
||||
/// Returns the lowest global index of the rates supported by the station.
|
||||
uint32_t GetLowestIndex (MinstrelHtWifiRemoteStation *station);
|
||||
|
||||
/// Returns the lowest global index of the rates supported by in the group.
|
||||
uint32_t GetLowestIndex (MinstrelHtWifiRemoteStation *station, uint32_t groupId);
|
||||
|
||||
/// Returns a list of only the VHT MCS supported by the device.
|
||||
WifiModeList GetVhtDeviceMcsList (void) const;
|
||||
|
||||
/// Returns a list of only the HT MCS supported by the device.
|
||||
WifiModeList GetHtDeviceMcsList (void) const;
|
||||
|
||||
Time m_updateStats; //!< How frequent do we calculate the stats (1/10 seconds).
|
||||
double m_lookAroundRate; //!< The % to try other rates than our current rate.
|
||||
double m_ewmaLevel; //!< Exponential weighted moving average level (or coefficient).
|
||||
@@ -344,7 +360,6 @@ private:
|
||||
|
||||
uint8_t m_numGroups; //!< Number of groups Minstrel should consider.
|
||||
uint8_t m_numRates; //!< Number of rates per group Minstrel should consider.
|
||||
uint8_t m_maxChWidth; //!< Number of rates per group Minstrel should consider.
|
||||
|
||||
bool m_useVhtOnly; //!< If only VHT MCS should be used, instead of HT and VHT.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user