From bdae7bf1374bfa033afbd7a97419833aed139a47 Mon Sep 17 00:00:00 2001 From: Gabriel Ferreira Date: Wed, 22 Jan 2025 17:27:19 +0100 Subject: [PATCH] antenna, spectrum: Trigger a channel matrix update on UPA setting changes --- src/antenna/model/phased-array-model.cc | 20 +++++ src/antenna/model/phased-array-model.h | 18 +++++ src/antenna/model/uniform-planar-array.cc | 10 +++ src/antenna/test/test-uniform-planar-array.cc | 74 +++++++++++++++++++ src/spectrum/model/three-gpp-channel-model.cc | 5 +- 5 files changed, 125 insertions(+), 2 deletions(-) diff --git a/src/antenna/model/phased-array-model.cc b/src/antenna/model/phased-array-model.cc index 4049adad0..912a969a5 100644 --- a/src/antenna/model/phased-array-model.cc +++ b/src/antenna/model/phased-array-model.cc @@ -18,6 +18,7 @@ namespace ns3 { uint32_t PhasedArrayModel::m_idCounter = 0; +SymmetricAdjacencyMatrix 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 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 */ diff --git a/src/antenna/model/phased-array-model.h b/src/antenna/model/phased-array-model.h index 4bcef80f6..98cc928c6 100644 --- a/src/antenna/model/phased-array-model.h +++ b/src/antenna/model/phased-array-model.h @@ -12,6 +12,7 @@ #include "ns3/matrix-array.h" #include "ns3/object.h" +#include "ns3/symmetric-adjacency-matrix.h" #include @@ -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 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 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 + 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 */ diff --git a/src/antenna/model/uniform-planar-array.cc b/src/antenna/model/uniform-planar-array.cc index e17b027f8..0d2413ed6 100644 --- a/src/antenna/model/uniform-planar-array.cc +++ b/src/antenna/model/uniform-planar-array.cc @@ -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 diff --git a/src/antenna/test/test-uniform-planar-array.cc b/src/antenna/test/test-uniform-planar-array.cc index 9f7c1c723..3db6ad901 100644 --- a/src/antenna/test/test-uniform-planar-array.cc +++ b/src/antenna/test/test-uniform-planar-array.cc @@ -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 element, std::string name) + : TestCase(name), + m_element(element){}; + + private: + /** + * Run the test + */ + void DoRun() override; + Ptr m_element; //!< the antenna element +}; + +void +UpdateOnChangeTestCase::DoRun() +{ + Ptr ant = CreateObject(); + 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 ant2 = CreateObject(); + 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; diff --git a/src/spectrum/model/three-gpp-channel-model.cc b/src/spectrum/model/three-gpp-channel-model.cc index f3892a360..9d372d5b1 100644 --- a/src/spectrum/model/three-gpp-channel-model.cc +++ b/src/spectrum/model/three-gpp-channel-model.cc @@ -2464,8 +2464,9 @@ ThreeGppChannelModel::AntennaSetupChanged(Ptr 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