diff --git a/examples/channel-models/three-gpp-v2v-channel-example.cc b/examples/channel-models/three-gpp-v2v-channel-example.cc index c0956a086..cb0b10c9b 100644 --- a/examples/channel-models/three-gpp-v2v-channel-example.cc +++ b/examples/channel-models/three-gpp-v2v-channel-example.cc @@ -41,7 +41,7 @@ #include "ns3/core-module.h" #include "ns3/network-module.h" #include -#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/uniform-planar-array.h" #include "ns3/three-gpp-spectrum-propagation-loss-model.h" #include "ns3/three-gpp-v2v-propagation-loss-model.h" #include "ns3/three-gpp-channel-model.h" @@ -61,9 +61,9 @@ static Ptr m_condModel; //!< the ChannelConditionModel ob * \param otherDevice the device towards which point the beam */ static void -DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice) +DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice) { - ThreeGppAntennaArrayModel::ComplexVector antennaWeights; + PhasedArrayModel::ComplexVector antennaWeights; // retrieve the position of the two devices Vector aPos = thisDevice->GetNode ()->GetObject ()->GetPosition (); @@ -72,31 +72,8 @@ DoBeamforming (Ptr thisDevice, Ptr thisAnt // compute the azimuth and the elevation angles Angles completeAngle (bPos,aPos); - double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle - if (hAngleRadian < 0) - { - hAngleRadian += 2.0 * M_PI; - } - double vAngleRadian = completeAngle.theta; // the elevation angle - - // retrieve the number of antenna elements - int totNoArrayElements = thisAntenna->GetNumberOfElements (); - - // the total power is divided equally among the antenna elements - double power = 1 / sqrt (totNoArrayElements); - - // compute the antenna weights - for (int ind = 0; ind < totNoArrayElements; ind++) - { - Vector loc = thisAntenna->GetElementLocation (ind); - double phase = -2 * M_PI * (sin (vAngleRadian) * cos (hAngleRadian) * loc.x - + sin (vAngleRadian) * sin (hAngleRadian) * loc.y - + cos (vAngleRadian) * loc.z); - antennaWeights.push_back (exp (std::complex (0, phase)) * power); - } - - // store the antenna weights - thisAntenna->SetBeamformingVector (antennaWeights); + PhasedArrayModel::ComplexVector bf = thisAntenna->GetBeamformingVector (completeAngle); + thisAntenna->SetBeamformingVector (bf); } /** @@ -212,8 +189,8 @@ main (int argc, char *argv[]) rxDev->SetNode (nodes.Get (1)); // create the antenna objects and set their dimensions - Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (-M_PI / 2)); - Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (M_PI / 2)); + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (-M_PI / 2)); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (M_PI / 2)); Ptr txMob; Ptr rxMob; diff --git a/src/antenna/doc/source/antenna-design.rst b/src/antenna/doc/source/antenna-design.rst index 33153be84..06af30e35 100644 --- a/src/antenna/doc/source/antenna-design.rst +++ b/src/antenna/doc/source/antenna-design.rst @@ -11,9 +11,27 @@ Overview The Antenna module provides: - #. a new base class (AntennaModel) that provides an interface for the modeling of the radiation pattern of an antenna; + #. a class (Angles) and utility functions to deal with angles + #. a base class (AntennaModel) that provides an interface for the modeling of the radiation pattern of an antenna; #. a set of classes derived from this base class that each models the radiation pattern of different types of antennas; - #. the class ThreeGppAntennaArrayModel, which implements the antenna model described in 3GPP TR 38.901 + #. a base class (PhasedArrayModel) that provides a flexible interface for modeling a number of Phase Antenna Array (PAA) models + #. a class (UniformPlanarArray) derived from this base class, implementing a Uniform Planar Arraya (UPA) supporting both rectangular and linear lattices + + +------ +Angles +------ + +The Angles class holds information about an angle in 3D space using spherical coordinates in radian units. +Specifically, it uses the azimuth-inclination convention, where + +* Inclination is the angle between the zenith direction (positive z-axis) and the desired direction. It is included in the range [0, pi] radians. +* Azimuth is the signed angle measured from the positive x-axis, where a positive direction goes towards the positive y-axis. It is included in the range [-pi, pi) radians. + +Multiple constructors are present, supporting the most common ways to encode information on a direction. +A static boolean variable allows the user to decide whether angles should be printed in radian or degree units. + +A number of angle-related utilities are offered, such as radians/degree conversions, for both scalars and vectors, and angle wrapping. ------------ @@ -107,37 +125,54 @@ beamwidth, and :math:`A_{max}` is the maximum attenuation in dB of the antenna. Note that this radiation pattern is independent of the inclination angle :math:`\theta`. -.. _sec-3gpp-antenna-model: -------------------------- -ThreeGppAntennaArrayModel -------------------------- -The class ThreeGppAntennaArrayModel implements the antenna model described in -3GPP TR 38.901 [38901]_, which is used by the classes ThreeGppSpectrumPropagationLossModel -and ThreeGppChannelModel. -Each instance of this class models an isotropic rectangular antenna array composed -of a single panel with NxM elements, where N is the number of rows and M is the -number of columns, configurable through the attributes "NumRows" and "NumColumns". -The radiation pattern of the antenna elements follows the model specified in -Sec. 7.3 of 3GPP TR 38.901; only vertical polarization is considered (i.e., -:math:`{\zeta = 0}`). -The directional gain of the antenna elements can be configured through the -attribute "ElementGain" (see formula 2.34 in [Mailloux]_ to choose a proper value). +ThreeGppAntennaModel +++++++++++++++++++++ + +This model implements the antenna element described in [38901]_. +Parameters are fixed from the technical report, thus no attributes nor setters are provided. +The model is largely based on the `ParabolicAntennaModel`_. + +------------------ +Phased Array Model +------------------ + +The class PhasedArrayModel has been created with flexibility in mind. +It abstracts the basic idea of a Phased Antenna Array (PAA) by removing any constraint on the +position of each element, and instead generalizes the concept of steering and beamforming vectors, +solely based on the generalized location of the antenna elements. + +Derived classes must implement the following functions: + +* GetNumberOfElements: returns the number of antenna elements +* GetElementLocation: returns the location of the antenna element with the specified index, normalized with respect to the wavelength +* GetElementFieldPattern: returns the horizontal and vertical components of the antenna element field pattern at the specified direction. Only vertical polarization is considered. + +The class PhasedArrayModel also assumes that all antenna elements are equal, a typical key assumption which allows to model the PAA field pattern as the sum of the array factor, given by the geometry of the location of the antenna elements, and the element field pattern. +Any class derived from AntennaModel is a valid antenna element for the PhasedArrayModel, allowing for a great flexibility of the framework. + + +UniformPlanarArray +++++++++++++++++++ + +The class UniformPlanarArray is a generic implementation of Uniform Planar Arrays (UPAs), +supporting rectangular and linear regular lattices. +It loosesly 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`. + By default, the 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 spacing between the horizontal and vertical elements can be configured through -the attributes "AntennaHorizontalSpacing" and "AntennaVerticalSpacing". +The slant angle is instead fixed and assumed to be 0. -**Note:** +The number of antenna elements in the vertical and horizontal directions can be configured +through the attributes "NumRows" and "NumColumns", while the spacing between the horizontal +and vertical elements can be configured through the attributes "AntennaHorizontalSpacing" +and "AntennaVerticalSpacing". - * Currently, the model does not support multi-panel antennas, i.e., - :math:`N_{g} = M_{g} = 1`. +Note: vertical polarization is assumed for each antenna element, as described in [38901]_ (i.e., :math:`{\zeta = 0}`). - * Currently, the model supports only single polarized (i.e., P = 1) antenna - panels with vertical polarization (i.e., :math:`{\zeta = 0}`) - .. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design", Wiley, 2nd Ed. diff --git a/src/antenna/model/angles.cc b/src/antenna/model/angles.cc index 97092e970..d054e4d4b 100644 --- a/src/antenna/model/angles.cc +++ b/src/antenna/model/angles.cc @@ -28,27 +28,139 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("Angles"); -double DegreesToRadians (double degrees) +bool Angles::m_printDeg = false; + +const double DEG_TO_RAD = M_PI / 180.0; +const double RAD_TO_DEG = 180.0 / M_PI; + + +double +DegreesToRadians (double degrees) { - return degrees * M_PI / 180.0; + return degrees * DEG_TO_RAD; +} + + +double +RadiansToDegrees (double radians) +{ + return radians * RAD_TO_DEG; +} + + +std::vector +DegreesToRadians (const std::vector °rees) +{ + std::vector radians; + radians.reserve (degrees.size ()); + for (size_t i = 0; i < degrees.size (); i++) + { + radians.push_back (DegreesToRadians (degrees[i])); + } + return radians; } -double RadiansToDegrees (double radians) + +std::vector +RadiansToDegrees (const std::vector &radians) { - return radians * 180.0 / M_PI; + std::vector degrees; + degrees.reserve (radians.size ()); + for (size_t i = 0; i < radians.size (); i++) + { + degrees.push_back (RadiansToDegrees (radians[i])); + } + return degrees; } -std::ostream& operator<< (std::ostream& os, const Angles& a) + +double +WrapTo360 (double a) { - os << "(" << a.phi << ", " << a.theta << ")"; + a = fmod (a, 360); + if (a < 0) + { + a += 360; + } + + NS_ASSERT_MSG (0 <= a && a < 360, "Invalid wrap, a=" << a); + return a; +} + + +double +WrapTo180 (double a) +{ + a = fmod (a + 180, 360); + if (a < 0) + { + a += 360; + } + a -= 180; + + NS_ASSERT_MSG (-180 <= a && a < 180, "Invalid wrap, a=" << a); + return a; +} + + +double +WrapTo2Pi (double a) +{ + a = fmod (a, 2 * M_PI); + if (a < 0) + { + a += 2 * M_PI; + } + + NS_ASSERT_MSG (0 <= a && a < 2 * M_PI, "Invalid wrap, a=" << a); + return a; +} + + +double +WrapToPi (double a) +{ + a = fmod (a + M_PI, 2 * M_PI); + if (a < 0) + { + a += 2 * M_PI; + } + a -= M_PI; + + NS_ASSERT_MSG (-M_PI <= a && a < M_PI, "Invalid wrap, a=" << a); + return a; +} + + +std::ostream& +operator<< (std::ostream& os, const Angles& a) +{ + double azim, incl; + std::string unit; + + if (a.m_printDeg) + { + azim = RadiansToDegrees (a.m_azimuth); + incl = RadiansToDegrees (a.m_inclination); + unit = "deg"; + } + else + { + azim = a.m_azimuth; + incl = a.m_inclination; + unit = "rad"; + } + + os << "(" << azim << ", " << incl << ") " << unit; return os; } -std::istream &operator >> (std::istream &is, Angles &a) +std::istream& +operator>> (std::istream& is, Angles& a) { char c; - is >> a.phi >> c >> a.theta; + is >> a.m_azimuth >> c >> a.m_inclination; if (c != ':') { is.setstate (std::ios_base::failbit); @@ -58,31 +170,98 @@ std::istream &operator >> (std::istream &is, Angles &a) Angles::Angles () - : phi (0), - theta (0) -{ -} + : Angles (NAN, NAN) +{} -Angles::Angles (double p, double t) - : phi (p), - theta (t) +Angles::Angles (double azimuth, double inclination) + : m_azimuth (azimuth), + m_inclination (inclination) { + NormalizeAngles (); } Angles::Angles (Vector v) - : phi (std::atan2 (v.y, v.x)), - theta (std::acos (v.z / v.GetLength ())) + : m_azimuth (std::atan2 (v.y, v.x)), + m_inclination (std::acos (v.z / v.GetLength ())) { + // azimuth and inclination angles for zero-length vectors are not defined + if (v.x == 0.0 && v.y == 0.0 && v.z == 0.0) + { + m_azimuth = NAN; + m_inclination = NAN; + } + + NormalizeAngles (); } Angles::Angles (Vector v, Vector o) - : phi (std::atan2 (v.y - o.y, v.x - o.x)), - theta (std::acos ((v.z - o.z) / CalculateDistance (v, o))) + : Angles (v - o) +{} + + + +void +Angles::SetAzimuth (double azimuth) { + m_azimuth = azimuth; + NormalizeAngles (); } +void +Angles::SetInclination (double inclination) +{ + m_inclination = inclination; + NormalizeAngles (); +} + + +double +Angles::GetAzimuth (void) const +{ + return m_azimuth; +} + + +double +Angles::GetInclination (void) const +{ + return m_inclination; +} + + +void +Angles::NormalizeAngles (void) +{ + CheckIfValid (); + + // Normalize azimuth angle + if (std::isnan (m_azimuth)) + { + return; + } + + m_azimuth = WrapToPi (m_azimuth); +} + + +void +Angles::CheckIfValid (void) const +{ + if (std::isfinite (m_inclination) || std::isfinite (m_azimuth)) + { + NS_ASSERT_MSG (0.0 <= m_inclination && m_inclination <= M_PI, + "m_inclination=" << m_inclination << " not valid, should be in [0, pi] rad"); + } + else + { + // infinite or nan inclination or azimuth angle + NS_LOG_WARN ("Undefined angle: " << *this); + } + +} + } diff --git a/src/antenna/model/angles.h b/src/antenna/model/angles.h index 712102527..e4c5da8d0 100644 --- a/src/antenna/model/angles.h +++ b/src/antenna/model/angles.h @@ -23,6 +23,7 @@ #include +#include namespace ns3 { @@ -31,63 +32,107 @@ namespace ns3 { * \brief converts degrees to radians * * \param degrees the angle in degrees - * * \return the angle in radians */ double DegreesToRadians (double degrees); +/** + * \brief converts degrees to radians + * + * \param degrees the angles in degrees + * \return the angles in radians + */ +std::vector DegreesToRadians (const std::vector °rees); + /** * \brief converts radians to degrees * * \param radians the angle in radians - * * \return the angle in degrees */ double RadiansToDegrees (double radians); /** + * \brief converts radians to degrees * - * struct holding the azimuth and inclination angles of spherical - * coordinates. The notation is the one used in "Antenna Theory - Analysis - * and Design", C.A. Balanis, Wiley, 2nd Ed., section 2.2 "Radiation - * pattern". - * This notation corresponds to the standard spherical coordinates, with phi + * \param radians the angles in radians + * \return the angles in degrees + */ +std::vector RadiansToDegrees (const std::vector &radians); + +/** + * \brief Wrap angle in [0, 360) + * + * \param a the angle in degrees + * \return the wrapped angle in degrees + */ +double WrapTo360 (double a); + +/** + * \brief Wrap angle in [-180, 180) + * + * \param a the angle in degrees + * \return the wrapped angle in degrees + */ +double WrapTo180 (double a); + +/** + * \brief Wrap angle in [0, 2*M_PI) + * + * \param a the angle in radians + * \return the wrapped angle in radians + */ +double WrapTo2Pi (double a); + +/** + * \brief Wrap angle in [-M_PI, M_PI) + * + * \param a the angle in radians + * \return the wrapped angle in radians + */ +double WrapToPi (double a); + +/** + * + * Class holding the azimuth and inclination angles of spherical coordinates. + * The notation is the one used in "Antenna Theory - Analysis + * and Design", C.A. Balanis, Wiley, 2nd Ed., section 2.2 "Radiation pattern". + * This notation corresponds to the standard spherical coordinates, with azimuth * measured counterclockwise in the x-y plane off the x-axis, and - * theta measured off the z-axis. + * inclination measured off the z-axis. + * Azimuth is consistently normalized to be in [-M_PI, M_PI). * * ^ * z | - * |_ theta + * |_ inclination * | \ * | /| * |/ | y * +--------> * / \| * /___/ - * x / phi + * x / azimuth * |/ * */ -struct Angles +class Angles { +public: /** - * default constructor, will initialize phi and theta to zero + * This constructor allows to specify azimuth and inclination. + * Inclination must be in [0, M_PI], while azimuth is + * automatically notmalized in [-M_PI, M_PI) * + * \param azimuth the azimuth angle in radians + * \param inclination the inclination angle in radians */ - Angles (); + Angles (double azimuth, double inclination); /** - * this constructor allows to specify phi and theta - * - * \param phi the azimuth angle in radians - * \param theta the inclination angle in radians - * - */ - Angles (double phi, double theta); - - /** - * this constructor will initialize phi and theta by converting the + * This constructor will initialize azimuth and inclination by converting the * given 3D vector from cartesian coordinates to spherical coordinates + * Note: azimuth and inclination angles for a zero-length vector are not defined + * and are thus initialized to NAN * * \param v the 3D vector in cartesian coordinates * @@ -95,7 +140,7 @@ struct Angles Angles (Vector v); /** - * this constructor initializes an Angles instance with the angles + * This constructor initializes an Angles instance with the angles * of the spherical coordinates of point v respect to point o * * \param v the point (in cartesian coordinates) for which the angles are determined @@ -105,40 +150,69 @@ struct Angles Angles (Vector v, Vector o); /** - * the azimuth angle in radians - * + * Setter for azimuth angle + * + * \param azimuth angle in radians */ - double phi; + void SetAzimuth (double azimuth); /** - * the inclination angle in radians - * + * Setter for inclination angle + * + * \param inclination angle in radians. Must be in [0, M_PI] */ - double theta; + void SetInclination (double inclination); + + /** + * Getter for azimuth angle + * + * \return azimuth angle in radians + */ + double GetAzimuth (void) const; + + /** + * Getter for inclination angle + * + * \return inclination angle in radians + */ + double GetInclination (void) const; + + // friend methods + friend std::ostream& operator<< (std::ostream& os, const Angles& a); + friend std::istream& operator>> (std::istream& is, Angles& a); + + static bool m_printDeg; //!< flag for printing in radians or degrees units + +private: + /** + * Default constructor is disabled + */ + Angles (); + + /** + * Normalize the angle azimuth angle range between in [-M_PI, M_PI) + * while checking if the angle is valid, i.e., finite and within + * the bounds. + * + * Note: while an arbitrary value for the azimuth angle is valid + * and can be wrapped in [-M_PI, M_PI), an inclination angle outside + * the [0, M_PI] range can be ambiguos and is thus not valid. + */ + void NormalizeAngles (void); + + /** + * Check if Angle is valid or not + * Warns the user if the Angle is undefined (non-finite azimuth or inclination), + * throws an assert if the inclination angle is invalid (not in [0, M_PI]) + */ + void CheckIfValid (void) const; + + + double m_azimuth; //!< the azimuth angle in radians + double m_inclination; //!< the inclination angle in radians }; - -/** - * print a struct Angles to output - * - * \param os the output stream - * \param a the Angles struct - * - * \return a reference to the output stream - */ -std::ostream& operator<< ( std::ostream& os, const Angles& a); - -/** - * initialize a struct Angles from input - * - * \param is the input stream - * \param a the Angles struct - * - * \return a reference to the input stream - */ -std::istream &operator >> (std::istream &is, Angles &a); - } // namespace ns3 #endif // ANGLES_H diff --git a/src/antenna/model/cosine-antenna-model.cc b/src/antenna/model/cosine-antenna-model.cc index b7becaca1..0836ee986 100644 --- a/src/antenna/model/cosine-antenna-model.cc +++ b/src/antenna/model/cosine-antenna-model.cc @@ -34,19 +34,25 @@ NS_LOG_COMPONENT_DEFINE ("CosineAntennaModel"); NS_OBJECT_ENSURE_REGISTERED (CosineAntennaModel); -TypeId +TypeId CosineAntennaModel::GetTypeId () { static TypeId tid = TypeId ("ns3::CosineAntennaModel") .SetParent () - .SetGroupName("Antenna") + .SetGroupName ("Antenna") .AddConstructor () - .AddAttribute ("Beamwidth", - "The 3dB beamwidth (degrees)", - DoubleValue (60), - MakeDoubleAccessor (&CosineAntennaModel::SetBeamwidth, - &CosineAntennaModel::GetBeamwidth), - MakeDoubleChecker (0, 180)) + .AddAttribute ("VerticalBeamwidth", + "The 3 dB vertical beamwidth (degrees). A beamwidth of 360 deg corresponds to constant gain", + DoubleValue (360), + MakeDoubleAccessor (&CosineAntennaModel::SetVerticalBeamwidth, + &CosineAntennaModel::GetVerticalBeamwidth), + MakeDoubleChecker (0, 360)) + .AddAttribute ("HorizontalBeamwidth", + "The 3 dB horizontal beamwidth (degrees). A beamwidth of 360 deg corresponds to constant gain", + DoubleValue (120), + MakeDoubleAccessor (&CosineAntennaModel::SetHorizontalBeamwidth, + &CosineAntennaModel::GetHorizontalBeamwidth), + MakeDoubleChecker (0, 360)) .AddAttribute ("Orientation", "The angle (degrees) that expresses the orientation of the antenna on the x-y plane relative to the x axis", DoubleValue (0.0), @@ -62,67 +68,110 @@ CosineAntennaModel::GetTypeId () return tid; } -void -CosineAntennaModel::SetBeamwidth (double beamwidthDegrees) -{ - NS_LOG_FUNCTION (this << beamwidthDegrees); - m_beamwidthRadians = DegreesToRadians (beamwidthDegrees); - m_exponent = -3.0 / (20 * std::log10 (std::cos (m_beamwidthRadians / 4.0))); - NS_LOG_LOGIC (this << " m_exponent = " << m_exponent); -} double -CosineAntennaModel::GetBeamwidth () const +CosineAntennaModel::GetExponentFromBeamwidth (double beamwidthDegrees) { - return RadiansToDegrees (m_beamwidthRadians); + NS_LOG_FUNCTION (beamwidthDegrees); + + // The formula in obtained by inverting the power pattern P(alpha) in a single direction, + // while imposing that P(alpha0/2) = 0.5 = -3 dB, with respect to the exponent + // See CosineAntennaModel::GetGainDb for more information. + // + // The undetermined case of alpha0=360 is treated separately. + double exponent; + if (beamwidthDegrees == 360.0) + { + exponent = 0.0; + } + else + { + exponent = -3.0 / (20 * std::log10 (std::cos (DegreesToRadians (beamwidthDegrees / 4.0)))); + } + + return exponent; } -void + +double +CosineAntennaModel::GetBeamwidthFromExponent (double exponent) +{ + NS_LOG_FUNCTION (exponent); + + // The formula in obtained by inverting the power pattern P(alpha) in a single direction, + // while imposing that P(alpha0/2) = 0.5 = -3 dB, with respect to the beamwidth. + // See CosineAntennaModel::GetGainDb for more information. + double beamwidthRadians = 4 * std::acos (std::pow (0.5, 1 / (2 * exponent))); + return RadiansToDegrees (beamwidthRadians); +} + + +void +CosineAntennaModel::SetVerticalBeamwidth (double verticalBeamwidthDegrees) +{ + NS_LOG_FUNCTION (this << verticalBeamwidthDegrees); + m_verticalExponent = GetExponentFromBeamwidth (verticalBeamwidthDegrees); +} + + +void +CosineAntennaModel::SetHorizontalBeamwidth (double horizontalBeamwidthDegrees) +{ + NS_LOG_FUNCTION (this << horizontalBeamwidthDegrees); + m_horizontalExponent = GetExponentFromBeamwidth (horizontalBeamwidthDegrees); +} + + +double +CosineAntennaModel::GetVerticalBeamwidth () const +{ + return GetBeamwidthFromExponent (m_verticalExponent); +} + + +double +CosineAntennaModel::GetHorizontalBeamwidth () const +{ + return GetBeamwidthFromExponent (m_horizontalExponent); +} + + +void CosineAntennaModel::SetOrientation (double orientationDegrees) { NS_LOG_FUNCTION (this << orientationDegrees); m_orientationRadians = DegreesToRadians (orientationDegrees); } + double CosineAntennaModel::GetOrientation () const { return RadiansToDegrees (m_orientationRadians); } -double + +double CosineAntennaModel::GetGainDb (Angles a) { NS_LOG_FUNCTION (this << a); - // azimuth angle w.r.t. the reference system of the antenna - double phi = a.phi - m_orientationRadians; // make sure phi is in (-pi, pi] - while (phi <= -M_PI) - { - phi += M_PI+M_PI; - } - while (phi > M_PI) - { - phi -= M_PI+M_PI; - } + a.SetAzimuth (a.GetAzimuth () - m_orientationRadians); - NS_LOG_LOGIC ("phi = " << phi ); + NS_LOG_LOGIC (a); - // element factor: amplitude gain of a single antenna element in linear units - double ef = std::pow (std::cos (phi / 2.0), m_exponent); - - // the array factor is not considered. Note that if we did consider - // the array factor, the actual beamwidth would change, and in - // particular it would be different from the one specified by the - // user. Hence it is not desirable to use the array factor, for the - // ease of use of this model. - - double gainDb = 20 * std::log10 (ef); + // The element power gain is computed as a product of cosine functions on the two axis + // The power pattern of the element is equal to: + // P(az,el) = cos(az/2)^2m * cos(pi/2 - incl/2)^2n, + // where az is the azimuth angle, and incl is the inclination angle. + double gain = (std::pow (std::cos (a.GetAzimuth () / 2), 2 * m_horizontalExponent)) * + (std::pow (std::cos ((M_PI / 2 - a.GetInclination ()) / 2), 2 * m_verticalExponent)); + double gainDb = 10 * std::log10 (gain); + NS_LOG_LOGIC ("gain = " << gainDb << " + " << m_maxGain << " dB"); return gainDb + m_maxGain; } } - diff --git a/src/antenna/model/cosine-antenna-model.h b/src/antenna/model/cosine-antenna-model.h index ffca5f1a1..9b855561b 100644 --- a/src/antenna/model/cosine-antenna-model.h +++ b/src/antenna/model/cosine-antenna-model.h @@ -28,48 +28,89 @@ namespace ns3 { /** - * - * \brief Cosine Antenna Model * - * This class implements the cosine model as described in: + * \brief Cosine Antenna Model * - * Li Chunjian, "Efficient Antenna Patterns for Three-Sector WCDMA Systems" + * This class implements the cosine model, similarly to what is described in: + * Cosine Antenna Element, Mathworks, Phased Array System Toolbox (Sep. 2020) + * Available online: https://www.mathworks.com/help/phased/ug/cosine-antenna-element.html * - * Note that only the element factor of the above model is - * considered. Also, an additional constant gain is added to model the - * radiation pattern on the vertical plane (to account for the fact - * that the elevation angle is not included in the model). + * The power pattern of the element is equal to: + // P(az,el) = cos(az/2)^2m * cos(pi/2 - incl/2)^2n, + // where az is the azimuth angle, and incl is the inclination angle. + * + * Differently from the source, the response is defined for azimuth and elevation angles + * between –180 and 180 degrees and is always positive. + * There is no response at the backside of a cosine antenna. + * The cosine response pattern achieves a maximum value of 1 (0 dB) at 0 degrees azimuth + * and 90 degrees inclination. + * An extra settable gain is added to the original model, to improve its generality. */ class CosineAntennaModel : public AntennaModel { public: - // inherited from Object static TypeId GetTypeId (); // inherited from AntennaModel virtual double GetGainDb (Angles a); + /** + * Get the vertical 3 dB beamwidth of the cosine antenna model. + * \return the vertical beamwidth in degrees + */ + double GetVerticalBeamwidth (void) const; - // attribute getters/setters - void SetBeamwidth (double beamwidthDegrees); - double GetBeamwidth () const; - void SetOrientation (double orientationDegrees); - double GetOrientation () const; + /** + * Get the horizontal 3 dB beamwidth of the cosine antenna model. + * \return the horizontal beamwidth in degrees + */ + double GetHorizontalBeamwidth (void) const; + + /** + * Get the horizontal orientation of the antenna element. + * \return the horizontal orientation in degrees + */ + double GetOrientation (void) const; private: /** - * this is the variable "n" in the paper by Chunjian - * + * Set the vertical 3 dB beamwidth (bilateral) of the cosine antenna model. + * \param verticalBeamwidthDegrees the vertical beamwidth in degrees */ - double m_exponent; + void SetVerticalBeamwidth (double verticalBeamwidthDegrees); - double m_beamwidthRadians; + /** + * Set the horizontal 3 dB beamwidth (bilateral) of the cosine antenna model. + * \param horizontalBeamwidthDegrees the horizontal beamwidth in degrees + */ + void SetHorizontalBeamwidth (double horizontalBeamwidthDegrees); - double m_orientationRadians; + /** + * Set the horizontal orientation of the antenna element. + * \param orientationDegrees the horizontal orientation in degrees + */ + void SetOrientation (double orientationDegrees); - double m_maxGain; + /** + * Compute the exponent of the cosine antenna model from the beamwidth + * \param beamwidthRadians the beamwidth in degrees + * \return the exponent + */ + static double GetExponentFromBeamwidth (double beamwidthDegrees); + + /** + * Compute the beamwidth of the cosine antenna model from the exponent + * \param exponent the exponent + * \return beamwidth in degrees + */ + static double GetBeamwidthFromExponent (double exponent); + + double m_verticalExponent; //!< exponent of the vertical direction + double m_horizontalExponent; //!< exponent of the horizontal direction + double m_orientationRadians; //!< orientation in radians in the horizontal direction (bearing) + double m_maxGain; //!< antenna gain in dB towards the main orientation }; diff --git a/src/antenna/model/parabolic-antenna-model.cc b/src/antenna/model/parabolic-antenna-model.cc index c1c584b95..b7bc2dc96 100644 --- a/src/antenna/model/parabolic-antenna-model.cc +++ b/src/antenna/model/parabolic-antenna-model.cc @@ -93,7 +93,7 @@ ParabolicAntennaModel::GetGainDb (Angles a) { NS_LOG_FUNCTION (this << a); // azimuth angle w.r.t. the reference system of the antenna - double phi = a.phi - m_orientationRadians; + double phi = a.GetAzimuth () - m_orientationRadians; // make sure phi is in (-pi, pi] while (phi <= -M_PI) diff --git a/src/antenna/model/phased-array-model.cc b/src/antenna/model/phased-array-model.cc new file mode 100644 index 000000000..d6ad35dd9 --- /dev/null +++ b/src/antenna/model/phased-array-model.cc @@ -0,0 +1,169 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "phased-array-model.h" +#include +#include +#include +#include +#include +#include + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("PhasedArrayModel"); + +NS_OBJECT_ENSURE_REGISTERED (PhasedArrayModel); + +std::ostream& +operator<< (std::ostream& os, const PhasedArrayModel::ComplexVector& cv) +{ + size_t N = cv.size (); + + // 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} +{} + + +PhasedArrayModel::~PhasedArrayModel () +{ + m_beamformingVector.clear (); +} + + +TypeId +PhasedArrayModel::GetTypeId () +{ + static TypeId tid = TypeId ("ns3::PhasedArrayModel") + .SetParent () + .SetGroupName ("Antenna") + .AddAttribute ("AntennaElement", + "A pointer to the antenna element used by the phased array", + PointerValue (CreateObject ()), + MakePointerAccessor (&PhasedArrayModel::m_antennaElement), + MakePointerChecker ()) + ; + return tid; +} + + +void +PhasedArrayModel::SetBeamformingVector (const ComplexVector &beamformingVector) +{ + NS_LOG_FUNCTION (this << beamformingVector); + NS_ASSERT_MSG (beamformingVector.size () == GetNumberOfElements (), + beamformingVector.size () << " != " << GetNumberOfElements ()); + m_beamformingVector = beamformingVector; + m_isBfVectorValid = true; +} + + +PhasedArrayModel::ComplexVector +PhasedArrayModel::GetBeamformingVector () 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; +} + + +double +PhasedArrayModel::ComputeNorm (const ComplexVector &vector) +{ + double norm = 0; + + for (uint64_t i = 0; i < vector.size (); i++) + { + norm += std::norm (vector[i]); + } + + return std::sqrt (norm); + +} + + +PhasedArrayModel::ComplexVector +PhasedArrayModel::GetBeamformingVector (Angles a) const +{ + NS_LOG_FUNCTION (this << a); + + ComplexVector beamformingVector = GetSteeringVector (a); + double norm = ComputeNorm (beamformingVector); + + for (uint64_t i = 0; i < beamformingVector.size (); i++) + { + beamformingVector[i] = std::conj (beamformingVector[i]) / norm; + } + + return beamformingVector; +} + + + +PhasedArrayModel::ComplexVector +PhasedArrayModel::GetSteeringVector (Angles a) const +{ + ComplexVector steeringVector; + steeringVector.resize (GetNumberOfElements ()); + for (uint64_t i = 0; i < GetNumberOfElements (); i++) + { + Vector loc = GetElementLocation (i); + double phase = -2 * M_PI * (sin (a.GetInclination ()) * cos (a.GetAzimuth ()) * loc.x + + sin (a.GetInclination ()) * sin (a.GetAzimuth ()) * loc.y + + cos (a.GetInclination ()) * loc.z); + steeringVector[i] = std::polar (1.0, phase); + } + return steeringVector; +} + + +void +PhasedArrayModel::SetAntennaElement (Ptr antennaElement) +{ + NS_LOG_FUNCTION (this); + m_antennaElement = antennaElement; +} + + +Ptr +PhasedArrayModel::GetAntennaElement () const +{ + NS_LOG_FUNCTION (this); + return m_antennaElement; +} + + +} /* namespace ns3 */ + diff --git a/src/antenna/model/phased-array-model.h b/src/antenna/model/phased-array-model.h new file mode 100644 index 000000000..f658894d4 --- /dev/null +++ b/src/antenna/model/phased-array-model.h @@ -0,0 +1,145 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PHASED_ARRAY_MODEL_H +#define PHASED_ARRAY_MODEL_H + +#include +#include +#include +#include + +namespace ns3 { + + +/** + * \ingroup antenna + * + * \brief Class implementing the phased array model virtual base class. + */ +class PhasedArrayModel : public Object +{ +public: + /** + * Constructor + */ + PhasedArrayModel (void); + + + /** + * Destructor + */ + virtual ~PhasedArrayModel (void); + + + // inherited from Object + static TypeId GetTypeId (void); + + + typedef std::vector > ComplexVector; //!< type definition for complex vectors + + /** + * Returns the horizontal and vertical components of the antenna element field + * pattern at the specified direction. Only vertical 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 GetElementFieldPattern (Angles a) const = 0; + + + /** + * Returns the location of the antenna element with the specified + * index, normalized with respect to the wavelength. + * \param idx index of the antenna element + * \return the 3D vector that represents the position of the element + */ + virtual Vector GetElementLocation (uint64_t index) const = 0; + + + /** + * Returns the number of antenna elements + * \return the number of antenna elements + */ + virtual uint64_t GetNumberOfElements (void) const = 0; + + + /** + * Sets the beamforming vector to be used + * \param beamformingVector the beamforming vector + */ + void SetBeamformingVector (const ComplexVector &beamformingVector); + + + /** + * Returns the beamforming vector that is currently being used + * \return the current beamforming vector + */ + ComplexVector GetBeamformingVector (void) const; + + + /** + * Returns the beamforming vector that points towards the specified position + * \param a the beamforming angle + * \return the beamforming vector + */ + ComplexVector GetBeamformingVector (Angles a) const; + + + /** + * Returns the steering vector that points toward the specified position + * \param a the steering angle + * \return the steering vector + */ + ComplexVector GetSteeringVector (Angles a) const; + + + /** + * Sets the antenna model to be used + * \param antennaElement the antenna model + */ + void SetAntennaElement (Ptr antennaElement); + + + /** + * Returns a pointer to the AntennaModel instance used to model the elements of the array + * \return pointer to the AntennaModel instance + */ + Ptr GetAntennaElement (void) const; + +protected: + /** + * Utility method to compute the euclidean norm of a ComplexVector + * \param vector the ComplexVector + * \return the euclidean norm + */ + static double ComputeNorm (const ComplexVector &vector); + + 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 + +}; + + +std::ostream& operator<< (std::ostream& os, const PhasedArrayModel::ComplexVector& cv); + +} /* namespace ns3 */ + +#endif /* PHASED_ARRAY_MODEL_H */ diff --git a/src/antenna/model/three-gpp-antenna-array-model.cc b/src/antenna/model/three-gpp-antenna-array-model.cc deleted file mode 100644 index 30f38ec16..000000000 --- a/src/antenna/model/three-gpp-antenna-array-model.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -/* -* Copyright (c) 2019 SIGNET Lab, Department of Information Engineering, -* University of Padova -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation; -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -*/ - -#include "three-gpp-antenna-array-model.h" -#include "ns3/log.h" -#include "ns3/double.h" -#include "ns3/uinteger.h" -#include "ns3/boolean.h" - -namespace ns3 { - -NS_LOG_COMPONENT_DEFINE ("ThreeGppAntennaArrayModel"); - -NS_OBJECT_ENSURE_REGISTERED (ThreeGppAntennaArrayModel); - -ThreeGppAntennaArrayModel::ThreeGppAntennaArrayModel (void) -{ - NS_LOG_FUNCTION (this); - m_isOmniTx = false; -} - -ThreeGppAntennaArrayModel::~ThreeGppAntennaArrayModel (void) -{ - NS_LOG_FUNCTION (this); -} - -TypeId -ThreeGppAntennaArrayModel::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::ThreeGppAntennaArrayModel") - .SetParent () - .AddConstructor () - .AddAttribute ("AntennaHorizontalSpacing", - "Horizontal spacing between antenna elements, in multiples of wave length", - DoubleValue (0.5), - MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disH), - MakeDoubleChecker ()) - .AddAttribute ("AntennaVerticalSpacing", - "Vertical spacing between antenna elements, in multiples of wave length", - DoubleValue (0.5), - MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disV), - MakeDoubleChecker ()) - .AddAttribute ("NumColumns", - "Horizontal size of the array", - UintegerValue (4), - MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numColumns), - MakeUintegerChecker ()) - .AddAttribute ("NumRows", - "Vertical size of the array", - UintegerValue (4), - MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numRows), - MakeUintegerChecker ()) - .AddAttribute ("BearingAngle", - "The bearing angle in radians", - DoubleValue (0.0), - MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_alpha), - MakeDoubleChecker (-M_PI, M_PI)) - .AddAttribute ("DowntiltAngle", - "The downtilt angle in radians", - DoubleValue (0.0), - MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_beta), - MakeDoubleChecker (0, M_PI)) - .AddAttribute ("ElementGain", - "Directional gain of an antenna element in dBi", - DoubleValue (4.97), - MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_gE), - MakeDoubleChecker (0, 8)) - .AddAttribute ("IsotropicElements", - "If true, use an isotropic radiation pattern (for testing purposes)", - BooleanValue (false), - MakeBooleanAccessor (&ThreeGppAntennaArrayModel::m_isIsotropic), - MakeBooleanChecker ()) - ; - return tid; -} - -bool -ThreeGppAntennaArrayModel::IsOmniTx (void) const -{ - NS_LOG_FUNCTION (this); - return m_isOmniTx; -} - -void -ThreeGppAntennaArrayModel::ChangeToOmniTx (void) -{ - NS_LOG_FUNCTION (this); - m_isOmniTx = true; -} - -void -ThreeGppAntennaArrayModel::SetBeamformingVector (const ComplexVector &beamformingVector) -{ - NS_LOG_FUNCTION (this); - m_isOmniTx = false; - m_beamformingVector = beamformingVector; -} - -const ThreeGppAntennaArrayModel::ComplexVector & -ThreeGppAntennaArrayModel::GetBeamformingVector(void) const -{ - NS_LOG_FUNCTION (this); - return m_beamformingVector; -} - -std::pair -ThreeGppAntennaArrayModel::GetElementFieldPattern (Angles a) const -{ - NS_LOG_FUNCTION (this); - - // normalize phi (if needed) - a.phi = fmod (a.phi + M_PI, 2 * M_PI); - if (a.phi < 0) - a.phi += M_PI; - else - a.phi -= M_PI; - - NS_ASSERT_MSG (a.theta >= 0 && a.theta <= M_PI, "The vertical angle should be between 0 and M_PI"); - NS_ASSERT_MSG (a.phi >= -M_PI && a.phi <= M_PI, "The horizontal angle should be between -M_PI and M_PI"); - - // 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 - double thetaPrime = std::acos (cos (m_beta)*cos (a.theta) + sin (m_beta)*cos (a.phi-m_alpha)*sin (a.theta)); - double phiPrime = std::arg (std::complex (cos (m_beta)*sin (a.theta)*cos (a.phi-m_alpha) - sin (m_beta)*cos (a.theta), sin (a.phi-m_alpha)*sin (a.theta))); - NS_LOG_DEBUG (a.theta << " " << thetaPrime << " " << a.phi << " " << phiPrime); - - double aPrimeDb = GetRadiationPattern (thetaPrime, phiPrime); - double aPrime = pow (10, aPrimeDb / 10); // convert to linear - - // compute psi using eq. 7.1-15 in 3GPP TR 38.901, assuming that the slant - // angle (gamma) is 0 - double psi = std::arg (std::complex (cos (m_beta) * sin (a.theta) - sin (m_beta) * cos (a.theta)* cos (a.phi - m_alpha), sin (m_beta)* sin (a.phi-m_alpha))); - NS_LOG_DEBUG ("psi " << psi); - - // compute the antenna element field pattern in the vertical polarization using - // eq. 7.3-4 in 3GPP TR 38.901 - // NOTE we assume vertical polarization, hence the field pattern in the - // horizontal polarization is 0 - double fieldThetaPrime = std::sqrt (aPrime); - - // convert the antenna element field pattern to GCS using eq. 7.1-11 - // in 3GPP TR 38.901 - double fieldTheta = cos (psi) * fieldThetaPrime; - double fieldPhi = sin (psi) * fieldThetaPrime; - NS_LOG_DEBUG (a.phi/M_PI*180 << " " << a.theta/M_PI*180 << " " << fieldTheta*fieldTheta + fieldPhi*fieldPhi); - - return std::make_pair (fieldPhi, fieldTheta); -} - -double -ThreeGppAntennaArrayModel::GetRadiationPattern (double thetaRadian, double phiRadian) const -{ - if (m_isIsotropic) - { - return 0; - } - - // convert the angles in degrees - double thetaDeg = thetaRadian * 180 / M_PI; - double phiDeg = phiRadian * 180 / M_PI; - NS_ASSERT_MSG (thetaDeg >= 0 && thetaDeg <= 180, "the vertical angle should be the range of [0,180]"); - NS_ASSERT_MSG (phiDeg >= -180 && phiDeg <= 180, "the horizontal angle should be the range of [-180,180]"); - - // compute the radiation power pattern using equations in table 7.3-1 in - // 3GPP TR 38.901 - double A_M = 30; // front-back ratio expressed in dB - double SLA = 30; // side-lobe level limit expressed in dB - - double A_v = -1 * std::min (SLA,12 * pow ((thetaDeg - 90) / 65,2)); // vertical cut of the radiation power pattern (dB) - double A_h = -1 * std::min (A_M,12 * pow (phiDeg / 65,2)); // horizontal cut of the radiation power pattern (dB) - - double A = m_gE - 1 * std::min (A_M,- A_v - A_h); // 3D radiation power pattern (dB) - - return A; // 3D radiation power pattern in dB -} - -Vector -ThreeGppAntennaArrayModel::GetElementLocation (uint64_t index) const -{ - NS_LOG_FUNCTION (this); - - // 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); - - // convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP - // TR 38.901 - Vector loc; - loc.x = cos(m_alpha)*cos (m_beta)*xPrime - sin (m_alpha)*yPrime + cos (m_alpha)*sin (m_beta)*zPrime; - loc.y = sin (m_alpha)*cos(m_beta)*xPrime + cos (m_alpha)*yPrime + sin (m_alpha)*sin (m_beta)*zPrime; - loc.z = -sin (m_beta)*xPrime+cos(m_beta)*zPrime; - return loc; -} - -uint64_t -ThreeGppAntennaArrayModel::GetNumberOfElements (void) const -{ - NS_LOG_FUNCTION (this); - return m_numRows * m_numColumns; -} - -} /* namespace ns3 */ diff --git a/src/antenna/model/three-gpp-antenna-array-model.h b/src/antenna/model/three-gpp-antenna-array-model.h deleted file mode 100644 index cec7d7e8e..000000000 --- a/src/antenna/model/three-gpp-antenna-array-model.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -/* -* Copyright (c) 2019 SIGNET Lab, Department of Information Engineering, -* University of Padova -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation; -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -*/ - -#ifndef THREE_GPP_ANTENNA_ARRAY_MODEL_H_ -#define THREE_GPP_ANTENNA_ARRAY_MODEL_H_ - -#include -#include - -namespace ns3 { - -/** - * \ingroup antenna - * - * \brief Class implementing the antenna model defined in 3GPP TR 38.901 V15.0.0 - * - * \note the current implementation supports the modeling of antenna arrays - * composed of a single panel and with single (vertical) polarization. - */ -class ThreeGppAntennaArrayModel : public Object -{ -public: - - /** - * Constructor - */ - ThreeGppAntennaArrayModel (void); - - /** - * Destructor - */ - virtual ~ThreeGppAntennaArrayModel (void); - - // inherited from Object - static TypeId GetTypeId (void); - - typedef std::vector > ComplexVector; //!< type definition for complex vectors - - /** - * Returns the horizontal and vertical components of the antenna element field - * pattern at the specified direction. Only vertical 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 - */ - std::pair GetElementFieldPattern (Angles a) const; - - /** - * Returns the location of the antenna element with the specified - * index assuming the left bottom corner is (0,0,0), normalized - * with respect to the wavelength. - * Antenna elements are scanned row by row, left to right and bottom to top. - * For example, an antenna with 2 rows and 3 columns will be ordered as follows: - * ^ z - * | 3 4 5 - * | 0 1 2 - * ----------> y - * - * \param index index of the antenna element - * \return the 3D vector that represents the position of the element - */ - virtual Vector GetElementLocation (uint64_t index) const; - - /** - * Returns the number of antenna elements - * \return the number of antenna elements - */ - virtual uint64_t GetNumberOfElements (void) const; - - /** - * Returns true if the antenna is configured for omnidirectional transmissions - * \return whether the transmission is set to omni - */ - bool IsOmniTx (void) const; - - /** - * Change the antenna model to omnidirectional (ignoring the beams) - */ - void ChangeToOmniTx (void); - - /** - * Sets the beamforming vector to be used - * \param beamformingVector the beamforming vector - */ - void SetBeamformingVector (const ComplexVector &beamformingVector); - - /** - * Returns the beamforming vector that is currently being used - * \return the current beamforming vector - */ - const ComplexVector & GetBeamformingVector (void) const; - -private: - /** - * Returns the radiation power pattern of a single antenna element in dB, - * generated according to Table 7.3-1 in 3GPP TR 38.901 - * \param vAngleRadian the vertical angle in radians - * \param hAngleRadian the horizontal angle in radians - * \return the radiation power pattern in dB - */ - double GetRadiationPattern (double vAngleRadian, double hAngleRadian) const; - - bool m_isOmniTx; //!< true if the antenna is configured for omni transmissions - ComplexVector m_beamformingVector; //!< the beamforming vector in use - uint32_t m_numColumns; //!< number of columns - uint32_t m_numRows; //!< number of rows - double m_disV; //!< antenna spacing in the vertical direction in multiples of wave length - double m_disH; //!< antenna spacing in the horizontal direction in multiples of wave length - double m_alpha; //!< the bearing angle in radians - double m_beta; //!< the downtilt angle in radians - double m_gE; //!< directional gain of a single antenna element (dBi) - bool m_isIsotropic; //!< if true, antenna elements are isotropic -}; - -} /* namespace ns3 */ - -#endif /* SRC_THREE_GPP_ANTENNA_ARRAY_MODEL_H_ */ diff --git a/src/antenna/model/three-gpp-antenna-model.cc b/src/antenna/model/three-gpp-antenna-model.cc new file mode 100644 index 000000000..407a08b36 --- /dev/null +++ b/src/antenna/model/three-gpp-antenna-model.cc @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include "antenna-model.h" +#include "three-gpp-antenna-model.h" + + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ThreeGppAntennaModel"); + +NS_OBJECT_ENSURE_REGISTERED (ThreeGppAntennaModel); + + +TypeId +ThreeGppAntennaModel::GetTypeId () +{ + static TypeId tid = TypeId ("ns3::ThreeGppAntennaModel") + .SetParent () + .SetGroupName ("Antenna") + .AddConstructor () + ; + return tid; +} + +ThreeGppAntennaModel::ThreeGppAntennaModel (void) + : m_verticalBeamwidthDegrees {65}, + m_horizontalBeamwidthDegrees {65}, + m_aMax {30}, + m_slaV {30}, + m_geMax {8.0} +{} + + +ThreeGppAntennaModel::~ThreeGppAntennaModel (void) +{} + + +double +ThreeGppAntennaModel::GetVerticalBeamwidth () const +{ + return m_verticalBeamwidthDegrees; +} + + +double +ThreeGppAntennaModel::GetHorizontalBeamwidth () const +{ + return m_horizontalBeamwidthDegrees; +} + + +double +ThreeGppAntennaModel::GetSlaV () const +{ + return m_slaV; +} + + +double +ThreeGppAntennaModel::GetMaxAttenuation () const +{ + return m_aMax; +} + + +double +ThreeGppAntennaModel::GetAntennaElementGain () const +{ + return m_geMax; +} + + +double +ThreeGppAntennaModel::GetGainDb (Angles a) +{ + NS_LOG_FUNCTION (this << a); + + double phiDeg = RadiansToDegrees (a.GetAzimuth ()); + double thetaDeg = RadiansToDegrees (a.GetInclination ()); + + NS_ASSERT_MSG (-180.0 <= phiDeg && phiDeg <= 180.0, "Out of boundaries: phiDeg=" << phiDeg); + NS_ASSERT_MSG (0.0 <= thetaDeg && thetaDeg <= 180.0, "Out of boundaries: thetaDeg=" << thetaDeg); + + // compute the radiation power pattern using equations in table 7.3-1 in + // 3GPP TR 38.901 + double vertGain = -std::min (m_slaV, 12 * pow ((thetaDeg - 90) / m_verticalBeamwidthDegrees, 2)); // vertical cut of the radiation power pattern (dB) + double horizGain = -std::min (m_aMax, 12 * pow (phiDeg / m_horizontalBeamwidthDegrees, 2)); // horizontal cut of the radiation power pattern (dB) + + double gainDb = m_geMax - std::min (m_aMax, -(vertGain + horizGain)); // 3D radiation power pattern (dB) + + NS_LOG_DEBUG ("gain=" << gainDb << " dB"); + return gainDb; + +} + + +} + diff --git a/src/antenna/model/three-gpp-antenna-model.h b/src/antenna/model/three-gpp-antenna-model.h new file mode 100644 index 000000000..dfb602190 --- /dev/null +++ b/src/antenna/model/three-gpp-antenna-model.h @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef THREE_GPP_ANTENNA_MODEL_H +#define THREE_GPP_ANTENNA_MODEL_H + + +#include +#include + +namespace ns3 { + +/** + * + * \brief Antenna model based on a parabolic approximation of the main lobe radiation pattern. + * + * This class implements the parabolic model as described in 3GPP TR 38.901 v15.0.0 + * + */ +class ThreeGppAntennaModel : public AntennaModel +{ +public: + ThreeGppAntennaModel (void); + virtual ~ThreeGppAntennaModel (void) override; + + // inherited from Object + static TypeId GetTypeId (); + + // inherited from AntennaModel + virtual double GetGainDb (Angles a) override; + + /** + * Get the vertical beamwidth of the antenna element. + * \return the vertical beamwidth in degrees + */ + double GetVerticalBeamwidth () const; + + /** + * Get the horizontal beamwidth of the antenna element. + * \return the horizontal beamwidth in degrees + */ + double GetHorizontalBeamwidth () const; + + /** + * Get the side-lobe attenuation in the vertical direction of the antenna element. + * \return side-lobe attenuation in the vertical direction in dB + */ + double GetSlaV () const; + + /** + * Get the naximum attenuation of the antenna element. + * \return the naximum attenuation in dB + */ + double GetMaxAttenuation () const; + + /** + * Get the maximum directional gain of the antenna element. + * \return the maximum directional gain in dBi + */ + double GetAntennaElementGain () const; + +private: + double m_verticalBeamwidthDegrees; //!< beamwidth in the vertical direction (\theta_{3dB}) [deg] + double m_horizontalBeamwidthDegrees; //!< beamwidth in the horizontal direction (\phi_{3dB}) [deg] + double m_aMax; //!< maximum attenuation (A_{max}) [dB] + double m_slaV; //!< side-lobe attenuation in the vertical direction (SLA_V) [dB] + double m_geMax; //!< maximum directional gain of the antenna element (G_{E,max}) [dBi] +}; + + + +} // namespace ns3 + + +#endif // THREE_GPP_ANTENNA_MODEL_H diff --git a/src/antenna/model/uniform-planar-array.cc b/src/antenna/model/uniform-planar-array.cc new file mode 100644 index 000000000..b57467baa --- /dev/null +++ b/src/antenna/model/uniform-planar-array.cc @@ -0,0 +1,233 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "uniform-planar-array.h" +#include +#include +#include +#include + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("UniformPlanarArray"); + +NS_OBJECT_ENSURE_REGISTERED (UniformPlanarArray); + + + +UniformPlanarArray::UniformPlanarArray () + : PhasedArrayModel (), + m_numColumns {1}, + m_numRows {1}, + m_disV {0.5}, + m_disH {0.5}, + m_alpha {0}, + m_beta {0} +{} + +UniformPlanarArray::~UniformPlanarArray () +{} + +TypeId +UniformPlanarArray::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::UniformPlanarArray") + .SetParent () + .AddConstructor () + .SetGroupName ("Antenna") + .AddAttribute ("AntennaHorizontalSpacing", + "Horizontal spacing between antenna elements, in multiples of wave length", + DoubleValue (0.5), + MakeDoubleAccessor (&UniformPlanarArray::SetAntennaHorizontalSpacing, + &UniformPlanarArray::GetAntennaHorizontalSpacing), + MakeDoubleChecker (0.0)) + .AddAttribute ("AntennaVerticalSpacing", + "Vertical spacing between antenna elements, in multiples of wave length", + DoubleValue (0.5), + MakeDoubleAccessor (&UniformPlanarArray::SetAntennaVerticalSpacing, + &UniformPlanarArray::GetAntennaVerticalSpacing), + MakeDoubleChecker (0.0)) + .AddAttribute ("NumColumns", + "Horizontal size of the array", + UintegerValue (4), + MakeUintegerAccessor (&UniformPlanarArray::SetNumColumns, + &UniformPlanarArray::GetNumColumns), + MakeUintegerChecker (1)) + .AddAttribute ("NumRows", + "Vertical size of the array", + UintegerValue (4), + MakeUintegerAccessor (&UniformPlanarArray::SetNumRows, + &UniformPlanarArray::GetNumRows), + MakeUintegerChecker (1)) + .AddAttribute ("BearingAngle", + "The bearing angle in radians", + DoubleValue (0.0), + MakeDoubleAccessor (&UniformPlanarArray::m_alpha), + MakeDoubleChecker (-M_PI, M_PI)) + .AddAttribute ("DowntiltAngle", + "The downtilt angle in radians", + DoubleValue (0.0), + MakeDoubleAccessor (&UniformPlanarArray::m_beta), + MakeDoubleChecker (-M_PI, M_PI)) + ; + return tid; +} + + +void +UniformPlanarArray::SetNumColumns (uint32_t n) +{ + NS_LOG_FUNCTION (this << n); + if (n != m_numColumns) + { + m_isBfVectorValid = false; + } + m_numColumns = n; +} + + +uint32_t +UniformPlanarArray::GetNumColumns (void) const +{ + return m_numColumns; +} + + +void +UniformPlanarArray::SetNumRows (uint32_t n) +{ + NS_LOG_FUNCTION (this << n); + if (n != m_numRows) + { + m_isBfVectorValid = false; + } + m_numRows = n; +} + + +uint32_t +UniformPlanarArray::GetNumRows (void) const +{ + return m_numRows; +} + + +void +UniformPlanarArray::SetAntennaHorizontalSpacing (double s) +{ + NS_LOG_FUNCTION (this << s); + NS_ABORT_MSG_IF (s <= 0, "Trying to set an invalid spacing: " << s); + + if (s != m_disH) + { + m_isBfVectorValid = false; + } + m_disH = s; +} + + +double +UniformPlanarArray::GetAntennaHorizontalSpacing (void) const +{ + return m_disH; +} + + +void +UniformPlanarArray::SetAntennaVerticalSpacing (double s) +{ + NS_LOG_FUNCTION (this << s); + NS_ABORT_MSG_IF (s <= 0, "Trying to set an invalid spacing: " << s); + + if (s != m_disV) + { + m_isBfVectorValid = false; + } + m_disV = s; +} + + +double +UniformPlanarArray::GetAntennaVerticalSpacing (void) const +{ + return m_disV; +} + + +std::pair +UniformPlanarArray::GetElementFieldPattern (Angles a) const +{ + NS_LOG_FUNCTION (this << a); + + // 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 + double thetaPrime = std::acos (cos (m_beta) * cos (a.GetInclination ()) + sin (m_beta) * cos (a.GetAzimuth () - m_alpha) * sin (a.GetInclination ())); + double phiPrime = std::arg (std::complex (cos (m_beta) * sin (a.GetInclination ()) * cos (a.GetAzimuth () - m_alpha) - sin (m_beta) * cos (a.GetInclination ()), sin (a.GetAzimuth () - m_alpha) * sin (a.GetInclination ()))); + Angles aPrime (phiPrime, thetaPrime); + NS_LOG_DEBUG (a << " -> " << aPrime); + + // compute the antenna element field pattern in the vertical polarization using + // eq. 7.3-4 in 3GPP TR 38.901 + // NOTE we assume vertical polarization, hence the field pattern in the + // horizontal polarization is 0 + double aPrimeDb = m_antennaElement->GetGainDb (aPrime); + double fieldThetaPrime = pow (10, aPrimeDb / 20); // convert to linear magnitude + + // compute psi using eq. 7.1-15 in 3GPP TR 38.901, assuming that the slant + // angle (gamma) is 0 + double psi = std::arg (std::complex (cos (m_beta) * sin (a.GetInclination ()) - sin (m_beta) * cos (a.GetInclination ()) * cos (a.GetAzimuth () - m_alpha), sin (m_beta) * sin (a.GetAzimuth () - m_alpha))); + NS_LOG_DEBUG ("psi " << psi); + + // convert the antenna element field pattern to GCS using eq. 7.1-11 + // in 3GPP TR 38.901 + double fieldTheta = cos (psi) * fieldThetaPrime; + double fieldPhi = sin (psi) * fieldThetaPrime; + NS_LOG_DEBUG (RadiansToDegrees (a.GetAzimuth ()) << " " << RadiansToDegrees (a.GetInclination ()) << " " << fieldTheta * fieldTheta + fieldPhi * fieldPhi); + + return std::make_pair (fieldPhi, fieldTheta); +} + + +Vector +UniformPlanarArray::GetElementLocation (uint64_t index) const +{ + NS_LOG_FUNCTION (this << index); + + // 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); + + // convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP + // TR 38.901 + Vector loc; + loc.x = cos (m_alpha) * cos (m_beta) * xPrime - sin (m_alpha) * yPrime + cos (m_alpha) * sin (m_beta) * zPrime; + loc.y = sin (m_alpha) * cos (m_beta) * xPrime + cos (m_alpha) * yPrime + sin (m_alpha) * sin (m_beta) * zPrime; + loc.z = -sin (m_beta) * xPrime + cos (m_beta) * zPrime; + return loc; +} + +uint64_t +UniformPlanarArray::GetNumberOfElements () const +{ + return m_numRows * m_numColumns; +} + +} /* namespace ns3 */ diff --git a/src/antenna/model/uniform-planar-array.h b/src/antenna/model/uniform-planar-array.h new file mode 100644 index 000000000..fe5c9941f --- /dev/null +++ b/src/antenna/model/uniform-planar-array.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef UNIFORM_PLANAR_ARRAY_H +#define UNIFORM_PLANAR_ARRAY_H + + +#include +#include + + +namespace ns3 { + + +/** + * \ingroup antenna + * + * \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 (vertical) polarization. + */ +class UniformPlanarArray : public PhasedArrayModel +{ +public: + /** + * Constructor + */ + UniformPlanarArray (void); + + + /** + * Destructor + */ + virtual ~UniformPlanarArray (void); + + + // inherited from Object + static TypeId GetTypeId (void); + + + /** + * Returns the horizontal and vertical components of the antenna element field + * pattern at the specified direction. Only vertical 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 + */ + std::pair GetElementFieldPattern (Angles a) const override; + + + /** + * Returns the location of the antenna element with the specified + * index assuming the left bottom corner is (0,0,0), normalized + * with respect to the wavelength. + * Antenna elements are scanned row by row, left to right and bottom to top. + * For example, an antenna with 2 rows and 3 columns will be ordered as follows: + * ^ z + * | 3 4 5 + * | 0 1 2 + * ----------> y + * + * \param index index of the antenna 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 + * \return the number of antenna elements + */ + uint64_t GetNumberOfElements (void) 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); + + + /** + * Get the number of columns of the phased array + * \return the number of columns + */ + uint32_t GetNumColumns (void) const; + + + /** + * Set the number of rows 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 rows + */ + void SetNumRows (uint32_t n); + + + /** + * Get the number of rows of the phased array + * \return the number of rows + */ + uint32_t GetNumRows (void) const; + + + /** + * Set the horizontal spacing for the antenna elements of the phased array + * This method resets the stored beamforming vector to a ComplexVector + * of the correct size, but zero-filled + * \param s the horizontal spacing in multiples of wavelength + */ + void SetAntennaHorizontalSpacing (double s); + + + /** + * Get the horizontal spacing for the antenna elements of the phased array + * \return the horizontal spacing in multiples of wavelength + */ + double GetAntennaHorizontalSpacing (void) const; + + + /** + * Set the vertical spacing for the antenna elements of the phased array + * This method resets the stored beamforming vector to a ComplexVector + * of the correct size, but zero-filled + * \param s the vertical spacing in multiples of wavelength + */ + void SetAntennaVerticalSpacing (double s); + + + /** + * Get the vertical spacing for the antenna elements of the phased array + * \return the vertical spacing in multiples of wavelength + */ + double GetAntennaVerticalSpacing (void) const; + + + uint32_t m_numColumns; //!< number of columns + uint32_t m_numRows; //!< number of rows + double m_disV; //!< antenna spacing in the vertical direction in multiples of wave length + double m_disH; //!< antenna spacing in the horizontal direction in multiples of wave length + double m_alpha; //!< the bearing angle in radians + double m_beta; //!< the downtilt angle in radians + +}; + +} /* namespace ns3 */ + +#endif /* UNIFORM_PLANAR_ARRAY_H */ diff --git a/src/antenna/test/test-angles.cc b/src/antenna/test/test-angles.cc index 40ef0522c..da239bcdf 100644 --- a/src/antenna/test/test-angles.cc +++ b/src/antenna/test/test-angles.cc @@ -44,7 +44,7 @@ private: std::string OneVectorConstructorTestCase::BuildNameString (Vector v) { std::ostringstream oss; - oss << " v = " << v; + oss << " v = " << v; return oss.str (); } @@ -53,15 +53,14 @@ OneVectorConstructorTestCase::OneVectorConstructorTestCase (Vector v, Angles a) : TestCase (BuildNameString (v)), m_v (v), m_a (a) -{ -} +{} void OneVectorConstructorTestCase::DoRun () { Angles a (m_v); - NS_TEST_EXPECT_MSG_EQ_TOL ( a.phi, m_a.phi, 1e-10, "incorrect phi"); - NS_TEST_EXPECT_MSG_EQ_TOL ( a.theta, m_a.theta, 1e-10, "incorrect theta"); + NS_TEST_EXPECT_MSG_EQ_TOL ( a.GetAzimuth (), m_a.GetAzimuth (), 1e-10, "incorrect phi"); + NS_TEST_EXPECT_MSG_EQ_TOL ( a.GetInclination (), m_a.GetInclination (), 1e-10, "incorrect theta"); } @@ -85,7 +84,7 @@ private: std::string TwoVectorsConstructorTestCase::BuildNameString (Vector v, Vector o) { std::ostringstream oss; - oss << " v = " << v << ", o = " << o; + oss << " v = " << v << ", o = " << o; return oss.str (); } @@ -95,15 +94,14 @@ TwoVectorsConstructorTestCase::TwoVectorsConstructorTestCase (Vector v, Vector o m_v (v), m_o (o), m_a (a) -{ -} +{} void TwoVectorsConstructorTestCase::DoRun () { Angles a (m_v, m_o); - NS_TEST_EXPECT_MSG_EQ_TOL ( a.phi, m_a.phi, 1e-10, "incorrect phi"); - NS_TEST_EXPECT_MSG_EQ_TOL ( a.theta, m_a.theta, 1e-10, "incorrect theta"); + NS_TEST_EXPECT_MSG_EQ_TOL ( a.GetAzimuth (), m_a.GetAzimuth (), 1e-10, "incorrect phi"); + NS_TEST_EXPECT_MSG_EQ_TOL ( a.GetInclination (), m_a.GetInclination (), 1e-10, "incorrect theta"); } @@ -120,92 +118,92 @@ public: AnglesTestSuite::AnglesTestSuite () : TestSuite ("angles", UNIT) { - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, 1), Angles (0, 0)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -1), Angles (0, M_PI)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, 1), Angles (0, 0)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -1), Angles (0, M_PI)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (2, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-2, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 2, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, -2, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, 2), Angles (0, 0)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -2), Angles (0, M_PI)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (2, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-2, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 2, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, -2, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, 2), Angles (0, 0)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -2), Angles (0, M_PI)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, 1), Angles (0, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, -1), Angles (0, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, 0), Angles (M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, -1, 0), Angles (-M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, 1), Angles (M_PI, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, -1), Angles (M_PI, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 1, 0), Angles (3*M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, -1, 0), Angles (-3*M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, 1), Angles (M_PI_2, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, -1), Angles (M_PI_2, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, 1), Angles (-M_PI_2, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, -1), Angles (-M_PI_2, 3*M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, 1), Angles (0, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 0, -1), Angles (0, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, 0), Angles (M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, -1, 0), Angles (-M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, 1), Angles (M_PI, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 0, -1), Angles (M_PI, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 1, 0), Angles (3 * M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, -1, 0), Angles (-3 * M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, 1), Angles (M_PI_2, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, 1, -1), Angles (M_PI_2, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, 1), Angles (-M_PI_2, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (0, -1, -1), Angles (-M_PI_2, 3 * M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, std::sqrt (2)), Angles (M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, -std::sqrt (2)), Angles (M_PI_4, 3*M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, std::sqrt (2)), Angles (M_PI_4, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (1, 1, -std::sqrt (2)), Angles (M_PI_4, 3 * M_PI_4)), TestCase::QUICK); AddTestCase (new OneVectorConstructorTestCase (Vector (1, -1, std::sqrt (2)), Angles (-M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 1, std::sqrt (2)), Angles (3*M_PI_4, M_PI_4)), TestCase::QUICK); + AddTestCase (new OneVectorConstructorTestCase (Vector (-1, 1, std::sqrt (2)), Angles (3 * M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, 0), Vector (0, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, 0), Vector (0, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, 0), Vector (0, 0, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, 0), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, 1), Vector (0, 0, 0), Angles (0, 0)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -1), Vector (0, 0, 0), Angles (0, M_PI)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, 0), Vector (0, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, 0), Vector (0, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, 0), Vector (0, 0, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, 0), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, 1), Vector (0, 0, 0), Angles (0, 0)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -1), Vector (0, 0, 0), Angles (0, M_PI)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 0, 0), Vector (0, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-2, 0, 0), Vector (0, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 2, 0), Vector (0, 0, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -2, 0), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, 2), Vector (0, 0, 0), Angles (0, 0)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -2), Vector (0, 0, 0), Angles (0, M_PI)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 0, 0), Vector (0, 0, 0), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-2, 0, 0), Vector (0, 0, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 2, 0), Vector (0, 0, 0), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -2, 0), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, 2), Vector (0, 0, 0), Angles (0, 0)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -2), Vector (0, 0, 0), Angles (0, M_PI)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, 1), Vector (0, 0, 0), Angles (0, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, -1), Vector (0, 0, 0), Angles (0, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, 0), Vector (0, 0, 0), Angles (M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, -1, 0), Vector (0, 0, 0), Angles (-M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, 1), Vector (0, 0, 0), Angles (M_PI, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, -1), Vector (0, 0, 0), Angles (M_PI, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 1, 0), Vector (0, 0, 0), Angles (3*M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, -1, 0), Vector (0, 0, 0), Angles (-3*M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, 1), Vector (0, 0, 0), Angles (M_PI_2, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, -1), Vector (0, 0, 0), Angles (M_PI_2, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, 1), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, -1), Vector (0, 0, 0), Angles (-M_PI_2, 3*M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, 1), Vector (0, 0, 0), Angles (0, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 0, -1), Vector (0, 0, 0), Angles (0, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, 0), Vector (0, 0, 0), Angles (M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, -1, 0), Vector (0, 0, 0), Angles (-M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, 1), Vector (0, 0, 0), Angles (M_PI, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 0, -1), Vector (0, 0, 0), Angles (M_PI, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 1, 0), Vector (0, 0, 0), Angles (3 * M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, -1, 0), Vector (0, 0, 0), Angles (-3 * M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, 1), Vector (0, 0, 0), Angles (M_PI_2, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 1, -1), Vector (0, 0, 0), Angles (M_PI_2, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, 1), Vector (0, 0, 0), Angles (-M_PI_2, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -1, -1), Vector (0, 0, 0), Angles (-M_PI_2, 3 * M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, std::sqrt (2)), Vector (0, 0, 0), Angles (M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, -std::sqrt (2)), Vector (0, 0, 0), Angles (M_PI_4, 3*M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, std::sqrt (2)), Vector (0, 0, 0), Angles (M_PI_4, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 1, -std::sqrt (2)), Vector (0, 0, 0), Angles (M_PI_4, 3 * M_PI_4)), TestCase::QUICK); AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, -1, std::sqrt (2)), Vector (0, 0, 0), Angles (-M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 1, std::sqrt (2)), Vector (0, 0, 0), Angles (3*M_PI_4, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 1, std::sqrt (2)), Vector (0, 0, 0), Angles (3 * M_PI_4, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (3, 2, 2), Vector (2, 2, 2), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 2, 2), Vector (2, 2, 2), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 3, 2), Vector (2, 2, 2), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 2, 2), Vector (-1, 3, 2), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (4, -2, 7), Vector (4, -2, 6), Angles (0, 0)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -5, -1), Vector (0, -5, 0), Angles (0, M_PI)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (3, 2, 2), Vector (2, 2, 2), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (1, 2, 2), Vector (2, 2, 2), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 3, 2), Vector (2, 2, 2), Angles (M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 2, 2), Vector (-1, 3, 2), Angles (-M_PI_2, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (4, -2, 7), Vector (4, -2, 6), Angles (0, 0)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -5, -1), Vector (0, -5, 0), Angles (0, M_PI)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-2, 2, -1), Vector (-4, 2, -1), Angles (0, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 2, 0), Vector (4, 2, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-2, 2, -1), Vector (-4, 2, -1), Angles (0, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (2, 2, 0), Vector (4, 2, 0), Angles (M_PI, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 4, 4), Vector (-2, 4, 3), Angles (0, M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -2, -6), Vector (-1, -2, -5), Angles (0, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (77, 3, 43), Vector (78, 2, 43), Angles (3*M_PI_4, M_PI_2)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (-1, 4, 4), Vector (-2, 4, 3), Angles (0, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, -2, -6), Vector (-1, -2, -5), Angles (0, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (77, 3, 43), Vector (78, 2, 43), Angles (3 * M_PI_4, M_PI_2)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (24, -2, -6 -std::sqrt (2)), Vector (23, -3, -6), Angles (M_PI_4, 3*M_PI_4)), TestCase::QUICK); - AddTestCase (new TwoVectorsConstructorTestCase (Vector (0.5, 11.45, std::sqrt (2)-1), Vector (-0.5, 12.45, -1), Angles (-M_PI_4, M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (24, -2, -6 - std::sqrt (2)), Vector (23, -3, -6), Angles (M_PI_4, 3 * M_PI_4)), TestCase::QUICK); + AddTestCase (new TwoVectorsConstructorTestCase (Vector (0.5, 11.45, std::sqrt (2) - 1), Vector (-0.5, 12.45, -1), Angles (-M_PI_4, M_PI_4)), TestCase::QUICK); -}; +} static AnglesTestSuite staticAnglesTestSuiteInstance; diff --git a/src/antenna/test/test-cosine-antenna.cc b/src/antenna/test/test-cosine-antenna.cc index 80de162fb..0409b476c 100644 --- a/src/antenna/test/test-cosine-antenna.cc +++ b/src/antenna/test/test-cosine-antenna.cc @@ -59,7 +59,7 @@ private: std::string CosineAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g) { std::ostringstream oss; - oss << "theta=" << a.theta << " , phi=" << a.phi + oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth () << ", beamdwidth=" << b << "deg" << ", orientation=" << o << ", maxGain=" << g << " dB"; @@ -84,7 +84,8 @@ CosineAntennaModelTestCase::DoRun () NS_LOG_FUNCTION (this << BuildNameString (m_a, m_b, m_o, m_g)); Ptr a = CreateObject (); - a->SetAttribute ("Beamwidth", DoubleValue (m_b)); + a->SetAttribute ("HorizontalBeamwidth", DoubleValue (m_b)); + a->SetAttribute ("VerticalBeamwidth", DoubleValue (m_b)); a->SetAttribute ("Orientation", DoubleValue (m_o)); a->SetAttribute ("MaxGain", DoubleValue (m_g)); double actualGain = a->GetGainDb (m_a); @@ -117,89 +118,96 @@ CosineAntennaModelTestSuite::CosineAntennaModelTestSuite () // phideg = (2*acos(10^(targetgaindb/(20*n))))*180/pi // e.g., with a 60 deg beamwidth, gain is -20dB at +- 74.945 degrees from boresight - // phi, theta, beamwidth, orientation, maxGain, expectedGain, condition - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 60, 0, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 60, 0, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 60, 0, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (150), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (180), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-180), 0), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + // phi, theta, beamwidth, orientation, maxGain, expectedGain, condition + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 60, 0, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 60, 0, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 60, 0, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (150), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (180), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-180), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); // test positive orientation - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 60, 60, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 60, 60, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 60, 60, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (150), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (160), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (210), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (240), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-40), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), 0), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 60, 60, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 60, 60, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 60, 60, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (150), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (160), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (210), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (240), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-40), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); // test negative orientation and different beamwidths // with a 100 deg beamwidth, gain is -20dB at +- 117.47 degrees from boresight - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 100, -150, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), 0), 100, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), 0), 100, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-32.531), 0), 100, -150, 0, -20, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (92.531), 0), 100, -150, 0, -20, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 100, -150, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (90)), 100, -150, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (90)), 100, -150, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-32.531),DegreesToRadians (90)), 100, -150, 0, -20, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (92.531), DegreesToRadians (90)), 100, -150, 0, -20, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); // with a 150 deg beamwidth, gain is -10dB at +- 124.93 degrees from boresight, and -20dB at +- 155.32 degrees from boresight - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 150, -150, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (135), 0), 150, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-75), 0), 150, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (85.070), 0), 150, -150, 0, -10, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-25.070), 0), 150, -150, 0, -10, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (5.3230), 0), 150, -150, 0, -20, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (54.677), 0), 150, -150, 0, -20, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 150, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (20), 0), 150, -150, 0, -20, LESSTHAN), TestCase::QUICK); - + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 150, -150, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (135), DegreesToRadians (90)), 150, -150, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-75), DegreesToRadians (90)), 150, -150, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (85.070), DegreesToRadians (90)), 150, -150, 0, -10, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-25.070),DegreesToRadians (90)), 150, -150, 0, -10, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (5.3230), DegreesToRadians (90)), 150, -150, 0, -20, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (54.677), DegreesToRadians (90)), 150, -150, 0, -20, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 150, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (20), DegreesToRadians (90)), 150, -150, 0, -20, LESSTHAN), TestCase::QUICK); + // test flat beam, with beamwidth=360 deg + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 360, 0, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (180), DegreesToRadians (90)), 360, 0, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-180), DegreesToRadians (90)), 360, 0, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (0)), 360, 0, 0, 0, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians(180)), 360, 0, 0, 0, EQUAL), TestCase::QUICK); + // test maxGain - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 60, 0, 10, 10, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 60, 0, 22, 19, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 60, 0, -4, -7, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), 0), 60, 0, 10, -10, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 60, 0, -20, -40, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), 0), 60, 0, 40, 20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 100, -150, 2, 2, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), 0), 100, -150, 4, 1, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), 0), 100, -150, -1, -4, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 60, 0, 10, 10, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 60, 0, 22, 19, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 60, 0, -4, -7, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (90)), 60, 0, 10, -10, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 60, 0, -20, -40, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (90)), 60, 0, 40, 20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 100, -150, 2, 2, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (90)), 100, -150, 4, 1, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (90)), 100, -150, -1, -4, EQUAL), TestCase::QUICK); // test elevation angle - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 2), 60, 0, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 2), 60, 0, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 2), 60, 0, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), 2), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-180), 2), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), -3), 60, 60, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), -3), 60, 60, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), -3), 60, 60, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), -3), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), -3), 100, -150, 0, 0, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), -3), 100, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), -3), 100, -150, 0, -3, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), -3), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), 9.5), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 9.5), 60, 0, 10, 10, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 9.5), 60, 0, 22, 19, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 9.5), 60, 0, -4, -7, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), 9.5), 60, 0, 40, 20, LESSTHAN), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 9.5), 100, -150, 2, 2, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), 9.5), 100, -150, 4, 1, EQUAL), TestCase::QUICK); - AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), 9.5), 100, -150, -1, -4, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (60)), 60, 0, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (60)), 60, 0, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (60)), 60, 0, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (60)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-180), DegreesToRadians (60)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (120)), 60, 60, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (120)), 60, 60, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (120)), 60, 60, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), DegreesToRadians (120)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (140)), 100, -150, 0, -3, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (140)), 100, -150, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (140)), 100, -150, 0, -6, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (140)), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (60)), 60, 0, 10, 7, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (60)), 60, 0, 22, 16, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (60)), 60, 0, -4, -10, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (60)), 60, 0, 10, -13, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (60)), 60, 0, -20, -43, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (60)), 60, 0, 40, 17, LESSTHAN), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (40)), 100, -150, 2, -1, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (40)), 100, -150, 4, -2, EQUAL), TestCase::QUICK); + AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (40)), 100, -150, -1, -7, EQUAL), TestCase::QUICK); }; diff --git a/src/antenna/test/test-isotropic-antenna.cc b/src/antenna/test/test-isotropic-antenna.cc index 56c4c8299..d803d6862 100644 --- a/src/antenna/test/test-isotropic-antenna.cc +++ b/src/antenna/test/test-isotropic-antenna.cc @@ -45,7 +45,7 @@ private: std::string IsotropicAntennaModelTestCase::BuildNameString (Angles a) { std::ostringstream oss; - oss << "theta=" << a.theta << " , phi=" << a.phi; + oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth (); return oss.str (); } diff --git a/src/antenna/test/test-parabolic-antenna.cc b/src/antenna/test/test-parabolic-antenna.cc index b86e0656a..421b839e7 100644 --- a/src/antenna/test/test-parabolic-antenna.cc +++ b/src/antenna/test/test-parabolic-antenna.cc @@ -59,7 +59,7 @@ private: std::string ParabolicAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g) { std::ostringstream oss; - oss << "theta=" << a.theta << " , phi=" << a.phi + oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth () << ", beamdwidth=" << b << "deg" << ", orientation=" << o << ", maxAttenuation=" << g << " dB"; @@ -115,70 +115,70 @@ ParabolicAntennaModelTestSuite::ParabolicAntennaModelTestSuite () { // with a 60 deg beamwidth, gain is -20dB at +-77.460 degrees from boresight - // phi, theta, beamwidth, orientation, maxAttn, expectedGain, condition - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 60, 0, 20, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (100), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (150), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (180), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-180), 0), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + // phi, theta, beamwidth, orientation, maxAttn, expectedGain, condition + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 60, 0, 20, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (150), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (180), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-180), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); // with a 60 deg beamwidth, gain is -10dB at +-54.772 degrees from boresight // test positive orientation - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 60, 60, 10, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 60, 60, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 60, 60, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (150), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (160), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (210), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (240), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-40), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-120), 0), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 60, 60, 10, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 60, 60, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 60, 60, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (150), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (160), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (210), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (240), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-40), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-120), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK); // test negative orientation and different beamwidths // with a 80 deg beamwidth, gain is -20dB at +- 73.030 degrees from boresight - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), 0), 80, -150, 10, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-110), 0), 80, -150, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-190), 0), 80, -150, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-70), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (92), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), 0), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (90)), 80, -150, 10, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-110), DegreesToRadians (90)), 80, -150, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-190), DegreesToRadians (90)), 80, -150, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-70), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (92), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK); // test elevation angle - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), 2), 60, 0, 20, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), 2), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), 2), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), 2), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-180), 2), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), -3), 60, 60, 20, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), -3), 60, 60, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), -3), 60, 60, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-120), -3), 60, 60, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), -3), 100, -150, 10, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), -3), 100, -150, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-200), -3), 100, -150, 10, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), -3), 100, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), 9.5), 100, -150, 10, -10, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), 9.5), 60, 0, 20, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), 9.5), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), 9.5), 60, 0, 20, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (100), 9.5), 60, 0, 20, -20, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), 9.5), 100, -150, 30, 0, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), 9.5), 100, -150, 30, -3, EQUAL), TestCase::QUICK); - AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-200), 9.5), 100, -150, 30, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (88)), 60, 0, 20, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (88)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (88)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (88)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-180), DegreesToRadians (88)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (93)), 60, 60, 20, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (93)), 60, 60, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (93)), 60, 60, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-120), DegreesToRadians (93)), 60, 60, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (93)), 100, -150, 10, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (93)), 100, -150, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (93)), 100, -150, 10, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (93)), 100, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (80.5)), 100, -150, 10, -10, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (80.5)), 60, 0, 20, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (80.5)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (80.5)), 60, 0, 20, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (80.5)), 60, 0, 20, -20, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (80.5)), 100, -150, 30, 0, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-100), DegreesToRadians (80.5)), 100, -150, 30, -3, EQUAL), TestCase::QUICK); + AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (80.5)), 100, -150, 30, -3, EQUAL), TestCase::QUICK); }; diff --git a/src/antenna/test/test-uniform-planar-array.cc b/src/antenna/test/test-uniform-planar-array.cc new file mode 100644 index 000000000..7d405d088 --- /dev/null +++ b/src/antenna/test/test-uniform-planar-array.cc @@ -0,0 +1,216 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ns3/log.h" +#include "ns3/test.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "ns3/pointer.h" +#include "ns3/uniform-planar-array.h" +#include "ns3/isotropic-antenna-model.h" +#include "ns3/three-gpp-antenna-model.h" +#include "ns3/simulator.h" +#include "cmath" +#include "string" +#include "iostream" +#include "sstream" + + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TestUniformPlanarArray"); + +/** + * \ingroup tests + * + * \brief UniformPlanarArray Test Case + */ +class UniformPlanarArrayTestCase : public TestCase +{ +public: + /** + * Generate a string containing all relevant parameters + * \param element the antenna element + * \param rows the number of rows + * \param cols the number of columns + * \param rowSpace the row spacing + * \param colSpace the column spacing + * \param alpha the bearing angle + * \param beta the tilting angle + * \param direction the direction + * \return the string containing all relevant parameters + */ + static std::string BuildNameString (Ptr element, uint32_t rows, uint32_t cols,double rowSpace, double colSpace, + double alpha, double beta, Angles direction); + /** + * The constructor of the test case + * \param element the antenna element + * \param rows the number of rows + * \param cols the number of columns + * \param rowSpace the row spacing + * \param colSpace the column spacing + * \param alpha the bearing angle + * \param beta the tilting angle + * \param direction the direction + * \param expectedGainDb the expected antenna gain [dB] + */ + UniformPlanarArrayTestCase (Ptr element, uint32_t rows, uint32_t cols, double rowSpace, double colSpace, + double alpha, double beta, Angles direction, double expectedGainDb); + +private: + /** + * Run the test + */ + virtual void DoRun (void); + /** + * Compute the gain of the antenna array + * \param a the antenna array + * \return the gain of the antenna array [dB] + */ + double ComputeGain (Ptr a); + + Ptr m_element; //!< the antenna element + uint32_t m_rows; //!< the number of rows + uint32_t m_cols; //!< the number of columns + double m_rowSpace; //!< the row spacing + double m_colSpace; //!< the column spacing + double m_alpha; //!< the bearing angle [rad] + double m_beta; //!< the titling angle [rad] + Angles m_direction; //!< the testing direction + double m_expectedGain; //!< the expected antenna gain [dB] +}; + +std::string UniformPlanarArrayTestCase::BuildNameString (Ptr element, uint32_t rows, uint32_t cols, double rowSpace, double colSpace, + double alpha, double beta, Angles direction) +{ + std::ostringstream oss; + oss << "UPA=" << rows << "x" << cols + << ", row spacing=" << rowSpace << "*lambda" + << ", col spacing=" << colSpace << "*lambda" + << ", bearing=" << RadiansToDegrees (alpha) << " deg" + << ", tilting=" << RadiansToDegrees (beta) << " deg" + << ", element=" << element->GetInstanceTypeId ().GetName () + << ", direction=" << direction; + return oss.str (); +} + + +UniformPlanarArrayTestCase::UniformPlanarArrayTestCase (Ptr element, uint32_t rows, uint32_t cols, double rowSpace, double colSpace, + double alpha, double beta, Angles direction, double expectedGainDb) + : TestCase (BuildNameString (element, rows, cols, rowSpace, colSpace, alpha, beta, direction)), + m_element (element), + m_rows (rows), + m_cols (cols), + m_rowSpace (rowSpace), + m_colSpace (colSpace), + m_alpha (alpha), + m_beta (beta), + m_direction (direction), + m_expectedGain (expectedGainDb) +{} + + +double +UniformPlanarArrayTestCase::ComputeGain (Ptr a) +{ + // compute gain + PhasedArrayModel::ComplexVector sv = a->GetSteeringVector (m_direction); + NS_TEST_EXPECT_MSG_EQ (sv.size (), a->GetNumberOfElements (), "steering vector of wrong size"); + PhasedArrayModel::ComplexVector bf = a->GetBeamformingVector (m_direction); + NS_TEST_EXPECT_MSG_EQ (bf.size (), a->GetNumberOfElements (), "beamforming vector of wrong size"); + std::pair fp = a->GetElementFieldPattern (m_direction); + + // scalar product dot (sv, bf) + std::complex prod {0}; + for (size_t i = 0; i < sv.size (); i++) + { + prod += sv[i] * bf[i]; + } + double bfGain = std::pow (std::abs (prod), 2); + double bfGainDb = 10 * std::log10 (bfGain); + + // power gain from two polarizations + double elementPowerGain = std::pow (std::get<0> (fp), 2) + std::pow (std::get<1> (fp), 2); + double elementPowerGainDb = 10 * std::log10 (elementPowerGain); + + // sum BF and element gains + return bfGainDb + elementPowerGainDb; +} + + +void +UniformPlanarArrayTestCase::DoRun () +{ + NS_LOG_FUNCTION (this << BuildNameString (m_element, m_rows, m_cols, m_rowSpace, m_colSpace, m_alpha, m_beta, m_direction)); + + Ptr a = CreateObject (); + a->SetAttribute ("AntennaElement", PointerValue (m_element)); + a->SetAttribute ("NumRows", UintegerValue (m_rows)); + a->SetAttribute ("NumColumns", UintegerValue (m_cols)); + a->SetAttribute ("AntennaVerticalSpacing", DoubleValue (m_rowSpace)); + a->SetAttribute ("AntennaHorizontalSpacing", DoubleValue (m_colSpace)); + a->SetAttribute ("BearingAngle", DoubleValue (m_alpha)); + a->SetAttribute ("DowntiltAngle", DoubleValue (m_beta)); + + double actualGainDb = ComputeGain (a); + NS_TEST_EXPECT_MSG_EQ_TOL (actualGainDb, m_expectedGain, 0.001, "wrong value of the radiation pattern"); +} + + +/** + * \ingroup tests + * + * \brief UniformPlanarArray Test Suite + */ +class UniformPlanarArrayTestSuite : public TestSuite +{ +public: + UniformPlanarArrayTestSuite (); +}; + +UniformPlanarArrayTestSuite::UniformPlanarArrayTestSuite () + : TestSuite ("uniform-planar-array-test", UNIT) +{ + Ptr isotropic = CreateObject (); + Ptr tgpp = CreateObject (); + + // element, rows, cols, rowSpace, colSpace, bearing, tilting, direction (azimuth, inclination), expectedGainDb + // Single element arrays: check if bearing/tilting works on antenna element + AddTestCase (new UniformPlanarArrayTestCase (isotropic, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (0), Angles (DegreesToRadians (0), DegreesToRadians (90)), 0.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (0), Angles (DegreesToRadians (0), DegreesToRadians (90)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (90), DegreesToRadians (0), Angles (DegreesToRadians (90), DegreesToRadians (90)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (-90), DegreesToRadians (0), Angles (DegreesToRadians (-90), DegreesToRadians (90)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (180), DegreesToRadians (0), Angles (DegreesToRadians (180), DegreesToRadians (90)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (-180), DegreesToRadians (0), Angles (DegreesToRadians (-180), DegreesToRadians (90)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (45), Angles (DegreesToRadians (0), DegreesToRadians (135)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (-45), Angles (DegreesToRadians (0), DegreesToRadians (45)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (90), Angles (DegreesToRadians (0), DegreesToRadians (180)), 8.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 1, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (-90), Angles (DegreesToRadians (0), DegreesToRadians (0)), 8.0), TestCase::QUICK); + + // linear array + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (0), Angles (DegreesToRadians (0), DegreesToRadians (90)), 18.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 1, 0.5, 0.5, DegreesToRadians (90), DegreesToRadians (0), Angles (DegreesToRadians (90), DegreesToRadians (90)), 18.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 1, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (45), Angles (DegreesToRadians (0), DegreesToRadians (135)), 18.0), TestCase::QUICK); + + // planar array + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 10, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (0), Angles (DegreesToRadians (0), DegreesToRadians (90)), 28.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 10, 0.5, 0.5, DegreesToRadians (90), DegreesToRadians (0), Angles (DegreesToRadians (90), DegreesToRadians (90)), 28.0), TestCase::QUICK); + AddTestCase (new UniformPlanarArrayTestCase ( tgpp, 10, 10, 0.5, 0.5, DegreesToRadians (0), DegreesToRadians (45), Angles (DegreesToRadians (0), DegreesToRadians (135)), 28.0), TestCase::QUICK); +} + +static UniformPlanarArrayTestSuite staticUniformPlanarArrayTestSuiteInstance; diff --git a/src/antenna/wscript b/src/antenna/wscript index 33f5c4f1f..5d3d85ade 100644 --- a/src/antenna/wscript +++ b/src/antenna/wscript @@ -10,7 +10,9 @@ def build(bld): 'model/isotropic-antenna-model.cc', 'model/cosine-antenna-model.cc', 'model/parabolic-antenna-model.cc', - 'model/three-gpp-antenna-array-model.cc', + 'model/three-gpp-antenna-model.cc', + 'model/phased-array-model.cc', + 'model/uniform-planar-array.cc', ] module_test = bld.create_ns3_module_test_library('antenna') @@ -20,6 +22,7 @@ def build(bld): 'test/test-isotropic-antenna.cc', 'test/test-cosine-antenna.cc', 'test/test-parabolic-antenna.cc', + 'test/test-uniform-planar-array.cc', ] # Tests encapsulating example programs should be listed here @@ -36,7 +39,9 @@ def build(bld): 'model/isotropic-antenna-model.h', 'model/cosine-antenna-model.h', 'model/parabolic-antenna-model.h', - 'model/three-gpp-antenna-array-model.h', + 'model/three-gpp-antenna-model.h', + 'model/phased-array-model.h', + 'model/uniform-planar-array.h', ] bld.ns3_python_bindings() diff --git a/src/lte/examples/lena-rem-sector-antenna.cc b/src/lte/examples/lena-rem-sector-antenna.cc index 614a219bd..7ba869119 100644 --- a/src/lte/examples/lena-rem-sector-antenna.cc +++ b/src/lte/examples/lena-rem-sector-antenna.cc @@ -37,7 +37,7 @@ using std::vector; int main (int argc, char *argv[]) { - CommandLine cmd (__FILE__); + CommandLine cmd; cmd.Parse (argc, argv); ConfigStore inputConfig; @@ -178,20 +178,20 @@ main (int argc, char *argv[]) // Beam width is made quite narrow so sectors can be noticed in the REM lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel"); lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (0)); - lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100)); - lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); + lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100)); + lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (0))); lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel"); lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (360/3)); - lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100)); - lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); + lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100)); + lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (1))); lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel"); lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (2*360/3)); - lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100)); - lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); + lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100)); + lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (2))); for (uint32_t i = 0; i < nEnb; i++) @@ -205,7 +205,7 @@ main (int argc, char *argv[]) } // by default, simulation will anyway stop right after the REM has been generated - Simulator::Stop (Seconds (0.0069)); + Simulator::Stop (Seconds (0.0069)); Ptr remHelper = CreateObject (); remHelper->SetAttribute ("ChannelPath", StringValue ("/ChannelList/0")); diff --git a/src/lte/test/test-lte-antenna.cc b/src/lte/test/test-lte-antenna.cc index 03e3cad90..b40876942 100644 --- a/src/lte/test/test-lte-antenna.cc +++ b/src/lte/test/test-lte-antenna.cc @@ -158,8 +158,12 @@ LteEnbAntennaTestCase::DoRun (void) lteHelper->SetSchedulerAttribute ("UlCqiFilter", EnumValue (FfMacScheduler::PUSCH_UL_CQI)); lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel"); lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (m_orientationDegrees)); - lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (m_beamwidthDegrees)); - lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); + lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (m_beamwidthDegrees)); + lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0)); + + // set DL and UL bandwidth. + lteHelper->SetEnbDeviceAttribute ("DlBandwidth", UintegerValue (25)); + lteHelper->SetEnbDeviceAttribute ("UlBandwidth", UintegerValue (25)); enbDevs = lteHelper->InstallEnbDevice (enbNodes); ueDevs = lteHelper->InstallUeDevice (ueNodes); @@ -220,6 +224,7 @@ LteEnbAntennaTestCase::DoRun (void) } // remember that propagation loss is 0dB double calculatedAntennaGainDbDl = - (enbTxPowerDbm - calculatedSinrDbDl - noisePowerDbm - ueNoiseFigureDb); + NS_LOG_INFO ("expected " << m_antennaGainDb << " actual " << calculatedAntennaGainDbDl << " tol " << tolerance); NS_TEST_ASSERT_MSG_EQ_TOL (calculatedAntennaGainDbDl, m_antennaGainDb, tolerance, "Wrong DL antenna gain!"); } double expectedSinrUl = ueTxPowerDbm + m_antennaGainDb - noisePowerDbm + enbNoiseFigureDb; diff --git a/src/spectrum/doc/spectrum.rst b/src/spectrum/doc/spectrum.rst index 4a88af812..cba0ce038 100644 --- a/src/spectrum/doc/spectrum.rst +++ b/src/spectrum/doc/spectrum.rst @@ -586,8 +586,6 @@ the given geographic origin point, and is tested in the ``rand-cart-around-geo`` test suite by verifying that the generated points do not exceed the given maximum distance radius from the origin point. -.. _sec-3gpp-fast-fading-model: - 3GPP TR 38.901 fast fading model ================================ The framework described by TR 38.901 [TR38901]_ is a 3D statistical Spatial @@ -634,12 +632,12 @@ ThreeGppChannelModel and ThreeGppSpectrumPropagationLossModel. * Issue regarding the blockage model: according to 3GPP TR 38.901 v15.0.0 (2018-06) section 7.6.4.1, the blocking region for self-blocking is provided in LCS. - + However, here, clusterAOA and clusterZOA are in GCS and blocking check is performed for self-blocking similar to non-self blocking, that is in GCS. One would expect the angles to be transposed to LCS before checking self-blockage. - + ThreeGppSpectrumPropagationLossModel #################################### @@ -660,7 +658,7 @@ The method DoCalcRxPowerSpectralDensity uses m_deviceAntennaMap to obtain the antenna objects associated to the transmitting and receiving devices, and calls the method GetCurrentBeamformingVector to retrieve the beamforming vectors. For each device using the channel, the m_deviceAntennaMap contains the associated -antenna object of type ThreeGppAntennaArrayModel. Since the mapping is one-to-one, +antenna object of type PhasedArrayModel. Since the mapping is one-to-one, the model supports a single antenna object for each device. The m_deviceAntennaMap has to be initialized by inserting the device-antenna pairs using the method AddDevice. @@ -698,6 +696,7 @@ distribution depends on the parameter :math:`v_{scatt}`. The value of :math:`v_{scatt}` can be configured using the attribute "vScatt" (by default it is set to 0, so that the scattering effect is not considered). + ThreeGppChannelModel #################### @@ -760,7 +759,7 @@ The test suite ThreeGppChannelTestSuite includes three test cases: of the class ThreeGppSpectrumPropagationLossModel. It builds a simple network composed of two nodes, computes the power spectral density received by the receiving node, and - + 1. Checks if the long term components for the direct and the reverse link are the same, 2. Checks if the long term component is updated when changing diff --git a/src/spectrum/examples/three-gpp-channel-example.cc b/src/spectrum/examples/three-gpp-channel-example.cc index e21635c25..bbeb6c2eb 100644 --- a/src/spectrum/examples/three-gpp-channel-example.cc +++ b/src/spectrum/examples/three-gpp-channel-example.cc @@ -30,7 +30,7 @@ #include "ns3/core-module.h" #include "ns3/three-gpp-channel-model.h" -#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/uniform-planar-array.h" #include #include "ns3/three-gpp-spectrum-propagation-loss-model.h" #include "ns3/net-device.h" @@ -57,9 +57,9 @@ static Ptr m_spectrumLossModel; //!< the S * \param otherDevice the device towards which point the beam */ static void -DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice) +DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice) { - ThreeGppAntennaArrayModel::ComplexVector antennaWeights; + PhasedArrayModel::ComplexVector antennaWeights; // retrieve the position of the two devices Vector aPos = thisDevice->GetNode ()->GetObject ()->GetPosition (); @@ -67,13 +67,9 @@ DoBeamforming (Ptr thisDevice, Ptr thisAnt // compute the azimuth and the elevation angles Angles completeAngle (bPos,aPos); - - double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle - if (hAngleRadian < 0) - { - hAngleRadian += 2.0 * M_PI; - } - double vAngleRadian = completeAngle.theta; // the elevation angle + double hAngleRadian = completeAngle.GetAzimuth (); + + double vAngleRadian = completeAngle.GetInclination (); // the elevation angle // retrieve the number of antenna elements int totNoArrayElements = thisAntenna->GetNumberOfElements (); @@ -232,8 +228,8 @@ main (int argc, char *argv[]) nodes.Get (1)->AggregateObject (rxMob); // create the antenna objects and set their dimensions - Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); - Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); // initialize the devices in the ThreeGppSpectrumPropagationLossModel m_spectrumLossModel->AddDevice (txDev, txAntenna); diff --git a/src/spectrum/model/matrix-based-channel-model.h b/src/spectrum/model/matrix-based-channel-model.h index 443312937..37bccff96 100644 --- a/src/spectrum/model/matrix-based-channel-model.h +++ b/src/spectrum/model/matrix-based-channel-model.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include namespace ns3 { @@ -51,7 +51,7 @@ public: typedef std::vector DoubleVector; //!< type definition for vectors of doubles typedef std::vector Double2DVector; //!< type definition for matrices of doubles typedef std::vector Double3DVector; //!< type definition for 3D matrices of doubles - typedef std::vector Complex2DVector; //!< type definition for complex matrices + typedef std::vector Complex2DVector; //!< type definition for complex matrices typedef std::vector Complex3DVector; //!< type definition for complex 3D matrices @@ -108,8 +108,8 @@ public: */ virtual Ptr GetChannel (Ptr aMob, Ptr bMob, - Ptr aAntenna, - Ptr bAntenna) = 0; + Ptr aAntenna, + Ptr bAntenna) = 0; /** * Calculate the channel key using the Cantor function diff --git a/src/spectrum/model/three-gpp-channel-model.cc b/src/spectrum/model/three-gpp-channel-model.cc index d9bb785fc..d5bc867a9 100644 --- a/src/spectrum/model/three-gpp-channel-model.cc +++ b/src/spectrum/model/three-gpp-channel-model.cc @@ -22,7 +22,7 @@ #include "three-gpp-channel-model.h" #include "ns3/log.h" -#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/phased-array-model.h" #include "ns3/node.h" #include "ns3/double.h" #include "ns3/string.h" @@ -970,8 +970,8 @@ ThreeGppChannelModel::ChannelMatrixNeedsUpdate (Ptr Ptr ThreeGppChannelModel::GetChannel (Ptr aMob, Ptr bMob, - Ptr aAntenna, - Ptr bAntenna) + Ptr aAntenna, + Ptr bAntenna) { NS_LOG_FUNCTION (this); @@ -1038,8 +1038,8 @@ ThreeGppChannelModel::GetChannel (Ptr aMob, Ptr ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr channelCondition, - Ptr sAntenna, - Ptr uAntenna, + Ptr sAntenna, + Ptr uAntenna, Angles &uAngle, Angles &sAngle, double dis2D, double hBS, double hUT) const { @@ -1333,17 +1333,17 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr c { Xn = -1; } - clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (m_normalRv->GetValue () * ASA / 7) + uAngle.phi * 180 / M_PI; //(7.5-11) - clusterAod[cIndex] = clusterAod[cIndex] * Xn + (m_normalRv->GetValue () * ASD / 7) + sAngle.phi * 180 / M_PI; + clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (m_normalRv->GetValue () * ASA / 7) + RadiansToDegrees (uAngle.GetAzimuth ()); //(7.5-11) + clusterAod[cIndex] = clusterAod[cIndex] * Xn + (m_normalRv->GetValue () * ASD / 7) + RadiansToDegrees (sAngle.GetAzimuth ()); if (o2i) { clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + 90; //(7.5-16) } else { - clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + uAngle.theta * 180 / M_PI; //(7.5-16) + clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + RadiansToDegrees (uAngle.GetInclination ()); //(7.5-16) } - clusterZod[cIndex] = clusterZod[cIndex] * Xn + (m_normalRv->GetValue () * ZSD / 7) + sAngle.theta * 180 / M_PI + table3gpp->m_offsetZOD; //(7.5-19) + clusterZod[cIndex] = clusterZod[cIndex] * Xn + (m_normalRv->GetValue () * ZSD / 7) + RadiansToDegrees (sAngle.GetInclination ()) + table3gpp->m_offsetZOD; //(7.5-19) } @@ -1351,10 +1351,10 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr c { //The 7.5-12 can be rewrite as Theta_n,ZOA = Theta_n,ZOA - (Theta_1,ZOA - Theta_LOS,ZOA) = Theta_n,ZOA - diffZOA, //Similar as AOD, ZSA and ZSD. - double diffAoa = clusterAoa[0] - uAngle.phi * 180 / M_PI; - double diffAod = clusterAod[0] - sAngle.phi * 180 / M_PI; - double diffZsa = clusterZoa[0] - uAngle.theta * 180 / M_PI; - double diffZsd = clusterZod[0] - sAngle.theta * 180 / M_PI; + double diffAoa = clusterAoa[0] - RadiansToDegrees (uAngle.GetAzimuth ()); + double diffAod = clusterAod[0] - RadiansToDegrees (sAngle.GetAzimuth ()); + double diffZsa = clusterZoa[0] - RadiansToDegrees (uAngle.GetInclination ()); + double diffZsd = clusterZod[0] - RadiansToDegrees (sAngle.GetInclination ()); for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) { @@ -1376,69 +1376,12 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr c for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++) { double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA * offSetAlpha[mInd]; //(7.5-13) - while (tempAoa > 360) - { - tempAoa -= 360; - } - - while (tempAoa < 0) - { - tempAoa += 360; - - } - NS_ASSERT_MSG (tempAoa >= 0 && tempAoa <= 360, "the AOA should be the range of [0,360]"); - rayAoa_radian[nInd][mInd] = tempAoa * M_PI / 180; - - double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd]; - while (tempAod > 360) - { - tempAod -= 360; - } - - while (tempAod < 0) - { - tempAod += 360; - } - NS_ASSERT_MSG (tempAod >= 0 && tempAod <= 360, "the AOD should be the range of [0,360]"); - rayAod_radian[nInd][mInd] = tempAod * M_PI / 180; - double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA * offSetAlpha[mInd]; //(7.5-18) + std::tie (rayAoa_radian[nInd][mInd], rayZoa_radian[nInd][mInd]) = WrapAngles (DegreesToRadians (tempAoa), DegreesToRadians (tempZoa)); - while (tempZoa > 360) - { - tempZoa -= 360; - } - - while (tempZoa < 0) - { - tempZoa += 360; - } - - if (tempZoa > 180) - { - tempZoa = 360 - tempZoa; - } - - NS_ASSERT_MSG (tempZoa >= 0&&tempZoa <= 180, "the ZOA should be the range of [0,180]"); - rayZoa_radian[nInd][mInd] = tempZoa * M_PI / 180; - - double tempZod = clusterZod[nInd] + 0.375 * pow (10,table3gpp->m_uLgZSD) * offSetAlpha[mInd]; //(7.5-20) - - while (tempZod > 360) - { - tempZod -= 360; - } - - while (tempZod < 0) - { - tempZod += 360; - } - if (tempZod > 180) - { - tempZod = 360 - tempZod; - } - NS_ASSERT_MSG (tempZod >= 0&&tempZod <= 180, "the ZOD should be the range of [0,180]"); - rayZod_radian[nInd][mInd] = tempZod * M_PI / 180; + double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd]; //(7.5-13) + double tempZod = clusterZod[nInd] + 0.375 * pow (10,table3gpp->m_uLgZSD) * offSetAlpha[mInd]; //(7.5-20) + std::tie (rayAod_radian[nInd][mInd], rayZod_radian[nInd][mInd]) = WrapAngles (DegreesToRadians (tempAod), DegreesToRadians (tempZod)); } } DoubleVector angle_degree; @@ -1712,16 +1655,16 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr c if (los) //(7.5-29) && (7.5-30) { std::complex ray (0,0); - double rxPhaseDiff = 2 * M_PI * (sin (uAngle.theta) * cos (uAngle.phi) * uLoc.x - + sin (uAngle.theta) * sin (uAngle.phi) * uLoc.y - + cos (uAngle.theta) * uLoc.z); - double txPhaseDiff = 2 * M_PI * (sin (sAngle.theta) * cos (sAngle.phi) * sLoc.x - + sin (sAngle.theta) * sin (sAngle.phi) * sLoc.y - + cos (sAngle.theta) * sLoc.z); + double rxPhaseDiff = 2 * M_PI * (sin (uAngle.GetInclination ()) * cos (uAngle.GetAzimuth ()) * uLoc.x + + sin (uAngle.GetInclination ()) * sin (uAngle.GetAzimuth ()) * uLoc.y + + cos (uAngle.GetInclination ()) * uLoc.z); + double txPhaseDiff = 2 * M_PI * (sin (sAngle.GetInclination ()) * cos (sAngle.GetAzimuth ()) * sLoc.x + + sin (sAngle.GetInclination ()) * sin (sAngle.GetAzimuth ()) * sLoc.y + + cos (sAngle.GetInclination ()) * sLoc.z); double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta; - std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.phi, uAngle.theta)); - std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.phi, sAngle.theta)); + std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.GetAzimuth (), uAngle.GetInclination ())); + std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.GetAzimuth (), sAngle.GetInclination ())); double lambda = 3e8 / m_frequency; // the wavelength of the carrier frequency @@ -1816,6 +1759,27 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr c return channelParams; } +std::pair +ThreeGppChannelModel::WrapAngles (double azimuthRad, double inclinationRad) +{ + inclinationRad = WrapTo2Pi (inclinationRad); + if (inclinationRad > M_PI) + { + // inclination must be in [0, M_PI] + inclinationRad -= M_PI; + azimuthRad += M_PI; + } + + azimuthRad = WrapTo2Pi (azimuthRad); + + NS_ASSERT_MSG (0 <= inclinationRad && inclinationRad <= M_PI, + "inclinationRad=" << inclinationRad << " not valid, should be in [0, pi]"); + NS_ASSERT_MSG (0 <= azimuthRad && azimuthRad <= 2 * M_PI, + "azimuthRad=" << azimuthRad << " not valid, should be in [0, 2*pi]"); + + return std::make_pair (azimuthRad, inclinationRad); +} + MatrixBasedChannelModel::DoubleVector ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptr params, const DoubleVector &clusterAOA, @@ -2018,13 +1982,13 @@ ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptrm_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (A1 * M_PI / 180) - 1))) / M_PI; //(7.6-23) + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (A1)) - 1))) / M_PI; //(7.6-23) double F_A2 = atan (signA2 * M_PI / 2 * sqrt (M_PI / lambda * - params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (A2 * M_PI / 180) - 1))) / M_PI; + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (A2)) - 1))) / M_PI; double F_Z1 = atan (signZ1 * M_PI / 2 * sqrt (M_PI / lambda * - params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (Z1 * M_PI / 180) - 1))) / M_PI; + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (Z1)) - 1))) / M_PI; double F_Z2 = atan (signZ2 * M_PI / 2 * sqrt (M_PI / lambda * - params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (Z2 * M_PI / 180) - 1))) / M_PI; + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (Z2)) - 1))) / M_PI; double L_dB = -20 * log10 (1 - (F_A1 + F_A2) * (F_Z1 + F_Z2)); //(7.6-22) powerAttenuation[cInd] += L_dB; NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by no-self blocking, " diff --git a/src/spectrum/model/three-gpp-channel-model.h b/src/spectrum/model/three-gpp-channel-model.h index 874383205..e205aa136 100644 --- a/src/spectrum/model/three-gpp-channel-model.h +++ b/src/spectrum/model/three-gpp-channel-model.h @@ -117,8 +117,8 @@ public: */ Ptr GetChannel (Ptr aMob, Ptr bMob, - Ptr aAntenna, - Ptr bAntenna) override; + Ptr aAntenna, + Ptr bAntenna) override; /** * \brief Assign a fixed random variable stream number to the random variables * used by this model. @@ -129,6 +129,20 @@ public: int64_t AssignStreams (int64_t stream); private: + /** + * Wrap an (azimuth, inclination) angle pair in a valid range. + * Specifically, inclination must be in [0, M_PI] and azimuth in [0, 2*M_PI). + * If the inclination angle is outside of its range, the azimuth angle is + * rotated by M_PI. + * This methods aims specifically at solving the problem of generating angles at + * the boundaries of the angle domain, specifically, generating angle distributions + * close to inclinationRad=0 and inclinationRad=M_PI. + * + * \param azimuthRad the azimuth angle in radians + * \param inclinationRad the inclination angle in radians + * \return the wrapped (azimuth, inclination) angle pair in radians + */ + static std::pair WrapAngles (double azimuthRad, double inclinationRad); /** * \brief Shuffle the elements of a simple sequence container of type double * \param first Pointer to the first element among the elements to be shuffled @@ -217,8 +231,8 @@ private: * \return the channel realization */ Ptr GetNewChannel (Vector locUT, Ptr channelCondition, - Ptr sAntenna, - Ptr uAntenna, + Ptr sAntenna, + Ptr uAntenna, Angles &uAngle, Angles &sAngle, double dis2D, double hBS, double hUT) const; diff --git a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc index 1b16898ef..f0ec90473 100644 --- a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc +++ b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc @@ -23,7 +23,7 @@ #include "ns3/log.h" #include "three-gpp-spectrum-propagation-loss-model.h" #include "ns3/net-device.h" -#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/phased-array-model.h" #include "ns3/node.h" #include "ns3/channel-condition-model.h" #include "ns3/double.h" @@ -95,7 +95,7 @@ ThreeGppSpectrumPropagationLossModel::GetChannelModel () const } void -ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr n, Ptr a) +ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr n, Ptr a) { NS_ASSERT_MSG (m_deviceAntennaMap.find (n->GetNode ()->GetId ()) == m_deviceAntennaMap.end (), "Device is already present in the map"); m_deviceAntennaMap.insert (std::make_pair (n->GetNode ()->GetId (), a)); @@ -121,10 +121,10 @@ ThreeGppSpectrumPropagationLossModel::GetChannelModelAttribute (const std::strin m_channelModel->GetAttribute (name, value); } -ThreeGppAntennaArrayModel::ComplexVector +PhasedArrayModel::ComplexVector ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr params, - const ThreeGppAntennaArrayModel::ComplexVector &sW, - const ThreeGppAntennaArrayModel::ComplexVector &uW) const + const PhasedArrayModel::ComplexVector &sW, + const PhasedArrayModel::ComplexVector &uW) const { NS_LOG_FUNCTION (this); @@ -134,7 +134,7 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr (params->m_channel[0][0].size ()); for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) @@ -156,7 +156,7 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr txPsd, - ThreeGppAntennaArrayModel::ComplexVector longTerm, + PhasedArrayModel::ComplexVector longTerm, Ptr params, const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const { @@ -171,7 +171,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr tx // NOTE the update of Doppler is simplified by only taking the center angle of // each cluster in to consideration. double slotTime = Simulator::Now ().GetSeconds (); - ThreeGppAntennaArrayModel::ComplexVector doppler; + PhasedArrayModel::ComplexVector doppler; for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) { // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3 @@ -226,17 +226,17 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr tx return tempPsd; } -ThreeGppAntennaArrayModel::ComplexVector +PhasedArrayModel::ComplexVector ThreeGppSpectrumPropagationLossModel::GetLongTerm (uint32_t aId, uint32_t bId, Ptr channelMatrix, - const ThreeGppAntennaArrayModel::ComplexVector &aW, - const ThreeGppAntennaArrayModel::ComplexVector &bW) const + const PhasedArrayModel::ComplexVector &aW, + const PhasedArrayModel::ComplexVector &bW) const { - ThreeGppAntennaArrayModel::ComplexVector longTerm; // vector containing the long term component for each cluster + PhasedArrayModel::ComplexVector longTerm; // vector containing the long term component for each cluster // check if the channel matrix was generated considering a as the s-node and // b as the u-node or viceversa - ThreeGppAntennaArrayModel::ComplexVector sW, uW; + PhasedArrayModel::ComplexVector sW, uW; if (!channelMatrix->IsReverse (aId, bId)) { sW = aW; @@ -311,28 +311,22 @@ ThreeGppSpectrumPropagationLossModel::DoCalcRxPowerSpectralDensity (Ptr aAntenna = m_deviceAntennaMap.at (aId); + Ptr aAntenna = m_deviceAntennaMap.at (aId); NS_LOG_DEBUG ("a node " << a->GetObject () << " antenna " << aAntenna); // retrieve the antenna of the device b NS_ASSERT_MSG (m_deviceAntennaMap.find (bId) != m_deviceAntennaMap.end (), "Antenna not found for device " << bId); - Ptr bAntenna = m_deviceAntennaMap.at (bId); + Ptr bAntenna = m_deviceAntennaMap.at (bId); NS_LOG_DEBUG ("b node " << bId << " antenna " << bAntenna); - if (aAntenna->IsOmniTx () || bAntenna->IsOmniTx () ) - { - NS_LOG_LOGIC ("Omni transmission, do nothing."); - return rxPsd; - } - Ptr channelMatrix = m_channelModel->GetChannel (a, b, aAntenna, bAntenna); // get the precoding and combining vectors - ThreeGppAntennaArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector (); - ThreeGppAntennaArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector (); + PhasedArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector (); + PhasedArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector (); // retrieve the long term component - ThreeGppAntennaArrayModel::ComplexVector longTerm = GetLongTerm (aId, bId, channelMatrix, aW, bW); + PhasedArrayModel::ComplexVector longTerm = GetLongTerm (aId, bId, channelMatrix, aW, bW); // apply the beamforming gain rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, a->GetVelocity (), b->GetVelocity ()); diff --git a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h index 2e9f809e9..d8a069f5b 100644 --- a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h +++ b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h @@ -46,7 +46,7 @@ class ChannelCondition; * returns the PSD of the received signal. * * \see MatrixBasedChannelModel - * \see ThreeGppAntennaArrayModel + * \see PhasedArrayModel * \see ChannelCondition */ class ThreeGppSpectrumPropagationLossModel : public SpectrumPropagationLossModel @@ -85,9 +85,9 @@ public: /** * Add a device-antenna pair * \param n a pointer to the NetDevice - * \param a a pointer to the associated ThreeGppAntennaArrayModel + * \param a a pointer to the associated PhasedArrayModel */ - void AddDevice (Ptr n, Ptr a); + void AddDevice (Ptr n, Ptr a); /** @@ -136,10 +136,10 @@ private: */ struct LongTerm : public SimpleRefCount { - ThreeGppAntennaArrayModel::ComplexVector m_longTerm; //!< vector containing the long term component for each cluster + PhasedArrayModel::ComplexVector m_longTerm; //!< vector containing the long term component for each cluster Ptr m_channel; //!< pointer to the channel matrix used to compute the long term - ThreeGppAntennaArrayModel::ComplexVector m_sW; //!< the beamforming vector for the node s used to compute the long term - ThreeGppAntennaArrayModel::ComplexVector m_uW; //!< the beamforming vector for the node u used to compute the long term + PhasedArrayModel::ComplexVector m_sW; //!< the beamforming vector for the node s used to compute the long term + PhasedArrayModel::ComplexVector m_uW; //!< the beamforming vector for the node u used to compute the long term }; /** @@ -159,10 +159,10 @@ private: * \param bW the beamforming vector of the second device * \return vector containing the long term compoenent for each cluster */ - ThreeGppAntennaArrayModel::ComplexVector GetLongTerm (uint32_t aId, uint32_t bId, + PhasedArrayModel::ComplexVector GetLongTerm (uint32_t aId, uint32_t bId, Ptr channelMatrix, - const ThreeGppAntennaArrayModel::ComplexVector &aW, - const ThreeGppAntennaArrayModel::ComplexVector &bW) const; + const PhasedArrayModel::ComplexVector &aW, + const PhasedArrayModel::ComplexVector &bW) const; /** * Computes the long term component * \param channelMatrix the channel matrix H @@ -170,9 +170,9 @@ private: * \param uW the beamforming vector of the u device * \return the long term component */ - ThreeGppAntennaArrayModel::ComplexVector CalcLongTerm (Ptr channelMatrix, - const ThreeGppAntennaArrayModel::ComplexVector &sW, - const ThreeGppAntennaArrayModel::ComplexVector &uW) const; + PhasedArrayModel::ComplexVector CalcLongTerm (Ptr channelMatrix, + const PhasedArrayModel::ComplexVector &sW, + const PhasedArrayModel::ComplexVector &uW) const; /** * Computes the beamforming gain and applies it to the tx PSD @@ -184,11 +184,11 @@ private: * \return the rx PSD */ Ptr CalcBeamformingGain (Ptr txPsd, - ThreeGppAntennaArrayModel::ComplexVector longTerm, + PhasedArrayModel::ComplexVector longTerm, Ptr params, const Vector &sSpeed, const Vector &uSpeed) const; - std::unordered_map > m_deviceAntennaMap; //!< map containig the associations + std::unordered_map > m_deviceAntennaMap; //!< map containig the associations mutable std::unordered_map < uint32_t, Ptr > m_longTermMap; //!< map containing the long term components Ptr m_channelModel; //!< the model to generate the channel matrix diff --git a/src/spectrum/test/three-gpp-channel-test-suite.cc b/src/spectrum/test/three-gpp-channel-test-suite.cc index df1866841..55f05b4e1 100644 --- a/src/spectrum/test/three-gpp-channel-test-suite.cc +++ b/src/spectrum/test/three-gpp-channel-test-suite.cc @@ -27,7 +27,8 @@ #include "ns3/pointer.h" #include "ns3/node-container.h" #include "ns3/constant-position-mobility-model.h" -#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/uniform-planar-array.h" +#include "ns3/isotropic-antenna-model.h" #include "ns3/three-gpp-channel-model.h" #include "ns3/simple-net-device.h" #include "ns3/simulator.h" @@ -71,7 +72,7 @@ private: * \param txAntenna the antenna object associated to the first node * \param rxAntenna the antenna object associated to the second node */ - void DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna); + void DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna); std::vector m_normVector; //!< each element is the norm of a channel realization }; @@ -86,7 +87,7 @@ ThreeGppChannelMatrixComputationTest::~ThreeGppChannelMatrixComputationTest () } void -ThreeGppChannelMatrixComputationTest::DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna) +ThreeGppChannelMatrixComputationTest::DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna) { uint64_t txAntennaElements = txAntenna->GetNumberOfElements (); uint64_t rxAntennaElements = rxAntenna->GetNumberOfElements (); @@ -153,8 +154,12 @@ ThreeGppChannelMatrixComputationTest::DoRun (void) nodes.Get (1)->AggregateObject (rxMob); // create the tx and rx antennas and set the their dimensions - Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true)); - Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true)); + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), + "NumRows", UintegerValue (txAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), + "NumRows", UintegerValue (rxAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); // generate the channel matrix Ptr channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna); @@ -235,7 +240,7 @@ private: * \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 channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update); + void DoGetChannel (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update); Ptr m_currentChannel; //!< used by DoGetChannel to store the current channel matrix }; @@ -250,7 +255,7 @@ ThreeGppChannelMatrixUpdateTest::~ThreeGppChannelMatrixUpdateTest () } void -ThreeGppChannelMatrixUpdateTest::DoGetChannel (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update) +ThreeGppChannelMatrixUpdateTest::DoGetChannel (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update) { // retrieve the channel matrix Ptr channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna); @@ -312,22 +317,29 @@ ThreeGppChannelMatrixUpdateTest::DoRun (void) nodes.Get (1)->AggregateObject (rxMob); // create the tx and rx antennas and set the their dimensions - Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true)); - Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true)); - + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), + "NumRows", UintegerValue (txAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), + "NumRows", UintegerValue (rxAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); + // check if the channel matrix is correctly updated // compute the channel matrix for the first time uint32_t firstTimeMs = 1; // time instant at which the channel matrix is generated for the first time - Simulator::Schedule (MilliSeconds (firstTimeMs), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, true); + Simulator::Schedule (MilliSeconds (firstTimeMs), &ThreeGppChannelMatrixUpdateTest::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 (firstTimeMs + updatePeriodMs / 2), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, false); + Simulator::Schedule (MilliSeconds (firstTimeMs + updatePeriodMs / 2), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, + this, channelModel, txMob, rxMob, txAntenna, rxAntenna, false); // call GetChannel when the update period is exceeded, the channel matrix // should be recomputed - Simulator::Schedule (MilliSeconds (firstTimeMs + updatePeriodMs + 1), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, true); + Simulator::Schedule (MilliSeconds (firstTimeMs + updatePeriodMs + 1), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, + this, channelModel, txMob, rxMob, txAntenna, rxAntenna, true); Simulator::Run (); Simulator::Destroy (); @@ -367,7 +379,7 @@ private: * \param otherDevice the device to communicate with * \param otherAntenna the antenna object associated to otherDevice */ - void DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna); + void DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna); /** * Test of the long term component is correctly updated when the channel @@ -400,35 +412,15 @@ ThreeGppSpectrumPropagationLossModelTest::~ThreeGppSpectrumPropagationLossModelT } void -ThreeGppSpectrumPropagationLossModelTest::DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna) +ThreeGppSpectrumPropagationLossModelTest::DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna) { - ThreeGppAntennaArrayModel::ComplexVector antennaWeights; - Vector aPos = thisDevice->GetNode ()->GetObject ()->GetPosition (); Vector bPos = otherDevice->GetNode ()->GetObject ()->GetPosition (); // compute the azimuth and the elevation angles Angles completeAngle (bPos,aPos); - double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle - if (hAngleRadian < 0) - { - hAngleRadian += 2.0 * M_PI; - } - double vAngleRadian = completeAngle.theta; // the elevation angle - - int totNoArrayElements = thisAntenna->GetNumberOfElements (); - double power = 1 / sqrt (totNoArrayElements); - - for (int ind = 0; ind < totNoArrayElements; ind++) - { - Vector loc = thisAntenna->GetElementLocation (ind); - double phase = -2 * M_PI * (sin (vAngleRadian) * cos (hAngleRadian) * loc.x - + sin (vAngleRadian) * sin (hAngleRadian) * loc.y - + cos (vAngleRadian) * loc.z); - antennaWeights.push_back (exp (std::complex (0, phase)) * power); - } - + PhasedArrayModel::ComplexVector antennaWeights = thisAntenna->GetBeamformingVector (completeAngle); thisAntenna->SetBeamformingVector (antennaWeights); } @@ -499,9 +491,13 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun () nodes.Get (1)->AggregateObject (rxMob); // create the tx and rx antennas and set the their dimensions - Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1])); - Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1])); - + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), + "NumRows", UintegerValue (txAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), + "NumRows", UintegerValue (rxAntennaElements [1]), + "AntennaElement", PointerValue(CreateObject ())); + // initialize ThreeGppSpectrumPropagationLossModel lossModel->AddDevice (txDev, txAntenna); lossModel->AddDevice (rxDev, rxAntenna); @@ -526,7 +522,7 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun () // 2) check if the long term is updated when changing the BF vector // change the position of the rx device and recompute the beamforming vectors rxMob->SetPosition (Vector (10.0, 5.0, 10.0)); - ThreeGppAntennaArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector (); + PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector (); txBfVector [0] = std::complex (0.0, 0.0); txAntenna->SetBeamformingVector (txBfVector); @@ -537,7 +533,8 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun () rxPsdOld = rxPsdNew; // 3) check if the long term is updated when the channel matrix is recomputed - Simulator::Schedule (MilliSeconds (101), &ThreeGppSpectrumPropagationLossModelTest::CheckLongTermUpdate, this, lossModel, txPsd, txMob, rxMob, rxPsdOld); + Simulator::Schedule (MilliSeconds (101), &ThreeGppSpectrumPropagationLossModelTest::CheckLongTermUpdate, + this, lossModel, txPsd, txMob, rxMob, rxPsdOld); Simulator::Run (); Simulator::Destroy ();