A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
uniform-planar-array.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 University of Padova, Dep. of Information Engineering, SIGNET lab.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
8
9#include "ns3/boolean.h"
10#include "ns3/double.h"
11#include "ns3/log.h"
12#include "ns3/uinteger.h"
13
14namespace ns3
15{
16
17NS_LOG_COMPONENT_DEFINE("UniformPlanarArray");
18
19NS_OBJECT_ENSURE_REGISTERED(UniformPlanarArray);
20
25
29
32{
33 static TypeId tid =
34 TypeId("ns3::UniformPlanarArray")
36 .AddConstructor<UniformPlanarArray>()
37 .SetGroupName("Antenna")
38 .AddAttribute(
39 "AntennaHorizontalSpacing",
40 "Horizontal spacing between antenna elements, in multiples of wave length",
41 DoubleValue(0.5),
45 .AddAttribute("AntennaVerticalSpacing",
46 "Vertical spacing between antenna elements, in multiples of wave length",
47 DoubleValue(0.5),
51 .AddAttribute("NumColumns",
52 "Horizontal size of the array",
57 .AddAttribute("NumRows",
58 "Vertical size of the array",
63 .AddAttribute(
64 "BearingAngle",
65 "The bearing angle in radians",
66 DoubleValue(0.0),
68 MakeDoubleChecker<double>(-M_PI, M_PI))
69 .AddAttribute(
70 "DowntiltAngle",
71 "The downtilt angle in radians",
72 DoubleValue(0.0),
74 MakeDoubleChecker<double>(-M_PI, M_PI))
75 .AddAttribute("PolSlantAngle",
76 "The polarization slant angle in radians",
77 DoubleValue(0.0),
80 MakeDoubleChecker<double>(-M_PI, M_PI))
81 .AddAttribute("NumVerticalPorts",
82 "Vertical number of ports",
87 .AddAttribute("NumHorizontalPorts",
88 "Horizontal number of ports",
93 .AddAttribute("IsDualPolarized",
94 "If true, dual polarized antenna",
95 BooleanValue(false),
99 return tid;
100}
101
102void
104{
105 NS_LOG_FUNCTION(this << n);
106 if (n != m_numColumns)
107 {
108 m_isBfVectorValid = false;
110 }
111 m_numColumns = n;
112}
113
119
120void
122{
123 NS_LOG_FUNCTION(this << n);
124 if (n != m_numRows)
125 {
126 m_isBfVectorValid = false;
128 }
129 m_numRows = n;
130}
131
134{
135 return m_numRows;
136}
137
138void
140{
141 if (alpha != m_alpha)
142 {
143 m_alpha = alpha;
144 m_cosAlpha = cos(m_alpha);
145 m_sinAlpha = sin(m_alpha);
147 }
148}
149
150void
152{
153 if (beta != m_beta)
154 {
155 m_beta = beta;
156 m_cosBeta = cos(m_beta);
157 m_sinBeta = sin(m_beta);
159 }
160}
161
162void
164{
165 if (polSlant != m_polSlant)
166 {
167 m_polSlant = polSlant;
168 m_cosPolSlant[0] = cos(m_polSlant);
169 m_sinPolSlant[0] = sin(m_polSlant);
171 }
172}
173
174void
176{
177 NS_LOG_FUNCTION(this << s);
178 NS_ABORT_MSG_IF(s <= 0, "Trying to set an invalid spacing: " << s);
179
180 if (s != m_disH)
181 {
182 m_isBfVectorValid = false;
184 }
185 m_disH = s;
186}
187
188double
193
194void
196{
197 NS_LOG_FUNCTION(this << s);
198 NS_ABORT_MSG_IF(s <= 0, "Trying to set an invalid spacing: " << s);
199
200 if (s != m_disV)
201 {
202 m_isBfVectorValid = false;
204 }
205 m_disV = s;
206}
207
208double
213
214std::pair<double, double>
216{
217 NS_LOG_FUNCTION(this << a);
218 NS_ASSERT_MSG(polIndex < GetNumPols(), "Polarization index can be 0 or 1.");
219
220 // convert the theta and phi angles from GCS to LCS using eq. 7.1-7 and 7.1-8 in 3GPP TR 38.901
221 // NOTE we assume a fixed slant angle of 0 degrees
222 double inclination = a.GetInclination();
223 double azimuth = a.GetAzimuth();
224 double cosIncl = cos(inclination);
225 double sinIncl = sin(inclination);
226 double cosAzim = cos(azimuth - m_alpha);
227 double sinAzim = sin(azimuth - m_alpha);
228 double thetaPrime = std::acos(m_cosBeta * cosIncl + m_sinBeta * cosAzim * sinIncl);
229 double phiPrime =
230 std::arg(std::complex<double>(m_cosBeta * sinIncl * cosAzim - m_sinBeta * cosIncl,
231 sinAzim * sinIncl));
232 Angles aPrime(phiPrime, thetaPrime);
233 NS_LOG_DEBUG(a << " -> " << aPrime);
234
235 // compute the antenna element field patterns using eq. 7.3-4 and 7.3-5 in 3GPP TR 38.901,
236 // using the configured polarization slant angle (m_polSlant)
237 // NOTE: the slant angle (assumed to be 0) differs from the polarization slant angle
238 // (m_polSlant, given by the attribute), in 3GPP TR 38.901
239 double aPrimeDb = m_antennaElement->GetGainDb(aPrime);
240 double fieldThetaPrime =
241 pow(10, aPrimeDb / 20) * m_cosPolSlant[polIndex]; // convert to linear magnitude
242 double fieldPhiPrime =
243 pow(10, aPrimeDb / 20) * m_sinPolSlant[polIndex]; // convert to linear magnitude
244
245 // compute psi using eq. 7.1-15 in 3GPP TR 38.901, assuming that the slant
246 // angle (gamma) is 0
247 double psi = std::arg(std::complex<double>(m_cosBeta * sinIncl - m_sinBeta * cosIncl * cosAzim,
248 m_sinBeta * sinAzim));
249 NS_LOG_DEBUG("psi " << psi);
250
251 // convert the antenna element field pattern to GCS using eq. 7.1-11
252 // in 3GPP TR 38.901
253 double fieldTheta = cos(psi) * fieldThetaPrime - sin(psi) * fieldPhiPrime;
254 double fieldPhi = sin(psi) * fieldThetaPrime + cos(psi) * fieldPhiPrime;
256 << " " << RadiansToDegrees(a.GetInclination()) << " "
257 << fieldTheta * fieldTheta + fieldPhi * fieldPhi);
258
259 return std::make_pair(fieldPhi, fieldTheta);
260}
261
262Vector
264{
265 NS_LOG_FUNCTION(this << index);
266 uint64_t tmpIndex = index;
267 // for dual polarization, the top half corresponds to one polarization and
268 // lower half corresponds to the other polarization
269 if (m_isDualPolarized && tmpIndex >= m_numRows * m_numColumns)
270 {
271 tmpIndex -= m_numRows * m_numColumns;
272 }
273 // compute the element coordinates in the LCS
274 // assume the left bottom corner is (0,0,0), and the rectangular antenna array is on the y-z
275 // plane.
276 double xPrime = 0;
277 double yPrime = m_disH * (tmpIndex % m_numColumns);
278 double zPrime = m_disV * floor(tmpIndex / m_numColumns);
279
280 // convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP
281 // TR 38.901
282 Vector loc;
283 loc.x = m_cosAlpha * m_cosBeta * xPrime - m_sinAlpha * yPrime + m_cosAlpha * m_sinBeta * zPrime;
284 loc.y = m_sinAlpha * m_cosBeta * xPrime + m_cosAlpha * yPrime + m_sinAlpha * m_sinBeta * zPrime;
285 loc.z = -m_sinBeta * xPrime + m_cosBeta * zPrime;
286 return loc;
287}
288
289uint8_t
291{
292 return m_isDualPolarized ? 2 : 1;
293}
294
295size_t
297{
298 // From 38.901 [M, N, P, Mg, Ng] = [m_numRows, m_numColumns, 2, 1, 1]
299 return GetNumPols() * m_numRows * m_numColumns;
300 // with dual polarization, the number of antenna elements double up
301}
302
303void
305{
306 NS_LOG_FUNCTION(this);
307 NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0");
308 NS_ASSERT_MSG(((m_numRows % nPorts) == 0),
309 "The number of vertical ports must divide number of rows");
310 if (nPorts != m_numVPorts)
311 {
312 m_numVPorts = nPorts;
314 }
315}
316
317void
319{
320 NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0");
321 NS_ASSERT_MSG(((m_numColumns % nPorts) == 0),
322 "The number of horizontal ports must divide number of columns");
323 if (nPorts != m_numHPorts)
324 {
325 m_numHPorts = nPorts;
327 }
328}
329
330uint16_t
335
336uint16_t
341
342uint16_t
347
348size_t
353
354size_t
359
360size_t
362{
363 // Multiply the number of rows and number of columns belonging to one antenna port.
364 // This also holds for dual polarization, where each polarization belongs to a separate port.
366}
367
368uint16_t
369UniformPlanarArray::ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const
370{
371 NS_ASSERT_MSG(portIndex < GetNumPorts(), "Port should be less than total Ports");
372 NS_ASSERT(subElementIndex < (GetHElemsPerPort() * GetVElemsPerPort()));
373
374 // In case the array is dual-polarized, change to the index that belongs to the first
375 // polarization
376 auto firstPolPortIdx = portIndex;
377 auto polarizationOffset = 0;
378 auto arraySize = GetNumHorizontalPorts() * GetNumVerticalPorts();
379 if (firstPolPortIdx >= arraySize)
380 {
381 firstPolPortIdx = portIndex - arraySize;
382 polarizationOffset = GetNumColumns() * GetNumRows();
383 }
384 // column-major indexing
385 auto hPortIdx = firstPolPortIdx / GetNumVerticalPorts();
386 auto vPortIdx = firstPolPortIdx % GetNumVerticalPorts();
387 auto hElemIdx = (hPortIdx * GetHElemsPerPort()) + (subElementIndex % GetHElemsPerPort());
388 auto vElemIdx = (vPortIdx * GetVElemsPerPort()) + (subElementIndex / GetHElemsPerPort());
389 return (vElemIdx * GetNumColumns() + hElemIdx + polarizationOffset);
390}
391
392bool
397
398void
400{
401 if (isDualPol != m_isDualPolarized)
402 {
403 m_isDualPolarized = isDualPol;
404 if (isDualPol)
405 {
406 m_cosPolSlant[1] = cos(m_polSlant - M_PI / 2);
407 m_sinPolSlant[1] = sin(m_polSlant - M_PI / 2);
408 }
410 }
411}
412
413double
415{
416 return m_alpha;
417}
418
419double
421{
422 return m_beta;
423}
424
425double
427{
428 return m_polSlant;
429}
430
431uint8_t
432UniformPlanarArray::GetElemPol(size_t elemIndex) const
433{
434 NS_ASSERT(elemIndex < GetNumElems());
435 return (elemIndex < GetNumRows() * GetNumColumns()) ? 0 : 1;
436}
437
438} /* namespace ns3 */
Class holding the azimuth and inclination angles of spherical coordinates.
Definition angles.h:107
double GetInclination() const
Getter for inclination angle.
Definition angles.cc:236
double GetAzimuth() const
Getter for azimuth angle.
Definition angles.cc:230
AttributeValue implementation for Boolean.
Definition boolean.h:26
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Class implementing the phased array model virtual base class.
Ptr< AntennaModel > m_antennaElement
the model of the antenna element in use
bool m_isBfVectorValid
ensures the validity of the beamforming vector
void InvalidateChannels() const
After changing the antenna settings, InvalidateChannels() should be called to mark up-to-date channel...
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
double m_disV
antenna spacing in the vertical direction in multiples of wave length
double m_sinAlpha
the sine of alpha
void SetPolSlant(double polSlant)
Set the polarization slant angle This method sets the polarization slant angle and computes its cosin...
uint16_t GetNumPorts() const override
Get the total number of antenna ports.
double m_disH
antenna spacing in the horizontal direction in multiples of wave length
void SetBeta(double beta)
Set the downtilt angle This method sets the downtilt angle and computes its cosine and sine.
bool m_isDualPolarized
if true antenna elements are dual-polarized
uint16_t ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const override
Maps element within a port to an index of element within the antenna array.
void SetNumRows(uint32_t n) override
Set the number of rows of the phased array This method resets the stored beamforming vector to a Comp...
bool IsDualPol() const override
Check if an antenna array contains dual-polarized elements.
static TypeId GetTypeId()
Get the type ID.
void SetAlpha(double alpha)
Set the bearing angle This method sets the bearing angle and computes its cosine and sine.
void SetNumColumns(uint32_t n) override
Set the number of columns of the phased array This method resets the stored beamforming vector to a C...
double GetAntennaVerticalSpacing() const
Get the vertical spacing for the antenna elements of the phased array.
uint16_t GetNumVerticalPorts() const override
Get the number of vertical antenna ports.
uint16_t m_numVPorts
Number of vertical ports.
std::pair< double, double > GetElementFieldPattern(Angles a, uint8_t polIndex=0) const override
Returns the horizontal and vertical components of the antenna element field pattern at the specified ...
double m_polSlant
the polarization slant angle in radians
uint8_t GetElemPol(size_t elemIndex) const override
Returns the index of polarization to which belongs the antenna element with a specific index.
uint32_t GetNumRows() const override
Get the number of rows of the phased array.
double GetPolSlant() const override
Returns polarization angle of first polarization.
double m_cosBeta
the cosine of Beta
void SetAntennaVerticalSpacing(double s)
Set the vertical spacing for the antenna elements of the phased array This method resets the stored b...
double GetAntennaHorizontalSpacing() const
Get the horizontal spacing for the antenna elements of the phased array.
~UniformPlanarArray() override
Destructor.
uint32_t m_numRows
number of rows
Vector GetElementLocation(uint64_t index) const override
Returns the location of the antenna element with the specified index assuming the left bottom corner ...
uint32_t m_numColumns
number of columns
double m_alpha
the bearing angle in radians
uint16_t GetNumHorizontalPorts() const override
Get the number of horizontal antenna ports.
uint16_t m_numHPorts
Number of horizontal ports.
void SetDualPol(bool isDualPol)
Set the polarization.
size_t GetHElemsPerPort() const override
Get the number of horizontal elements belonging to each port.
void SetNumVerticalPorts(uint16_t nPorts) override
Set the number of vertical antenna ports.
size_t GetVElemsPerPort() const override
Get the number of vertical elements belonging to each port.
uint32_t GetNumColumns() const override
Get the number of columns of the phased array.
void SetNumHorizontalPorts(uint16_t nPorts) override
Set the number of horizontal antenna ports.
std::vector< double > m_cosPolSlant
the cosine of polarization slant angle
double GetAlpha() const
Returns bearing angle of first polarization.
double GetBeta() const
Returns downtilt angle of first polarization.
double m_sinBeta
the sine of Beta
size_t GetNumElems() const override
Returns the number of total antenna elements.
void SetAntennaHorizontalSpacing(double s)
Set the horizontal spacing for the antenna elements of the phased array This method resets the stored...
double m_beta
the downtilt angle in radians
double m_cosAlpha
the cosine of alpha
size_t GetNumElemsPerPort() const override
Get the total number of elements belonging to each port.
uint8_t GetNumPols() const override
Returns the number of polarizations, 2 in the case that the antenna is dual-polarized,...
std::vector< double > m_sinPolSlant
the sine polarization slant angle
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition double.h:32
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double RadiansToDegrees(double radians)
converts radians to degrees
Definition angles.cc:34