antenna: Extend antenna array to support multiple ports and dual pol. of antenna elements
antenna: Fix PhasedArrayAntennaModel Doxygen antenna: Fix UniformPlanarArray Doxygen antenna: Rename Get horizontal vertical number of elements in the port antenna: fix phased-array-model.cc antenna: Fix (remove 3gpp comment) antenna: Add units to GetPolSlant antenna: Fix IsPolDual -> IsDualPol, add function SetDualPol, Remove SetPolarization antenna: Remove GetNumPolarizations function to reduce the dependency between spectrum and antenna antenna: Simplify the code in GetBeamformingVector in PhasedArrayModel antenna: Rename GetPolAngle->GetPolSlant antenna: Fix GetBeamformingVector normalization description, add 3GPP reference antenna: Expand explanation of why is done the normalization of the BF weights in GetBeamformingVector antenna: Enable access to public Get and Set functions antenna: Refactor and move the code related to polarization to antenna model fix variable name in antenna antenna fix doxygen antenna: Doc. for dual-polarization and multiple ports in UniformPlannarArray remote trailing whitespaces antenna: Return back cos and sin optimization of pol slant angle antenna: Fix documentation regarding the polarization slant angle antenna: UniformPlannarArray Initialize cos/sin of -90 antenna: Change parameter names Remove new line antenna: Suggestions proposed by Eduardo Almeida antenna: Add a 3GPP reference for a multi-port antenna array model
This commit is contained in:
@@ -160,10 +160,10 @@ UniformPlanarArray
|
||||
|
||||
The class UniformPlanarArray is a generic implementation of Uniform Planar Arrays (UPAs),
|
||||
supporting rectangular and linear regular lattices.
|
||||
It loosely follows the implementation described in the 3GPP TR 38.901 [38901]_,
|
||||
considering only a single a single panel, i.e., :math:`N_{g} = M_{g} = 1`.
|
||||
It closely follows the implementation described in the 3GPP TR 38.901 [38901]_,
|
||||
considering only a single panel, i.e., :math:`N_{g} = M_{g} = 1`.
|
||||
|
||||
By default, the array is orthogonal to the x-axis, pointing towards the positive
|
||||
By default, the antenna array is orthogonal to the x-axis, pointing towards the positive
|
||||
direction, but the orientation can be changed through the attributes "BearingAngle",
|
||||
which adjusts the azimuth angle, and "DowntiltAngle", which adjusts the elevation angle.
|
||||
The slant angle is instead fixed and assumed to be 0.
|
||||
@@ -173,8 +173,24 @@ through the attributes "NumRows" and "NumColumns", while the spacing between the
|
||||
and vertical elements can be configured through the attributes "AntennaHorizontalSpacing"
|
||||
and "AntennaVerticalSpacing".
|
||||
|
||||
The polarization of each antenna element in the array is determined by the polarization
|
||||
slant angle through the attribute "PolSlantAngle", as described in [38901]_ (i.e., :math:`{\zeta}`).
|
||||
UniformPlannarArray supports the concept of antenna ports following the sub-array partition
|
||||
model for TXRU virtualization, as described in Section 5.2.2 of 3GPP TR 36.897 [36897]_.
|
||||
The number of antenna ports in vertical and horizontal directions can be configured through
|
||||
the attributes "NumVerticalPorts" and "NumHorizontalPorts", respectively. For example,
|
||||
if "NumRows" and "NumColumns" are configured to 2 and 4, and the number of
|
||||
"NumVerticalPorts" and "NumHorizontalPorts" to 1 and 2, then the antenna elements belonging
|
||||
to the first two columns of the antenna array will belong to the first antenna port,
|
||||
and the third and the fourth columns will belong to the second antenna port. Note that
|
||||
"NumRows" and "NumColumns" must be a multiple of "NumVerticalPorts" and "NumHorizontalPorts",
|
||||
respectively.
|
||||
|
||||
Whether the antenna is dual-polarized or not is configured through the attribute
|
||||
"IsDualPolarized". In case the antenna array is dual polarized, the total number
|
||||
of antenna elements is doubled and the two polarizations are overlapped in space.
|
||||
The polarization slant angle of the antenna elements belonging to the first polarization
|
||||
are configured through the attribute "PolSlantAngle"; while the antenna elements of
|
||||
the second polarization have the polarization slant angle minus 90 degrees,
|
||||
as described in [38901]_ (i.e., :math:`{\zeta}`).
|
||||
|
||||
|
||||
.. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design", Wiley, 2nd Ed.
|
||||
@@ -193,3 +209,6 @@ slant angle through the attribute "PolSlantAngle", as described in [38901]_ (i.e
|
||||
.. [38901] 3GPP. 2018. TR 38.901, Study on channel model for frequencies from 0.5 to 100 GHz, V15.0.0. (2018-06).
|
||||
|
||||
.. [Mailloux] Robert J. Mailloux, "Phased Array Antenna Handbook", Artech House, 2nd Ed.
|
||||
|
||||
.. [TR36897] 3GPP. 2015. TR 36.897. Study on elevation beamforming / Full-Dimension (FD)
|
||||
Multiple Input Multiple Output (MIMO) for LTE. V13.0.0. (2015-06)
|
||||
|
||||
@@ -34,28 +34,6 @@ NS_LOG_COMPONENT_DEFINE("PhasedArrayModel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(PhasedArrayModel);
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const PhasedArrayModel::ComplexVector& cv)
|
||||
{
|
||||
size_t N = cv.GetSize();
|
||||
|
||||
// empty
|
||||
if (N == 0)
|
||||
{
|
||||
os << "[]";
|
||||
return os;
|
||||
}
|
||||
|
||||
// non-empty
|
||||
os << "[";
|
||||
for (std::size_t i = 0; i < N - 1; ++i)
|
||||
{
|
||||
os << cv[i] << ", ";
|
||||
}
|
||||
os << cv[N - 1] << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
PhasedArrayModel::PhasedArrayModel()
|
||||
: m_isBfVectorValid{false}
|
||||
{
|
||||
@@ -101,13 +79,30 @@ PhasedArrayModel::GetBeamformingVector() const
|
||||
return m_beamformingVector;
|
||||
}
|
||||
|
||||
const PhasedArrayModel::ComplexVector&
|
||||
PhasedArrayModel::GetBeamformingVectorRef() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_isBfVectorValid,
|
||||
"The beamforming vector should be Set before it's Get, and should refer to the "
|
||||
"current array configuration");
|
||||
return m_beamformingVector;
|
||||
}
|
||||
|
||||
PhasedArrayModel::ComplexVector
|
||||
PhasedArrayModel::GetBeamformingVector(Angles a) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << a);
|
||||
|
||||
ComplexVector beamformingVector = GetSteeringVector(a);
|
||||
double normRes = norm(beamformingVector);
|
||||
// The normalization takes into account the total number of ports as only a
|
||||
// portion (K,L) of beam weights associated with a specific port are non-zero.
|
||||
// See 3GPP Section 5.2.2 36.897. This normalization corresponds to
|
||||
// a sub-array partition model (which is different from the full-connection
|
||||
// model). Note that the total number of ports used to perform normalization
|
||||
// is the ratio between the total number of antenna elements and the
|
||||
// number of antenna elements per port.
|
||||
double normRes = norm(beamformingVector) / sqrt(GetNumPorts());
|
||||
|
||||
for (size_t i = 0; i < GetNumberOfElements(); i++)
|
||||
{
|
||||
|
||||
@@ -73,17 +73,7 @@ class PhasedArrayModel : public Object
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal and vertical components of the antenna element field
|
||||
* pattern at the specified direction. Single polarization is considered.
|
||||
* \param a the angle indicating the interested direction
|
||||
* \return a pair in which the first element is the horizontal component
|
||||
* of the field pattern and the second element is the vertical
|
||||
* component of the field pattern
|
||||
*/
|
||||
virtual std::pair<double, double> GetElementFieldPattern(Angles a) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the location of the antenna element with the specified
|
||||
* \brief Returns the location of the antenna element with the specified
|
||||
* index, normalized with respect to the wavelength.
|
||||
* \param index the index of the antenna element
|
||||
* \return the 3D vector that represents the position of the element
|
||||
@@ -91,11 +81,129 @@ class PhasedArrayModel : public Object
|
||||
virtual Vector GetElementLocation(uint64_t index) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of antenna elements
|
||||
* \brief Returns the number of antenna elements
|
||||
* \return the number of antenna elements
|
||||
*/
|
||||
virtual size_t GetNumberOfElements() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Returns the horizontal and vertical components of the antenna element field
|
||||
* pattern at the specified direction. Single polarization is considered.
|
||||
* \param a the angle indicating the interested direction
|
||||
* \param polIndex the index of the polarization for which will be retrieved the field
|
||||
* pattern
|
||||
* \return a pair in which the first element is the horizontal component of the field
|
||||
* pattern and the second element is the vertical component of the field pattern
|
||||
*/
|
||||
virtual std::pair<double, double> GetElementFieldPattern(Angles a,
|
||||
uint8_t polIndex = 0) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Set the vertical number of ports
|
||||
* \param nPorts the vertical number of ports
|
||||
*/
|
||||
virtual void SetNumVerticalPorts(uint16_t nPorts) = 0;
|
||||
|
||||
/**
|
||||
* \brief Set the horizontal number of ports
|
||||
* \param nPorts the horizontal number of ports
|
||||
*/
|
||||
virtual void SetNumHorizontalPorts(uint16_t nPorts) = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the vertical number of ports
|
||||
* \return the vertical number of ports
|
||||
*/
|
||||
virtual uint16_t GetNumVerticalPorts() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the horizontal number of ports
|
||||
* \return the horizontal number of ports
|
||||
*/
|
||||
virtual uint16_t GetNumHorizontalPorts() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the number of ports
|
||||
* \return the number of ports
|
||||
*/
|
||||
virtual uint16_t GetNumPorts() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the number of polarizations
|
||||
* \return the number of polarizations
|
||||
*/
|
||||
virtual uint8_t GetNumPols() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the vertical number of antenna elements per port
|
||||
* \return the vertical number of antenna elements per port
|
||||
*/
|
||||
virtual size_t GetVElemsPerPort() const = 0;
|
||||
/**
|
||||
* \brief Get the horizontal number of antenna elements per port
|
||||
* \return the horizontal number of antenna elements per port
|
||||
*/
|
||||
virtual size_t GetHElemsPerPort() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the number of elements per port
|
||||
* \return the number of elements per port
|
||||
*/
|
||||
virtual size_t GetNumElemsPerPort() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Set the number of columns
|
||||
* \param nColumns the number of columns to be set
|
||||
*/
|
||||
virtual void SetNumColumns(uint32_t nColumns) = 0;
|
||||
|
||||
/**
|
||||
* \brief Set the number of rows
|
||||
* \param nRows the number of rows to be set
|
||||
*/
|
||||
virtual void SetNumRows(uint32_t nRows) = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the number of columns
|
||||
* \return the number of columns in the antenna array
|
||||
*/
|
||||
virtual uint32_t GetNumColumns() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the number of rows
|
||||
* \return the number of rows in the antenna array
|
||||
*/
|
||||
virtual uint32_t GetNumRows() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the polarization slant angle
|
||||
* \return the polarization slant angle
|
||||
*/
|
||||
virtual double GetPolSlant() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Get the indication whether the antenna array is dual polarized
|
||||
* \return Returns true if the antenna array is dual polarized
|
||||
*/
|
||||
virtual bool IsDualPol() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Calculate the index in the antenna array from the port index and the element in the
|
||||
* port
|
||||
* \param portIndex the port index
|
||||
* \param subElementIndex the element index in the port
|
||||
* \return the antenna element index in the antenna array
|
||||
*/
|
||||
virtual uint16_t ArrayIndexFromPortIndex(uint16_t portIndex,
|
||||
uint16_t subElementIndex) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the index of the polarization to which belongs that antenna element
|
||||
* \param elementIndex the antenna element for which will be returned the polarization index
|
||||
* \return the polarization index
|
||||
*/
|
||||
virtual uint8_t GetElemPol(size_t elementIndex) const = 0;
|
||||
|
||||
/**
|
||||
* Sets the beamforming vector to be used
|
||||
* \param beamformingVector the beamforming vector
|
||||
@@ -108,6 +216,12 @@ class PhasedArrayModel : public Object
|
||||
*/
|
||||
ComplexVector GetBeamformingVector() const;
|
||||
|
||||
/**
|
||||
* Returns the const reference of the beamforming vector that is currently being used
|
||||
* \return the const reference of the current beamforming vector
|
||||
*/
|
||||
const PhasedArrayModel::ComplexVector& GetBeamformingVectorRef() const;
|
||||
|
||||
/**
|
||||
* Returns the beamforming vector that points towards the specified position
|
||||
* \param a the beamforming angle
|
||||
@@ -149,15 +263,6 @@ class PhasedArrayModel : public Object
|
||||
uint32_t m_id{0}; //!< the ID of this antenna array instance
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Stream insertion operator.
|
||||
*
|
||||
* \param [in] os The reference to the output stream.
|
||||
* \param [in] cv A vector of complex values.
|
||||
* \returns The reference to the output stream.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os, const PhasedArrayModel::ComplexVector& cv);
|
||||
|
||||
} /* namespace ns3 */
|
||||
|
||||
#endif /* PHASED_ARRAY_MODEL_H */
|
||||
|
||||
@@ -84,8 +84,27 @@ UniformPlanarArray::GetTypeId()
|
||||
.AddAttribute("PolSlantAngle",
|
||||
"The polarization slant angle in radians",
|
||||
DoubleValue(0.0),
|
||||
MakeDoubleAccessor(&UniformPlanarArray::SetPolSlant),
|
||||
MakeDoubleChecker<double>(-M_PI, M_PI));
|
||||
MakeDoubleAccessor(&UniformPlanarArray::SetPolSlant,
|
||||
&UniformPlanarArray::GetPolSlant),
|
||||
MakeDoubleChecker<double>(-M_PI, M_PI))
|
||||
.AddAttribute("NumVerticalPorts",
|
||||
"Vertical number of ports",
|
||||
UintegerValue(1),
|
||||
MakeUintegerAccessor(&UniformPlanarArray::GetNumVerticalPorts,
|
||||
&UniformPlanarArray::SetNumVerticalPorts),
|
||||
MakeUintegerChecker<uint32_t>())
|
||||
.AddAttribute("NumHorizontalPorts",
|
||||
"Horizontal number of ports",
|
||||
UintegerValue(1),
|
||||
MakeUintegerAccessor(&UniformPlanarArray::GetNumHorizontalPorts,
|
||||
&UniformPlanarArray::SetNumHorizontalPorts),
|
||||
MakeUintegerChecker<uint32_t>())
|
||||
.AddAttribute("IsDualPolarized",
|
||||
"If true, dual polarized antenna",
|
||||
BooleanValue(false),
|
||||
MakeBooleanAccessor(&UniformPlanarArray::SetDualPol,
|
||||
&UniformPlanarArray::IsDualPol),
|
||||
MakeBooleanChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
@@ -143,8 +162,8 @@ void
|
||||
UniformPlanarArray::SetPolSlant(double polSlant)
|
||||
{
|
||||
m_polSlant = polSlant;
|
||||
m_cosPolSlant = cos(m_polSlant);
|
||||
m_sinPolSlant = sin(m_polSlant);
|
||||
m_cosPolSlant[0] = cos(m_polSlant);
|
||||
m_sinPolSlant[0] = sin(m_polSlant);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -186,9 +205,10 @@ UniformPlanarArray::GetAntennaVerticalSpacing() const
|
||||
}
|
||||
|
||||
std::pair<double, double>
|
||||
UniformPlanarArray::GetElementFieldPattern(Angles a) const
|
||||
UniformPlanarArray::GetElementFieldPattern(Angles a, uint8_t polIndex) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << a);
|
||||
NS_ASSERT_MSG(polIndex < GetNumPols(), "Polarization index can be 0 or 1.");
|
||||
|
||||
// convert the theta and phi angles from GCS to LCS using eq. 7.1-7 and 7.1-8 in 3GPP TR 38.901
|
||||
// NOTE we assume a fixed slant angle of 0 degrees
|
||||
@@ -208,8 +228,10 @@ UniformPlanarArray::GetElementFieldPattern(Angles a) const
|
||||
// NOTE: the slant angle (assumed to be 0) differs from the polarization slant angle
|
||||
// (m_polSlant, given by the attribute), in 3GPP TR 38.901
|
||||
double aPrimeDb = m_antennaElement->GetGainDb(aPrime);
|
||||
double fieldThetaPrime = pow(10, aPrimeDb / 20) * m_cosPolSlant; // convert to linear magnitude
|
||||
double fieldPhiPrime = pow(10, aPrimeDb / 20) * m_sinPolSlant; // convert to linear magnitude
|
||||
double fieldThetaPrime =
|
||||
pow(10, aPrimeDb / 20) * m_cosPolSlant[polIndex]; // convert to linear magnitude
|
||||
double fieldPhiPrime =
|
||||
pow(10, aPrimeDb / 20) * m_sinPolSlant[polIndex]; // convert to linear magnitude
|
||||
|
||||
// compute psi using eq. 7.1-15 in 3GPP TR 38.901, assuming that the slant
|
||||
// angle (gamma) is 0
|
||||
@@ -232,13 +254,19 @@ Vector
|
||||
UniformPlanarArray::GetElementLocation(uint64_t index) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << index);
|
||||
|
||||
uint64_t tmpIndex = index;
|
||||
// for dual polarization, the top half corresponds to one polarization and
|
||||
// lower half corresponds to the other polarization
|
||||
if (m_isDualPolarized && tmpIndex >= m_numRows * m_numColumns)
|
||||
{
|
||||
tmpIndex -= m_numRows * m_numColumns;
|
||||
}
|
||||
// compute the element coordinates in the LCS
|
||||
// assume the left bottom corner is (0,0,0), and the rectangular antenna array is on the y-z
|
||||
// plane.
|
||||
double xPrime = 0;
|
||||
double yPrime = m_disH * (index % m_numColumns);
|
||||
double zPrime = m_disV * floor(index / m_numColumns);
|
||||
double yPrime = m_disH * (tmpIndex % m_numColumns);
|
||||
double zPrime = m_disV * floor(tmpIndex / m_numColumns);
|
||||
|
||||
// convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP
|
||||
// TR 38.901
|
||||
@@ -249,10 +277,129 @@ UniformPlanarArray::GetElementLocation(uint64_t index) const
|
||||
return loc;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
UniformPlanarArray::GetNumPols() const
|
||||
{
|
||||
return m_isDualPolarized ? 2 : 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
UniformPlanarArray::GetNumberOfElements() const
|
||||
{
|
||||
return m_numRows * m_numColumns;
|
||||
// From 38.901 [M, N, P, Mg, Ng] = [m_numRows, m_numColumns, 2, 1, 1]
|
||||
return GetNumPols() * m_numRows * m_numColumns;
|
||||
// with dual polarization, the number of antenna elements double up
|
||||
}
|
||||
|
||||
void
|
||||
UniformPlanarArray::SetNumVerticalPorts(uint16_t nPorts)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0");
|
||||
NS_ASSERT_MSG(((m_numRows % nPorts) == 0),
|
||||
"The number of vertical ports must divide number of rows");
|
||||
m_numVPorts = nPorts;
|
||||
}
|
||||
|
||||
void
|
||||
UniformPlanarArray::SetNumHorizontalPorts(uint16_t nPorts)
|
||||
{
|
||||
NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0");
|
||||
NS_ASSERT_MSG(((m_numColumns % nPorts) == 0),
|
||||
"The number of horizontal ports must divide number of columns");
|
||||
m_numHPorts = nPorts;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
UniformPlanarArray::GetNumVerticalPorts() const
|
||||
{
|
||||
return m_numVPorts;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
UniformPlanarArray::GetNumHorizontalPorts() const
|
||||
{
|
||||
return m_numHPorts;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
UniformPlanarArray::GetNumPorts() const
|
||||
{
|
||||
return GetNumPols() * m_numVPorts * m_numHPorts;
|
||||
}
|
||||
|
||||
size_t
|
||||
UniformPlanarArray::GetVElemsPerPort() const
|
||||
{
|
||||
return m_numRows / m_numVPorts;
|
||||
}
|
||||
|
||||
size_t
|
||||
UniformPlanarArray::GetHElemsPerPort() const
|
||||
{
|
||||
return m_numColumns / m_numHPorts;
|
||||
}
|
||||
|
||||
size_t
|
||||
UniformPlanarArray::GetNumElemsPerPort() const
|
||||
{
|
||||
// Multiply the number of rows and number of columns belonging to one antenna port.
|
||||
// This also holds for dual polarization, where each polarization belongs to a separate port.
|
||||
return GetVElemsPerPort() * GetHElemsPerPort();
|
||||
}
|
||||
|
||||
uint16_t
|
||||
UniformPlanarArray::ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const
|
||||
{
|
||||
NS_ASSERT_MSG(portIndex < GetNumPorts(), "Port should be less than total Ports");
|
||||
NS_ASSERT(subElementIndex < (GetHElemsPerPort() * GetVElemsPerPort()));
|
||||
|
||||
// In case the array is dual-polarized, change to the index that belongs to the first
|
||||
// polarization
|
||||
auto firstPolPortIdx = portIndex;
|
||||
auto polarizationOffset = 0;
|
||||
auto arraySize = GetNumHorizontalPorts() * GetNumVerticalPorts();
|
||||
if (firstPolPortIdx > arraySize)
|
||||
{
|
||||
firstPolPortIdx = portIndex - arraySize;
|
||||
polarizationOffset = GetNumColumns() * GetNumRows();
|
||||
}
|
||||
// column-major indexing
|
||||
auto hPortIdx = firstPolPortIdx / GetNumVerticalPorts();
|
||||
auto vPortIdx = firstPolPortIdx % GetNumVerticalPorts();
|
||||
auto hElemIdx = (hPortIdx * GetHElemsPerPort()) + (subElementIndex % GetHElemsPerPort());
|
||||
auto vElemIdx = (vPortIdx * GetVElemsPerPort()) + (subElementIndex / GetHElemsPerPort());
|
||||
return (vElemIdx * GetNumColumns() + hElemIdx + polarizationOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
UniformPlanarArray::IsDualPol() const
|
||||
{
|
||||
return m_isDualPolarized;
|
||||
}
|
||||
|
||||
void
|
||||
UniformPlanarArray::SetDualPol(bool isDualPol)
|
||||
{
|
||||
m_isDualPolarized = isDualPol;
|
||||
if (isDualPol)
|
||||
{
|
||||
m_cosPolSlant[1] = cos(m_polSlant - M_PI / 2);
|
||||
m_sinPolSlant[1] = sin(m_polSlant - M_PI / 2);
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
UniformPlanarArray::GetPolSlant() const
|
||||
{
|
||||
return m_polSlant;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
UniformPlanarArray::GetElemPol(size_t elemIndex) const
|
||||
{
|
||||
NS_ASSERT(elemIndex < GetNumElems());
|
||||
return (elemIndex < GetNumRows() * GetNumColumns()) ? 0 : 1;
|
||||
}
|
||||
|
||||
} /* namespace ns3 */
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace ns3
|
||||
* \brief Class implementing Uniform Planar Array (UPA) model.
|
||||
*
|
||||
* \note the current implementation supports the modeling of antenna arrays
|
||||
* composed of a single panel and with single (configured) polarization.
|
||||
* composed of a single panel and with single or dual polarization.
|
||||
*/
|
||||
class UniformPlanarArray : public PhasedArrayModel
|
||||
{
|
||||
@@ -54,13 +54,15 @@ class UniformPlanarArray : public PhasedArrayModel
|
||||
|
||||
/**
|
||||
* Returns the horizontal and vertical components of the antenna element field
|
||||
* pattern at the specified direction. Single polarization is considered.
|
||||
* pattern at the specified direction and for the specified polarization.
|
||||
* \param a the angle indicating the interested direction
|
||||
* \param polIndex the index of the polarization for which will be retrieved the field
|
||||
* pattern
|
||||
* \return a pair in which the first element is the horizontal component
|
||||
* of the field pattern and the second element is the vertical
|
||||
* component of the field pattern
|
||||
*/
|
||||
std::pair<double, double> GetElementFieldPattern(Angles a) const override;
|
||||
std::pair<double, double> GetElementFieldPattern(Angles a, uint8_t polIndex = 0) const override;
|
||||
|
||||
/**
|
||||
* Returns the location of the antenna element with the specified
|
||||
@@ -72,32 +74,55 @@ class UniformPlanarArray : public PhasedArrayModel
|
||||
* | 3 4 5
|
||||
* | 0 1 2
|
||||
* ----------> y
|
||||
* In case of dual-polarized antennas, the antennas of the first and the second polarization
|
||||
* are overlapped in space.
|
||||
*
|
||||
* \param index index of the antenna element
|
||||
* \return the 3D vector that represents the position of the element
|
||||
* \return the 3D vector that
|
||||
* represents the position of the element
|
||||
*/
|
||||
Vector GetElementLocation(uint64_t index) const override;
|
||||
|
||||
/**
|
||||
* Returns the number of antenna elements
|
||||
* Check if an antenna array contains dual-polarized elements
|
||||
*
|
||||
* \return true if antenna has two polarization otherwise false
|
||||
*/
|
||||
bool IsDualPol() const override;
|
||||
|
||||
/**
|
||||
* Returns polarization angle of first polarization
|
||||
* \return polarization angle in radians
|
||||
*/
|
||||
double GetPolSlant() const override;
|
||||
|
||||
/**
|
||||
* Returns the number of polarizations, 2 in the case that
|
||||
* the antenna is dual-polarized, otherwise 1
|
||||
* \return
|
||||
*/
|
||||
uint8_t GetNumPols() const override;
|
||||
|
||||
/**
|
||||
* Returns the number of total antenna elements. Note that if the antenna
|
||||
* is dual-polarized the number of total antenna elements is doubled.
|
||||
* \return the number of antenna elements
|
||||
*/
|
||||
size_t GetNumberOfElements() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set the number of columns of the phased array
|
||||
* This method resets the stored beamforming vector to a ComplexVector
|
||||
* of the correct size, but zero-filled
|
||||
* \param n the number of columns
|
||||
*/
|
||||
void SetNumColumns(uint32_t n);
|
||||
void SetNumColumns(uint32_t n) override;
|
||||
|
||||
/**
|
||||
* Get the number of columns of the phased array
|
||||
* \return the number of columns
|
||||
*/
|
||||
uint32_t GetNumColumns() const;
|
||||
uint32_t GetNumColumns() const override;
|
||||
|
||||
/**
|
||||
* Set the number of rows of the phased array
|
||||
@@ -105,13 +130,69 @@ class UniformPlanarArray : public PhasedArrayModel
|
||||
* of the correct size, but zero-filled
|
||||
* \param n the number of rows
|
||||
*/
|
||||
void SetNumRows(uint32_t n);
|
||||
void SetNumRows(uint32_t n) override;
|
||||
|
||||
/**
|
||||
* Get the number of rows of the phased array
|
||||
* \return the number of rows
|
||||
*/
|
||||
uint32_t GetNumRows() const;
|
||||
uint32_t GetNumRows() const override;
|
||||
|
||||
/**
|
||||
* Set the number of vertical antenna ports
|
||||
* \param nPorts The number of vertical ports to be configured
|
||||
*/
|
||||
void SetNumVerticalPorts(uint16_t nPorts) override;
|
||||
|
||||
/**
|
||||
* Set the number of horizontal antenna ports
|
||||
* \param nPorts
|
||||
*/
|
||||
void SetNumHorizontalPorts(uint16_t nPorts) override;
|
||||
|
||||
/**
|
||||
* Get the number of vertical antenna ports
|
||||
* \return the number of vertical antenna ports
|
||||
*/
|
||||
uint16_t GetNumVerticalPorts() const override;
|
||||
|
||||
/**
|
||||
* Get the number of horizontal antenna ports
|
||||
* \return the number of horizontal antenna ports
|
||||
*/
|
||||
uint16_t GetNumHorizontalPorts() const override;
|
||||
|
||||
/**
|
||||
* Get the total number of antenna ports
|
||||
* \return the number of antenna ports
|
||||
*/
|
||||
uint16_t GetNumPorts() const override;
|
||||
|
||||
/**
|
||||
* Get the number of vertical elements belonging to each port
|
||||
* \return the number of vertical elements belonging of each port
|
||||
*/
|
||||
size_t GetVElemsPerPort() const override;
|
||||
|
||||
/**
|
||||
* Get the number of horizontal elements belonging to each port
|
||||
* \return the number of horizontal elements belonging to each port
|
||||
*/
|
||||
size_t GetHElemsPerPort() const override;
|
||||
|
||||
/**
|
||||
* Get the total number of elements belonging to each port
|
||||
* \return the number of elements per port
|
||||
*/
|
||||
size_t GetNumElemsPerPort() const override;
|
||||
|
||||
/**
|
||||
* Maps element within a port to an index of element within the antenna array
|
||||
* \param portIndex the port index
|
||||
* \param subElementIndex the element index within the port
|
||||
* \return the element index in the antenna array
|
||||
*/
|
||||
uint16_t ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const override;
|
||||
|
||||
/**
|
||||
* \brief Set the bearing angle
|
||||
@@ -165,19 +246,37 @@ class UniformPlanarArray : public PhasedArrayModel
|
||||
*/
|
||||
double GetAntennaVerticalSpacing() const;
|
||||
|
||||
/**
|
||||
* Set the polarization
|
||||
* \param isDualPol whether to set the antenna array to be dual-polarized,
|
||||
* if true, antenna will be dual-polarized
|
||||
*/
|
||||
void SetDualPol(bool isDualPol);
|
||||
|
||||
/**
|
||||
* Returns the index of polarization to which belongs the antenna element with a specific index
|
||||
* \param elemIndex the antenna element index
|
||||
* \return the polarization index
|
||||
*/
|
||||
uint8_t GetElemPol(size_t elemIndex) const override;
|
||||
|
||||
private:
|
||||
uint32_t m_numColumns{1}; //!< number of columns
|
||||
uint32_t m_numRows{1}; //!< number of rows
|
||||
double m_disV{0.5}; //!< antenna spacing in the vertical direction in multiples of wave length
|
||||
double m_disH{0.5}; //!< antenna spacing in the horizontal direction in multiples of wave length
|
||||
double m_alpha{0.0}; //!< the bearing angle in radians
|
||||
double m_cosAlpha{1.0}; //!< the cosine of alpha
|
||||
double m_sinAlpha{0.0}; //!< the sine of alpha
|
||||
double m_beta{0.0}; //!< the downtilt angle in radians
|
||||
double m_cosBeta{1.0}; //!< the cosine of Beta
|
||||
double m_sinBeta{0.0}; //!< the sine of Beta
|
||||
double m_polSlant{0.0}; //!< the polarization slant angle in radians
|
||||
double m_cosPolSlant{1.0}; //!< the cosine of polarization slant angle
|
||||
double m_sinPolSlant{0.0}; //!< the sine polarization slant angle
|
||||
double m_alpha{0.0}; //!< the bearing angle in radians
|
||||
double m_cosAlpha{1.0}; //!< the cosine of alpha
|
||||
double m_sinAlpha{0.0}; //!< the sine of alpha
|
||||
double m_beta{0.0}; //!< the downtilt angle in radians
|
||||
double m_cosBeta{1.0}; //!< the cosine of Beta
|
||||
double m_sinBeta{0.0}; //!< the sine of Beta
|
||||
double m_polSlant{0.0}; //!< the polarization slant angle in radians
|
||||
bool m_isDualPolarized{false}; //!< if true antenna elements are dual-polarized
|
||||
uint16_t m_numVPorts{1}; //!< Number of vertical ports
|
||||
uint16_t m_numHPorts{1}; //!< Number of horizontal ports
|
||||
std::vector<double> m_cosPolSlant{1.0, 0.0}; //!< the cosine of polarization slant angle
|
||||
std::vector<double> m_sinPolSlant{0.0, -1.0}; //!< the sine polarization slant angle
|
||||
};
|
||||
|
||||
} /* namespace ns3 */
|
||||
|
||||
Reference in New Issue
Block a user