5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
realistic-beamforming-algorithm.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "realistic-beamforming-algorithm.h"
6
7#include "nr-gnb-phy.h"
8#include "nr-mac-scheduler-ns3.h"
9#include "nr-ue-phy.h"
10#include "nr-ue-rrc.h"
11
12#include "ns3/double.h"
13#include "ns3/mobility-model.h"
14#include "ns3/node.h"
15#include "ns3/nr-spectrum-value-helper.h"
16#include "ns3/random-variable-stream.h"
17#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
18#include "ns3/uinteger.h"
19
20namespace ns3
21{
22
23NS_LOG_COMPONENT_DEFINE("RealisticBeamformingAlgorithm");
24NS_OBJECT_ENSURE_REGISTERED(RealisticBeamformingAlgorithm);
25
27{
28 m_normalRandomVariable = CreateObject<NormalRandomVariable>();
29}
30
31void
32RealisticBeamformingAlgorithm::Install(const Ptr<NrSpectrumPhy>& gnbSpectrumPhy,
33 const Ptr<NrSpectrumPhy>& ueSpectrumPhy,
34 const Ptr<NrMacScheduler>& scheduler)
35{
36 NS_LOG_FUNCTION(this);
37 m_gnbSpectrumPhy = gnbSpectrumPhy;
38 m_ueSpectrumPhy = ueSpectrumPhy;
39 m_scheduler = scheduler;
40 m_nrUePhy = DynamicCast<NrUePhy>(m_ueSpectrumPhy->GetPhy());
41}
42
43int64_t
45{
46 NS_LOG_FUNCTION(this << stream);
47 m_normalRandomVariable->SetStream(stream);
48 return 1;
49}
50
51void
52RealisticBeamformingAlgorithm::DoDispose()
53{
54 m_gnbDevice = nullptr;
55 m_ueDevice = nullptr;
56 m_gnbSpectrumPhy = nullptr;
57 m_ueSpectrumPhy = nullptr;
58 m_scheduler = nullptr;
59 m_nrUePhy = nullptr;
60}
61
62TypeId
64{
65 static TypeId tid =
66 TypeId("ns3::RealisticBeamformingAlgorithm")
67 .SetParent<Object>()
68 .AddConstructor<RealisticBeamformingAlgorithm>()
69 .AddAttribute(
70 "OversamplingFactor",
71 "Samples per antenna row/column",
72 UintegerValue(1),
73 MakeUintegerAccessor(&RealisticBeamformingAlgorithm::m_oversamplingFactor),
74 MakeUintegerChecker<uint8_t>(1, 4))
75 .AddAttribute("UseSnrSrs",
76 "Denotes whether the SRS measurement will be SNR or SINR. If False"
77 "SINR is used, if True the SNR",
78 BooleanValue(true),
79 MakeBooleanAccessor(&RealisticBeamformingAlgorithm::SetUseSnrSrs,
80 &RealisticBeamformingAlgorithm::UseSnrSrs),
81 MakeBooleanChecker());
82 return tid;
83}
84
85uint8_t
86RealisticBeamformingAlgorithm::GetSrsSymbolsPerSlot()
87{
88 NS_LOG_FUNCTION(this);
89 NS_ABORT_MSG_UNLESS(m_scheduler, "Scheduler for the given ccId does not exist!");
90 return (DynamicCast<NrMacSchedulerNs3>(m_scheduler))->GetSrsCtrlSyms();
91}
92
93RealisticBeamformingAlgorithm::TriggerEventConf
94RealisticBeamformingAlgorithm::GetTriggerEventConf() const
95{
96 NS_LOG_FUNCTION(this);
97 NS_ABORT_MSG_UNLESS(m_gnbSpectrumPhy, "gNB spectrum PHY for the given ccId does not exist!");
98 Ptr<RealisticBfManager> realBf =
99 DynamicCast<RealisticBfManager>(m_gnbSpectrumPhy->GetBeamManager());
100 NS_ABORT_MSG_UNLESS(
101 realBf,
102 "Realistic BF manager at gNB does not exist. Realistic BF manager at gNB should "
103 "be installed when using realistic BF algorithm.");
104
105 TriggerEventConf conf;
106 conf.event = realBf->GetTriggerEvent();
107 conf.updatePeriodicity = realBf->GetUpdatePeriodicity();
108 conf.updateDelay = realBf->GetUpdateDelay();
109 return conf;
110}
111
112void
113RealisticBeamformingAlgorithm::SetUseSnrSrs(bool v)
114{
115 m_useSnrSrs = v;
116}
117
118bool
119RealisticBeamformingAlgorithm::UseSnrSrs() const
120{
121 return m_useSnrSrs;
122}
123
124void
125RealisticBeamformingAlgorithm::NotifySrsSinrReport(uint16_t cellId, uint16_t rnti, double srsSinr)
126{
127 NS_LOG_FUNCTION(this);
128 if (!m_useSnrSrs)
129 {
130 NotifySrsReport(cellId, rnti, srsSinr);
131 }
132}
133
134void
135RealisticBeamformingAlgorithm::NotifySrsSnrReport(uint16_t cellId, uint16_t rnti, double srsSnr)
136{
137 NS_LOG_FUNCTION(this);
138 if (m_useSnrSrs)
139 {
140 NotifySrsReport(cellId, rnti, srsSnr);
141 }
142}
143
144void
145RealisticBeamformingAlgorithm::NotifySrsReport(uint16_t cellId, uint16_t rnti, double srsReport)
146{
147 NS_LOG_FUNCTION(this);
148 NS_ABORT_MSG_UNLESS(m_gnbSpectrumPhy && m_ueSpectrumPhy,
149 "Function install must be called to install gNB and UE pair");
150 if (m_nrUePhy->GetRnti() != rnti)
151 {
152 NS_LOG_INFO("Ignoring SRS report. Not for me. Report for RNTI:"
153 << rnti << ", and my RNTI is:" << m_nrUePhy->GetRnti());
154 return;
155 }
156 // update SRS symbols counter
157 m_srsSymbolsCounter++;
158
159 // update max SRS SINR/SNR, i.e., reset when m_srsSymbolsCounter == 1, otherwise do max
160 m_maxSrsSinrPerSlot =
161 (m_srsSymbolsCounter > 1) ? std::max(srsReport, m_maxSrsSinrPerSlot) : srsReport;
162
163 // if we reached the last SRS symbol, check whether some event should be triggered
164 if (m_srsSymbolsCounter == GetSrsSymbolsPerSlot())
165 {
166 // reset symbols per slot counter
167 m_srsSymbolsCounter = 0;
168
169 TriggerEventConf conf = GetTriggerEventConf();
170
171 if (conf.event == RealisticBfManager::SRS_COUNT)
172 {
173 // it is time to update SRS periodicity counter
174 m_srsPeriodicityCounter++;
175 // reset or increase SRS periodicity counter
176 if (m_srsPeriodicityCounter == conf.updatePeriodicity)
177 {
178 NS_LOG_INFO("Update periodicity for updating BF reached. Time to trigger realistic "
179 "BF helper callback.");
180 // it is time to trigger helpers callback
181 Simulator::ScheduleNow(&RealisticBeamformingAlgorithm::NotifyHelper, this);
182 // and reset the counter
183 m_srsPeriodicityCounter = 0;
184 }
185 }
186 else if (conf.event == RealisticBfManager::DELAYED_UPDATE)
187 {
188 NS_LOG_INFO("Received all SRS symbols per current slot. Scheduler realistic BF helper "
189 "callback");
191 dui.updateTime = Simulator::Now() + conf.updateDelay;
192 dui.srsSinr = m_maxSrsSinrPerSlot; // SNR or SINR
193 dui.channelMatrix = GetChannelMatrix();
194 m_delayedUpdateInfo.push(dui);
195 // schedule delayed update
196 Simulator::Schedule(conf.updateDelay,
197 &RealisticBeamformingAlgorithm::NotifyHelper,
198 this);
199 Simulator::Schedule(conf.updateDelay + NanoSeconds(1),
200 &RealisticBeamformingAlgorithm::RemoveUsedDelayedUpdateInfo,
201 this);
202 // we add 1 second just to be sure that will be removed after NotifyHelper, even if it
203 // is added into event sequence after, should be called after
204 }
205 else
206 {
207 NS_ABORT_MSG("Unknown trigger event type.");
208 }
209 }
210}
211
212void
213RealisticBeamformingAlgorithm::RemoveUsedDelayedUpdateInfo()
214{
215 NS_LOG_FUNCTION(this);
216 NS_ASSERT_MSG(!m_delayedUpdateInfo.empty(), " No elements in m_delayedUpdateInfo queue.");
217 m_delayedUpdateInfo.pop(); // we can now delete this first element
218}
219
220void
221RealisticBeamformingAlgorithm::NotifyHelper()
222{
223 NS_LOG_FUNCTION(this);
224 m_helperCallback(m_gnbSpectrumPhy, m_ueSpectrumPhy);
225}
226
227void
228RealisticBeamformingAlgorithm::SetTriggerCallback(RealisticBfHelperCallback callback)
229{
230 m_helperCallback = callback;
231}
232
233Ptr<const MatrixBasedChannelModel::ChannelMatrix>
234RealisticBeamformingAlgorithm::GetChannelMatrix() const
235{
236 NS_LOG_FUNCTION(this);
237 Ptr<SpectrumChannel> gnbSpectrumChannel =
238 m_gnbSpectrumPhy
239 ->GetSpectrumChannel(); // SpectrumChannel should be const.. but need to change ns-3-dev
240
241 Ptr<SpectrumChannel> ueSpectrumChannel = m_ueSpectrumPhy->GetSpectrumChannel();
242
243 Ptr<PhasedArraySpectrumPropagationLossModel> gnbThreeGppSpectrumPropModel =
244 gnbSpectrumChannel->GetPhasedArraySpectrumPropagationLossModel();
245 Ptr<ThreeGppSpectrumPropagationLossModel> threeGppSplm =
246 DynamicCast<ThreeGppSpectrumPropagationLossModel>(gnbThreeGppSpectrumPropModel);
247 Ptr<MatrixBasedChannelModel> matrixBasedChannelModel = threeGppSplm->GetChannelModel();
248 Ptr<ThreeGppChannelModel> channelModel =
249 DynamicCast<ThreeGppChannelModel>(matrixBasedChannelModel);
250
251 NS_ASSERT(channelModel != nullptr);
252
253 Ptr<const MatrixBasedChannelModel::ChannelMatrix> originalChannelMatrix =
254 channelModel->GetChannel(m_gnbSpectrumPhy->GetMobility(),
255 m_ueSpectrumPhy->GetMobility(),
256 m_gnbSpectrumPhy->GetAntenna()->GetObject<PhasedArrayModel>(),
257 m_ueSpectrumPhy->GetAntenna()->GetObject<PhasedArrayModel>());
258
259 Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrixCopy =
260 Copy<const MatrixBasedChannelModel::ChannelMatrix>(originalChannelMatrix);
261 return channelMatrixCopy;
262}
263
264BeamformingVectorPair
266{
267 NS_ABORT_MSG_IF(m_gnbSpectrumPhy == nullptr || m_ueSpectrumPhy == nullptr,
268 "Gnb or UE PHY layer not set.");
269 double distance =
270 m_gnbSpectrumPhy->GetMobility()->GetDistanceFrom(m_ueSpectrumPhy->GetMobility());
271 NS_ABORT_MSG_IF(distance == 0,
272 "Beamforming method cannot be performed between two devices that are placed in "
273 "the same position.");
274
275 double max = 0;
276 double maxTxTheta = 0;
277 double maxRxTheta = 0;
278 uint16_t maxTxSector = 0;
279 uint16_t maxRxSector = 0;
280 PhasedArrayModel::ComplexVector maxTxW;
281 PhasedArrayModel::ComplexVector maxRxW;
282
283 TriggerEventConf conf = GetTriggerEventConf();
284 double srsSinr = 0;
285 Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix = nullptr;
286
287 if (conf.event == RealisticBfManager::DELAYED_UPDATE)
288 {
289 NS_ASSERT(!m_delayedUpdateInfo.empty());
290 DelayedUpdateInfo dui = m_delayedUpdateInfo.front();
291 NS_ABORT_MSG_UNLESS(dui.updateTime == Simulator::Now(),
292 "Current time should be equal to the updateTime from the "
293 "DelayedUpdateInfo structure."); // sanity check that we are using
294 // correct dui
295 srsSinr = dui.srsSinr;
296 channelMatrix = dui.channelMatrix;
297 }
298 else
299 {
300 srsSinr = m_maxSrsSinrPerSlot;
301 channelMatrix = GetChannelMatrix();
302 }
303
304 Ptr<UniformPlanarArray> gnbUpa =
305 DynamicCast<UniformPlanarArray>(m_gnbSpectrumPhy->GetAntenna());
306 Ptr<UniformPlanarArray> ueUpa = DynamicCast<UniformPlanarArray>(m_ueSpectrumPhy->GetAntenna());
307 NS_ASSERT_MSG(gnbUpa, "gNB antenna should be UniformPlanarArray");
308 NS_ASSERT_MSG(ueUpa, "UE antenna should be UniformPlanarArray");
309
310 uint16_t txNumCols = gnbUpa->GetNumColumns();
311 uint16_t txNumRows = gnbUpa->GetNumRows();
312 uint16_t rxNumCols = ueUpa->GetNumColumns();
313 uint16_t rxNumRows = ueUpa->GetNumRows();
314
315 NS_ASSERT(gnbUpa->GetNumElems() && ueUpa->GetNumElems());
316
317 double txZenithStep = 180 / ((txNumRows > 1 ? m_oversamplingFactor : 1) * txNumRows);
318 double txSectorStep = 1.0 / (txNumCols > 1 ? m_oversamplingFactor : 1);
319 double rxZenithStep = 180 / ((rxNumRows > 1 ? m_oversamplingFactor : 1) * rxNumRows);
320 double rxSectorStep = 1.0 / (rxNumCols > 1 ? m_oversamplingFactor : 1);
321
322 for (double txZenith = 0; txZenith < 180; txZenith += txZenithStep)
323 {
324 // Calculate beam elevation to center it into the middle of the wedge, and not at the start
325 double txTheta = txZenith + txZenithStep * 0.5;
326 for (double txSector = 0; txSector < txNumCols; txSector += txSectorStep)
327 {
328 NS_ASSERT(txSector < UINT16_MAX);
329 m_gnbSpectrumPhy->GetBeamManager()->SetSector(txSector, txTheta);
330 PhasedArrayModel::ComplexVector gnbW =
331 m_gnbSpectrumPhy->GetBeamManager()->GetCurrentBeamformingVector();
332
333 for (double rxZenith = 0; rxZenith < 180; rxZenith += txZenithStep)
334 {
335 // Calculate beam elevation to center it into the middle of the wedge, and not at
336 // the start
337 double rxTheta = rxZenith + rxZenithStep * 0.5;
338 for (double rxSector = 0; rxSector < rxNumCols; rxSector += rxSectorStep)
339 {
340 NS_ASSERT(rxSector < UINT16_MAX);
341 m_ueSpectrumPhy->GetBeamManager()->SetSector(rxSector, rxTheta);
342 PhasedArrayModel::ComplexVector ueW =
343 m_ueSpectrumPhy->GetBeamManager()->GetCurrentBeamformingVector();
344
345 NS_ABORT_MSG_IF(gnbW.GetSize() == 0 || ueW.GetSize() == 0,
346 "Beamforming vectors must be initialized in order to calculate "
347 "the long term matrix.");
348
349 const UniformPlanarArray::ComplexVector estimatedLongTermComponent =
350 GetEstimatedLongTermComponent(
351 channelMatrix,
352 gnbW,
353 ueW,
354 m_gnbSpectrumPhy->GetObject<MobilityModel>(),
355 m_ueSpectrumPhy->GetObject<MobilityModel>(),
356 srsSinr,
357 m_gnbSpectrumPhy->GetAntenna()->GetObject<PhasedArrayModel>(),
358 m_ueSpectrumPhy->GetAntenna()->GetObject<PhasedArrayModel>());
359
360 double estimatedLongTermMetric =
361 CalculateTheEstimatedLongTermMetric(estimatedLongTermComponent);
362
363 NS_LOG_LOGIC(
364 " Estimated long term metric value: "
365 << estimatedLongTermMetric << " gnb theta " << txTheta << " ue theta "
366 << rxTheta << " gnb sector "
367 << (M_PI * static_cast<double>(txSector) / static_cast<double>(txNumCols) -
368 0.5 * M_PI) /
369 M_PI * 180
370 << " ue sector "
371 << (M_PI * static_cast<double>(rxSector) / static_cast<double>(rxNumCols) -
372 0.5 * M_PI) /
373 M_PI * 180);
374
375 if (max < estimatedLongTermMetric)
376 {
377 max = estimatedLongTermMetric;
378 maxTxSector = txSector;
379 maxRxSector = rxSector;
380 maxTxTheta = txTheta;
381 maxRxTheta = rxTheta;
382 maxTxW = gnbW;
383 maxRxW = ueW;
384 }
385 }
386 }
387 }
388 }
389
390 BeamformingVectorPair bfPair = std::make_pair(
391 BeamformingVector(std::make_pair(
392 maxTxW,
393 BeamId(maxTxSector * (txNumCols > 1 ? m_oversamplingFactor : 1), maxTxTheta))),
394 BeamformingVector(std::make_pair(
395 maxRxW,
396 BeamId(maxRxSector * (rxNumCols > 1 ? m_oversamplingFactor : 1), maxRxTheta))));
397 NS_LOG_DEBUG(
398 "Beamforming vectors for gNB with node id: "
399 << m_gnbSpectrumPhy->GetMobility()->GetObject<Node>()->GetId()
400 << " and UE with node id: " << m_ueSpectrumPhy->GetMobility()->GetObject<Node>()->GetId()
401 << " txTheta " << maxTxTheta << " rxTheta " << maxRxTheta << " tx sector "
402 << (M_PI * static_cast<double>(maxTxSector) / static_cast<double>(txNumCols) - 0.5 * M_PI) /
403 M_PI * 180
404 << " rx sector "
405 << (M_PI * static_cast<double>(maxRxSector) / static_cast<double>(rxNumCols) - 0.5 * M_PI) /
406 M_PI * 180);
407
408 return bfPair;
409}
410
411double
412RealisticBeamformingAlgorithm::CalculateTheEstimatedLongTermMetric(
413 const UniformPlanarArray::ComplexVector& longTermComponent) const
414{
415 NS_LOG_FUNCTION(this);
416
417 double totalSum = 0;
418 for (std::complex<double> c : longTermComponent.GetValues())
419 {
420 totalSum += c.imag() * c.imag() + c.real() * c.real();
421 }
422 return totalSum;
423}
424
425UniformPlanarArray::ComplexVector
426RealisticBeamformingAlgorithm::GetEstimatedLongTermComponent(
427 const Ptr<const MatrixBasedChannelModel::ChannelMatrix>& channelMatrix,
428 const UniformPlanarArray::ComplexVector& aW,
429 const UniformPlanarArray::ComplexVector& bW,
430 Ptr<const MobilityModel> a,
431 Ptr<const MobilityModel> b,
432 double srsSinr,
433 Ptr<const PhasedArrayModel> aArray,
434 Ptr<const PhasedArrayModel> bArray) const
435{
436 NS_LOG_FUNCTION(this);
437
438 // check if the channel matrix was generated considering a as the s-node and
439 // b as the u-node or vice-versa
440 UniformPlanarArray::ComplexVector sW;
441 UniformPlanarArray::ComplexVector uW;
442 if (!channelMatrix->IsReverse(aArray->GetId(), bArray->GetId()))
443 {
444 sW = aW;
445 uW = bW;
446 }
447 else
448 {
449 sW = bW;
450 uW = aW;
451 }
452
453 uint16_t sAntenna = static_cast<uint16_t>(sW.GetSize());
454 uint16_t uAntenna = static_cast<uint16_t>(uW.GetSize());
455
456 NS_LOG_DEBUG("Calculate the estimation of the long term component with sAntenna: "
457 << sAntenna << " uAntenna: " << uAntenna);
458 NS_ABORT_IF(srsSinr == 0);
459
460 double varError = 1 / (srsSinr); // SINR the SINR from UL SRS reception
461 uint8_t numCluster = static_cast<uint8_t>(channelMatrix->m_channel.GetNumPages());
462
463 UniformPlanarArray::ComplexVector estimatedlongTerm(numCluster);
464 for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
465 {
466 std::complex<double> txSum(0, 0);
467 for (uint16_t sIndex = 0; sIndex < sAntenna; sIndex++)
468 {
469 std::complex<double> rxSum(0, 0);
470 for (uint16_t uIndex = 0; uIndex < uAntenna; uIndex++)
471 {
472 // error is generated from the normal random variable with mean 0 and variance
473 // varError*sqrt(1/2) for real/imaginary parts
474 std::complex<double> error =
475 std::complex<double>(m_normalRandomVariable->GetValue(0, sqrt(0.5) * varError),
476 m_normalRandomVariable->GetValue(0, sqrt(0.5) * varError));
477 std::complex<double> hEstimate =
478 channelMatrix->m_channel(uIndex, sIndex, cIndex) + error;
479 rxSum += uW[uIndex] * (hEstimate);
480 }
481 txSum = txSum + sW[sIndex] * rxSum;
482 }
483 estimatedlongTerm[cIndex] = txSum;
484 }
485 return estimatedlongTerm;
486}
487
488} // namespace ns3
Representation of a beam id.
Definition beam-id.h:26
void NotifySrsReport(uint16_t cellId, uint16_t rnti, double srsReport)
Saves SRS report (SNR or SINR depending on the configuration)
virtual BeamformingVectorPair GetBeamformingVectors()
Function that generates the beamforming vectors for a pair of communicating devices by using the dire...
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model....
void NotifySrsSnrReport(uint16_t cellId, uint16_t rnti, double srsSnr)
Saves SRS SNR report.
void NotifySrsSinrReport(uint16_t cellId, uint16_t rnti, double srsSinr)
Saves SRS SINR report.
std::pair< PhasedArrayModel::ComplexVector, BeamId > BeamformingVector
Physical representation of a beam.
Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix