antenna, spectrum: Trigger a channel matrix update on UPA setting changes

This commit is contained in:
Gabriel Ferreira
2025-01-22 17:27:19 +01:00
parent ec5e7466ab
commit bdae7bf137
5 changed files with 125 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ namespace ns3
{
uint32_t PhasedArrayModel::m_idCounter = 0;
SymmetricAdjacencyMatrix<bool> PhasedArrayModel::m_outOfDateAntennaPairChannel;
NS_LOG_COMPONENT_DEFINE("PhasedArrayModel");
@@ -27,6 +28,8 @@ PhasedArrayModel::PhasedArrayModel()
: m_isBfVectorValid{false}
{
m_id = m_idCounter++;
m_outOfDateAntennaPairChannel.AddRow();
m_outOfDateAntennaPairChannel.SetValueAdjacent(m_id, true);
}
PhasedArrayModel::~PhasedArrayModel()
@@ -137,4 +140,21 @@ PhasedArrayModel::GetId() const
return m_id;
}
bool
PhasedArrayModel::IsChannelOutOfDate(Ptr<const PhasedArrayModel> antennaB) const
{
// Check that channel needs update
bool needsUpdate = m_outOfDateAntennaPairChannel.GetValue(m_id, antennaB->m_id);
// Assume the channel will be updated (needsUpdate == true), reset these
m_outOfDateAntennaPairChannel.SetValue(m_id, antennaB->m_id, false);
return needsUpdate;
}
void
PhasedArrayModel::InvalidateChannels() const
{
m_outOfDateAntennaPairChannel.SetValueAdjacent(m_id, true);
}
} /* namespace ns3 */

View File

@@ -12,6 +12,7 @@
#include "ns3/matrix-array.h"
#include "ns3/object.h"
#include "ns3/symmetric-adjacency-matrix.h"
#include <complex>
@@ -243,13 +244,30 @@ class PhasedArrayModel : public Object
*/
uint32_t GetId() const;
/**
* Returns whether the channel needs to be updated due to antenna setting changes.
* @param antennaB the second antenna of the pair for the channel we want to check
* @return whether a channel update is needed due to antenna settings changes
*/
bool IsChannelOutOfDate(Ptr<const PhasedArrayModel> antennaB) const;
protected:
/**
* After changing the antenna settings, InvalidateChannels() should be called to mark
* up-to-date channels as out-of-date
*/
void InvalidateChannels() const;
ComplexVector m_beamformingVector; //!< the beamforming vector in use
Ptr<AntennaModel> m_antennaElement; //!< the model of the antenna element in use
bool m_isBfVectorValid; //!< ensures the validity of the beamforming vector
static uint32_t
m_idCounter; //!< the ID counter that is used to determine the unique antenna array ID
uint32_t m_id{0}; //!< the ID of this antenna array instance
static SymmetricAdjacencyMatrix<bool>
m_outOfDateAntennaPairChannel; //!< matrix indicating whether a channel matrix between a
//!< pair of antennas needs to be updated after a change in
//!< one of the antennas configurations
};
} /* namespace ns3 */

View File

@@ -106,6 +106,7 @@ UniformPlanarArray::SetNumColumns(uint32_t n)
if (n != m_numColumns)
{
m_isBfVectorValid = false;
InvalidateChannels();
}
m_numColumns = n;
}
@@ -123,6 +124,7 @@ UniformPlanarArray::SetNumRows(uint32_t n)
if (n != m_numRows)
{
m_isBfVectorValid = false;
InvalidateChannels();
}
m_numRows = n;
}
@@ -139,6 +141,7 @@ UniformPlanarArray::SetAlpha(double alpha)
m_alpha = alpha;
m_cosAlpha = cos(m_alpha);
m_sinAlpha = sin(m_alpha);
InvalidateChannels();
}
void
@@ -147,6 +150,7 @@ UniformPlanarArray::SetBeta(double beta)
m_beta = beta;
m_cosBeta = cos(m_beta);
m_sinBeta = sin(m_beta);
InvalidateChannels();
}
void
@@ -155,6 +159,7 @@ UniformPlanarArray::SetPolSlant(double polSlant)
m_polSlant = polSlant;
m_cosPolSlant[0] = cos(m_polSlant);
m_sinPolSlant[0] = sin(m_polSlant);
InvalidateChannels();
}
void
@@ -166,6 +171,7 @@ UniformPlanarArray::SetAntennaHorizontalSpacing(double s)
if (s != m_disH)
{
m_isBfVectorValid = false;
InvalidateChannels();
}
m_disH = s;
}
@@ -185,6 +191,7 @@ UniformPlanarArray::SetAntennaVerticalSpacing(double s)
if (s != m_disV)
{
m_isBfVectorValid = false;
InvalidateChannels();
}
m_disV = s;
}
@@ -292,6 +299,7 @@ UniformPlanarArray::SetNumVerticalPorts(uint16_t nPorts)
NS_ASSERT_MSG(((m_numRows % nPorts) == 0),
"The number of vertical ports must divide number of rows");
m_numVPorts = nPorts;
InvalidateChannels();
}
void
@@ -301,6 +309,7 @@ UniformPlanarArray::SetNumHorizontalPorts(uint16_t nPorts)
NS_ASSERT_MSG(((m_numColumns % nPorts) == 0),
"The number of horizontal ports must divide number of columns");
m_numHPorts = nPorts;
InvalidateChannels();
}
uint16_t
@@ -380,6 +389,7 @@ UniformPlanarArray::SetDualPol(bool isDualPol)
m_cosPolSlant[1] = cos(m_polSlant - M_PI / 2);
m_sinPolSlant[1] = sin(m_polSlant - M_PI / 2);
}
InvalidateChannels();
}
double

