wifi: Compute correct HE-SIG-B duration for HE MU
This commit is contained in:
committed by
Sébastien Deronne
parent
f4093b3097
commit
fb875b768c
@@ -2054,12 +2054,59 @@ WifiPhy::GetPhySigA2Duration (WifiPreamble preamble)
|
||||
Time
|
||||
WifiPhy::GetPhySigBDuration (WifiTxVector txVector)
|
||||
{
|
||||
switch (txVector.GetPreambleType ())
|
||||
if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_MU) //See section 27.3.10.8 of IEEE 802.11ax draft 4.0.
|
||||
{
|
||||
/*
|
||||
* Compute the number of bits used by common field.
|
||||
* Assume that compression bit in HE-SIG-A is not set (i.e. not
|
||||
* full band MU-MIMO); the field is present.
|
||||
*/
|
||||
uint16_t bw = txVector.GetChannelWidth ();
|
||||
std::size_t commonFieldSize = 4 /* CRC */ + 6 /* tail */;
|
||||
if (bw <= 40)
|
||||
{
|
||||
commonFieldSize += 8; //only one allocation subfield
|
||||
}
|
||||
else
|
||||
{
|
||||
commonFieldSize += 8 * (bw / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the number of bits used by user-specific field.
|
||||
* MU-MIMO is not supported; only one station per RU.
|
||||
* The user-specific field is composed of N user block fields
|
||||
* spread over each corresponding HE-SIG-B content channel.
|
||||
* Each user block field contains either two or one users' data
|
||||
* (the latter being for odd number of stations per content channel).
|
||||
* Padding will be handled further down in the code.
|
||||
*/
|
||||
std::pair<std::size_t, std::size_t> numStaPerContentChannel = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
std::size_t maxNumStaPerContentChannel = std::max (numStaPerContentChannel.first, numStaPerContentChannel.second);
|
||||
std::size_t maxNumUserBlockFields = maxNumStaPerContentChannel / 2; //handle last user block with single user, if any, further down
|
||||
std::size_t userSpecificFieldSize = maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
|
||||
if (maxNumStaPerContentChannel % 2 != 0)
|
||||
{
|
||||
userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute duration of HE-SIG-B considering that padding
|
||||
* is added up to the next OFDM symbol.
|
||||
* Nss = 1 and GI = 800 ns for HE-SIG-B.
|
||||
*/
|
||||
Time symbolDuration = MicroSeconds (4);
|
||||
double numDataBitsPerSymbol = GetHeSigBMode (txVector).GetDataRate (20, 800, 1) * symbolDuration.GetNanoSeconds () / 1e9;
|
||||
double numSymbols = ceil ((commonFieldSize + userSpecificFieldSize) / numDataBitsPerSymbol);
|
||||
|
||||
return FemtoSeconds (static_cast<uint64_t> (numSymbols * symbolDuration.GetFemtoSeconds ()));
|
||||
}
|
||||
else if (txVector.GetPreambleType () == WIFI_PREAMBLE_VHT_MU)
|
||||
{
|
||||
case WIFI_PREAMBLE_VHT_MU:
|
||||
case WIFI_PREAMBLE_HE_MU:
|
||||
return MicroSeconds (4);
|
||||
default:
|
||||
}
|
||||
else
|
||||
{
|
||||
// no SIG-B
|
||||
return MicroSeconds (0);
|
||||
}
|
||||
|
||||
@@ -554,23 +554,131 @@ TxDurationTest::DoRun (void)
|
||||
1536},
|
||||
std::list<HeMuUserInfo> { {{true, HeRu::RU_242_TONE, 1}, WifiPhy::GetHeMcs0 (), 1},
|
||||
{{true, HeRu::RU_242_TONE, 2}, WifiPhy::GetHeMcs0 (), 1} },
|
||||
40, 800, NanoSeconds (1489600)) //equivalent to HE_SU for 20 MHz with extra HE-SIG-B (i.e. 4 us)
|
||||
40, 800, NanoSeconds (1493600)) //equivalent to HE_SU for 20 MHz with 2 extra HE-SIG-B (i.e. 8 us)
|
||||
&& CheckHeMuTxDuration (std::list<uint32_t> {1536,
|
||||
1536},
|
||||
std::list<HeMuUserInfo> { {{true, HeRu::RU_242_TONE, 1}, WifiPhy::GetHeMcs1 (), 1},
|
||||
{{true, HeRu::RU_242_TONE, 2}, WifiPhy::GetHeMcs0 (), 1} },
|
||||
40, 800, NanoSeconds (1489600)) //shouldn't change if first PSDU is shorter
|
||||
40, 800, NanoSeconds (1493600)) //shouldn't change if first PSDU is shorter
|
||||
&& CheckHeMuTxDuration (std::list<uint32_t> {1536,
|
||||
76},
|
||||
std::list<HeMuUserInfo> { {{true, HeRu::RU_242_TONE, 1}, WifiPhy::GetHeMcs0 (), 1},
|
||||
{{true, HeRu::RU_242_TONE, 2}, WifiPhy::GetHeMcs0 (), 1} },
|
||||
40, 800, NanoSeconds (1489600));
|
||||
40, 800, NanoSeconds (1493600));
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ax MU duration failed");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief HE-SIG-B duration test
|
||||
*/
|
||||
class HeSigBDurationTest : public TestCase
|
||||
{
|
||||
public:
|
||||
HeSigBDurationTest ();
|
||||
virtual ~HeSigBDurationTest ();
|
||||
virtual void DoRun (void);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Build a TXVECTOR for HE MU with the given bandwith and user informations.
|
||||
*
|
||||
* \param bw the channel width of the PPDU in MHz
|
||||
* \param userInfos the list of HE MU specific user transmission parameters
|
||||
*
|
||||
* \return the configured HE MU TXVECTOR
|
||||
*/
|
||||
static WifiTxVector BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos);
|
||||
};
|
||||
|
||||
HeSigBDurationTest::HeSigBDurationTest ()
|
||||
: TestCase ("Check HE-SIG-B duration computation")
|
||||
{
|
||||
}
|
||||
|
||||
HeSigBDurationTest::~HeSigBDurationTest ()
|
||||
{
|
||||
}
|
||||
|
||||
WifiTxVector
|
||||
HeSigBDurationTest::BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos)
|
||||
{
|
||||
WifiTxVector txVector;
|
||||
txVector.SetPreambleType (WIFI_PREAMBLE_HE_MU);
|
||||
txVector.SetChannelWidth (bw);
|
||||
txVector.SetGuardInterval (3200);
|
||||
txVector.SetStbc (0);
|
||||
txVector.SetNess (0);
|
||||
std::list<uint16_t> staIds;
|
||||
uint16_t staId = 1;
|
||||
for (const auto & userInfo : userInfos)
|
||||
{
|
||||
txVector.SetHeMuUserInfo (staId, userInfo);
|
||||
staIds.push_back (staId++);
|
||||
}
|
||||
return txVector;
|
||||
}
|
||||
|
||||
void
|
||||
HeSigBDurationTest::DoRun (void)
|
||||
{
|
||||
//20 MHz band
|
||||
std::list<HeMuUserInfo> userInfos;
|
||||
userInfos.push_back ({{true, HeRu::RU_106_TONE, 1}, WifiPhy::GetHeMcs11 (), 1});
|
||||
userInfos.push_back ({{true, HeRu::RU_106_TONE, 2}, WifiPhy::GetHeMcs10 (), 4});
|
||||
WifiTxVector txVector = BuildTxVector (20, userInfos);
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetHeSigBMode (txVector), WifiPhy::GetVhtMcs5 (), "HE-SIG-B should be sent at MCS 5");
|
||||
std::pair<std::size_t, std::size_t> numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Both users should be on HE-SIG-B content channel 1");
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 0, "Both users should be on HE-SIG-B content channel 2");
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetPhySigBDuration (txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
|
||||
|
||||
//40 MHz band, even number of users per HE-SIG-B content channel
|
||||
userInfos.push_back ({{true, HeRu::RU_52_TONE, 5}, WifiPhy::GetHeMcs4 (), 1});
|
||||
userInfos.push_back ({{true, HeRu::RU_52_TONE, 6}, WifiPhy::GetHeMcs6 (), 2});
|
||||
userInfos.push_back ({{true, HeRu::RU_52_TONE, 7}, WifiPhy::GetHeMcs5 (), 3});
|
||||
userInfos.push_back ({{true, HeRu::RU_52_TONE, 8}, WifiPhy::GetHeMcs6 (), 2});
|
||||
txVector = BuildTxVector (40, userInfos);
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetHeSigBMode (txVector), WifiPhy::GetVhtMcs4 (), "HE-SIG-B should be sent at MCS 4");
|
||||
numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 4, "Four users should be on HE-SIG-B content channel 2");
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetPhySigBDuration (txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
|
||||
|
||||
//40 MHz band, odd number of users per HE-SIG-B content channel
|
||||
userInfos.push_back ({{true, HeRu::RU_26_TONE, 13}, WifiPhy::GetHeMcs3 (), 1});
|
||||
txVector = BuildTxVector (40, userInfos);
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetHeSigBMode (txVector), WifiPhy::GetVhtMcs3 (), "HE-SIG-B should be sent at MCS 3");
|
||||
numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 5, "Five users should be on HE-SIG-B content channel 2");
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetPhySigBDuration (txVector), MicroSeconds (8), "HE-SIG-B should last two OFDM symbols");
|
||||
|
||||
//80 MHz band
|
||||
userInfos.push_back ({{true, HeRu::RU_242_TONE, 3}, WifiPhy::GetHeMcs1 (), 1});
|
||||
userInfos.push_back ({{true, HeRu::RU_242_TONE, 4}, WifiPhy::GetHeMcs4 (), 1});
|
||||
txVector = BuildTxVector (80, userInfos);
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetHeSigBMode (txVector), WifiPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
|
||||
numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 3, "Three users should be on HE-SIG-B content channel 1");
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 6, "Six users should be on HE-SIG-B content channel 2");
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetPhySigBDuration (txVector), MicroSeconds (16), "HE-SIG-B should last four OFDM symbols");
|
||||
|
||||
//160 MHz band
|
||||
userInfos.push_back ({{false, HeRu::RU_996_TONE, 1}, WifiPhy::GetHeMcs1 (), 1});
|
||||
txVector = BuildTxVector (160, userInfos);
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetHeSigBMode (txVector), WifiPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
|
||||
numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 4, "Four users should be on HE-SIG-B content channel 1");
|
||||
NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 7, "Seven users should be on HE-SIG-B content channel 2");
|
||||
NS_TEST_EXPECT_MSG_EQ (WifiPhy::GetPhySigBDuration (txVector), MicroSeconds (20), "HE-SIG-B should last five OFDM symbols");
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -586,6 +694,7 @@ public:
|
||||
TxDurationTestSuite::TxDurationTestSuite ()
|
||||
: TestSuite ("wifi-devices-tx-duration", UNIT)
|
||||
{
|
||||
AddTestCase (new HeSigBDurationTest, TestCase::QUICK);
|
||||
AddTestCase (new TxDurationTest, TestCase::QUICK);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user