5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
beamforming-vector.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "beamforming-vector.h"
6
7#include "ns3/angles.h"
8#include "ns3/uinteger.h"
9
10namespace ns3
11{
12
13PhasedArrayModel::ComplexVector
14CreateQuasiOmniBfv(const Ptr<const UniformPlanarArray>& antenna)
15{
16 auto antennaRows = antenna->GetNumRows();
17 auto antennaColumns = antenna->GetNumColumns();
18 auto numElemsPerPort = antenna->GetNumElemsPerPort();
19
20 double power = 1 / sqrt(numElemsPerPort);
21 size_t numPolarizations = antenna->IsDualPol() ? 2 : 1;
22
23 PhasedArrayModel::ComplexVector omni(antennaRows * antennaColumns * numPolarizations);
24 uint16_t bfIndex = 0;
25 for (size_t pol = 0; pol < numPolarizations; pol++)
26 {
27 for (uint32_t ind = 0; ind < antennaRows; ind++)
28 {
29 std::complex<double> c = 0.0;
30 if (antennaRows % 2 == 0)
31 {
32 c = exp(std::complex<double>(0, M_PI * ind * ind / antennaRows));
33 }
34 else
35 {
36 c = exp(std::complex<double>(0, M_PI * ind * (ind + 1) / antennaRows));
37 }
38 for (uint32_t ind2 = 0; ind2 < antennaColumns; ind2++)
39 {
40 std::complex<double> d = 0.0;
41 if (antennaColumns % 2 == 0)
42 {
43 d = exp(std::complex<double>(0, M_PI * ind2 * ind2 / antennaColumns));
44 }
45 else
46 {
47 d = exp(std::complex<double>(0, M_PI * ind2 * (ind2 + 1) / antennaColumns));
48 }
49 omni[bfIndex] = (c * d * power);
50 bfIndex++;
51 }
52 }
53 }
54 return omni;
55}
56
57PhasedArrayModel::ComplexVector
58CreateDirectionalBfv(const Ptr<const UniformPlanarArray>& antenna, double sector, double elevation)
59{
60 UintegerValue uintValueNumColumns;
61 antenna->GetAttribute("NumColumns", uintValueNumColumns);
62
63 double hAngle_radian =
64 M_PI * (sector / static_cast<double>(uintValueNumColumns.Get())) - 0.5 * M_PI;
65 double vAngle_radian = elevation * M_PI / 180;
66 uint16_t size = antenna->GetNumElems();
67 PhasedArrayModel::ComplexVector tempVector(size);
68 auto numAnalogBeamElements = (antenna->GetVElemsPerPort() * antenna->GetHElemsPerPort());
69 auto power = 1.0 / sqrt(numAnalogBeamElements);
70 for (auto ind = 0; ind < size; ind++)
71 {
72 Vector loc = antenna->GetElementLocation(ind);
73 double phase =
74 -2 * M_PI *
75 (sin(vAngle_radian) * cos(hAngle_radian) * loc.x +
76 sin(vAngle_radian) * sin(hAngle_radian) * loc.y + cos(vAngle_radian) * loc.z);
77 tempVector[ind] = (exp(std::complex<double>(0, phase)) * power);
78 }
79 return tempVector;
80}
81
82PhasedArrayModel::ComplexVector
83CreateDirectionalBfvAz(const Ptr<const UniformPlanarArray>& antenna, double azimuth, double zenith)
84{
85 UintegerValue uintValueNumColumns;
86 antenna->GetAttribute("NumColumns", uintValueNumColumns);
87
88 double hAngle_radian = azimuth * M_PI / 180;
89 double vAngle_radian = zenith * M_PI / 180;
90 uint16_t size = antenna->GetNumElems();
91 double power = 1 / sqrt(size);
92 PhasedArrayModel::ComplexVector tempVector(size);
93 if (size == 1)
94 {
95 tempVector[0] = power; // single AE, no BF
96 }
97 else
98 {
99 for (auto ind = 0; ind < size; ind++)
100 {
101 Vector loc = antenna->GetElementLocation(ind);
102 double phase =
103 -2 * M_PI *
104 (sin(vAngle_radian) * cos(hAngle_radian) * loc.x +
105 sin(vAngle_radian) * sin(hAngle_radian) * loc.y + cos(vAngle_radian) * loc.z);
106 tempVector[ind] = exp(std::complex<double>(0, phase)) * power;
107 }
108 }
109 return tempVector;
110}
111
112PhasedArrayModel::ComplexVector
113CreateDirectPathBfv(const Ptr<MobilityModel>& a,
114 const Ptr<MobilityModel>& b,
115 const Ptr<const UniformPlanarArray>& antenna)
116{
117 // retrieve the position of the two devices
118 Vector aPos = a->GetPosition();
119 Vector bPos = b->GetPosition();
120
121 // compute the azimuth and the elevation angles
122 Angles completeAngle(bPos, aPos);
123
124 double hAngleRadian = completeAngle.GetAzimuth();
125
126 double vAngleRadian = completeAngle.GetInclination(); // the elevation angle
127
128 // retrieve the number of antenna elements
129 int totNoArrayElements = antenna->GetNumElems();
130 auto numElemsPerPort = antenna->GetNumElemsPerPort();
131
132 // the total power is divided equally among the antenna elements
133 double power = 1 / sqrt(numElemsPerPort);
134
135 PhasedArrayModel::ComplexVector antennaWeights(totNoArrayElements);
136 // compute the antenna weights
137 for (int ind = 0; ind < totNoArrayElements; ind++)
138 {
139 Vector loc = antenna->GetElementLocation(ind);
140 double phase = -2 * M_PI *
141 (sin(vAngleRadian) * cos(hAngleRadian) * loc.x +
142 sin(vAngleRadian) * sin(hAngleRadian) * loc.y + cos(vAngleRadian) * loc.z);
143 antennaWeights[ind] = exp(std::complex<double>(0, phase)) * power;
144 }
145
146 return antennaWeights;
147}
148
149PhasedArrayModel::ComplexVector
150CreateKroneckerBfv(const Ptr<const UniformPlanarArray>& antenna, double rowAngle, double colAngle)
151{
152 // retrieve the number of antenna elements to create bf vector
153 PhasedArrayModel::ComplexVector bfVector(antenna->GetNumElems());
154 auto vPhasePerEl =
155 -2.0 * M_PI * antenna->GetAntennaVerticalSpacing() * cos(rowAngle * M_PI / 180.0);
156 auto hPhasePerEl =
157 -2.0 * M_PI * antenna->GetAntennaHorizontalSpacing() * cos(colAngle * M_PI / 180.0);
158
159 auto numAnalogBeamElements = antenna->GetVElemsPerPort() * antenna->GetHElemsPerPort();
160
161 // normalize because the total power is divided equally among the analog beams elements
162 auto normalizer = 1.0 / sqrt(numAnalogBeamElements);
163
164 auto numCols = antenna->GetNumColumns();
165 auto numRows = antenna->GetNumRows();
166
167 // compute the antenna weights (bfvector)
168 for (auto elIdx = size_t{0}; elIdx < antenna->GetNumElems(); elIdx++)
169 {
170 auto colIdx = elIdx % numCols;
171 auto rowIdx = elIdx / numCols;
172 auto isSkippedCol = (colIdx >= antenna->GetHElemsPerPort());
173 auto isSkippedRow = (rowIdx >= antenna->GetVElemsPerPort());
174 if (isSkippedCol || isSkippedRow || (elIdx >= numRows * numCols))
175 {
176 bfVector[elIdx] = 0.0;
177 continue;
178 }
179 auto combPhase = rowIdx * vPhasePerEl + colIdx * hPhasePerEl;
180 bfVector[elIdx] = normalizer * std::complex<double>(cos(combPhase), sin(combPhase));
181 }
182 return bfVector;
183}
184} // namespace ns3
PhasedArrayModel::ComplexVector CreateDirectionalBfvAz(const Ptr< const UniformPlanarArray > &antenna, double azimuth, double zenith)
Creates a beamforming vector for a given azimuth and zenith.
PhasedArrayModel::ComplexVector CreateDirectionalBfv(const Ptr< const UniformPlanarArray > &antenna, double sector, double elevation)
Creates a beamforming vector for a given sector and elevation.
PhasedArrayModel::ComplexVector CreateQuasiOmniBfv(const Ptr< const UniformPlanarArray > &antenna)
Create a quasi omni beamforming vector.