antenna: (merges !481) Update antenna module
- Introduce PhasedArrayModel - Use the new PhasedArrayModel framework across modules (e.g., 3gpp channel model) - Improve Angles class. Furthermore, Angles has been translated from elevation to inclination and from degrees to radians - Update antenna module doc - Fix random angle generation for the 3gpp channel model. Specifically, cluster and sub-cluster angles might be generated with inclination angles outside the inclination range [0, pi], and have now been fixed.
This commit is contained in:
committed by
Tom Henderson
parent
8d4e5772c8
commit
2cfcebe0d0
@@ -41,7 +41,7 @@
|
|||||||
#include "ns3/core-module.h"
|
#include "ns3/core-module.h"
|
||||||
#include "ns3/network-module.h"
|
#include "ns3/network-module.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#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-spectrum-propagation-loss-model.h"
|
||||||
#include "ns3/three-gpp-v2v-propagation-loss-model.h"
|
#include "ns3/three-gpp-v2v-propagation-loss-model.h"
|
||||||
#include "ns3/three-gpp-channel-model.h"
|
#include "ns3/three-gpp-channel-model.h"
|
||||||
@@ -61,9 +61,9 @@ static Ptr<ChannelConditionModel> m_condModel; //!< the ChannelConditionModel ob
|
|||||||
* \param otherDevice the device towards which point the beam
|
* \param otherDevice the device towards which point the beam
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAntenna, Ptr<NetDevice> otherDevice)
|
DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<PhasedArrayModel> thisAntenna, Ptr<NetDevice> otherDevice)
|
||||||
{
|
{
|
||||||
ThreeGppAntennaArrayModel::ComplexVector antennaWeights;
|
PhasedArrayModel::ComplexVector antennaWeights;
|
||||||
|
|
||||||
// retrieve the position of the two devices
|
// retrieve the position of the two devices
|
||||||
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
||||||
@@ -72,31 +72,8 @@ DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAnt
|
|||||||
// compute the azimuth and the elevation angles
|
// compute the azimuth and the elevation angles
|
||||||
Angles completeAngle (bPos,aPos);
|
Angles completeAngle (bPos,aPos);
|
||||||
|
|
||||||
double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle
|
PhasedArrayModel::ComplexVector bf = thisAntenna->GetBeamformingVector (completeAngle);
|
||||||
if (hAngleRadian < 0)
|
thisAntenna->SetBeamformingVector (bf);
|
||||||
{
|
|
||||||
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<double> (0, phase)) * power);
|
|
||||||
}
|
|
||||||
|
|
||||||
// store the antenna weights
|
|
||||||
thisAntenna->SetBeamformingVector (antennaWeights);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,8 +189,8 @@ main (int argc, char *argv[])
|
|||||||
rxDev->SetNode (nodes.Get (1));
|
rxDev->SetNode (nodes.Get (1));
|
||||||
|
|
||||||
// create the antenna objects and set their dimensions
|
// create the antenna objects and set their dimensions
|
||||||
Ptr<ThreeGppAntennaArrayModel> txAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (-M_PI / 2));
|
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (-M_PI / 2));
|
||||||
Ptr<ThreeGppAntennaArrayModel> rxAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (M_PI / 2));
|
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (M_PI / 2));
|
||||||
|
|
||||||
Ptr<MobilityModel> txMob;
|
Ptr<MobilityModel> txMob;
|
||||||
Ptr<MobilityModel> rxMob;
|
Ptr<MobilityModel> rxMob;
|
||||||
|
|||||||
@@ -11,9 +11,27 @@ Overview
|
|||||||
|
|
||||||
The Antenna module provides:
|
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;
|
#. 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
|
antenna. Note that this radiation pattern is independent of the inclination angle
|
||||||
:math:`\theta`.
|
:math:`\theta`.
|
||||||
|
|
||||||
.. _sec-3gpp-antenna-model:
|
|
||||||
|
|
||||||
-------------------------
|
|
||||||
ThreeGppAntennaArrayModel
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
The class ThreeGppAntennaArrayModel implements the antenna model described in
|
ThreeGppAntennaModel
|
||||||
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
|
This model implements the antenna element described in [38901]_.
|
||||||
of a single panel with NxM elements, where N is the number of rows and M is the
|
Parameters are fixed from the technical report, thus no attributes nor setters are provided.
|
||||||
number of columns, configurable through the attributes "NumRows" and "NumColumns".
|
The model is largely based on the `ParabolicAntennaModel`_.
|
||||||
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}`).
|
Phased Array Model
|
||||||
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).
|
|
||||||
|
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
|
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",
|
direction, but the orientation can be changed through the attributes "BearingAngle",
|
||||||
which adjusts the azimuth angle, and "DowntiltAngle", which adjusts the elevation angle.
|
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 slant angle is instead fixed and assumed to be 0.
|
||||||
the attributes "AntennaHorizontalSpacing" and "AntennaVerticalSpacing".
|
|
||||||
|
|
||||||
**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.,
|
Note: vertical polarization is assumed for each antenna element, as described in [38901]_ (i.e., :math:`{\zeta = 0}`).
|
||||||
:math:`N_{g} = M_{g} = 1`.
|
|
||||||
|
|
||||||
* 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.
|
.. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design", Wiley, 2nd Ed.
|
||||||
|
|
||||||
|
|||||||
@@ -28,27 +28,139 @@ namespace ns3 {
|
|||||||
|
|
||||||
NS_LOG_COMPONENT_DEFINE ("Angles");
|
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<double>
|
||||||
|
DegreesToRadians (const std::vector<double> °rees)
|
||||||
|
{
|
||||||
|
std::vector<double> 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<double>
|
||||||
|
RadiansToDegrees (const std::vector<double> &radians)
|
||||||
{
|
{
|
||||||
return radians * 180.0 / M_PI;
|
std::vector<double> 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;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::istream &operator >> (std::istream &is, Angles &a)
|
std::istream&
|
||||||
|
operator>> (std::istream& is, Angles& a)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
is >> a.phi >> c >> a.theta;
|
is >> a.m_azimuth >> c >> a.m_inclination;
|
||||||
if (c != ':')
|
if (c != ':')
|
||||||
{
|
{
|
||||||
is.setstate (std::ios_base::failbit);
|
is.setstate (std::ios_base::failbit);
|
||||||
@@ -58,31 +170,98 @@ std::istream &operator >> (std::istream &is, Angles &a)
|
|||||||
|
|
||||||
|
|
||||||
Angles::Angles ()
|
Angles::Angles ()
|
||||||
: phi (0),
|
: Angles (NAN, NAN)
|
||||||
theta (0)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Angles::Angles (double p, double t)
|
Angles::Angles (double azimuth, double inclination)
|
||||||
: phi (p),
|
: m_azimuth (azimuth),
|
||||||
theta (t)
|
m_inclination (inclination)
|
||||||
{
|
{
|
||||||
|
NormalizeAngles ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Angles::Angles (Vector v)
|
Angles::Angles (Vector v)
|
||||||
: phi (std::atan2 (v.y, v.x)),
|
: m_azimuth (std::atan2 (v.y, v.x)),
|
||||||
theta (std::acos (v.z / v.GetLength ()))
|
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)
|
Angles::Angles (Vector v, Vector o)
|
||||||
: phi (std::atan2 (v.y - o.y, v.x - o.x)),
|
: Angles (v - o)
|
||||||
theta (std::acos ((v.z - o.z) / CalculateDistance (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <ns3/vector.h>
|
#include <ns3/vector.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace ns3 {
|
namespace ns3 {
|
||||||
|
|
||||||
@@ -31,63 +32,107 @@ namespace ns3 {
|
|||||||
* \brief converts degrees to radians
|
* \brief converts degrees to radians
|
||||||
*
|
*
|
||||||
* \param degrees the angle in degrees
|
* \param degrees the angle in degrees
|
||||||
*
|
|
||||||
* \return the angle in radians
|
* \return the angle in radians
|
||||||
*/
|
*/
|
||||||
double DegreesToRadians (double degrees);
|
double DegreesToRadians (double degrees);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief converts degrees to radians
|
||||||
|
*
|
||||||
|
* \param degrees the angles in degrees
|
||||||
|
* \return the angles in radians
|
||||||
|
*/
|
||||||
|
std::vector<double> DegreesToRadians (const std::vector<double> °rees);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief converts radians to degrees
|
* \brief converts radians to degrees
|
||||||
*
|
*
|
||||||
* \param radians the angle in radians
|
* \param radians the angle in radians
|
||||||
*
|
|
||||||
* \return the angle in degrees
|
* \return the angle in degrees
|
||||||
*/
|
*/
|
||||||
double RadiansToDegrees (double radians);
|
double RadiansToDegrees (double radians);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* \brief converts radians to degrees
|
||||||
*
|
*
|
||||||
* struct holding the azimuth and inclination angles of spherical
|
* \param radians the angles in radians
|
||||||
* coordinates. The notation is the one used in "Antenna Theory - Analysis
|
* \return the angles in degrees
|
||||||
* and Design", C.A. Balanis, Wiley, 2nd Ed., section 2.2 "Radiation
|
*/
|
||||||
* pattern".
|
std::vector<double> RadiansToDegrees (const std::vector<double> &radians);
|
||||||
* This notation corresponds to the standard spherical coordinates, with phi
|
|
||||||
|
/**
|
||||||
|
* \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
|
* 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 |
|
* z |
|
||||||
* |_ theta
|
* |_ inclination
|
||||||
* | \
|
* | \
|
||||||
* | /|
|
* | /|
|
||||||
* |/ | y
|
* |/ | 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
|
* This constructor will initialize azimuth and inclination by converting the
|
||||||
*
|
|
||||||
* \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
|
|
||||||
* given 3D vector from cartesian coordinates to spherical coordinates
|
* 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
|
* \param v the 3D vector in cartesian coordinates
|
||||||
*
|
*
|
||||||
@@ -95,7 +140,7 @@ struct Angles
|
|||||||
Angles (Vector v);
|
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
|
* of the spherical coordinates of point v respect to point o
|
||||||
*
|
*
|
||||||
* \param v the point (in cartesian coordinates) for which the angles are determined
|
* \param v the point (in cartesian coordinates) for which the angles are determined
|
||||||
@@ -105,40 +150,69 @@ struct Angles
|
|||||||
Angles (Vector v, Vector o);
|
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
|
} // namespace ns3
|
||||||
|
|
||||||
#endif // ANGLES_H
|
#endif // ANGLES_H
|
||||||
|
|||||||
@@ -34,19 +34,25 @@ NS_LOG_COMPONENT_DEFINE ("CosineAntennaModel");
|
|||||||
NS_OBJECT_ENSURE_REGISTERED (CosineAntennaModel);
|
NS_OBJECT_ENSURE_REGISTERED (CosineAntennaModel);
|
||||||
|
|
||||||
|
|
||||||
TypeId
|
TypeId
|
||||||
CosineAntennaModel::GetTypeId ()
|
CosineAntennaModel::GetTypeId ()
|
||||||
{
|
{
|
||||||
static TypeId tid = TypeId ("ns3::CosineAntennaModel")
|
static TypeId tid = TypeId ("ns3::CosineAntennaModel")
|
||||||
.SetParent<AntennaModel> ()
|
.SetParent<AntennaModel> ()
|
||||||
.SetGroupName("Antenna")
|
.SetGroupName ("Antenna")
|
||||||
.AddConstructor<CosineAntennaModel> ()
|
.AddConstructor<CosineAntennaModel> ()
|
||||||
.AddAttribute ("Beamwidth",
|
.AddAttribute ("VerticalBeamwidth",
|
||||||
"The 3dB beamwidth (degrees)",
|
"The 3 dB vertical beamwidth (degrees). A beamwidth of 360 deg corresponds to constant gain",
|
||||||
DoubleValue (60),
|
DoubleValue (360),
|
||||||
MakeDoubleAccessor (&CosineAntennaModel::SetBeamwidth,
|
MakeDoubleAccessor (&CosineAntennaModel::SetVerticalBeamwidth,
|
||||||
&CosineAntennaModel::GetBeamwidth),
|
&CosineAntennaModel::GetVerticalBeamwidth),
|
||||||
MakeDoubleChecker<double> (0, 180))
|
MakeDoubleChecker<double> (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<double> (0, 360))
|
||||||
.AddAttribute ("Orientation",
|
.AddAttribute ("Orientation",
|
||||||
"The angle (degrees) that expresses the orientation of the antenna on the x-y plane relative to the x axis",
|
"The angle (degrees) that expresses the orientation of the antenna on the x-y plane relative to the x axis",
|
||||||
DoubleValue (0.0),
|
DoubleValue (0.0),
|
||||||
@@ -62,67 +68,110 @@ CosineAntennaModel::GetTypeId ()
|
|||||||
return tid;
|
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
|
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)
|
CosineAntennaModel::SetOrientation (double orientationDegrees)
|
||||||
{
|
{
|
||||||
NS_LOG_FUNCTION (this << orientationDegrees);
|
NS_LOG_FUNCTION (this << orientationDegrees);
|
||||||
m_orientationRadians = DegreesToRadians (orientationDegrees);
|
m_orientationRadians = DegreesToRadians (orientationDegrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double
|
double
|
||||||
CosineAntennaModel::GetOrientation () const
|
CosineAntennaModel::GetOrientation () const
|
||||||
{
|
{
|
||||||
return RadiansToDegrees (m_orientationRadians);
|
return RadiansToDegrees (m_orientationRadians);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
|
||||||
|
double
|
||||||
CosineAntennaModel::GetGainDb (Angles a)
|
CosineAntennaModel::GetGainDb (Angles a)
|
||||||
{
|
{
|
||||||
NS_LOG_FUNCTION (this << 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]
|
// make sure phi is in (-pi, pi]
|
||||||
while (phi <= -M_PI)
|
a.SetAzimuth (a.GetAzimuth () - m_orientationRadians);
|
||||||
{
|
|
||||||
phi += M_PI+M_PI;
|
|
||||||
}
|
|
||||||
while (phi > M_PI)
|
|
||||||
{
|
|
||||||
phi -= M_PI+M_PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_LOG_LOGIC ("phi = " << phi );
|
NS_LOG_LOGIC (a);
|
||||||
|
|
||||||
// element factor: amplitude gain of a single antenna element in linear units
|
// The element power gain is computed as a product of cosine functions on the two axis
|
||||||
double ef = std::pow (std::cos (phi / 2.0), m_exponent);
|
// The power pattern of the element is equal to:
|
||||||
|
// P(az,el) = cos(az/2)^2m * cos(pi/2 - incl/2)^2n,
|
||||||
// the array factor is not considered. Note that if we did consider
|
// where az is the azimuth angle, and incl is the inclination angle.
|
||||||
// the array factor, the actual beamwidth would change, and in
|
double gain = (std::pow (std::cos (a.GetAzimuth () / 2), 2 * m_horizontalExponent)) *
|
||||||
// particular it would be different from the one specified by the
|
(std::pow (std::cos ((M_PI / 2 - a.GetInclination ()) / 2), 2 * m_verticalExponent));
|
||||||
// user. Hence it is not desirable to use the array factor, for the
|
double gainDb = 10 * std::log10 (gain);
|
||||||
// ease of use of this model.
|
|
||||||
|
|
||||||
double gainDb = 20 * std::log10 (ef);
|
|
||||||
NS_LOG_LOGIC ("gain = " << gainDb << " + " << m_maxGain << " dB");
|
NS_LOG_LOGIC ("gain = " << gainDb << " + " << m_maxGain << " dB");
|
||||||
return gainDb + m_maxGain;
|
return gainDb + m_maxGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,48 +28,89 @@
|
|||||||
namespace ns3 {
|
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
|
* The power pattern of the element is equal to:
|
||||||
* considered. Also, an additional constant gain is added to model the
|
// P(az,el) = cos(az/2)^2m * cos(pi/2 - incl/2)^2n,
|
||||||
* radiation pattern on the vertical plane (to account for the fact
|
// where az is the azimuth angle, and incl is the inclination angle.
|
||||||
* that the elevation angle is not included in the model).
|
*
|
||||||
|
* 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
|
class CosineAntennaModel : public AntennaModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// inherited from Object
|
// inherited from Object
|
||||||
static TypeId GetTypeId ();
|
static TypeId GetTypeId ();
|
||||||
|
|
||||||
// inherited from AntennaModel
|
// inherited from AntennaModel
|
||||||
virtual double GetGainDb (Angles a);
|
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);
|
* Get the horizontal 3 dB beamwidth of the cosine antenna model.
|
||||||
double GetBeamwidth () const;
|
* \return the horizontal beamwidth in degrees
|
||||||
void SetOrientation (double orientationDegrees);
|
*/
|
||||||
double GetOrientation () const;
|
double GetHorizontalBeamwidth (void) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the horizontal orientation of the antenna element.
|
||||||
|
* \return the horizontal orientation in degrees
|
||||||
|
*/
|
||||||
|
double GetOrientation (void) const;
|
||||||
|
|
||||||
private:
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ ParabolicAntennaModel::GetGainDb (Angles a)
|
|||||||
{
|
{
|
||||||
NS_LOG_FUNCTION (this << a);
|
NS_LOG_FUNCTION (this << a);
|
||||||
// azimuth angle w.r.t. the reference system of the antenna
|
// 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]
|
// make sure phi is in (-pi, pi]
|
||||||
while (phi <= -M_PI)
|
while (phi <= -M_PI)
|
||||||
|
|||||||
169
src/antenna/model/phased-array-model.cc
Normal file
169
src/antenna/model/phased-array-model.cc
Normal file
@@ -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 <ns3/isotropic-antenna-model.h>
|
||||||
|
#include <ns3/log.h>
|
||||||
|
#include <ns3/double.h>
|
||||||
|
#include <ns3/uinteger.h>
|
||||||
|
#include <ns3/boolean.h>
|
||||||
|
#include <ns3/pointer.h>
|
||||||
|
|
||||||
|
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<Object> ()
|
||||||
|
.SetGroupName ("Antenna")
|
||||||
|
.AddAttribute ("AntennaElement",
|
||||||
|
"A pointer to the antenna element used by the phased array",
|
||||||
|
PointerValue (CreateObject<IsotropicAntennaModel> ()),
|
||||||
|
MakePointerAccessor (&PhasedArrayModel::m_antennaElement),
|
||||||
|
MakePointerChecker<AntennaModel> ())
|
||||||
|
;
|
||||||
|
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<double> (1.0, phase);
|
||||||
|
}
|
||||||
|
return steeringVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PhasedArrayModel::SetAntennaElement (Ptr<AntennaModel> antennaElement)
|
||||||
|
{
|
||||||
|
NS_LOG_FUNCTION (this);
|
||||||
|
m_antennaElement = antennaElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ptr<const AntennaModel>
|
||||||
|
PhasedArrayModel::GetAntennaElement () const
|
||||||
|
{
|
||||||
|
NS_LOG_FUNCTION (this);
|
||||||
|
return m_antennaElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace ns3 */
|
||||||
|
|
||||||
145
src/antenna/model/phased-array-model.h
Normal file
145
src/antenna/model/phased-array-model.h
Normal file
@@ -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 <ns3/object.h>
|
||||||
|
#include <ns3/angles.h>
|
||||||
|
#include <complex>
|
||||||
|
#include <ns3/antenna-model.h>
|
||||||
|
|
||||||
|
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<std::complex<double> > 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<double, double> 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<AntennaModel> antennaElement);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the AntennaModel instance used to model the elements of the array
|
||||||
|
* \return pointer to the AntennaModel instance
|
||||||
|
*/
|
||||||
|
Ptr<const AntennaModel> 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<AntennaModel> 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 */
|
||||||
@@ -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<Object> ()
|
|
||||||
.AddConstructor<ThreeGppAntennaArrayModel> ()
|
|
||||||
.AddAttribute ("AntennaHorizontalSpacing",
|
|
||||||
"Horizontal spacing between antenna elements, in multiples of wave length",
|
|
||||||
DoubleValue (0.5),
|
|
||||||
MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disH),
|
|
||||||
MakeDoubleChecker<double> ())
|
|
||||||
.AddAttribute ("AntennaVerticalSpacing",
|
|
||||||
"Vertical spacing between antenna elements, in multiples of wave length",
|
|
||||||
DoubleValue (0.5),
|
|
||||||
MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disV),
|
|
||||||
MakeDoubleChecker<double> ())
|
|
||||||
.AddAttribute ("NumColumns",
|
|
||||||
"Horizontal size of the array",
|
|
||||||
UintegerValue (4),
|
|
||||||
MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numColumns),
|
|
||||||
MakeUintegerChecker<uint32_t> ())
|
|
||||||
.AddAttribute ("NumRows",
|
|
||||||
"Vertical size of the array",
|
|
||||||
UintegerValue (4),
|
|
||||||
MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numRows),
|
|
||||||
MakeUintegerChecker<uint32_t> ())
|
|
||||||
.AddAttribute ("BearingAngle",
|
|
||||||
"The bearing angle in radians",
|
|
||||||
DoubleValue (0.0),
|
|
||||||
MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_alpha),
|
|
||||||
MakeDoubleChecker<double> (-M_PI, M_PI))
|
|
||||||
.AddAttribute ("DowntiltAngle",
|
|
||||||
"The downtilt angle in radians",
|
|
||||||
DoubleValue (0.0),
|
|
||||||
MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_beta),
|
|
||||||
MakeDoubleChecker<double> (0, M_PI))
|
|
||||||
.AddAttribute ("ElementGain",
|
|
||||||
"Directional gain of an antenna element in dBi",
|
|
||||||
DoubleValue (4.97),
|
|
||||||
MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_gE),
|
|
||||||
MakeDoubleChecker<double> (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<double, double>
|
|
||||||
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<double> (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<double> (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 */
|
|
||||||
@@ -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 <ns3/antenna-model.h>
|
|
||||||
#include <complex>
|
|
||||||
|
|
||||||
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<std::complex<double> > 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<double, double> 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_ */
|
|
||||||
118
src/antenna/model/three-gpp-antenna-model.cc
Normal file
118
src/antenna/model/three-gpp-antenna-model.cc
Normal file
@@ -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 <ns3/log.h>
|
||||||
|
#include <ns3/double.h>
|
||||||
|
#include <cmath>
|
||||||
|
#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<AntennaModel> ()
|
||||||
|
.SetGroupName ("Antenna")
|
||||||
|
.AddConstructor<ThreeGppAntennaModel> ()
|
||||||
|
;
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
90
src/antenna/model/three-gpp-antenna-model.h
Normal file
90
src/antenna/model/three-gpp-antenna-model.h
Normal file
@@ -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 <ns3/object.h>
|
||||||
|
#include <ns3/antenna-model.h>
|
||||||
|
|
||||||
|
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
|
||||||
233
src/antenna/model/uniform-planar-array.cc
Normal file
233
src/antenna/model/uniform-planar-array.cc
Normal file
@@ -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 <ns3/log.h>
|
||||||
|
#include <ns3/double.h>
|
||||||
|
#include <ns3/uinteger.h>
|
||||||
|
#include <ns3/boolean.h>
|
||||||
|
|
||||||
|
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<PhasedArrayModel> ()
|
||||||
|
.AddConstructor<UniformPlanarArray> ()
|
||||||
|
.SetGroupName ("Antenna")
|
||||||
|
.AddAttribute ("AntennaHorizontalSpacing",
|
||||||
|
"Horizontal spacing between antenna elements, in multiples of wave length",
|
||||||
|
DoubleValue (0.5),
|
||||||
|
MakeDoubleAccessor (&UniformPlanarArray::SetAntennaHorizontalSpacing,
|
||||||
|
&UniformPlanarArray::GetAntennaHorizontalSpacing),
|
||||||
|
MakeDoubleChecker<double> (0.0))
|
||||||
|
.AddAttribute ("AntennaVerticalSpacing",
|
||||||
|
"Vertical spacing between antenna elements, in multiples of wave length",
|
||||||
|
DoubleValue (0.5),
|
||||||
|
MakeDoubleAccessor (&UniformPlanarArray::SetAntennaVerticalSpacing,
|
||||||
|
&UniformPlanarArray::GetAntennaVerticalSpacing),
|
||||||
|
MakeDoubleChecker<double> (0.0))
|
||||||
|
.AddAttribute ("NumColumns",
|
||||||
|
"Horizontal size of the array",
|
||||||
|
UintegerValue (4),
|
||||||
|
MakeUintegerAccessor (&UniformPlanarArray::SetNumColumns,
|
||||||
|
&UniformPlanarArray::GetNumColumns),
|
||||||
|
MakeUintegerChecker<uint32_t> (1))
|
||||||
|
.AddAttribute ("NumRows",
|
||||||
|
"Vertical size of the array",
|
||||||
|
UintegerValue (4),
|
||||||
|
MakeUintegerAccessor (&UniformPlanarArray::SetNumRows,
|
||||||
|
&UniformPlanarArray::GetNumRows),
|
||||||
|
MakeUintegerChecker<uint32_t> (1))
|
||||||
|
.AddAttribute ("BearingAngle",
|
||||||
|
"The bearing angle in radians",
|
||||||
|
DoubleValue (0.0),
|
||||||
|
MakeDoubleAccessor (&UniformPlanarArray::m_alpha),
|
||||||
|
MakeDoubleChecker<double> (-M_PI, M_PI))
|
||||||
|
.AddAttribute ("DowntiltAngle",
|
||||||
|
"The downtilt angle in radians",
|
||||||
|
DoubleValue (0.0),
|
||||||
|
MakeDoubleAccessor (&UniformPlanarArray::m_beta),
|
||||||
|
MakeDoubleChecker<double> (-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<double, double>
|
||||||
|
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<double> (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<double> (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 */
|
||||||
166
src/antenna/model/uniform-planar-array.h
Normal file
166
src/antenna/model/uniform-planar-array.h
Normal file
@@ -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 <ns3/object.h>
|
||||||
|
#include <ns3/phased-array-model.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<double, double> 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 */
|
||||||
@@ -44,7 +44,7 @@ private:
|
|||||||
std::string OneVectorConstructorTestCase::BuildNameString (Vector v)
|
std::string OneVectorConstructorTestCase::BuildNameString (Vector v)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << " v = " << v;
|
oss << " v = " << v;
|
||||||
return oss.str ();
|
return oss.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,15 +53,14 @@ OneVectorConstructorTestCase::OneVectorConstructorTestCase (Vector v, Angles a)
|
|||||||
: TestCase (BuildNameString (v)),
|
: TestCase (BuildNameString (v)),
|
||||||
m_v (v),
|
m_v (v),
|
||||||
m_a (a)
|
m_a (a)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OneVectorConstructorTestCase::DoRun ()
|
OneVectorConstructorTestCase::DoRun ()
|
||||||
{
|
{
|
||||||
Angles a (m_v);
|
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.GetAzimuth (), m_a.GetAzimuth (), 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.GetInclination (), m_a.GetInclination (), 1e-10, "incorrect theta");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -85,7 +84,7 @@ private:
|
|||||||
std::string TwoVectorsConstructorTestCase::BuildNameString (Vector v, Vector o)
|
std::string TwoVectorsConstructorTestCase::BuildNameString (Vector v, Vector o)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << " v = " << v << ", o = " << o;
|
oss << " v = " << v << ", o = " << o;
|
||||||
return oss.str ();
|
return oss.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,15 +94,14 @@ TwoVectorsConstructorTestCase::TwoVectorsConstructorTestCase (Vector v, Vector o
|
|||||||
m_v (v),
|
m_v (v),
|
||||||
m_o (o),
|
m_o (o),
|
||||||
m_a (a)
|
m_a (a)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TwoVectorsConstructorTestCase::DoRun ()
|
TwoVectorsConstructorTestCase::DoRun ()
|
||||||
{
|
{
|
||||||
Angles a (m_v, m_o);
|
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.GetAzimuth (), m_a.GetAzimuth (), 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.GetInclination (), m_a.GetInclination (), 1e-10, "incorrect theta");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -120,92 +118,92 @@ public:
|
|||||||
AnglesTestSuite::AnglesTestSuite ()
|
AnglesTestSuite::AnglesTestSuite ()
|
||||||
: TestSuite ("angles", UNIT)
|
: 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 (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 (-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, -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, 0)), TestCase::QUICK);
|
||||||
AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -1), Angles (0, M_PI)), 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 (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 (-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, -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, 0)), TestCase::QUICK);
|
||||||
AddTestCase (new OneVectorConstructorTestCase (Vector (0, 0, -2), Angles (0, M_PI)), 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, 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, 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, -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, 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, 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 (-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, 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, 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, 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, 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, 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, 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, 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 (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 (-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, -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, 0)), TestCase::QUICK);
|
||||||
AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -1), Vector (0, 0, 0), Angles (0, M_PI)), 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 (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 (-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, -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, 0)), TestCase::QUICK);
|
||||||
AddTestCase (new TwoVectorsConstructorTestCase (Vector (0, 0, -2), Vector (0, 0, 0), Angles (0, M_PI)), 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, 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, 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, -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, 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, 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 (-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, 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, 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, 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, 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, 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, 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, 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 (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 (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 (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 (-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 (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 (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, -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, 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 (-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 (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 (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 (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 (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;
|
static AnglesTestSuite staticAnglesTestSuiteInstance;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ private:
|
|||||||
std::string CosineAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g)
|
std::string CosineAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "theta=" << a.theta << " , phi=" << a.phi
|
oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth ()
|
||||||
<< ", beamdwidth=" << b << "deg"
|
<< ", beamdwidth=" << b << "deg"
|
||||||
<< ", orientation=" << o
|
<< ", orientation=" << o
|
||||||
<< ", maxGain=" << g << " dB";
|
<< ", maxGain=" << g << " dB";
|
||||||
@@ -84,7 +84,8 @@ CosineAntennaModelTestCase::DoRun ()
|
|||||||
NS_LOG_FUNCTION (this << BuildNameString (m_a, m_b, m_o, m_g));
|
NS_LOG_FUNCTION (this << BuildNameString (m_a, m_b, m_o, m_g));
|
||||||
|
|
||||||
Ptr<CosineAntennaModel> a = CreateObject<CosineAntennaModel> ();
|
Ptr<CosineAntennaModel> a = CreateObject<CosineAntennaModel> ();
|
||||||
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 ("Orientation", DoubleValue (m_o));
|
||||||
a->SetAttribute ("MaxGain", DoubleValue (m_g));
|
a->SetAttribute ("MaxGain", DoubleValue (m_g));
|
||||||
double actualGain = a->GetGainDb (m_a);
|
double actualGain = a->GetGainDb (m_a);
|
||||||
@@ -117,89 +118,96 @@ CosineAntennaModelTestSuite::CosineAntennaModelTestSuite ()
|
|||||||
// phideg = (2*acos(10^(targetgaindb/(20*n))))*180/pi
|
// 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
|
// e.g., with a 60 deg beamwidth, gain is -20dB at +- 74.945 degrees from boresight
|
||||||
|
|
||||||
// phi, theta, beamwidth, orientation, maxGain, expectedGain, condition
|
// 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 (0), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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 (100), DegreesToRadians (90)), 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 (150), DegreesToRadians (90)), 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 (180), DegreesToRadians (90)), 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 (-100), DegreesToRadians (90)), 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 (-150), DegreesToRadians (90)), 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 (-180), DegreesToRadians (90)), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK);
|
||||||
|
|
||||||
// test positive orientation
|
// test positive orientation
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 60, 60, 0, 0, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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 (150), DegreesToRadians (90)), 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 (160), DegreesToRadians (90)), 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 (210), DegreesToRadians (90)), 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 (240), DegreesToRadians (90)), 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 (-40), DegreesToRadians (90)), 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 (-90), DegreesToRadians (90)), 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 (-120), DegreesToRadians (90)), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK);
|
||||||
|
|
||||||
// test negative orientation and different beamwidths
|
// test negative orientation and different beamwidths
|
||||||
// with a 100 deg beamwidth, gain is -20dB at +- 117.47 degrees from boresight
|
// 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 (-150), DegreesToRadians (90)), 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 (-100), DegreesToRadians (90)), 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 (-200), DegreesToRadians (90)), 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 (-32.531),DegreesToRadians (90)), 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 (92.531), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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 (0), DegreesToRadians (90)), 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 (60), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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 (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
|
// 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 (-150), DegreesToRadians (90)), 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 (135), DegreesToRadians (90)), 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 (-75), DegreesToRadians (90)), 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 (85.070), DegreesToRadians (90)), 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 (-25.070),DegreesToRadians (90)), 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 (5.3230), DegreesToRadians (90)), 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 (54.677), DegreesToRadians (90)), 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 (30), DegreesToRadians (90)), 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 (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
|
// test maxGain
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 0), 60, 0, 10, 10, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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 (100), DegreesToRadians (90)), 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 (-150), DegreesToRadians (90)), 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 (-100), DegreesToRadians (90)), 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 (-200), DegreesToRadians (90)), 100, -150, -1, -4, EQUAL), TestCase::QUICK);
|
||||||
|
|
||||||
|
|
||||||
// test elevation angle
|
// test elevation angle
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 2), 60, 0, 0, 0, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (60)), 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 (30), DegreesToRadians (60)), 60, 0, 0, -6, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 2), 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 (-90), 2), 60, 0, 0, -20, LESSTHAN), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (60)), 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 (-180), DegreesToRadians (60)), 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 (60), DegreesToRadians (120)), 60, 60, 0, -3, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), -3), 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), -3), 60, 60, 0, -3, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (120)), 60, 60, 0, -6, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), -3), 60, 60, 0, -20, LESSTHAN), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-120), DegreesToRadians (120)), 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 (-150), DegreesToRadians (140)), 100, -150, 0, -3, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), -3), 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), -3), 100, -150, 0, -3, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), DegreesToRadians (140)), 100, -150, 0, -6, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), -3), 100, -150, 0, -20, LESSTHAN), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (140)), 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), DegreesToRadians (60)), 60, 0, 10, 7, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (0), 9.5), 60, 0, 10, 10, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), DegreesToRadians (60)), 60, 0, 22, 16, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (30), 9.5), 60, 0, 22, 19, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), DegreesToRadians (60)), 60, 0, -4, -10, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-30), 9.5), 60, 0, -4, -7, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-90), DegreesToRadians (60)), 60, 0, 10, -13, LESSTHAN), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), 9.5), 60, 0, 40, 20, LESSTHAN), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (90), DegreesToRadians (60)), 60, 0, -20, -43, LESSTHAN), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), 9.5), 100, -150, 2, 2, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (100), DegreesToRadians (60)), 60, 0, 40, 17, LESSTHAN), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-100), 9.5), 100, -150, 4, 1, EQUAL), TestCase::QUICK);
|
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-150), DegreesToRadians (40)), 100, -150, 2, -1, EQUAL), TestCase::QUICK);
|
||||||
AddTestCase (new CosineAntennaModelTestCase (Angles (DegreesToRadians (-200), 9.5), 100, -150, -1, -4, 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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ private:
|
|||||||
std::string IsotropicAntennaModelTestCase::BuildNameString (Angles a)
|
std::string IsotropicAntennaModelTestCase::BuildNameString (Angles a)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "theta=" << a.theta << " , phi=" << a.phi;
|
oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth ();
|
||||||
return oss.str ();
|
return oss.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ private:
|
|||||||
std::string ParabolicAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g)
|
std::string ParabolicAntennaModelTestCase::BuildNameString (Angles a, double b, double o, double g)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "theta=" << a.theta << " , phi=" << a.phi
|
oss << "theta=" << a.GetInclination () << " , phi=" << a.GetAzimuth ()
|
||||||
<< ", beamdwidth=" << b << "deg"
|
<< ", beamdwidth=" << b << "deg"
|
||||||
<< ", orientation=" << o
|
<< ", orientation=" << o
|
||||||
<< ", maxAttenuation=" << g << " dB";
|
<< ", maxAttenuation=" << g << " dB";
|
||||||
@@ -115,70 +115,70 @@ ParabolicAntennaModelTestSuite::ParabolicAntennaModelTestSuite ()
|
|||||||
{
|
{
|
||||||
|
|
||||||
// with a 60 deg beamwidth, gain is -20dB at +-77.460 degrees from boresight
|
// with a 60 deg beamwidth, gain is -20dB at +-77.460 degrees from boresight
|
||||||
// phi, theta, beamwidth, orientation, maxAttn, expectedGain, condition
|
// 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 (0), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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 (100), DegreesToRadians (90)), 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 (150), DegreesToRadians (90)), 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 (180), DegreesToRadians (90)), 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 (-100), DegreesToRadians (90)), 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 (-150), DegreesToRadians (90)), 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 (-180), DegreesToRadians (90)), 60, 0, 20, -20, EQUAL), TestCase::QUICK);
|
||||||
|
|
||||||
// with a 60 deg beamwidth, gain is -10dB at +-54.772 degrees from boresight
|
// with a 60 deg beamwidth, gain is -10dB at +-54.772 degrees from boresight
|
||||||
// test positive orientation
|
// test positive orientation
|
||||||
AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), 0), 60, 60, 10, 0, EQUAL), TestCase::QUICK);
|
AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (60), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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 (150), DegreesToRadians (90)), 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 (160), DegreesToRadians (90)), 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 (210), DegreesToRadians (90)), 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 (240), DegreesToRadians (90)), 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 (-40), DegreesToRadians (90)), 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 (-90), DegreesToRadians (90)), 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 (-120), DegreesToRadians (90)), 60, 60, 10, -10, EQUAL), TestCase::QUICK);
|
||||||
|
|
||||||
// test negative orientation and different beamwidths
|
// test negative orientation and different beamwidths
|
||||||
// with a 80 deg beamwidth, gain is -20dB at +- 73.030 degrees from boresight
|
// 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 (-150), DegreesToRadians (90)), 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 (-110), DegreesToRadians (90)), 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 (-190), DegreesToRadians (90)), 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 (-70), DegreesToRadians (90)), 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 (92), DegreesToRadians (90)), 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 (-30), DegreesToRadians (90)), 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 (0), DegreesToRadians (90)), 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 (60), DegreesToRadians (90)), 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 (90), DegreesToRadians (90)), 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 (30), DegreesToRadians (90)), 80, -150, 10, -10, EQUAL), TestCase::QUICK);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// test elevation angle
|
// test elevation angle
|
||||||
AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), 2), 60, 0, 20, 0, EQUAL), TestCase::QUICK);
|
AddTestCase (new ParabolicAntennaModelTestCase (Angles (DegreesToRadians (0), DegreesToRadians (88)), 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), DegreesToRadians (88)), 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 (-30), DegreesToRadians (88)), 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 (-90), DegreesToRadians (88)), 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 (-180), DegreesToRadians (88)), 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 (60), DegreesToRadians (93)), 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 (90), DegreesToRadians (93)), 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 (30), DegreesToRadians (93)), 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 (-120), DegreesToRadians (93)), 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 (-150), DegreesToRadians (93)), 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 (-100), DegreesToRadians (93)), 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 (-200), DegreesToRadians (93)), 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 (-30), DegreesToRadians (93)), 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 (90), DegreesToRadians (80.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 (0), DegreesToRadians (80.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), DegreesToRadians (80.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 (-30), DegreesToRadians (80.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 (100), DegreesToRadians (80.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 (-150), DegreesToRadians (80.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 (-100), DegreesToRadians (80.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 (-200), DegreesToRadians (80.5)), 100, -150, 30, -3, EQUAL), TestCase::QUICK);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
216
src/antenna/test/test-uniform-planar-array.cc
Normal file
216
src/antenna/test/test-uniform-planar-array.cc
Normal file
@@ -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<AntennaModel> 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<AntennaModel> 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<UniformPlanarArray> a);
|
||||||
|
|
||||||
|
Ptr<AntennaModel> 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<AntennaModel> 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<AntennaModel> 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<UniformPlanarArray> 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<double, double> fp = a->GetElementFieldPattern (m_direction);
|
||||||
|
|
||||||
|
// scalar product dot (sv, bf)
|
||||||
|
std::complex<double> 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<UniformPlanarArray> a = CreateObject<UniformPlanarArray> ();
|
||||||
|
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<AntennaModel> isotropic = CreateObject<IsotropicAntennaModel> ();
|
||||||
|
Ptr<AntennaModel> tgpp = CreateObject<ThreeGppAntennaModel> ();
|
||||||
|
|
||||||
|
// 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;
|
||||||
@@ -10,7 +10,9 @@ def build(bld):
|
|||||||
'model/isotropic-antenna-model.cc',
|
'model/isotropic-antenna-model.cc',
|
||||||
'model/cosine-antenna-model.cc',
|
'model/cosine-antenna-model.cc',
|
||||||
'model/parabolic-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')
|
module_test = bld.create_ns3_module_test_library('antenna')
|
||||||
@@ -20,6 +22,7 @@ def build(bld):
|
|||||||
'test/test-isotropic-antenna.cc',
|
'test/test-isotropic-antenna.cc',
|
||||||
'test/test-cosine-antenna.cc',
|
'test/test-cosine-antenna.cc',
|
||||||
'test/test-parabolic-antenna.cc',
|
'test/test-parabolic-antenna.cc',
|
||||||
|
'test/test-uniform-planar-array.cc',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Tests encapsulating example programs should be listed here
|
# Tests encapsulating example programs should be listed here
|
||||||
@@ -36,7 +39,9 @@ def build(bld):
|
|||||||
'model/isotropic-antenna-model.h',
|
'model/isotropic-antenna-model.h',
|
||||||
'model/cosine-antenna-model.h',
|
'model/cosine-antenna-model.h',
|
||||||
'model/parabolic-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()
|
bld.ns3_python_bindings()
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ using std::vector;
|
|||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
CommandLine cmd (__FILE__);
|
CommandLine cmd;
|
||||||
cmd.Parse (argc, argv);
|
cmd.Parse (argc, argv);
|
||||||
|
|
||||||
ConfigStore inputConfig;
|
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
|
// Beam width is made quite narrow so sectors can be noticed in the REM
|
||||||
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (0));
|
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (0));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100));
|
lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
||||||
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (0)));
|
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (0)));
|
||||||
|
|
||||||
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (360/3));
|
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (360/3));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100));
|
lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
||||||
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (1)));
|
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (1)));
|
||||||
|
|
||||||
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (2*360/3));
|
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (2*360/3));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (100));
|
lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (100));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
||||||
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (2)));
|
enbDevs.Add ( lteHelper->InstallEnbDevice (threeSectorNodes.Get (2)));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < nEnb; i++)
|
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
|
// by default, simulation will anyway stop right after the REM has been generated
|
||||||
Simulator::Stop (Seconds (0.0069));
|
Simulator::Stop (Seconds (0.0069));
|
||||||
|
|
||||||
Ptr<RadioEnvironmentMapHelper> remHelper = CreateObject<RadioEnvironmentMapHelper> ();
|
Ptr<RadioEnvironmentMapHelper> remHelper = CreateObject<RadioEnvironmentMapHelper> ();
|
||||||
remHelper->SetAttribute ("ChannelPath", StringValue ("/ChannelList/0"));
|
remHelper->SetAttribute ("ChannelPath", StringValue ("/ChannelList/0"));
|
||||||
|
|||||||
@@ -158,8 +158,12 @@ LteEnbAntennaTestCase::DoRun (void)
|
|||||||
lteHelper->SetSchedulerAttribute ("UlCqiFilter", EnumValue (FfMacScheduler::PUSCH_UL_CQI));
|
lteHelper->SetSchedulerAttribute ("UlCqiFilter", EnumValue (FfMacScheduler::PUSCH_UL_CQI));
|
||||||
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
lteHelper->SetEnbAntennaModelType ("ns3::CosineAntennaModel");
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (m_orientationDegrees));
|
lteHelper->SetEnbAntennaModelAttribute ("Orientation", DoubleValue (m_orientationDegrees));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("Beamwidth", DoubleValue (m_beamwidthDegrees));
|
lteHelper->SetEnbAntennaModelAttribute ("HorizontalBeamwidth", DoubleValue (m_beamwidthDegrees));
|
||||||
lteHelper->SetEnbAntennaModelAttribute ("MaxGain", DoubleValue (0.0));
|
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);
|
enbDevs = lteHelper->InstallEnbDevice (enbNodes);
|
||||||
ueDevs = lteHelper->InstallUeDevice (ueNodes);
|
ueDevs = lteHelper->InstallUeDevice (ueNodes);
|
||||||
@@ -220,6 +224,7 @@ LteEnbAntennaTestCase::DoRun (void)
|
|||||||
}
|
}
|
||||||
// remember that propagation loss is 0dB
|
// remember that propagation loss is 0dB
|
||||||
double calculatedAntennaGainDbDl = - (enbTxPowerDbm - calculatedSinrDbDl - noisePowerDbm - ueNoiseFigureDb);
|
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!");
|
NS_TEST_ASSERT_MSG_EQ_TOL (calculatedAntennaGainDbDl, m_antennaGainDb, tolerance, "Wrong DL antenna gain!");
|
||||||
}
|
}
|
||||||
double expectedSinrUl = ueTxPowerDbm + m_antennaGainDb - noisePowerDbm + enbNoiseFigureDb;
|
double expectedSinrUl = ueTxPowerDbm + m_antennaGainDb - noisePowerDbm + enbNoiseFigureDb;
|
||||||
|
|||||||
@@ -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
|
test suite by verifying that the generated points do not exceed the given
|
||||||
maximum distance radius from the origin point.
|
maximum distance radius from the origin point.
|
||||||
|
|
||||||
.. _sec-3gpp-fast-fading-model:
|
|
||||||
|
|
||||||
3GPP TR 38.901 fast fading model
|
3GPP TR 38.901 fast fading model
|
||||||
================================
|
================================
|
||||||
The framework described by TR 38.901 [TR38901]_ is a 3D statistical Spatial
|
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
|
* 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
|
(2018-06) section 7.6.4.1, the blocking region for self-blocking is provided
|
||||||
in LCS.
|
in LCS.
|
||||||
|
|
||||||
However, here, clusterAOA and clusterZOA are in GCS and blocking check is
|
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.
|
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
|
One would expect the angles to be transposed to LCS before checking
|
||||||
self-blockage.
|
self-blockage.
|
||||||
|
|
||||||
|
|
||||||
ThreeGppSpectrumPropagationLossModel
|
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
|
antenna objects associated to the transmitting and receiving devices, and calls
|
||||||
the method GetCurrentBeamformingVector to retrieve the beamforming vectors.
|
the method GetCurrentBeamformingVector to retrieve the beamforming vectors.
|
||||||
For each device using the channel, the m_deviceAntennaMap contains the associated
|
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 model supports a single antenna object for each device.
|
||||||
The m_deviceAntennaMap has to be initialized by inserting the device-antenna
|
The m_deviceAntennaMap has to be initialized by inserting the device-antenna
|
||||||
pairs using the method AddDevice.
|
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"
|
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).
|
(by default it is set to 0, so that the scattering effect is not considered).
|
||||||
|
|
||||||
|
|
||||||
ThreeGppChannelModel
|
ThreeGppChannelModel
|
||||||
####################
|
####################
|
||||||
|
|
||||||
@@ -760,7 +759,7 @@ The test suite ThreeGppChannelTestSuite includes three test cases:
|
|||||||
of the class ThreeGppSpectrumPropagationLossModel. It builds a simple
|
of the class ThreeGppSpectrumPropagationLossModel. It builds a simple
|
||||||
network composed of two nodes, computes the power spectral density
|
network composed of two nodes, computes the power spectral density
|
||||||
received by the receiving node, and
|
received by the receiving node, and
|
||||||
|
|
||||||
1. Checks if the long term components for the direct and
|
1. Checks if the long term components for the direct and
|
||||||
the reverse link are the same,
|
the reverse link are the same,
|
||||||
2. Checks if the long term component is updated when changing
|
2. Checks if the long term component is updated when changing
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#include "ns3/core-module.h"
|
#include "ns3/core-module.h"
|
||||||
#include "ns3/three-gpp-channel-model.h"
|
#include "ns3/three-gpp-channel-model.h"
|
||||||
#include "ns3/three-gpp-antenna-array-model.h"
|
#include "ns3/uniform-planar-array.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
|
#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
|
||||||
#include "ns3/net-device.h"
|
#include "ns3/net-device.h"
|
||||||
@@ -57,9 +57,9 @@ static Ptr<ThreeGppSpectrumPropagationLossModel> m_spectrumLossModel; //!< the S
|
|||||||
* \param otherDevice the device towards which point the beam
|
* \param otherDevice the device towards which point the beam
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAntenna, Ptr<NetDevice> otherDevice)
|
DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<PhasedArrayModel> thisAntenna, Ptr<NetDevice> otherDevice)
|
||||||
{
|
{
|
||||||
ThreeGppAntennaArrayModel::ComplexVector antennaWeights;
|
PhasedArrayModel::ComplexVector antennaWeights;
|
||||||
|
|
||||||
// retrieve the position of the two devices
|
// retrieve the position of the two devices
|
||||||
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
||||||
@@ -67,13 +67,9 @@ DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAnt
|
|||||||
|
|
||||||
// compute the azimuth and the elevation angles
|
// compute the azimuth and the elevation angles
|
||||||
Angles completeAngle (bPos,aPos);
|
Angles completeAngle (bPos,aPos);
|
||||||
|
double hAngleRadian = completeAngle.GetAzimuth ();
|
||||||
double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle
|
|
||||||
if (hAngleRadian < 0)
|
double vAngleRadian = completeAngle.GetInclination (); // the elevation angle
|
||||||
{
|
|
||||||
hAngleRadian += 2.0 * M_PI;
|
|
||||||
}
|
|
||||||
double vAngleRadian = completeAngle.theta; // the elevation angle
|
|
||||||
|
|
||||||
// retrieve the number of antenna elements
|
// retrieve the number of antenna elements
|
||||||
int totNoArrayElements = thisAntenna->GetNumberOfElements ();
|
int totNoArrayElements = thisAntenna->GetNumberOfElements ();
|
||||||
@@ -232,8 +228,8 @@ main (int argc, char *argv[])
|
|||||||
nodes.Get (1)->AggregateObject (rxMob);
|
nodes.Get (1)->AggregateObject (rxMob);
|
||||||
|
|
||||||
// create the antenna objects and set their dimensions
|
// create the antenna objects and set their dimensions
|
||||||
Ptr<ThreeGppAntennaArrayModel> txAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2));
|
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2));
|
||||||
Ptr<ThreeGppAntennaArrayModel> rxAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2));
|
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2));
|
||||||
|
|
||||||
// initialize the devices in the ThreeGppSpectrumPropagationLossModel
|
// initialize the devices in the ThreeGppSpectrumPropagationLossModel
|
||||||
m_spectrumLossModel->AddDevice (txDev, txAntenna);
|
m_spectrumLossModel->AddDevice (txDev, txAntenna);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <ns3/object.h>
|
#include <ns3/object.h>
|
||||||
#include <ns3/nstime.h>
|
#include <ns3/nstime.h>
|
||||||
#include <ns3/vector.h>
|
#include <ns3/vector.h>
|
||||||
#include <ns3/three-gpp-antenna-array-model.h>
|
#include <ns3/phased-array-model.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace ns3 {
|
namespace ns3 {
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
typedef std::vector<double> DoubleVector; //!< type definition for vectors of doubles
|
typedef std::vector<double> DoubleVector; //!< type definition for vectors of doubles
|
||||||
typedef std::vector<DoubleVector> Double2DVector; //!< type definition for matrices of doubles
|
typedef std::vector<DoubleVector> Double2DVector; //!< type definition for matrices of doubles
|
||||||
typedef std::vector<Double2DVector> Double3DVector; //!< type definition for 3D matrices of doubles
|
typedef std::vector<Double2DVector> Double3DVector; //!< type definition for 3D matrices of doubles
|
||||||
typedef std::vector<ThreeGppAntennaArrayModel::ComplexVector> Complex2DVector; //!< type definition for complex matrices
|
typedef std::vector<PhasedArrayModel::ComplexVector> Complex2DVector; //!< type definition for complex matrices
|
||||||
typedef std::vector<Complex2DVector> Complex3DVector; //!< type definition for complex 3D matrices
|
typedef std::vector<Complex2DVector> Complex3DVector; //!< type definition for complex 3D matrices
|
||||||
|
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual Ptr<const ChannelMatrix> GetChannel (Ptr<const MobilityModel> aMob,
|
virtual Ptr<const ChannelMatrix> GetChannel (Ptr<const MobilityModel> aMob,
|
||||||
Ptr<const MobilityModel> bMob,
|
Ptr<const MobilityModel> bMob,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> aAntenna,
|
Ptr<const PhasedArrayModel> aAntenna,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> bAntenna) = 0;
|
Ptr<const PhasedArrayModel> bAntenna) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the channel key using the Cantor function
|
* Calculate the channel key using the Cantor function
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "three-gpp-channel-model.h"
|
#include "three-gpp-channel-model.h"
|
||||||
#include "ns3/log.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/node.h"
|
||||||
#include "ns3/double.h"
|
#include "ns3/double.h"
|
||||||
#include "ns3/string.h"
|
#include "ns3/string.h"
|
||||||
@@ -970,8 +970,8 @@ ThreeGppChannelModel::ChannelMatrixNeedsUpdate (Ptr<const ThreeGppChannelMatrix>
|
|||||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix>
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix>
|
||||||
ThreeGppChannelModel::GetChannel (Ptr<const MobilityModel> aMob,
|
ThreeGppChannelModel::GetChannel (Ptr<const MobilityModel> aMob,
|
||||||
Ptr<const MobilityModel> bMob,
|
Ptr<const MobilityModel> bMob,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> aAntenna,
|
Ptr<const PhasedArrayModel> aAntenna,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> bAntenna)
|
Ptr<const PhasedArrayModel> bAntenna)
|
||||||
{
|
{
|
||||||
NS_LOG_FUNCTION (this);
|
NS_LOG_FUNCTION (this);
|
||||||
|
|
||||||
@@ -1038,8 +1038,8 @@ ThreeGppChannelModel::GetChannel (Ptr<const MobilityModel> aMob,
|
|||||||
|
|
||||||
Ptr<ThreeGppChannelModel::ThreeGppChannelMatrix>
|
Ptr<ThreeGppChannelModel::ThreeGppChannelMatrix>
|
||||||
ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> channelCondition,
|
ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> channelCondition,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> sAntenna,
|
Ptr<const PhasedArrayModel> sAntenna,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> uAntenna,
|
Ptr<const PhasedArrayModel> uAntenna,
|
||||||
Angles &uAngle, Angles &sAngle,
|
Angles &uAngle, Angles &sAngle,
|
||||||
double dis2D, double hBS, double hUT) const
|
double dis2D, double hBS, double hUT) const
|
||||||
{
|
{
|
||||||
@@ -1333,17 +1333,17 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> c
|
|||||||
{
|
{
|
||||||
Xn = -1;
|
Xn = -1;
|
||||||
}
|
}
|
||||||
clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (m_normalRv->GetValue () * ASA / 7) + uAngle.phi * 180 / M_PI; //(7.5-11)
|
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) + sAngle.phi * 180 / M_PI;
|
clusterAod[cIndex] = clusterAod[cIndex] * Xn + (m_normalRv->GetValue () * ASD / 7) + RadiansToDegrees (sAngle.GetAzimuth ());
|
||||||
if (o2i)
|
if (o2i)
|
||||||
{
|
{
|
||||||
clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + 90; //(7.5-16)
|
clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + 90; //(7.5-16)
|
||||||
}
|
}
|
||||||
else
|
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<const ChannelCondition> 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,
|
//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.
|
//Similar as AOD, ZSA and ZSD.
|
||||||
double diffAoa = clusterAoa[0] - uAngle.phi * 180 / M_PI;
|
double diffAoa = clusterAoa[0] - RadiansToDegrees (uAngle.GetAzimuth ());
|
||||||
double diffAod = clusterAod[0] - sAngle.phi * 180 / M_PI;
|
double diffAod = clusterAod[0] - RadiansToDegrees (sAngle.GetAzimuth ());
|
||||||
double diffZsa = clusterZoa[0] - uAngle.theta * 180 / M_PI;
|
double diffZsa = clusterZoa[0] - RadiansToDegrees (uAngle.GetInclination ());
|
||||||
double diffZsd = clusterZod[0] - sAngle.theta * 180 / M_PI;
|
double diffZsd = clusterZod[0] - RadiansToDegrees (sAngle.GetInclination ());
|
||||||
|
|
||||||
for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
|
for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
|
||||||
{
|
{
|
||||||
@@ -1376,69 +1376,12 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> c
|
|||||||
for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++)
|
for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++)
|
||||||
{
|
{
|
||||||
double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA * offSetAlpha[mInd]; //(7.5-13)
|
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)
|
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)
|
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)
|
||||||
tempZoa -= 360;
|
std::tie (rayAod_radian[nInd][mInd], rayZod_radian[nInd][mInd]) = WrapAngles (DegreesToRadians (tempAod), DegreesToRadians (tempZod));
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DoubleVector angle_degree;
|
DoubleVector angle_degree;
|
||||||
@@ -1712,16 +1655,16 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> c
|
|||||||
if (los) //(7.5-29) && (7.5-30)
|
if (los) //(7.5-29) && (7.5-30)
|
||||||
{
|
{
|
||||||
std::complex<double> ray (0,0);
|
std::complex<double> ray (0,0);
|
||||||
double rxPhaseDiff = 2 * M_PI * (sin (uAngle.theta) * cos (uAngle.phi) * uLoc.x
|
double rxPhaseDiff = 2 * M_PI * (sin (uAngle.GetInclination ()) * cos (uAngle.GetAzimuth ()) * uLoc.x
|
||||||
+ sin (uAngle.theta) * sin (uAngle.phi) * uLoc.y
|
+ sin (uAngle.GetInclination ()) * sin (uAngle.GetAzimuth ()) * uLoc.y
|
||||||
+ cos (uAngle.theta) * uLoc.z);
|
+ cos (uAngle.GetInclination ()) * uLoc.z);
|
||||||
double txPhaseDiff = 2 * M_PI * (sin (sAngle.theta) * cos (sAngle.phi) * sLoc.x
|
double txPhaseDiff = 2 * M_PI * (sin (sAngle.GetInclination ()) * cos (sAngle.GetAzimuth ()) * sLoc.x
|
||||||
+ sin (sAngle.theta) * sin (sAngle.phi) * sLoc.y
|
+ sin (sAngle.GetInclination ()) * sin (sAngle.GetAzimuth ()) * sLoc.y
|
||||||
+ cos (sAngle.theta) * sLoc.z);
|
+ cos (sAngle.GetInclination ()) * sLoc.z);
|
||||||
|
|
||||||
double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta;
|
double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta;
|
||||||
std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.phi, uAngle.theta));
|
std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.GetAzimuth (), uAngle.GetInclination ()));
|
||||||
std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.phi, sAngle.theta));
|
std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.GetAzimuth (), sAngle.GetInclination ()));
|
||||||
|
|
||||||
double lambda = 3e8 / m_frequency; // the wavelength of the carrier frequency
|
double lambda = 3e8 / m_frequency; // the wavelength of the carrier frequency
|
||||||
|
|
||||||
@@ -1816,6 +1759,27 @@ ThreeGppChannelModel::GetNewChannel (Vector locUT, Ptr<const ChannelCondition> c
|
|||||||
return channelParams;
|
return channelParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<double, double>
|
||||||
|
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
|
MatrixBasedChannelModel::DoubleVector
|
||||||
ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptr<ThreeGppChannelModel::ThreeGppChannelMatrix> params,
|
ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptr<ThreeGppChannelModel::ThreeGppChannelMatrix> params,
|
||||||
const DoubleVector &clusterAOA,
|
const DoubleVector &clusterAOA,
|
||||||
@@ -2018,13 +1982,13 @@ ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptr<ThreeGppChannelModel::Three
|
|||||||
}
|
}
|
||||||
double lambda = 3e8 / m_frequency;
|
double lambda = 3e8 / m_frequency;
|
||||||
double F_A1 = atan (signA1 * M_PI / 2 * sqrt (M_PI / lambda *
|
double F_A1 = atan (signA1 * M_PI / 2 * sqrt (M_PI / lambda *
|
||||||
params->m_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 *
|
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 *
|
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 *
|
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)
|
double L_dB = -20 * log10 (1 - (F_A1 + F_A2) * (F_Z1 + F_Z2)); //(7.6-22)
|
||||||
powerAttenuation[cInd] += L_dB;
|
powerAttenuation[cInd] += L_dB;
|
||||||
NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by no-self blocking, "
|
NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by no-self blocking, "
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
Ptr<const ChannelMatrix> GetChannel (Ptr<const MobilityModel> aMob,
|
Ptr<const ChannelMatrix> GetChannel (Ptr<const MobilityModel> aMob,
|
||||||
Ptr<const MobilityModel> bMob,
|
Ptr<const MobilityModel> bMob,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> aAntenna,
|
Ptr<const PhasedArrayModel> aAntenna,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> bAntenna) override;
|
Ptr<const PhasedArrayModel> bAntenna) override;
|
||||||
/**
|
/**
|
||||||
* \brief Assign a fixed random variable stream number to the random variables
|
* \brief Assign a fixed random variable stream number to the random variables
|
||||||
* used by this model.
|
* used by this model.
|
||||||
@@ -129,6 +129,20 @@ public:
|
|||||||
int64_t AssignStreams (int64_t stream);
|
int64_t AssignStreams (int64_t stream);
|
||||||
|
|
||||||
private:
|
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<double, double> WrapAngles (double azimuthRad, double inclinationRad);
|
||||||
/**
|
/**
|
||||||
* \brief Shuffle the elements of a simple sequence container of type double
|
* \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
|
* \param first Pointer to the first element among the elements to be shuffled
|
||||||
@@ -217,8 +231,8 @@ private:
|
|||||||
* \return the channel realization
|
* \return the channel realization
|
||||||
*/
|
*/
|
||||||
Ptr<ThreeGppChannelMatrix> GetNewChannel (Vector locUT, Ptr<const ChannelCondition> channelCondition,
|
Ptr<ThreeGppChannelMatrix> GetNewChannel (Vector locUT, Ptr<const ChannelCondition> channelCondition,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> sAntenna,
|
Ptr<const PhasedArrayModel> sAntenna,
|
||||||
Ptr<const ThreeGppAntennaArrayModel> uAntenna,
|
Ptr<const PhasedArrayModel> uAntenna,
|
||||||
Angles &uAngle, Angles &sAngle,
|
Angles &uAngle, Angles &sAngle,
|
||||||
double dis2D, double hBS, double hUT) const;
|
double dis2D, double hBS, double hUT) const;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "ns3/log.h"
|
#include "ns3/log.h"
|
||||||
#include "three-gpp-spectrum-propagation-loss-model.h"
|
#include "three-gpp-spectrum-propagation-loss-model.h"
|
||||||
#include "ns3/net-device.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/node.h"
|
||||||
#include "ns3/channel-condition-model.h"
|
#include "ns3/channel-condition-model.h"
|
||||||
#include "ns3/double.h"
|
#include "ns3/double.h"
|
||||||
@@ -95,7 +95,7 @@ ThreeGppSpectrumPropagationLossModel::GetChannelModel () const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr<NetDevice> n, Ptr<const ThreeGppAntennaArrayModel> a)
|
ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr<NetDevice> n, Ptr<const PhasedArrayModel> a)
|
||||||
{
|
{
|
||||||
NS_ASSERT_MSG (m_deviceAntennaMap.find (n->GetNode ()->GetId ()) == m_deviceAntennaMap.end (), "Device is already present in the map");
|
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));
|
m_deviceAntennaMap.insert (std::make_pair (n->GetNode ()->GetId (), a));
|
||||||
@@ -121,10 +121,10 @@ ThreeGppSpectrumPropagationLossModel::GetChannelModelAttribute (const std::strin
|
|||||||
m_channelModel->GetAttribute (name, value);
|
m_channelModel->GetAttribute (name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreeGppAntennaArrayModel::ComplexVector
|
PhasedArrayModel::ComplexVector
|
||||||
ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &sW,
|
const PhasedArrayModel::ComplexVector &sW,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &uW) const
|
const PhasedArrayModel::ComplexVector &uW) const
|
||||||
{
|
{
|
||||||
NS_LOG_FUNCTION (this);
|
NS_LOG_FUNCTION (this);
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr<const MatrixBasedChannel
|
|||||||
NS_LOG_DEBUG ("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna);
|
NS_LOG_DEBUG ("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna);
|
||||||
//store the long term part to reduce computation load
|
//store the long term part to reduce computation load
|
||||||
//only the small scale fading needs to be updated if the large scale parameters and antenna weights remain unchanged.
|
//only the small scale fading needs to be updated if the large scale parameters and antenna weights remain unchanged.
|
||||||
ThreeGppAntennaArrayModel::ComplexVector longTerm;
|
PhasedArrayModel::ComplexVector longTerm;
|
||||||
uint8_t numCluster = static_cast<uint8_t> (params->m_channel[0][0].size ());
|
uint8_t numCluster = static_cast<uint8_t> (params->m_channel[0][0].size ());
|
||||||
|
|
||||||
for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
|
for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
|
||||||
@@ -156,7 +156,7 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr<const MatrixBasedChannel
|
|||||||
|
|
||||||
Ptr<SpectrumValue>
|
Ptr<SpectrumValue>
|
||||||
ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr<SpectrumValue> txPsd,
|
ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr<SpectrumValue> txPsd,
|
||||||
ThreeGppAntennaArrayModel::ComplexVector longTerm,
|
PhasedArrayModel::ComplexVector longTerm,
|
||||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
||||||
const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const
|
const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const
|
||||||
{
|
{
|
||||||
@@ -171,7 +171,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr<SpectrumValue> tx
|
|||||||
// NOTE the update of Doppler is simplified by only taking the center angle of
|
// NOTE the update of Doppler is simplified by only taking the center angle of
|
||||||
// each cluster in to consideration.
|
// each cluster in to consideration.
|
||||||
double slotTime = Simulator::Now ().GetSeconds ();
|
double slotTime = Simulator::Now ().GetSeconds ();
|
||||||
ThreeGppAntennaArrayModel::ComplexVector doppler;
|
PhasedArrayModel::ComplexVector doppler;
|
||||||
for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
|
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
|
// 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<SpectrumValue> tx
|
|||||||
return tempPsd;
|
return tempPsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreeGppAntennaArrayModel::ComplexVector
|
PhasedArrayModel::ComplexVector
|
||||||
ThreeGppSpectrumPropagationLossModel::GetLongTerm (uint32_t aId, uint32_t bId,
|
ThreeGppSpectrumPropagationLossModel::GetLongTerm (uint32_t aId, uint32_t bId,
|
||||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &aW,
|
const PhasedArrayModel::ComplexVector &aW,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &bW) const
|
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
|
// check if the channel matrix was generated considering a as the s-node and
|
||||||
// b as the u-node or viceversa
|
// b as the u-node or viceversa
|
||||||
ThreeGppAntennaArrayModel::ComplexVector sW, uW;
|
PhasedArrayModel::ComplexVector sW, uW;
|
||||||
if (!channelMatrix->IsReverse (aId, bId))
|
if (!channelMatrix->IsReverse (aId, bId))
|
||||||
{
|
{
|
||||||
sW = aW;
|
sW = aW;
|
||||||
@@ -311,28 +311,22 @@ ThreeGppSpectrumPropagationLossModel::DoCalcRxPowerSpectralDensity (Ptr<const Sp
|
|||||||
|
|
||||||
// retrieve the antenna of device a
|
// retrieve the antenna of device a
|
||||||
NS_ASSERT_MSG (m_deviceAntennaMap.find (aId) != m_deviceAntennaMap.end (), "Antenna not found for node " << aId);
|
NS_ASSERT_MSG (m_deviceAntennaMap.find (aId) != m_deviceAntennaMap.end (), "Antenna not found for node " << aId);
|
||||||
Ptr<const ThreeGppAntennaArrayModel> aAntenna = m_deviceAntennaMap.at (aId);
|
Ptr<const PhasedArrayModel> aAntenna = m_deviceAntennaMap.at (aId);
|
||||||
NS_LOG_DEBUG ("a node " << a->GetObject<Node> () << " antenna " << aAntenna);
|
NS_LOG_DEBUG ("a node " << a->GetObject<Node> () << " antenna " << aAntenna);
|
||||||
|
|
||||||
// retrieve the antenna of the device b
|
// retrieve the antenna of the device b
|
||||||
NS_ASSERT_MSG (m_deviceAntennaMap.find (bId) != m_deviceAntennaMap.end (), "Antenna not found for device " << bId);
|
NS_ASSERT_MSG (m_deviceAntennaMap.find (bId) != m_deviceAntennaMap.end (), "Antenna not found for device " << bId);
|
||||||
Ptr<const ThreeGppAntennaArrayModel> bAntenna = m_deviceAntennaMap.at (bId);
|
Ptr<const PhasedArrayModel> bAntenna = m_deviceAntennaMap.at (bId);
|
||||||
NS_LOG_DEBUG ("b node " << bId << " antenna " << bAntenna);
|
NS_LOG_DEBUG ("b node " << bId << " antenna " << bAntenna);
|
||||||
|
|
||||||
if (aAntenna->IsOmniTx () || bAntenna->IsOmniTx () )
|
|
||||||
{
|
|
||||||
NS_LOG_LOGIC ("Omni transmission, do nothing.");
|
|
||||||
return rxPsd;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix = m_channelModel->GetChannel (a, b, aAntenna, bAntenna);
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix = m_channelModel->GetChannel (a, b, aAntenna, bAntenna);
|
||||||
|
|
||||||
// get the precoding and combining vectors
|
// get the precoding and combining vectors
|
||||||
ThreeGppAntennaArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector ();
|
PhasedArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector ();
|
||||||
ThreeGppAntennaArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector ();
|
PhasedArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector ();
|
||||||
|
|
||||||
// retrieve the long term component
|
// 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
|
// apply the beamforming gain
|
||||||
rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, a->GetVelocity (), b->GetVelocity ());
|
rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, a->GetVelocity (), b->GetVelocity ());
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class ChannelCondition;
|
|||||||
* returns the PSD of the received signal.
|
* returns the PSD of the received signal.
|
||||||
*
|
*
|
||||||
* \see MatrixBasedChannelModel
|
* \see MatrixBasedChannelModel
|
||||||
* \see ThreeGppAntennaArrayModel
|
* \see PhasedArrayModel
|
||||||
* \see ChannelCondition
|
* \see ChannelCondition
|
||||||
*/
|
*/
|
||||||
class ThreeGppSpectrumPropagationLossModel : public SpectrumPropagationLossModel
|
class ThreeGppSpectrumPropagationLossModel : public SpectrumPropagationLossModel
|
||||||
@@ -85,9 +85,9 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Add a device-antenna pair
|
* Add a device-antenna pair
|
||||||
* \param n a pointer to the NetDevice
|
* \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<NetDevice> n, Ptr<const ThreeGppAntennaArrayModel> a);
|
void AddDevice (Ptr<NetDevice> n, Ptr<const PhasedArrayModel> a);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,10 +136,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
struct LongTerm : public SimpleRefCount<LongTerm>
|
struct LongTerm : public SimpleRefCount<LongTerm>
|
||||||
{
|
{
|
||||||
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<const MatrixBasedChannelModel::ChannelMatrix> m_channel; //!< pointer to the channel matrix used to compute the long term
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> 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
|
PhasedArrayModel::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_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
|
* \param bW the beamforming vector of the second device
|
||||||
* \return vector containing the long term compoenent for each cluster
|
* \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<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &aW,
|
const PhasedArrayModel::ComplexVector &aW,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &bW) const;
|
const PhasedArrayModel::ComplexVector &bW) const;
|
||||||
/**
|
/**
|
||||||
* Computes the long term component
|
* Computes the long term component
|
||||||
* \param channelMatrix the channel matrix H
|
* \param channelMatrix the channel matrix H
|
||||||
@@ -170,9 +170,9 @@ private:
|
|||||||
* \param uW the beamforming vector of the u device
|
* \param uW the beamforming vector of the u device
|
||||||
* \return the long term component
|
* \return the long term component
|
||||||
*/
|
*/
|
||||||
ThreeGppAntennaArrayModel::ComplexVector CalcLongTerm (Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
PhasedArrayModel::ComplexVector CalcLongTerm (Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &sW,
|
const PhasedArrayModel::ComplexVector &sW,
|
||||||
const ThreeGppAntennaArrayModel::ComplexVector &uW) const;
|
const PhasedArrayModel::ComplexVector &uW) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the beamforming gain and applies it to the tx PSD
|
* Computes the beamforming gain and applies it to the tx PSD
|
||||||
@@ -184,11 +184,11 @@ private:
|
|||||||
* \return the rx PSD
|
* \return the rx PSD
|
||||||
*/
|
*/
|
||||||
Ptr<SpectrumValue> CalcBeamformingGain (Ptr<SpectrumValue> txPsd,
|
Ptr<SpectrumValue> CalcBeamformingGain (Ptr<SpectrumValue> txPsd,
|
||||||
ThreeGppAntennaArrayModel::ComplexVector longTerm,
|
PhasedArrayModel::ComplexVector longTerm,
|
||||||
Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
|
||||||
const Vector &sSpeed, const Vector &uSpeed) const;
|
const Vector &sSpeed, const Vector &uSpeed) const;
|
||||||
|
|
||||||
std::unordered_map <uint32_t, Ptr<const ThreeGppAntennaArrayModel> > m_deviceAntennaMap; //!< map containig the <node, antenna> associations
|
std::unordered_map <uint32_t, Ptr<const PhasedArrayModel> > m_deviceAntennaMap; //!< map containig the <node, antenna> associations
|
||||||
mutable std::unordered_map < uint32_t, Ptr<const LongTerm> > m_longTermMap; //!< map containing the long term components
|
mutable std::unordered_map < uint32_t, Ptr<const LongTerm> > m_longTermMap; //!< map containing the long term components
|
||||||
Ptr<MatrixBasedChannelModel> m_channelModel; //!< the model to generate the channel matrix
|
Ptr<MatrixBasedChannelModel> m_channelModel; //!< the model to generate the channel matrix
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
#include "ns3/pointer.h"
|
#include "ns3/pointer.h"
|
||||||
#include "ns3/node-container.h"
|
#include "ns3/node-container.h"
|
||||||
#include "ns3/constant-position-mobility-model.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/three-gpp-channel-model.h"
|
||||||
#include "ns3/simple-net-device.h"
|
#include "ns3/simple-net-device.h"
|
||||||
#include "ns3/simulator.h"
|
#include "ns3/simulator.h"
|
||||||
@@ -71,7 +72,7 @@ private:
|
|||||||
* \param txAntenna the antenna object associated to the first node
|
* \param txAntenna the antenna object associated to the first node
|
||||||
* \param rxAntenna the antenna object associated to the second node
|
* \param rxAntenna the antenna object associated to the second node
|
||||||
*/
|
*/
|
||||||
void DoComputeNorm (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<ThreeGppAntennaArrayModel> txAntenna, Ptr<ThreeGppAntennaArrayModel> rxAntenna);
|
void DoComputeNorm (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<PhasedArrayModel> txAntenna, Ptr<PhasedArrayModel> rxAntenna);
|
||||||
|
|
||||||
std::vector<double> m_normVector; //!< each element is the norm of a channel realization
|
std::vector<double> m_normVector; //!< each element is the norm of a channel realization
|
||||||
};
|
};
|
||||||
@@ -86,7 +87,7 @@ ThreeGppChannelMatrixComputationTest::~ThreeGppChannelMatrixComputationTest ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ThreeGppChannelMatrixComputationTest::DoComputeNorm (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<ThreeGppAntennaArrayModel> txAntenna, Ptr<ThreeGppAntennaArrayModel> rxAntenna)
|
ThreeGppChannelMatrixComputationTest::DoComputeNorm (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<PhasedArrayModel> txAntenna, Ptr<PhasedArrayModel> rxAntenna)
|
||||||
{
|
{
|
||||||
uint64_t txAntennaElements = txAntenna->GetNumberOfElements ();
|
uint64_t txAntennaElements = txAntenna->GetNumberOfElements ();
|
||||||
uint64_t rxAntennaElements = rxAntenna->GetNumberOfElements ();
|
uint64_t rxAntennaElements = rxAntenna->GetNumberOfElements ();
|
||||||
@@ -153,8 +154,12 @@ ThreeGppChannelMatrixComputationTest::DoRun (void)
|
|||||||
nodes.Get (1)->AggregateObject (rxMob);
|
nodes.Get (1)->AggregateObject (rxMob);
|
||||||
|
|
||||||
// create the tx and rx antennas and set the their dimensions
|
// create the tx and rx antennas and set the their dimensions
|
||||||
Ptr<ThreeGppAntennaArrayModel> txAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true));
|
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (txAntennaElements [0]),
|
||||||
Ptr<ThreeGppAntennaArrayModel> rxAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true));
|
"NumRows", UintegerValue (txAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (rxAntennaElements [0]),
|
||||||
|
"NumRows", UintegerValue (rxAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
|
||||||
// generate the channel matrix
|
// generate the channel matrix
|
||||||
Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna);
|
Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna);
|
||||||
@@ -235,7 +240,7 @@ private:
|
|||||||
* \param rxAntenna the antenna object associated to the second node
|
* \param rxAntenna the antenna object associated to the second node
|
||||||
* \param update whether if the channel matrix should be updated or not
|
* \param update whether if the channel matrix should be updated or not
|
||||||
*/
|
*/
|
||||||
void DoGetChannel (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<ThreeGppAntennaArrayModel> txAntenna, Ptr<ThreeGppAntennaArrayModel> rxAntenna, bool update);
|
void DoGetChannel (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<PhasedArrayModel> txAntenna, Ptr<PhasedArrayModel> rxAntenna, bool update);
|
||||||
|
|
||||||
Ptr<const ThreeGppChannelModel::ChannelMatrix> m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
|
Ptr<const ThreeGppChannelModel::ChannelMatrix> m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
|
||||||
};
|
};
|
||||||
@@ -250,7 +255,7 @@ ThreeGppChannelMatrixUpdateTest::~ThreeGppChannelMatrixUpdateTest ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ThreeGppChannelMatrixUpdateTest::DoGetChannel (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<ThreeGppAntennaArrayModel> txAntenna, Ptr<ThreeGppAntennaArrayModel> rxAntenna, bool update)
|
ThreeGppChannelMatrixUpdateTest::DoGetChannel (Ptr<ThreeGppChannelModel> channelModel, Ptr<MobilityModel> txMob, Ptr<MobilityModel> rxMob, Ptr<PhasedArrayModel> txAntenna, Ptr<PhasedArrayModel> rxAntenna, bool update)
|
||||||
{
|
{
|
||||||
// retrieve the channel matrix
|
// retrieve the channel matrix
|
||||||
Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna);
|
Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna);
|
||||||
@@ -312,22 +317,29 @@ ThreeGppChannelMatrixUpdateTest::DoRun (void)
|
|||||||
nodes.Get (1)->AggregateObject (rxMob);
|
nodes.Get (1)->AggregateObject (rxMob);
|
||||||
|
|
||||||
// create the tx and rx antennas and set the their dimensions
|
// create the tx and rx antennas and set the their dimensions
|
||||||
Ptr<ThreeGppAntennaArrayModel> txAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true));
|
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (txAntennaElements [0]),
|
||||||
Ptr<ThreeGppAntennaArrayModel> rxAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true));
|
"NumRows", UintegerValue (txAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (rxAntennaElements [0]),
|
||||||
|
"NumRows", UintegerValue (rxAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
|
||||||
// check if the channel matrix is correctly updated
|
// check if the channel matrix is correctly updated
|
||||||
|
|
||||||
// compute the channel matrix for the first time
|
// 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
|
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
|
// call GetChannel before the update period is exceeded, the channel matrix
|
||||||
// should not be updated
|
// 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
|
// call GetChannel when the update period is exceeded, the channel matrix
|
||||||
// should be recomputed
|
// 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::Run ();
|
||||||
Simulator::Destroy ();
|
Simulator::Destroy ();
|
||||||
@@ -367,7 +379,7 @@ private:
|
|||||||
* \param otherDevice the device to communicate with
|
* \param otherDevice the device to communicate with
|
||||||
* \param otherAntenna the antenna object associated to otherDevice
|
* \param otherAntenna the antenna object associated to otherDevice
|
||||||
*/
|
*/
|
||||||
void DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAntenna, Ptr<NetDevice> otherDevice, Ptr<ThreeGppAntennaArrayModel> otherAntenna);
|
void DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<PhasedArrayModel> thisAntenna, Ptr<NetDevice> otherDevice, Ptr<PhasedArrayModel> otherAntenna);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of the long term component is correctly updated when the channel
|
* Test of the long term component is correctly updated when the channel
|
||||||
@@ -400,35 +412,15 @@ ThreeGppSpectrumPropagationLossModelTest::~ThreeGppSpectrumPropagationLossModelT
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ThreeGppSpectrumPropagationLossModelTest::DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<ThreeGppAntennaArrayModel> thisAntenna, Ptr<NetDevice> otherDevice, Ptr<ThreeGppAntennaArrayModel> otherAntenna)
|
ThreeGppSpectrumPropagationLossModelTest::DoBeamforming (Ptr<NetDevice> thisDevice, Ptr<PhasedArrayModel> thisAntenna, Ptr<NetDevice> otherDevice, Ptr<PhasedArrayModel> otherAntenna)
|
||||||
{
|
{
|
||||||
ThreeGppAntennaArrayModel::ComplexVector antennaWeights;
|
|
||||||
|
|
||||||
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
Vector aPos = thisDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
||||||
Vector bPos = otherDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
Vector bPos = otherDevice->GetNode ()->GetObject<MobilityModel> ()->GetPosition ();
|
||||||
|
|
||||||
// compute the azimuth and the elevation angles
|
// compute the azimuth and the elevation angles
|
||||||
Angles completeAngle (bPos,aPos);
|
Angles completeAngle (bPos,aPos);
|
||||||
|
|
||||||
double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle
|
PhasedArrayModel::ComplexVector antennaWeights = thisAntenna->GetBeamformingVector (completeAngle);
|
||||||
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<double> (0, phase)) * power);
|
|
||||||
}
|
|
||||||
|
|
||||||
thisAntenna->SetBeamformingVector (antennaWeights);
|
thisAntenna->SetBeamformingVector (antennaWeights);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,9 +491,13 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun ()
|
|||||||
nodes.Get (1)->AggregateObject (rxMob);
|
nodes.Get (1)->AggregateObject (rxMob);
|
||||||
|
|
||||||
// create the tx and rx antennas and set the their dimensions
|
// create the tx and rx antennas and set the their dimensions
|
||||||
Ptr<ThreeGppAntennaArrayModel> txAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]));
|
Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (txAntennaElements [0]),
|
||||||
Ptr<ThreeGppAntennaArrayModel> rxAntenna = CreateObjectWithAttributes<ThreeGppAntennaArrayModel> ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]));
|
"NumRows", UintegerValue (txAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray> ("NumColumns", UintegerValue (rxAntennaElements [0]),
|
||||||
|
"NumRows", UintegerValue (rxAntennaElements [1]),
|
||||||
|
"AntennaElement", PointerValue(CreateObject<IsotropicAntennaModel> ()));
|
||||||
|
|
||||||
// initialize ThreeGppSpectrumPropagationLossModel
|
// initialize ThreeGppSpectrumPropagationLossModel
|
||||||
lossModel->AddDevice (txDev, txAntenna);
|
lossModel->AddDevice (txDev, txAntenna);
|
||||||
lossModel->AddDevice (rxDev, rxAntenna);
|
lossModel->AddDevice (rxDev, rxAntenna);
|
||||||
@@ -526,7 +522,7 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun ()
|
|||||||
// 2) check if the long term is updated when changing the BF vector
|
// 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
|
// change the position of the rx device and recompute the beamforming vectors
|
||||||
rxMob->SetPosition (Vector (10.0, 5.0, 10.0));
|
rxMob->SetPosition (Vector (10.0, 5.0, 10.0));
|
||||||
ThreeGppAntennaArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector ();
|
PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector ();
|
||||||
txBfVector [0] = std::complex<double> (0.0, 0.0);
|
txBfVector [0] = std::complex<double> (0.0, 0.0);
|
||||||
txAntenna->SetBeamformingVector (txBfVector);
|
txAntenna->SetBeamformingVector (txBfVector);
|
||||||
|
|
||||||
@@ -537,7 +533,8 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun ()
|
|||||||
rxPsdOld = rxPsdNew;
|
rxPsdOld = rxPsdNew;
|
||||||
|
|
||||||
// 3) check if the long term is updated when the channel matrix is recomputed
|
// 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::Run ();
|
||||||
Simulator::Destroy ();
|
Simulator::Destroy ();
|
||||||
|
|||||||
Reference in New Issue
Block a user