From 08c6d2f2af1ef2b1c6545f886d92265c450e72ff Mon Sep 17 00:00:00 2001 From: Sebastien Deronne Date: Sat, 14 May 2022 09:26:22 +0200 Subject: [PATCH] wifi: Add UL MU-MIMO PHY tests --- src/wifi/test/wifi-phy-mu-mimo-test.cc | 791 ++++++++++++++++++++++++- 1 file changed, 788 insertions(+), 3 deletions(-) diff --git a/src/wifi/test/wifi-phy-mu-mimo-test.cc b/src/wifi/test/wifi-phy-mu-mimo-test.cc index 1c7b7ed7e..bf591b0c9 100644 --- a/src/wifi/test/wifi-phy-mu-mimo-test.cc +++ b/src/wifi/test/wifi-phy-mu-mimo-test.cc @@ -17,8 +17,11 @@ * Author: Sébastien Deronne */ +#include "ns3/ap-wifi-mac.h" +#include "ns3/boolean.h" +#include "ns3/double.h" +#include "ns3/he-configuration.h" #include "ns3/he-phy.h" -#include "ns3/he-ppdu.h" #include "ns3/interference-helper.h" #include "ns3/log.h" #include "ns3/multi-model-spectrum-channel.h" @@ -30,14 +33,15 @@ #include "ns3/spectrum-wifi-helper.h" #include "ns3/spectrum-wifi-phy.h" #include "ns3/test.h" +#include "ns3/uinteger.h" #include "ns3/wifi-mac-header.h" #include "ns3/wifi-net-device.h" #include "ns3/wifi-psdu.h" -#include "ns3/wifi-spectrum-signal-parameters.h" #include "ns3/wifi-spectrum-value-helper.h" #include "ns3/wifi-utils.h" #include +#include using namespace ns3; @@ -199,6 +203,13 @@ class MuMimoTestHePhy : public HePhy */ uint16_t GetStaId(const Ptr ppdu) const override; + /** + * Set the global PPDU UID counter. + * + * \param uid the value to which the global PPDU UID counter should be set + */ + void SetGlobalPpduUid(uint64_t uid); + private: uint16_t m_staId; ///< ID of the STA to which this PHY belongs to }; // class MuMimoTestHePhy @@ -219,6 +230,12 @@ MuMimoTestHePhy::GetStaId(const Ptr ppdu) const return HePhy::GetStaId(ppdu); } +void +MuMimoTestHePhy::SetGlobalPpduUid(uint64_t uid) +{ + m_globalPpduUid = uid; +} + /** * SpectrumWifiPhy used for testing MU-MIMO. */ @@ -238,10 +255,29 @@ class MuMimoSpectrumWifiPhy : public SpectrumWifiPhy MuMimoSpectrumWifiPhy(uint16_t staId); ~MuMimoSpectrumWifiPhy() override; + /** + * Set the global PPDU UID counter. + * + * \param uid the value to which the global PPDU UID counter should be set + */ + void SetPpduUid(uint64_t uid); + + /** + * Since we assume trigger frame was previously received from AP, this is used to set its UID + * + * \param uid the PPDU UID of the trigger frame + */ + void SetTriggerFrameUid(uint64_t uid); + + /** + * \return the current event + */ + Ptr GetCurrentEvent(); + + private: void DoInitialize() override; void DoDispose() override; - private: Ptr m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test }; // class MuMimoSpectrumWifiPhy @@ -279,6 +315,25 @@ MuMimoSpectrumWifiPhy::DoDispose() SpectrumWifiPhy::DoDispose(); } +void +MuMimoSpectrumWifiPhy::SetPpduUid(uint64_t uid) +{ + m_ofdmTestHePhy->SetGlobalPpduUid(uid); + m_previouslyRxPpduUid = uid; +} + +void +MuMimoSpectrumWifiPhy::SetTriggerFrameUid(uint64_t uid) +{ + m_previouslyRxPpduUid = uid; +} + +Ptr +MuMimoSpectrumWifiPhy::GetCurrentEvent() +{ + return m_currentEvent; +} + /** * \ingroup wifi-test * \ingroup tests @@ -1063,6 +1118,735 @@ TestDlMuMimoPhyTransmission::DoRun() Simulator::Destroy(); } +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief UL MU-MIMO PHY test + */ +class TestUlMuMimoPhyTransmission : public TestCase +{ + public: + TestUlMuMimoPhyTransmission(); + + private: + void DoSetup() override; + void DoTeardown() override; + void DoRun() override; + + /** + * Get TXVECTOR for HE TB PPDU. + * \param txStaId the ID of the TX STA + * \param nss the number of spatial streams used for the transmission + * \param bssColor the BSS color of the TX STA + * \return the TXVECTOR for HE TB PPDU + */ + WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const; + /** + * Set TRIGVECTOR for HE TB PPDU + * + * \param staIds the IDs of the STAs sollicited for the HE TB transmission + * \param bssColor the BSS color of the TX STA + */ + void SetTrigVector(const std::vector& staIds, uint8_t bssColor); + /** + * Send HE TB PPDU function + * \param txStaId the ID of the TX STA + * \param nss the number of spatial streams used for the transmission + * \param payloadSize the size of the payload in bytes + * \param uid the UID of the trigger frame that is initiating this transmission + * \param bssColor the BSS color of the TX STA + */ + void SendHeTbPpdu(uint16_t txStaId, + uint8_t nss, + std::size_t payloadSize, + uint64_t uid, + uint8_t bssColor); + + /** + * Send HE SU PPDU function + * \param txStaId the ID of the TX STA + * \param payloadSize the size of the payload in bytes + * \param uid the UID of the trigger frame that is initiating this transmission + * \param bssColor the BSS color of the TX STA + */ + void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor); + + /** + * Set the BSS color + * \param phy the PHY + * \param bssColor the BSS color + */ + void SetBssColor(Ptr phy, uint8_t bssColor); + + /** + * Run one function + */ + void RunOne(); + + /** + * Check the received PSDUs from a given STA + * \param staId the ID of the STA to check + * \param expectedSuccess the expected number of success + * \param expectedFailures the expected number of failures + * \param expectedBytes the expected number of bytes + */ + void CheckRxFromSta(uint16_t staId, + uint32_t expectedSuccess, + uint32_t expectedFailures, + uint32_t expectedBytes); + + /** + * Verify all events are cleared at end of TX or RX + */ + void VerifyEventsCleared(); + + /** + * Check the PHY state + * \param phy the PHY + * \param expectedState the expected state of the PHY + */ + void CheckPhyState(Ptr phy, WifiPhyState expectedState); + /// \copydoc CheckPhyState + void DoCheckPhyState(Ptr phy, WifiPhyState expectedState); + + /** + * Reset function + */ + void Reset(); + + /** + * Receive success function + * \param psdu the PSDU + * \param rxSignalInfo the info on the received signal (\see RxSignalInfo) + * \param txVector the transmit vector + * \param statusPerMpdu reception status per MPDU + */ + void RxSuccess(Ptr psdu, + RxSignalInfo rxSignalInfo, + WifiTxVector txVector, + std::vector statusPerMpdu); + + /** + * Receive failure function + * \param psdu the PSDU + */ + void RxFailure(Ptr psdu); + + /** + * Schedule test to perform. + * The interference generation should be scheduled apart. + * + * \param delay the reference delay to schedule the events + * \param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU + * \param expectedStateAtEnd the expected state of the PHY at the end of the reception + * \param expectedCountersPerSta the expected counters per STA + */ + void ScheduleTest( + Time delay, + const std::vector& txStaIds, + WifiPhyState expectedStateAtEnd, + const std::vector>& expectedCountersPerSta); + + /** + * Log scenario description + * + * \param log the scenario description to add to log + */ + void LogScenario(const std::string& log) const; + + Ptr m_phyAp; ///< PHY of AP + std::vector> m_phyStas; ///< PHYs of STAs + + std::vector m_countRxSuccessFromStas; ///< count RX success from STAs + std::vector m_countRxFailureFromStas; ///< count RX failure from STAs + std::vector m_countRxBytesFromStas; ///< count RX bytes from STAs + + Time m_delayStart; ///< delay between the start of each HE TB PPDUs + uint16_t m_frequency; ///< frequency in MHz + uint16_t m_channelWidth; ///< channel width in MHz + Time m_expectedPpduDuration; ///< expected duration to send MU PPDU +}; + +TestUlMuMimoPhyTransmission::TestUlMuMimoPhyTransmission() + : TestCase("UL MU-MIMO PHY test"), + m_countRxSuccessFromStas{}, + m_countRxFailureFromStas{}, + m_countRxBytesFromStas{}, + m_delayStart{Seconds(0)}, + m_frequency{DEFAULT_FREQUENCY}, + m_channelWidth{DEFAULT_CHANNEL_WIDTH}, + m_expectedPpduDuration{NanoSeconds(271200)} +{ +} + +void +TestUlMuMimoPhyTransmission::SendHeSuPpdu(uint16_t txStaId, + std::size_t payloadSize, + uint64_t uid, + uint8_t bssColor) +{ + NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor); + WifiConstPsduMap psdus; + + WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(), + 0, + WIFI_PREAMBLE_HE_SU, + 800, + 1, + 1, + 0, + m_channelWidth, + false, + false, + false, + bssColor); + + Ptr pkt = Create(payloadSize); + WifiMacHeader hdr; + hdr.SetType(WIFI_MAC_QOSDATA); + hdr.SetQosTid(0); + hdr.SetAddr1(Mac48Address("00:00:00:00:00:00")); + std::ostringstream addr; + addr << "00:00:00:00:00:0" << txStaId; + hdr.SetAddr2(Mac48Address(addr.str().c_str())); + hdr.SetSequenceNumber(1); + Ptr psdu = Create(pkt, hdr); + psdus.insert(std::make_pair(SU_STA_ID, psdu)); + + Ptr phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1); + phy->SetPpduUid(uid); + phy->Send(psdus, txVector); +} + +WifiTxVector +TestUlMuMimoPhyTransmission::GetTxVectorForHeTbPpdu(uint16_t txStaId, + uint8_t nss, + uint8_t bssColor) const +{ + WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(), + 0, + WIFI_PREAMBLE_HE_TB, + 1600, + 1, + nss, + 0, + m_channelWidth, + false, + false, + false, + bssColor); + + HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO + txVector.SetRu(ru, txStaId); + txVector.SetMode(HePhy::GetHeMcs7(), txStaId); + txVector.SetNss(nss, txStaId); + + return txVector; +} + +void +TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector& staIds, uint8_t bssColor) +{ + WifiTxVector txVector(HePhy::GetHeMcs7(), + 0, + WIFI_PREAMBLE_HE_TB, + 1600, + 1, + 1, + 0, + m_channelWidth, + false, + false, + false, + bssColor); + + HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO + for (auto staId : staIds) + { + txVector.SetRu(ru, staId); + txVector.SetMode(HePhy::GetHeMcs7(), staId); + txVector.SetNss(1, staId); + } + + uint16_t length; + std::tie(length, m_expectedPpduDuration) = + HePhy::ConvertHeTbPpduDurationToLSigLength(m_expectedPpduDuration, + txVector, + m_phyAp->GetPhyBand()); + txVector.SetLength(length); + auto hePhyAp = DynamicCast(m_phyAp->GetPhyEntity(WIFI_MOD_CLASS_HE)); + hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration); +} + +void +TestUlMuMimoPhyTransmission::SendHeTbPpdu(uint16_t txStaId, + uint8_t nss, + std::size_t payloadSize, + uint64_t uid, + uint8_t bssColor) +{ + NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor); + WifiConstPsduMap psdus; + + WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor); + Ptr pkt = Create(payloadSize); + WifiMacHeader hdr; + hdr.SetType(WIFI_MAC_QOSDATA); + hdr.SetQosTid(0); + hdr.SetAddr1(Mac48Address("00:00:00:00:00:00")); + std::ostringstream addr; + addr << "00:00:00:00:00:0" << txStaId; + hdr.SetAddr2(Mac48Address(addr.str().c_str())); + hdr.SetSequenceNumber(1); + Ptr psdu = Create(pkt, hdr); + psdus.insert(std::make_pair(txStaId, psdu)); + + Ptr phy = m_phyStas.at(txStaId - 1); + Time txDuration = + phy->CalculateTxDuration(psdu->GetSize(), txVector, phy->GetPhyBand(), txStaId); + txVector.SetLength( + HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first); + + phy->SetPpduUid(uid); + phy->Send(psdus, txVector); +} + +void +TestUlMuMimoPhyTransmission::RxSuccess(Ptr psdu, + RxSignalInfo rxSignalInfo, + WifiTxVector txVector, + std::vector /*statusPerMpdu*/) +{ + NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector); + NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > 0), true, "Incorrect SNR value"); + for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index) + { + std::ostringstream addr; + addr << "00:00:00:00:00:0" << index + 1; + if (psdu->GetAddr2() == Mac48Address(addr.str().c_str())) + { + m_countRxSuccessFromStas.at(index)++; + m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30); + break; + } + } +} + +void +TestUlMuMimoPhyTransmission::RxFailure(Ptr psdu) +{ + NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2()); + for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index) + { + std::ostringstream addr; + addr << "00:00:00:00:00:0" << index + 1; + if (psdu->GetAddr2() == Mac48Address(addr.str().c_str())) + { + m_countRxFailureFromStas.at(index)++; + break; + } + } +} + +void +TestUlMuMimoPhyTransmission::CheckRxFromSta(uint16_t staId, + uint32_t expectedSuccess, + uint32_t expectedFailures, + uint32_t expectedBytes) +{ + NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes); + NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessFromStas[staId - 1], + expectedSuccess, + "The number of successfully received packets from STA " + << staId << " is not correct!"); + NS_TEST_ASSERT_MSG_EQ(m_countRxFailureFromStas[staId - 1], + expectedFailures, + "The number of unsuccessfully received packets from STA " + << staId << " is not correct!"); + NS_TEST_ASSERT_MSG_EQ(m_countRxBytesFromStas[staId - 1], + expectedBytes, + "The number of bytes received from STA " << staId << " is not correct!"); +} + +void +TestUlMuMimoPhyTransmission::VerifyEventsCleared() +{ + NS_TEST_ASSERT_MSG_EQ(m_phyAp->GetCurrentEvent(), + nullptr, + "m_currentEvent for AP was not cleared"); + std::size_t sta = 1; + for (auto& phy : m_phyStas) + { + NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(), + nullptr, + "m_currentEvent for STA " << sta << " was not cleared"); + sta++; + } +} + +void +TestUlMuMimoPhyTransmission::CheckPhyState(Ptr phy, + WifiPhyState expectedState) +{ + // This is needed to make sure PHY state will be checked as the last event if a state change + // occurred at the exact same time as the check + Simulator::ScheduleNow(&TestUlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState); +} + +void +TestUlMuMimoPhyTransmission::DoCheckPhyState(Ptr phy, + WifiPhyState expectedState) +{ + WifiPhyState currentState; + PointerValue ptr; + phy->GetAttribute("State", ptr); + Ptr state = DynamicCast(ptr.Get()); + currentState = state->GetState(); + NS_LOG_FUNCTION(this << currentState << expectedState); + NS_TEST_ASSERT_MSG_EQ(currentState, + expectedState, + "PHY State " << currentState << " does not match expected state " + << expectedState << " at " << Simulator::Now()); +} + +void +TestUlMuMimoPhyTransmission::Reset() +{ + for (auto& counter : m_countRxSuccessFromStas) + { + counter = 0; + } + for (auto& counter : m_countRxFailureFromStas) + { + counter = 0; + } + for (auto& counter : m_countRxBytesFromStas) + { + counter = 0; + } + for (auto& phy : m_phyStas) + { + phy->SetPpduUid(0); + phy->SetTriggerFrameUid(0); + } + SetBssColor(m_phyAp, 0); +} + +void +TestUlMuMimoPhyTransmission::SetBssColor(Ptr phy, uint8_t bssColor) +{ + Ptr device = DynamicCast(phy->GetDevice()); + Ptr heConfiguration = device->GetHeConfiguration(); + heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor)); +} + +void +TestUlMuMimoPhyTransmission::DoSetup() +{ + // WifiHelper::EnableLogComponents(); + // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL); + + Ptr spectrumChannel = CreateObject(); + Ptr delayModel = + CreateObject(); + spectrumChannel->SetPropagationDelayModel(delayModel); + + Ptr apNode = CreateObject(); + Ptr apDev = CreateObject(); + apDev->SetStandard(WIFI_STANDARD_80211ax); + Ptr apMac = CreateObject(); + apMac->SetAttribute("BeaconGeneration", BooleanValue(false)); + apDev->SetMac(apMac); + m_phyAp = CreateObject(0); + Ptr heConfiguration = CreateObject(); + apDev->SetHeConfiguration(heConfiguration); + Ptr apInterferenceHelper = CreateObject(); + m_phyAp->SetInterferenceHelper(apInterferenceHelper); + Ptr apErrorModel = CreateObject(); + m_phyAp->SetErrorRateModel(apErrorModel); + m_phyAp->SetDevice(apDev); + m_phyAp->AddChannel(spectrumChannel); + m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax); + m_phyAp->SetReceiveOkCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxSuccess, this)); + m_phyAp->SetReceiveErrorCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxFailure, this)); + apDev->SetPhy(m_phyAp); + apNode->AddDevice(apDev); + + for (std::size_t i = 1; i <= 4; ++i) + { + Ptr staNode = CreateObject(); + Ptr staDev = CreateObject(); + staDev->SetStandard(WIFI_STANDARD_80211ax); + Ptr phy = CreateObject(i); + staDev->SetHeConfiguration(CreateObject()); + Ptr staInterferenceHelper = CreateObject(); + phy->SetInterferenceHelper(staInterferenceHelper); + Ptr staErrorModel = CreateObject(); + phy->SetErrorRateModel(staErrorModel); + phy->SetDevice(staDev); + phy->AddChannel(spectrumChannel); + phy->ConfigureStandard(WIFI_STANDARD_80211ax); + phy->SetAttribute("TxGain", DoubleValue(1.0)); + phy->SetAttribute("TxPowerStart", DoubleValue(16.0)); + phy->SetAttribute("TxPowerEnd", DoubleValue(16.0)); + phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default + phy->SetAttribute("RxGain", DoubleValue(2.0)); + staDev->SetPhy(phy); + staNode->AddDevice(staDev); + m_phyStas.push_back(phy); + m_countRxSuccessFromStas.push_back(0); + m_countRxFailureFromStas.push_back(0); + m_countRxBytesFromStas.push_back(0); + } +} + +void +TestUlMuMimoPhyTransmission::DoTeardown() +{ + for (auto& phy : m_phyStas) + { + phy->Dispose(); + phy = nullptr; + } +} + +void +TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const +{ + NS_LOG_INFO(log); +} + +void +TestUlMuMimoPhyTransmission::ScheduleTest( + Time delay, + const std::vector& txStaIds, + WifiPhyState expectedStateAtEnd, + const std::vector>& expectedCountersPerSta) +{ + static uint64_t uid = 0; + + // AP sends an SU packet preceding HE TB PPDUs + Simulator::Schedule(delay - MilliSeconds(10), + &TestUlMuMimoPhyTransmission::SendHeSuPpdu, + this, + 0, + 50, + ++uid, + 0); + + Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::SetTrigVector, this, txStaIds, 0); + + // STAs send MU UL PPDUs addressed to AP + uint16_t payloadSize = 1000; + std::size_t index = 0; + for (auto txStaId : txStaIds) + { + Simulator::Schedule(delay + (index * m_delayStart), + &TestUlMuMimoPhyTransmission::SendHeTbPpdu, + this, + txStaId, + 1, + payloadSize, + uid, + 0); + payloadSize++; + index++; + } + + // Verify it takes m_expectedPpduDuration to transmit the PPDUs + Simulator::Schedule(delay + m_expectedPpduDuration - NanoSeconds(1), + &TestUlMuMimoPhyTransmission::CheckPhyState, + this, + m_phyAp, + WifiPhyState::RX); + Simulator::Schedule(delay + m_expectedPpduDuration + + (m_delayStart * expectedCountersPerSta.size()), + &TestUlMuMimoPhyTransmission::CheckPhyState, + this, + m_phyAp, + expectedStateAtEnd); + + delay += MilliSeconds(100); + // Check reception state from STAs + uint16_t staId = 1; + for (const auto& expectedCounters : expectedCountersPerSta) + { + uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters); + uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters); + uint16_t expectedBytesFromSta = std::get<2>(expectedCounters); + Simulator::Schedule(delay + (m_delayStart * (staId - 1)), + &TestUlMuMimoPhyTransmission::CheckRxFromSta, + this, + staId, + expectedSuccessFromSta, + expectedFailuresFromSta, + expectedBytesFromSta); + staId++; + } + + // Verify events data have been cleared + Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::VerifyEventsCleared, this); + + delay += MilliSeconds(100); + Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this); +} + +void +TestUlMuMimoPhyTransmission::RunOne() +{ + RngSeedManager::SetSeed(1); + RngSeedManager::SetRun(1); + int64_t streamNumber = 0; + m_phyAp->AssignStreams(streamNumber); + for (auto& phy : m_phyStas) + { + phy->AssignStreams(streamNumber); + } + + auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0, + m_frequency, + m_channelWidth, + WIFI_STANDARD_80211ax, + WIFI_PHY_BAND_5GHZ)); + + m_phyAp->SetOperatingChannel( + WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0}); + for (auto& phy : m_phyStas) + { + phy->SetOperatingChannel( + WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0}); + } + + Time delay = Seconds(0.0); + Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this); + delay += Seconds(1.0); + + //--------------------------------------------------------------------------- + // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received + Simulator::Schedule(delay, + &TestUlMuMimoPhyTransmission::LogScenario, + this, + "Reception of HE TB PPDUs using full BW MU-MIMO"); + ScheduleTest(delay, + {1, 2, 3}, + WifiPhyState::IDLE, + { + std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been + // successfully received from STA 1 + std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been + // successfully received from STA 2 + std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been + // successfully received from STA 3 + }); + delay += Seconds(1.0); + + //--------------------------------------------------------------------------- + // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO + // have been impacted + Simulator::Schedule(delay, + &TestUlMuMimoPhyTransmission::LogScenario, + this, + "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU " + "PPDU arriving during the 400 ns window"); + // One HE SU arrives at AP during the 400ns window + Simulator::Schedule(delay + NanoSeconds(150), + &TestUlMuMimoPhyTransmission::SendHeSuPpdu, + this, + 4, + 1002, + 2, + 0); + ScheduleTest(delay, + {1, 2, 3}, + WifiPhyState::IDLE, + { + std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have + // failed (since interference from STA 4) + std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have + // failed (since interference from STA 4) + std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed + // (since interference from STA 4) + }); + delay += Seconds(1.0); + + //--------------------------------------------------------------------------- + // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been + // impacted + Simulator::Schedule(delay, + &TestUlMuMimoPhyTransmission::LogScenario, + this, + "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU " + "arriving during the HE portion"); + // One HE SU arrives at AP during the HE portion + Simulator::Schedule(delay + MicroSeconds(40), + &TestUlMuMimoPhyTransmission::SendHeSuPpdu, + this, + 4, + 1002, + 2, + 0); + ScheduleTest(delay, + {1, 2, 3}, + WifiPhyState::CCA_BUSY, + { + std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have + // failed (since interference from STA 4) + std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have + // failed (since interference from STA 4) + std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed + // (since interference from STA 4) + }); + delay += Seconds(1.0); + + Simulator::Run(); +} + +void +TestUlMuMimoPhyTransmission::DoRun() +{ + std::vector