antenna, spectrum: Trigger a channel matrix update on UPA setting changes
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user