View File

@@ -192,6 +192,76 @@ UniformPlanarArrayTestCase::DoRun()
"wrong value of the radiation pattern");
}
/**
* @ingroup antenna-tests
*
* @brief UpdateOnChange Test Case
*/
class UpdateOnChangeTestCase : public TestCase
{
public:
/**
* The constructor of the test case
* @param element the antenna element
* @param name the test case name
*/
UpdateOnChangeTestCase(Ptr<AntennaModel> element, std::string name)
: TestCase(name),
m_element(element){};
private:
/**
* Run the test
*/
void DoRun() override;
Ptr<AntennaModel> m_element; //!< the antenna element
};
void
UpdateOnChangeTestCase::DoRun()
{
Ptr<UniformPlanarArray> ant = CreateObject<UniformPlanarArray>();
ant->SetAttribute("AntennaElement", PointerValue(m_element));
ant->SetAttribute("NumRows", UintegerValue(10));
ant->SetAttribute("NumColumns", UintegerValue(10));
ant->SetAttribute("AntennaVerticalSpacing", DoubleValue(0.5));
ant->SetAttribute("AntennaHorizontalSpacing", DoubleValue(0.5));
ant->SetAttribute("BearingAngle", DoubleValue(DegreesToRadians(0)));
ant->SetAttribute("DowntiltAngle", DoubleValue(DegreesToRadians(45)));
Ptr<UniformPlanarArray> ant2 = CreateObject<UniformPlanarArray>();
ant2->SetAttribute("AntennaElement", PointerValue(m_element));
ant2->SetAttribute("NumRows", UintegerValue(10));
ant2->SetAttribute("NumColumns", UintegerValue(10));
ant2->SetAttribute("AntennaVerticalSpacing", DoubleValue(0.5));
ant2->SetAttribute("AntennaHorizontalSpacing", DoubleValue(0.5));
ant2->SetAttribute("BearingAngle", DoubleValue(DegreesToRadians(0)));
ant2->SetAttribute("DowntiltAngle", DoubleValue(DegreesToRadians(45)));
NS_TEST_ASSERT_MSG_EQ(ant.operator bool(), true, "AntennaModel is not a PhasedArrayModel");
// Initial state of array requires a channel update
NS_TEST_ASSERT_MSG_EQ(ant->IsChannelOutOfDate(ant2),
true,
"Expecting update, since the pair was never setup");
NS_TEST_ASSERT_MSG_EQ(
ant2->IsChannelOutOfDate(ant),
false,
"Not expecting update, since the pair was just updated and no settings changed");
ant->SetAlpha(DegreesToRadians(90));
NS_TEST_ASSERT_MSG_EQ(ant2->IsChannelOutOfDate(ant),
true,
"Expecting update, antenna parameter changed");
NS_TEST_ASSERT_MSG_EQ(
ant->IsChannelOutOfDate(ant2),
false,
"Not expecting update, since the pair was just updated and no settings changed");
ant->SetAlpha(DegreesToRadians(90));
NS_TEST_ASSERT_MSG_EQ(ant->IsChannelOutOfDate(ant2),
true,
"Expecting update, antenna parameter changed");
}
/**
* @ingroup antenna-tests
*
@@ -377,6 +447,10 @@ UniformPlanarArrayTestSuite::UniformPlanarArrayTestSuite()
Angles(DegreesToRadians(0), DegreesToRadians(135)),
28.0),
TestCase::Duration::QUICK);
AddTestCase(new UpdateOnChangeTestCase(tgpp,
"Test IsChannelOutOfDate() and InvalidateChannels() for "
"UniformPlanarArray with 3GPP antenna element"),
TestCase::Duration::QUICK);
}
static UniformPlanarArrayTestSuite staticUniformPlanarArrayTestSuiteInstance;

View File

@@ -2464,8 +2464,9 @@ ThreeGppChannelModel::AntennaSetupChanged(Ptr<const PhasedArrayModel> aAntenna,
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));
return (((uAntNumElems != chanNumRows) || (sAntNumElems != chanNumCols)) &&
((uAntNumElems != chanNumCols) || (sAntNumElems != chanNumRows))) ||
aAntenna->IsChannelOutOfDate(bAntenna);
}
Ptr<const MatrixBasedChannelModel::ChannelMatrix>