spectrum: Allow for a change in the number of antenna elements in 3GPP channel model
This commit is contained in:
@@ -1090,6 +1090,21 @@ ThreeGppChannelModel::ChannelMatrixNeedsUpdate(Ptr<const ThreeGppChannelParams>
|
||||
return channelParams->m_generatedTime > channelMatrix->m_generatedTime;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreeGppChannelModel::AntennaSetupChanged(Ptr<const PhasedArrayModel> aAntenna,
|
||||
Ptr<const PhasedArrayModel> bAntenna,
|
||||
Ptr<const ChannelMatrix> channelMatrix)
|
||||
{
|
||||
// This allows changing the number of antenna ports during execution,
|
||||
// which is used by nr's initial association.
|
||||
size_t sAntNumElems = aAntenna->GetNumElems();
|
||||
size_t uAntNumElems = bAntenna->GetNumElems();
|
||||
size_t chanNumRows = channelMatrix->m_channel.GetNumRows();
|
||||
size_t chanNumCols = channelMatrix->m_channel.GetNumCols();
|
||||
return ((uAntNumElems != chanNumRows) || (sAntNumElems != chanNumCols)) &&
|
||||
((uAntNumElems != chanNumCols) || (sAntNumElems != chanNumRows));
|
||||
}
|
||||
|
||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix>
|
||||
ThreeGppChannelModel::GetChannel(Ptr<const MobilityModel> aMob,
|
||||
Ptr<const MobilityModel> bMob,
|
||||
@@ -1162,6 +1177,7 @@ ThreeGppChannelModel::GetChannel(Ptr<const MobilityModel> aMob,
|
||||
NS_LOG_DEBUG("channel matrix present in the map");
|
||||
channelMatrix = m_channelMatrixMap[channelMatrixKey];
|
||||
updateMatrix = ChannelMatrixNeedsUpdate(channelParams, channelMatrix);
|
||||
updateMatrix |= AntennaSetupChanged(aAntenna, bAntenna, channelMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -335,6 +335,18 @@ class ThreeGppChannelModel : public MatrixBasedChannelModel
|
||||
bool ChannelMatrixNeedsUpdate(Ptr<const ThreeGppChannelParams> channelParams,
|
||||
Ptr<const ChannelMatrix> channelMatrix);
|
||||
|
||||
/**
|
||||
* Check if the channel matrix has to be updated due to
|
||||
* changes in the number of antenna ports
|
||||
* \param aAntenna the antenna array of node a
|
||||
* \param bAntenna the antenna array of node b
|
||||
* \param channelMatrix channel matrix structure
|
||||
* \return true if the channel matrix has to be updated, false otherwise
|
||||
*/
|
||||
bool AntennaSetupChanged(Ptr<const PhasedArrayModel> aAntenna,
|
||||
Ptr<const PhasedArrayModel> bAntenna,
|
||||
Ptr<const ChannelMatrix> channelMatrix);
|
||||
|
||||
std::unordered_map<uint64_t, Ptr<ChannelMatrix>>
|
||||
m_channelMatrixMap; //!< map containing the channel realizations per pair of
|
||||
//!< PhasedAntennaArray instances, the key of this map is reciprocal
|
||||
|
||||
@@ -496,6 +496,234 @@ ThreeGppChannelMatrixUpdateTest::DoRun()
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup spectrum-tests
|
||||
*
|
||||
* Test case for the ThreeGppChannelModel class.
|
||||
* It checks if the channel realizations are correctly
|
||||
* updated after a change in the number of antenna elements.
|
||||
*/
|
||||
class ThreeGppAntennaSetupChangedTest : public TestCase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
ThreeGppAntennaSetupChangedTest();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~ThreeGppAntennaSetupChangedTest() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Build the test scenario
|
||||
*/
|
||||
void DoRun() override;
|
||||
|
||||
/**
|
||||
* This method is used to schedule the channel matrix computation at different
|
||||
* time instants and to check if it correctly updated
|
||||
* \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
|
||||
* \param txMob the mobility model of the first node
|
||||
* \param rxMob the mobility model of the second node
|
||||
* \param txAntenna the antenna object associated to the first node
|
||||
* \param rxAntenna the antenna object associated to the second node
|
||||
* \param update whether if the channel matrix should be updated or not
|
||||
*/
|
||||
void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
|
||||
Ptr<MobilityModel> txMob,
|
||||
Ptr<MobilityModel> rxMob,
|
||||
Ptr<PhasedArrayModel> txAntenna,
|
||||
Ptr<PhasedArrayModel> rxAntenna,
|
||||
bool update);
|
||||
|
||||
Ptr<const ThreeGppChannelModel::ChannelMatrix>
|
||||
m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
|
||||
uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
|
||||
uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
|
||||
uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
|
||||
uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
|
||||
};
|
||||
|
||||
ThreeGppAntennaSetupChangedTest::ThreeGppAntennaSetupChangedTest()
|
||||
: TestCase("Check if the channel realizations are correctly updated after antenna port changes "
|
||||
"during the simulation")
|
||||
{
|
||||
}
|
||||
|
||||
ThreeGppAntennaSetupChangedTest::~ThreeGppAntennaSetupChangedTest()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ThreeGppAntennaSetupChangedTest::DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
|
||||
Ptr<MobilityModel> txMob,
|
||||
Ptr<MobilityModel> rxMob,
|
||||
Ptr<PhasedArrayModel> txAntenna,
|
||||
Ptr<PhasedArrayModel> rxAntenna,
|
||||
bool update)
|
||||
{
|
||||
// retrieve the channel matrix
|
||||
Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix =
|
||||
channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
|
||||
|
||||
if (m_currentChannel)
|
||||
{
|
||||
// compare the old and the new channel matrices
|
||||
NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
|
||||
update,
|
||||
Simulator::Now().GetMilliSeconds()
|
||||
<< " The channel matrix is not correctly updated");
|
||||
}
|
||||
m_currentChannel = channelMatrix;
|
||||
}
|
||||
|
||||
void
|
||||
ThreeGppAntennaSetupChangedTest::DoRun()
|
||||
{
|
||||
// Build the scenario for the test
|
||||
uint32_t updatePeriodMs = 100; // update period in ms
|
||||
|
||||
// create the channel condition model
|
||||
Ptr<ChannelConditionModel> channelConditionModel =
|
||||
CreateObject<AlwaysLosChannelConditionModel>();
|
||||
|
||||
// create the ThreeGppChannelModel object used to generate the channel matrix
|
||||
Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
|
||||
channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
|
||||
channelModel->SetAttribute("Scenario", StringValue("UMa"));
|
||||
channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
|
||||
channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
|
||||
|
||||
// create the tx and rx nodes
|
||||
NodeContainer nodes;
|
||||
nodes.Create(2);
|
||||
|
||||
// create the tx and rx devices
|
||||
Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
|
||||
Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
|
||||
|
||||
// associate the nodes and the devices
|
||||
nodes.Get(0)->AddDevice(txDev);
|
||||
txDev->SetNode(nodes.Get(0));
|
||||
nodes.Get(1)->AddDevice(rxDev);
|
||||
rxDev->SetNode(nodes.Get(1));
|
||||
|
||||
// create the tx and rx mobility models and set their positions
|
||||
Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
|
||||
txMob->SetPosition(Vector(0.0, 0.0, 10.0));
|
||||
Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
|
||||
rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
|
||||
|
||||
// associate the nodes and the mobility models
|
||||
nodes.Get(0)->AggregateObject(txMob);
|
||||
nodes.Get(1)->AggregateObject(rxMob);
|
||||
|
||||
// create the tx and rx antennas and set the their dimensions
|
||||
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
|
||||
"NumColumns",
|
||||
UintegerValue(m_txAntennaElements),
|
||||
"NumRows",
|
||||
UintegerValue(m_txAntennaElements),
|
||||
"AntennaElement",
|
||||
PointerValue(CreateObject<IsotropicAntennaModel>()),
|
||||
"NumVerticalPorts",
|
||||
UintegerValue(m_txPorts),
|
||||
"NumHorizontalPorts",
|
||||
UintegerValue(m_txPorts));
|
||||
|
||||
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
|
||||
"NumColumns",
|
||||
UintegerValue(m_rxAntennaElements),
|
||||
"NumRows",
|
||||
UintegerValue(m_rxAntennaElements),
|
||||
"AntennaElement",
|
||||
PointerValue(CreateObject<IsotropicAntennaModel>()),
|
||||
"NumVerticalPorts",
|
||||
UintegerValue(m_rxPorts),
|
||||
"NumHorizontalPorts",
|
||||
UintegerValue(m_rxPorts));
|
||||
|
||||
// check if the channel matrix is correctly updated
|
||||
|
||||
// compute the channel matrix for the first time
|
||||
Simulator::Schedule(MilliSeconds(1),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
true);
|
||||
|
||||
// call GetChannel before the update period is exceeded, the channel matrix
|
||||
// should not be updated
|
||||
Simulator::Schedule(MilliSeconds(2),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
false);
|
||||
|
||||
// after changing the number of antenna ports, the channel matrix
|
||||
// should be recomputed
|
||||
Simulator::Schedule(MilliSeconds(3),
|
||||
[&txAntenna]() { txAntenna->SetNumRows(txAntenna->GetNumRows() + 1); });
|
||||
Simulator::Schedule(MilliSeconds(4),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
true);
|
||||
|
||||
// after recomputing it once, the channel matrix should be cached
|
||||
Simulator::Schedule(MilliSeconds(5),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
false);
|
||||
|
||||
// after recomputing it once, the channel matrix should be cached
|
||||
Simulator::Schedule(MilliSeconds(6),
|
||||
[&rxAntenna]() { rxAntenna->SetNumRows(rxAntenna->GetNumRows() + 1); });
|
||||
Simulator::Schedule(MilliSeconds(7),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
true);
|
||||
|
||||
// after recomputing it once, the channel matrix should be cached
|
||||
Simulator::Schedule(MilliSeconds(8),
|
||||
&ThreeGppAntennaSetupChangedTest::DoGetChannel,
|
||||
this,
|
||||
channelModel,
|
||||
txMob,
|
||||
rxMob,
|
||||
txAntenna,
|
||||
rxAntenna,
|
||||
false);
|
||||
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup spectrum-tests
|
||||
* \brief A structure that holds the parameters for the function
|
||||
@@ -1239,6 +1467,7 @@ ThreeGppChannelTestSuite::ThreeGppChannelTestSuite()
|
||||
AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::Duration::QUICK);
|
||||
AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::Duration::QUICK);
|
||||
AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::Duration::QUICK);
|
||||
AddTestCase(new ThreeGppAntennaSetupChangedTest(), TestCase::Duration::QUICK);
|
||||
AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 1, 1),
|
||||
TestCase::Duration::QUICK);
|
||||
AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 2, 2),
|
||||
|
||||
Reference in New Issue
Block a user