From fb875b768c7744e337fad44ac2855d34393461dc Mon Sep 17 00:00:00 2001 From: Rediet Date: Tue, 25 Jun 2019 09:57:38 +0200 Subject: [PATCH] wifi: Compute correct HE-SIG-B duration for HE MU --- src/wifi/model/wifi-phy.cc | 55 ++++++++++++-- src/wifi/test/tx-duration-test.cc | 115 +++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 7 deletions(-) diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index 814c03c9c..f76f7cdba 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -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 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 (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); } diff --git a/src/wifi/test/tx-duration-test.cc b/src/wifi/test/tx-duration-test.cc index 505862dc0..5425e424f 100644 --- a/src/wifi/test/tx-duration-test.cc +++ b/src/wifi/test/tx-duration-test.cc @@ -554,23 +554,131 @@ TxDurationTest::DoRun (void) 1536}, std::list { {{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 {1536, 1536}, std::list { {{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 {1536, 76}, std::list { {{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 userInfos); +}; + +HeSigBDurationTest::HeSigBDurationTest () + : TestCase ("Check HE-SIG-B duration computation") +{ +} + +HeSigBDurationTest::~HeSigBDurationTest () +{ +} + +WifiTxVector +HeSigBDurationTest::BuildTxVector (uint16_t bw, std::list userInfos) +{ + WifiTxVector txVector; + txVector.SetPreambleType (WIFI_PREAMBLE_HE_MU); + txVector.SetChannelWidth (bw); + txVector.SetGuardInterval (3200); + txVector.SetStbc (0); + txVector.SetNess (0); + std::list 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 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 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); }