wifi: Add DL MU-MIMO PHY tests
This commit is contained in:
@@ -18,10 +18,24 @@
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "ns3/nist-error-rate-model.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/rng-seed-manager.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/spectrum-wifi-helper.h"
|
||||
#include "ns3/spectrum-wifi-phy.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/wifi-tx-vector.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 <list>
|
||||
|
||||
@@ -29,6 +43,9 @@ using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
|
||||
|
||||
constexpr uint32_t DEFAULT_FREQUENCY = 5180; // MHz
|
||||
constexpr uint16_t DEFAULT_CHANNEL_WIDTH = 20; // MHz
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -51,7 +68,7 @@ class TestDlMuTxVector : public TestCase
|
||||
*
|
||||
* \return the configured MU TXVECTOR
|
||||
*/
|
||||
static WifiTxVector BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos);
|
||||
static WifiTxVector BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos);
|
||||
};
|
||||
|
||||
TestDlMuTxVector::TestDlMuTxVector()
|
||||
@@ -60,7 +77,7 @@ TestDlMuTxVector::TestDlMuTxVector()
|
||||
}
|
||||
|
||||
WifiTxVector
|
||||
TestDlMuTxVector::BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos)
|
||||
TestDlMuTxVector::BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos)
|
||||
{
|
||||
WifiTxVector txVector;
|
||||
txVector.SetPreambleType(WIFI_PREAMBLE_HE_MU);
|
||||
@@ -159,6 +176,893 @@ TestDlMuTxVector::DoRun()
|
||||
"TX-VECTOR should not indicate all checks are passed");
|
||||
}
|
||||
|
||||
/**
|
||||
* HE PHY slightly modified so as to return a given
|
||||
* STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
|
||||
*/
|
||||
class MuMimoTestHePhy : public HePhy
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param staId the ID of the STA to which this PHY belongs to
|
||||
*/
|
||||
MuMimoTestHePhy(uint16_t staId);
|
||||
|
||||
/**
|
||||
* Return the STA ID that has been assigned to the station this PHY belongs to.
|
||||
* This is typically called for MU PPDUs, in order to pick the correct PSDU.
|
||||
*
|
||||
* \param ppdu the PPDU for which the STA ID is requested
|
||||
* \return the STA ID
|
||||
*/
|
||||
uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
|
||||
|
||||
private:
|
||||
uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
|
||||
}; // class MuMimoTestHePhy
|
||||
|
||||
MuMimoTestHePhy::MuMimoTestHePhy(uint16_t staId)
|
||||
: HePhy(),
|
||||
m_staId(staId)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t
|
||||
MuMimoTestHePhy::GetStaId(const Ptr<const WifiPpdu> ppdu) const
|
||||
{
|
||||
if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
|
||||
{
|
||||
return m_staId;
|
||||
}
|
||||
return HePhy::GetStaId(ppdu);
|
||||
}
|
||||
|
||||
/**
|
||||
* SpectrumWifiPhy used for testing MU-MIMO.
|
||||
*/
|
||||
class MuMimoSpectrumWifiPhy : public SpectrumWifiPhy
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param staId the ID of the STA to which this PHY belongs to
|
||||
*/
|
||||
MuMimoSpectrumWifiPhy(uint16_t staId);
|
||||
~MuMimoSpectrumWifiPhy() override;
|
||||
|
||||
void DoInitialize() override;
|
||||
void DoDispose() override;
|
||||
|
||||
private:
|
||||
Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
|
||||
}; // class MuMimoSpectrumWifiPhy
|
||||
|
||||
TypeId
|
||||
MuMimoSpectrumWifiPhy::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
|
||||
return tid;
|
||||
}
|
||||
|
||||
MuMimoSpectrumWifiPhy::MuMimoSpectrumWifiPhy(uint16_t staId)
|
||||
: SpectrumWifiPhy()
|
||||
{
|
||||
m_ofdmTestHePhy = Create<MuMimoTestHePhy>(staId);
|
||||
m_ofdmTestHePhy->SetOwner(this);
|
||||
}
|
||||
|
||||
MuMimoSpectrumWifiPhy::~MuMimoSpectrumWifiPhy()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MuMimoSpectrumWifiPhy::DoInitialize()
|
||||
{
|
||||
// Replace HE PHY instance with test instance
|
||||
m_phyEntities[WIFI_MOD_CLASS_HE] = m_ofdmTestHePhy;
|
||||
SpectrumWifiPhy::DoInitialize();
|
||||
}
|
||||
|
||||
void
|
||||
MuMimoSpectrumWifiPhy::DoDispose()
|
||||
{
|
||||
m_ofdmTestHePhy = nullptr;
|
||||
SpectrumWifiPhy::DoDispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief DL MU-MIMO PHY test
|
||||
*/
|
||||
class TestDlMuMimoPhyTransmission : public TestCase
|
||||
{
|
||||
public:
|
||||
TestDlMuMimoPhyTransmission();
|
||||
|
||||
private:
|
||||
void DoSetup() override;
|
||||
void DoTeardown() override;
|
||||
void DoRun() override;
|
||||
|
||||
/**
|
||||
* Receive success function for STA 1
|
||||
* \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 RxSuccessSta1(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> statusPerMpdu);
|
||||
/**
|
||||
* Receive success function for STA 2
|
||||
* \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 RxSuccessSta2(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> statusPerMpdu);
|
||||
/**
|
||||
* Receive success function for STA 3
|
||||
* \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 RxSuccessSta3(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> statusPerMpdu);
|
||||
|
||||
/**
|
||||
* Receive failure function for STA 1
|
||||
* \param psdu the PSDU
|
||||
*/
|
||||
void RxFailureSta1(Ptr<const WifiPsdu> psdu);
|
||||
/**
|
||||
* Receive failure function for STA 2
|
||||
* \param psdu the PSDU
|
||||
*/
|
||||
void RxFailureSta2(Ptr<const WifiPsdu> psdu);
|
||||
/**
|
||||
* Receive failure function for STA 3
|
||||
* \param psdu the PSDU
|
||||
*/
|
||||
void RxFailureSta3(Ptr<const WifiPsdu> psdu);
|
||||
|
||||
/**
|
||||
* Check the results for STA 1
|
||||
* \param expectedRxSuccess the expected number of RX success
|
||||
* \param expectedRxFailure the expected number of RX failures
|
||||
* \param expectedRxBytes the expected number of RX bytes
|
||||
*/
|
||||
void CheckResultsSta1(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes);
|
||||
/**
|
||||
* Check the results for STA 2
|
||||
* \param expectedRxSuccess the expected number of RX success
|
||||
* \param expectedRxFailure the expected number of RX failures
|
||||
* \param expectedRxBytes the expected number of RX bytes
|
||||
*/
|
||||
void CheckResultsSta2(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes);
|
||||
/**
|
||||
* Check the results for STA 3
|
||||
* \param expectedRxSuccess the expected number of RX success
|
||||
* \param expectedRxFailure the expected number of RX failures
|
||||
* \param expectedRxBytes the expected number of RX bytes
|
||||
*/
|
||||
void CheckResultsSta3(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes);
|
||||
|
||||
/**
|
||||
* Reset the results
|
||||
*/
|
||||
void ResetResults();
|
||||
|
||||
/**
|
||||
* STA info
|
||||
*/
|
||||
struct StaInfo
|
||||
{
|
||||
uint16_t staId; //!< STA ID
|
||||
uint8_t staNss; //!< Number of spatial streams used for the STA
|
||||
};
|
||||
|
||||
/**
|
||||
* Send DL MU-MIMO PPDU function
|
||||
* \param staInfos the STAs infos
|
||||
*/
|
||||
void SendMuPpdu(const std::vector<StaInfo>& staInfos);
|
||||
|
||||
/**
|
||||
* Generate interference function
|
||||
* \param interferencePsd the PSD of the interference to be generated
|
||||
* \param duration the duration of the interference
|
||||
*/
|
||||
void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
|
||||
/**
|
||||
* Stop interference function
|
||||
*/
|
||||
void StopInterference();
|
||||
|
||||
/**
|
||||
* Run one function
|
||||
*/
|
||||
void RunOne();
|
||||
|
||||
/**
|
||||
* Schedule now to check the PHY state
|
||||
* \param phy the PHY
|
||||
* \param expectedState the expected state of the PHY
|
||||
*/
|
||||
void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
|
||||
/**
|
||||
* Check the PHY state now
|
||||
* \param phy the PHY
|
||||
* \param expectedState the expected state of the PHY
|
||||
*/
|
||||
void DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
|
||||
|
||||
uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
|
||||
uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
|
||||
uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
|
||||
uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
|
||||
uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
|
||||
uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
|
||||
uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
|
||||
uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
|
||||
uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
|
||||
|
||||
Ptr<SpectrumWifiPhy> m_phyAp; ///< PHY of AP
|
||||
Ptr<MuMimoSpectrumWifiPhy> m_phySta1; ///< PHY of STA 1
|
||||
Ptr<MuMimoSpectrumWifiPhy> m_phySta2; ///< PHY of STA 2
|
||||
Ptr<MuMimoSpectrumWifiPhy> m_phySta3; ///< PHY of STA 3
|
||||
|
||||
uint8_t m_nss; ///< number of spatial streams per STA
|
||||
uint16_t m_frequency; ///< frequency in MHz
|
||||
uint16_t m_channelWidth; ///< channel width in MHz
|
||||
Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
|
||||
};
|
||||
|
||||
TestDlMuMimoPhyTransmission::TestDlMuMimoPhyTransmission()
|
||||
: TestCase("DL MU-MIMO PHY test"),
|
||||
m_countRxSuccessSta1{0},
|
||||
m_countRxSuccessSta2{0},
|
||||
m_countRxSuccessSta3{0},
|
||||
m_countRxFailureSta1{0},
|
||||
m_countRxFailureSta2{0},
|
||||
m_countRxFailureSta3{0},
|
||||
m_countRxBytesSta1{0},
|
||||
m_countRxBytesSta2{0},
|
||||
m_countRxBytesSta3{0},
|
||||
m_nss{1},
|
||||
m_frequency{DEFAULT_FREQUENCY},
|
||||
m_channelWidth{DEFAULT_CHANNEL_WIDTH},
|
||||
m_expectedPpduDuration{NanoSeconds(306400)}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::ResetResults()
|
||||
{
|
||||
m_countRxSuccessSta1 = 0;
|
||||
m_countRxSuccessSta2 = 0;
|
||||
m_countRxSuccessSta3 = 0;
|
||||
m_countRxFailureSta1 = 0;
|
||||
m_countRxFailureSta2 = 0;
|
||||
m_countRxFailureSta3 = 0;
|
||||
m_countRxBytesSta1 = 0;
|
||||
m_countRxBytesSta2 = 0;
|
||||
m_countRxBytesSta3 = 0;
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << staInfos.size());
|
||||
NS_ASSERT(staInfos.size() > 1);
|
||||
|
||||
WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
|
||||
0,
|
||||
WIFI_PREAMBLE_HE_MU,
|
||||
800,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
m_channelWidth,
|
||||
false,
|
||||
false);
|
||||
|
||||
WifiConstPsduMap psdus;
|
||||
HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
|
||||
for (const auto& staInfo : staInfos)
|
||||
{
|
||||
txVector.SetRu(ru, staInfo.staId);
|
||||
txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
|
||||
txVector.SetNss(staInfo.staNss, staInfo.staId);
|
||||
|
||||
Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType(WIFI_MAC_QOSDATA);
|
||||
hdr.SetQosTid(0);
|
||||
std::ostringstream addr;
|
||||
addr << "00:00:00:00:00:0" << staInfo.staId;
|
||||
hdr.SetAddr1(Mac48Address(addr.str().c_str()));
|
||||
hdr.SetSequenceNumber(1 + staInfo.staId);
|
||||
Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
|
||||
psdus.insert(std::make_pair(staInfo.staId, psdu));
|
||||
}
|
||||
|
||||
txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
|
||||
|
||||
NS_ASSERT(txVector.IsDlMuMimo());
|
||||
NS_ASSERT(!txVector.IsDlOfdma());
|
||||
|
||||
m_phyAp->Send(psdus, txVector);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxSuccessSta1(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> /*statusPerMpdu*/)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
|
||||
m_countRxSuccessSta1++;
|
||||
m_countRxBytesSta1 += (psdu->GetSize() - 30);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxSuccessSta2(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> /*statusPerMpdu*/)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
|
||||
m_countRxSuccessSta2++;
|
||||
m_countRxBytesSta2 += (psdu->GetSize() - 30);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxSuccessSta3(Ptr<const WifiPsdu> psdu,
|
||||
RxSignalInfo rxSignalInfo,
|
||||
WifiTxVector txVector,
|
||||
std::vector<bool> /*statusPerMpdu*/)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
|
||||
m_countRxSuccessSta3++;
|
||||
m_countRxBytesSta3 += (psdu->GetSize() - 30);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxFailureSta1(Ptr<const WifiPsdu> psdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu);
|
||||
m_countRxFailureSta1++;
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxFailureSta2(Ptr<const WifiPsdu> psdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu);
|
||||
m_countRxFailureSta2++;
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RxFailureSta3(Ptr<const WifiPsdu> psdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *psdu);
|
||||
m_countRxFailureSta3++;
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::CheckResultsSta1(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta1,
|
||||
expectedRxSuccess,
|
||||
"The number of successfully received packets by STA 1 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta1,
|
||||
expectedRxFailure,
|
||||
"The number of unsuccessfully received packets by STA 1 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta1,
|
||||
expectedRxBytes,
|
||||
"The number of bytes received by STA 1 is not correct!");
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::CheckResultsSta2(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta2,
|
||||
expectedRxSuccess,
|
||||
"The number of successfully received packets by STA 2 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta2,
|
||||
expectedRxFailure,
|
||||
"The number of unsuccessfully received packets by STA 2 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta2,
|
||||
expectedRxBytes,
|
||||
"The number of bytes received by STA 2 is not correct!");
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::CheckResultsSta3(uint32_t expectedRxSuccess,
|
||||
uint32_t expectedRxFailure,
|
||||
uint32_t expectedRxBytes)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta3,
|
||||
expectedRxSuccess,
|
||||
"The number of successfully received packets by STA 3 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta3,
|
||||
expectedRxFailure,
|
||||
"The number of unsuccessfully received packets by STA 3 is not correct!");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta3,
|
||||
expectedRxBytes,
|
||||
"The number of bytes received by STA 3 is not correct!");
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> 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(&TestDlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy,
|
||||
WifiPhyState expectedState)
|
||||
{
|
||||
WifiPhyState currentState;
|
||||
PointerValue ptr;
|
||||
phy->GetAttribute("State", ptr);
|
||||
Ptr<WifiPhyStateHelper> state = DynamicCast<WifiPhyStateHelper>(ptr.Get<WifiPhyStateHelper>());
|
||||
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
|
||||
TestDlMuMimoPhyTransmission::DoSetup()
|
||||
{
|
||||
Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
|
||||
Ptr<ConstantSpeedPropagationDelayModel> delayModel =
|
||||
CreateObject<ConstantSpeedPropagationDelayModel>();
|
||||
spectrumChannel->SetPropagationDelayModel(delayModel);
|
||||
|
||||
Ptr<Node> apNode = CreateObject<Node>();
|
||||
Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
|
||||
m_phyAp = CreateObject<SpectrumWifiPhy>();
|
||||
Ptr<InterferenceHelper> apInterferenceHelper = CreateObject<InterferenceHelper>();
|
||||
m_phyAp->SetInterferenceHelper(apInterferenceHelper);
|
||||
Ptr<ErrorRateModel> apErrorModel = CreateObject<NistErrorRateModel>();
|
||||
m_phyAp->SetErrorRateModel(apErrorModel);
|
||||
m_phyAp->SetDevice(apDev);
|
||||
m_phyAp->AddChannel(spectrumChannel);
|
||||
m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
|
||||
apDev->SetPhy(m_phyAp);
|
||||
apNode->AddDevice(apDev);
|
||||
|
||||
Ptr<Node> sta1Node = CreateObject<Node>();
|
||||
Ptr<WifiNetDevice> sta1Dev = CreateObject<WifiNetDevice>();
|
||||
m_phySta1 = CreateObject<MuMimoSpectrumWifiPhy>(1);
|
||||
Ptr<InterferenceHelper> sta1InterferenceHelper = CreateObject<InterferenceHelper>();
|
||||
m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
|
||||
Ptr<ErrorRateModel> sta1ErrorModel = CreateObject<NistErrorRateModel>();
|
||||
m_phySta1->SetErrorRateModel(sta1ErrorModel);
|
||||
m_phySta1->SetDevice(sta1Dev);
|
||||
m_phySta1->AddChannel(spectrumChannel);
|
||||
m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
|
||||
m_phySta1->SetReceiveOkCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta1, this));
|
||||
m_phySta1->SetReceiveErrorCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta1, this));
|
||||
sta1Dev->SetPhy(m_phySta1);
|
||||
sta1Node->AddDevice(sta1Dev);
|
||||
|
||||
Ptr<Node> sta2Node = CreateObject<Node>();
|
||||
Ptr<WifiNetDevice> sta2Dev = CreateObject<WifiNetDevice>();
|
||||
m_phySta2 = CreateObject<MuMimoSpectrumWifiPhy>(2);
|
||||
Ptr<InterferenceHelper> sta2InterferenceHelper = CreateObject<InterferenceHelper>();
|
||||
m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
|
||||
Ptr<ErrorRateModel> sta2ErrorModel = CreateObject<NistErrorRateModel>();
|
||||
m_phySta2->SetErrorRateModel(sta2ErrorModel);
|
||||
m_phySta2->SetDevice(sta2Dev);
|
||||
m_phySta2->AddChannel(spectrumChannel);
|
||||
m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
|
||||
m_phySta2->SetReceiveOkCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta2, this));
|
||||
m_phySta2->SetReceiveErrorCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta2, this));
|
||||
sta2Dev->SetPhy(m_phySta2);
|
||||
sta2Node->AddDevice(sta2Dev);
|
||||
|
||||
Ptr<Node> sta3Node = CreateObject<Node>();
|
||||
Ptr<WifiNetDevice> sta3Dev = CreateObject<WifiNetDevice>();
|
||||
m_phySta3 = CreateObject<MuMimoSpectrumWifiPhy>(3);
|
||||
Ptr<InterferenceHelper> sta3InterferenceHelper = CreateObject<InterferenceHelper>();
|
||||
m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
|
||||
Ptr<ErrorRateModel> sta3ErrorModel = CreateObject<NistErrorRateModel>();
|
||||
m_phySta3->SetErrorRateModel(sta3ErrorModel);
|
||||
m_phySta3->SetDevice(sta3Dev);
|
||||
m_phySta3->AddChannel(spectrumChannel);
|
||||
m_phySta3->ConfigureStandard(WIFI_STANDARD_80211ax);
|
||||
m_phySta3->SetReceiveOkCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta3, this));
|
||||
m_phySta3->SetReceiveErrorCallback(
|
||||
MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta3, this));
|
||||
sta3Dev->SetPhy(m_phySta3);
|
||||
sta3Node->AddDevice(sta3Dev);
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::DoTeardown()
|
||||
{
|
||||
m_phyAp->Dispose();
|
||||
m_phyAp = nullptr;
|
||||
m_phySta1->Dispose();
|
||||
m_phySta1 = nullptr;
|
||||
m_phySta2->Dispose();
|
||||
m_phySta2 = nullptr;
|
||||
m_phySta3->Dispose();
|
||||
m_phySta3 = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::RunOne()
|
||||
{
|
||||
RngSeedManager::SetSeed(1);
|
||||
RngSeedManager::SetRun(1);
|
||||
int64_t streamNumber = 0;
|
||||
m_phyAp->AssignStreams(streamNumber);
|
||||
m_phySta1->AssignStreams(streamNumber);
|
||||
m_phySta2->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});
|
||||
m_phySta1->SetOperatingChannel(
|
||||
WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
|
||||
m_phySta2->SetOperatingChannel(
|
||||
WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
|
||||
m_phySta3->SetOperatingChannel(
|
||||
WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
|
||||
|
||||
m_phyAp->SetNumberOfAntennas(8);
|
||||
m_phyAp->SetMaxSupportedTxSpatialStreams(8);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
|
||||
// STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
|
||||
// but should keep its PHY busy during all PPDU duration.
|
||||
Simulator::Schedule(Seconds(1.0),
|
||||
&TestDlMuMimoPhyTransmission::SendMuPpdu,
|
||||
this,
|
||||
std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
|
||||
|
||||
// Since it takes m_expectedPpduDuration to transmit the PPDU,
|
||||
// all 3 PHYs should be back to IDLE at the same time,
|
||||
// even the PHY that has no PSDU addressed to it.
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::CCA_BUSY);
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::IDLE);
|
||||
|
||||
// One PSDU of 1008 bytes should have been successfully received by STA 1
|
||||
Simulator::Schedule(Seconds(1.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta1,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1008);
|
||||
// One PSDU of 1016 bytes should have been successfully received by STA 2
|
||||
Simulator::Schedule(Seconds(1.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta2,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1016);
|
||||
// No PSDU should have been received by STA 3
|
||||
Simulator::Schedule(Seconds(1.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta3,
|
||||
this,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
Simulator::Schedule(Seconds(1.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
|
||||
// STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
|
||||
// but should keep its PHY busy during all PPDU duration.
|
||||
Simulator::Schedule(Seconds(2.0),
|
||||
&TestDlMuMimoPhyTransmission::SendMuPpdu,
|
||||
this,
|
||||
std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
|
||||
|
||||
// Since it takes m_expectedPpduDuration to transmit the PPDU,
|
||||
// all 3 PHYs should be back to IDLE at the same time,
|
||||
// even the PHY that has no PSDU addressed to it.
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::CCA_BUSY);
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::IDLE);
|
||||
|
||||
// One PSDU of 1008 bytes should have been successfully received by STA 1
|
||||
Simulator::Schedule(Seconds(2.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta1,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1008);
|
||||
// No PSDU should have been received by STA 2
|
||||
Simulator::Schedule(Seconds(2.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta2,
|
||||
this,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
// One PSDU of 1024 bytes should have been successfully received by STA 3
|
||||
Simulator::Schedule(Seconds(2.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta3,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1024);
|
||||
|
||||
Simulator::Schedule(Seconds(2.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
|
||||
// STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
|
||||
// but should keep its PHY busy during all PPDU duration.
|
||||
Simulator::Schedule(Seconds(3.0),
|
||||
&TestDlMuMimoPhyTransmission::SendMuPpdu,
|
||||
this,
|
||||
std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
|
||||
|
||||
// Since it takes m_expectedPpduDuration to transmit the PPDU,
|
||||
// all 3 PHYs should be back to IDLE at the same time,
|
||||
// even the PHY that has no PSDU addressed to it.
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::CCA_BUSY);
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::IDLE);
|
||||
|
||||
// No PSDU should have been received by STA 1
|
||||
Simulator::Schedule(Seconds(3.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta1,
|
||||
this,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
// One PSDU of 1016 bytes should have been successfully received by STA 2
|
||||
Simulator::Schedule(Seconds(3.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta2,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1016);
|
||||
// One PSDU of 1024 bytes should have been successfully received by STA 3
|
||||
Simulator::Schedule(Seconds(3.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta3,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1024);
|
||||
|
||||
Simulator::Schedule(Seconds(3.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
|
||||
// All STAs should receive their PSDUs.
|
||||
Simulator::Schedule(Seconds(4.0),
|
||||
&TestDlMuMimoPhyTransmission::SendMuPpdu,
|
||||
this,
|
||||
std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
|
||||
|
||||
// Since it takes m_expectedPpduDuration to transmit the PPDU,
|
||||
// all 3 PHYs should be back to IDLE at the same time.
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::RX);
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta1,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta2,
|
||||
WifiPhyState::IDLE);
|
||||
Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
|
||||
&TestDlMuMimoPhyTransmission::CheckPhyState,
|
||||
this,
|
||||
m_phySta3,
|
||||
WifiPhyState::IDLE);
|
||||
|
||||
// One PSDU of 1008 bytes should have been successfully received by STA 1
|
||||
Simulator::Schedule(Seconds(4.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta1,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1008);
|
||||
// One PSDU of 1016 bytes should have been successfully received by STA 2
|
||||
Simulator::Schedule(Seconds(4.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta2,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1016);
|
||||
// One PSDU of 1024 bytes should have been successfully received by STA 3
|
||||
Simulator::Schedule(Seconds(4.1),
|
||||
&TestDlMuMimoPhyTransmission::CheckResultsSta3,
|
||||
this,
|
||||
1,
|
||||
0,
|
||||
1024);
|
||||
|
||||
Simulator::Schedule(Seconds(4.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
|
||||
|
||||
Simulator::Run();
|
||||
}
|
||||
|
||||
void
|
||||
TestDlMuMimoPhyTransmission::DoRun()
|
||||
{
|
||||
std::vector<uint8_t> nssToTest{1, 2};
|
||||
for (auto nss : nssToTest)
|
||||
{
|
||||
m_nss = nss;
|
||||
m_frequency = 5180;
|
||||
m_channelWidth = 20;
|
||||
m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
|
||||
RunOne();
|
||||
|
||||
m_frequency = 5190;
|
||||
m_channelWidth = 40;
|
||||
m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
|
||||
RunOne();
|
||||
|
||||
m_frequency = 5210;
|
||||
m_channelWidth = 80;
|
||||
m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
|
||||
RunOne();
|
||||
|
||||
m_frequency = 5250;
|
||||
m_channelWidth = 160;
|
||||
m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
|
||||
RunOne();
|
||||
}
|
||||
// FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
|
||||
// with different nss over STAs are fixed
|
||||
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -175,6 +1079,7 @@ WifiPhyMuMimoTestSuite::WifiPhyMuMimoTestSuite()
|
||||
: TestSuite("wifi-phy-mu-mimo", UNIT)
|
||||
{
|
||||
AddTestCase(new TestDlMuTxVector, TestCase::QUICK);
|
||||
AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::QUICK);
|
||||
}
|
||||
|
||||
static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite; ///< the test suite
|
||||
|
||||
Reference in New Issue
Block a user