spectrum: Allow for a change in the number of antenna elements in 3GPP channel model

This commit is contained in:
Gabriel Ferreira
2024-04-16 14:52:15 +02:00
parent 5b6902b5b0
commit b7d097657c
3 changed files with 257 additions and 0 deletions

View File

@@ -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
{

View File

@@ -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

View File

@@ -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),