5#include "nr-initial-association.h"
7#include "beamforming-vector.h"
9#include "ns3/nr-module.h"
10#include "ns3/object.h"
16NS_LOG_COMPONENT_DEFINE(
"NrInitialAssociation");
17NS_OBJECT_ENSURE_REGISTERED(NrInitialAssociation);
19using LocalSearchParams = NrInitialAssociation::LocalSearchParams;
25 TypeId(
"ns3::NrInitialAssociation")
27 .SetGroupName(
"Initial Access")
31 "handoff margin (dB); UE attaches to any gNB whose RSRP is within hand off margin",
35 MakeDoubleChecker<double>())
36 .AddAttribute(
"PrimaryCarrierIndex",
37 "primary carrier index",
41 MakeDoubleChecker<double>())
43 .AddAttribute(
"NumMainInterfererGnb",
44 "Number of main interferer gNBs",
48 MakeDoubleChecker<double>());
56 m_numMainInterfererGnb = numInterfere;
62 return m_numMainInterfererGnb;
68 NS_ASSERT(m_associatedGnb !=
nullptr);
69 return m_associatedGnb;
81 return m_maxRsrps[gnbId];
87 return m_bestBfVectors[gnbId];
99 m_startSsb = startSsb;
105 m_numBandsSsb = numSsbRb;
111 NS_ASSERT_MSG(m_freq,
"Error freq in initial association must set first");
113 auto numGnbBeams = m_colBeamAngles.size() * m_rowBeamAngles.size();
116 return (numGnbBeams <= 4);
118 else if (m_freq <= 6e9)
120 return (numGnbBeams <= 8);
124 return (numGnbBeams <= 64);
131 m_handoffMargin = margin;
143 return m_handoffMargin;
149 return m_rowBeamAngles;
155 m_rowBeamAngles = rowBfVect;
161 return m_colBeamAngles;
167 m_colBeamAngles = colBfVect;
185 m_gnbDevices = gnbDevices;
191 m_primaryCarrierIndex = index;
197 return m_primaryCarrierIndex;
201NrInitialAssociation::ExtractUeParameters()
const
204 auto phy = ueDev->
GetPhy(m_primaryCarrierIndex);
205 auto spectrumPhy = phy->GetSpectrumPhy();
206 auto spectrumChannel = spectrumPhy->GetSpectrumChannel();
207 auto spectrumPropModel = StaticCast<ThreeGppSpectrumPropagationLossModel>(
208 spectrumChannel->GetPhasedArraySpectrumPropagationLossModel());
209 AntennaArrayModels antModel;
210 for (uint8_t i = 0; i < spectrumPhy->GetNumPanels(); i++)
212 auto bPhasedArrayModel = spectrumPhy->GetPanelByIndex(i)->GetObject<PhasedArrayModel>();
213 antModel.ueArrayModel.push_back(
214 Copy<UniformPlanarArray>(DynamicCast<UniformPlanarArray>(bPhasedArrayModel)));
215 antModel.ueArrayModel[i]->SetNumVerticalPorts(bPhasedArrayModel->GetNumRows());
216 antModel.ueArrayModel[i]->SetNumHorizontalPorts(bPhasedArrayModel->GetNumColumns());
220 StaticCast<ThreeGppSpectrumPropagationLossModel>(spectrumPropModel)->GetChannelModel();
221 ChannelParams chParams;
222 chParams.channelModel = StaticCast<ThreeGppChannelModel>(channel);
223 chParams.spectrumPropModel = spectrumPropModel;
224 NS_ASSERT_MSG(chParams.channelModel !=
nullptr,
225 "Channel Model should be to be ThreeGppChannelModel");
228 mobility.ueMobility = spectrumPhy->GetMobility();
229 chParams.pathLossModel =
230 StaticCast<ThreeGppPropagationLossModel>(spectrumChannel->GetPropagationLossModel());
231 LocalSearchParams lsps{.chParams = chParams, .mobility = mobility, .antennaArrays = antModel};
235Ptr<UniformPlanarArray>
236NrInitialAssociation::ExtractGnbParameters(
const Ptr<NetDevice>& gnbDevice,
237 LocalSearchParams& lsps)
const
239 auto& chParams = lsps.chParams;
240 auto& mobility = lsps.mobility;
241 auto& antenna = lsps.antennaArrays;
243 const auto gnbDev = gnbDevice->GetObject<NrGnbNetDevice>();
244 const auto phy = gnbDev->
GetPhy(m_primaryCarrierIndex);
245 const auto spectrumPhy = phy->GetSpectrumPhy();
246 chParams.spectralModel = spectrumPhy->GetRxSpectrumModel();
247 auto bPhasedArrayModel = spectrumPhy->GetAntenna()->GetObject<PhasedArrayModel>();
251 antenna.gnbArrayModel =
252 Copy<UniformPlanarArray>(DynamicCast<UniformPlanarArray>(bPhasedArrayModel));
253 mobility.gnbMobility = spectrumPhy->GetMobility();
254 const auto rowElemsPerPort = antenna.gnbArrayModel->GetVElemsPerPort();
255 const auto colElemsPerPort = antenna.gnbArrayModel->GetHElemsPerPort();
260 antenna.gnbArrayModel->SetNumVerticalPorts(1);
261 antenna.gnbArrayModel->SetNumHorizontalPorts(1);
262 antenna.gnbArrayModel->SetNumRows(rowElemsPerPort);
263 antenna.gnbArrayModel->SetNumColumns(colElemsPerPort);
265 return antenna.gnbArrayModel;
268PhasedArrayModel::ComplexVector
269NrInitialAssociation::GenBeamforming(
double angRow,
271 Ptr<UniformPlanarArray> gnbArrayModel)
const
273 auto bfVector = CreateKroneckerBfv(gnbArrayModel, angRow, angCol);
278NrInitialAssociation::ComputeRxPsd(Ptr<const SpectrumSignalParameters> spectrumSigParam)
const
280 auto& spectrumChannelMatrix = spectrumSigParam->spectrumChannelMatrix;
281 NS_ASSERT_MSG(spectrumChannelMatrix->GetNumPages() >= m_numBandsSsb,
282 "The primary carrier bandwidth should have at least 20 PRBs to fit SSBs");
283 auto numUePorts = spectrumChannelMatrix->GetNumRows();
285 for (
size_t iRb = m_startSsb; iRb < m_startSsb + m_numBandsSsb; iRb++)
289 for (
size_t idxAnt = 0; idxAnt < numUePorts; idxAnt++)
291 psdPerRb += norm(spectrumChannelMatrix->Elem(idxAnt, 0, iRb));
293 totalPsd += psdPerRb;
299NrInitialAssociation::ComputeMaxRsrp(
const Ptr<NetDevice>& gnbDevice, LocalSearchParams& lsps)
301 auto& chParams = lsps.chParams;
302 auto& mobility = lsps.mobility;
303 auto& antennas = lsps.antennaArrays;
305 antennas.gnbArrayModel = ExtractGnbParameters(gnbDevice, lsps);
307 NS_ASSERT_MSG(chParams.spectralModel->GetNumBands() >= m_numBandsSsb,
308 "The primary carrier bandwidth should have at least 20 PRBs to fit SSBs");
309 std::vector<int> activeRbs;
310 for (
size_t rbId = m_startSsb; rbId < m_numBandsSsb + m_startSsb; rbId++)
312 activeRbs.push_back(rbId);
314 NrAnglePair bfAngles;
316 DynamicCast<NrGnbNetDevice>(gnbDevice)->GetPhy(0)->GetTxPower(),
318 chParams.spectralModel,
319 NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_USED);
320 auto txParams = Create<SpectrumSignalParameters>();
321 for (
auto& i : antennas.ueArrayModel)
323 PhasedArrayModel::ComplexVector uebfVector(i->GetNumElems());
325 i->SetBeamformingVector(uebfVector);
328 auto gnbTxPower = DynamicCast<NrGnbNetDevice>(gnbDevice)->GetPhy(0)->GetTxPower();
329 for (
size_t k = 0; k < antennas.ueArrayModel.size(); k++)
331 for (
size_t j = 0; j < m_rowBeamAngles.size(); j++)
333 for (
size_t i = 0; i < m_colBeamAngles.size(); i++)
336 GenBeamforming(m_rowBeamAngles[j], m_colBeamAngles[i], antennas.gnbArrayModel);
337 antennas.gnbArrayModel->SetBeamformingVector(bf);
338 txParams->psd = Copy<SpectrumValue>(fakePsd);
339 auto rxParam = chParams.spectrumPropModel->DoCalcRxPowerSpectralDensity(
341 mobility.gnbMobility,
343 antennas.gnbArrayModel,
344 antennas.ueArrayModel[k]);
345 if (!rxParam->spectrumChannelMatrix)
350 auto eng = gnbTxPower * ComputeRxPsd(rxParam);
351 if (eng > lsps.maxPsdFound)
353 lsps.maxPsdFound = eng;
354 bfAngles = {m_rowBeamAngles[j], m_colBeamAngles[i]};
362 chParams.pathLossModel->CalcRxPower(0, mobility.gnbMobility, mobility.ueMobility);
363 m_bestBfVectors.push_back(bfAngles);
365 return pow(10.0, attenuation / 10.0) * lsps.maxPsdFound;
369NrInitialAssociation::ComputeRsrpRatio(
const double totalRsrp,
const std::vector<uint16_t> idxVal)
371 NS_ASSERT_MSG(m_numIntfGnbs > 0,
372 "Number of main interfering gNBs should not be negative " << m_numIntfGnbs);
373 NS_ASSERT_MSG(m_numIntfGnbs < m_maxRsrps.size(),
374 "Number of main interfering gNBs should be less than the number of gNB ");
377 auto j = m_maxRsrps.size() - nIntf;
378 while (nIntf <
int(m_numIntfGnbs))
381 auto gnbDev = m_gnbDevices.Get(idxVal[j]);
382 if (gnbDev != m_associatedGnb)
384 m_intfGnbDevs.Add(gnbDev);
385 intfRsrp += std::pow(10.0, m_maxRsrps[idxVal[j]] / 10.0);
389 return (totalRsrp - intfRsrp) / intfRsrp;
395 NS_ASSERT_MSG(!m_maxRsrps.empty(),
"Populate RSRP values first");
396 NS_ASSERT_MSG(m_associatedGnb,
"Association should be completed first");
397 m_numIntfGnbs = numIntf;
399 std::vector<uint16_t> idxVal(m_maxRsrps.size());
400 std::iota(idxVal.begin(), idxVal.end(), 0);
403 std::sort(idxVal.begin(), idxVal.end(), [&](
int i,
int j) {
404 return (m_maxRsrps[i] < m_maxRsrps[j]);
409 NS_ASSERT_MSG(totalInterference > 0,
410 "Initial detected power of interferer should be greater than 0");
412 m_numIntfGnbs = useRelRsrp
415 m_rsrpRatio = ComputeRsrpRatio(totalInterference, idxVal);
421 std::vector<double> cumSumIntf(m_maxRsrps.size());
422 cumSumIntf[0] = std::pow(10.0, m_maxRsrps[idxVal[0]] / 10.0);
423 for (
size_t i = 1; i < m_maxRsrps.size(); ++i)
426 cumSumIntf[i] = cumSumIntf[i - 1] + std::pow(10.0, m_maxRsrps[idxVal[i]] / 10.0);
434 auto totalInterference =
435 cumSumIntf[m_maxRsrps.size() - 1] -
437 m_rsrpAsscGnb / 10.0);
441 return totalInterference;
446 const double relRsrpThreshold,
447 const double totalInterference)
const
449 auto numIntfGnbs = m_maxRsrps.size() - 1;
450 for (
size_t i = 0; i < m_maxRsrps.size(); ++i)
454 if ((1 + relRsrpThreshold) * cumSumIntf[i] > relRsrpThreshold * totalInterference)
467 std::vector<double> powers;
468 powers.resize(m_gnbDevices.GetN());
469 std::transform(m_gnbDevices.Begin(),
472 [&](
const Ptr<NetDevice> gnbDev) { return ComputeMaxRsrp(gnbDev, lsps); });
473 m_maxRsrps.resize(powers.size());
474 std::transform(powers.begin(), powers.end(), m_maxRsrps.begin(), [&](
const double val) {
475 return 10 * log10(val);
479std::pair<Ptr<NetDevice>,
double>
482 auto localParams = ExtractUeParameters();
483 m_freq = localParams.chParams.channelModel->GetFrequency();
484 if (m_maxRsrps.empty())
486 PopulateRsrps(localParams);
488 auto maxVal = std::max_element(m_maxRsrps.begin(), m_maxRsrps.end());
489 std::vector<bool> assocFlag;
490 assocFlag.resize(m_maxRsrps.size());
493 std::transform(m_maxRsrps.begin(), m_maxRsrps.end(), assocFlag.begin(), [&](
const double val) {
494 return (*maxVal - val) <= m_handoffMargin;
496 auto numPossibleGnb = std::accumulate(assocFlag.begin(), assocFlag.end(), 0);
499 Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
500 x->SetAttribute(
"Min", DoubleValue(1));
501 x->SetAttribute(
"Max", DoubleValue(numPossibleGnb));
502 auto value = x->GetInteger();
504 for (
size_t i = 0; i < m_gnbDevices.GetN(); i++)
506 count = (assocFlag[i] ? count + 1 : count);
507 if (count ==
int(value))
509 m_associatedGnb = m_gnbDevices.Get(i);
510 m_beamformingVector = GenBeamforming(m_bestBfVectors[i].rowAng,
511 m_bestBfVectors[i].colAng,
512 localParams.antennaArrays.gnbArrayModel);
513 m_rsrpAsscGnb = m_maxRsrps[i];
514 return std::make_pair(m_associatedGnb, m_rsrpAsscGnb);
517 NS_FATAL_ERROR(
"Method should have returned");
523 return m_rsrpAsscGnb;
530 auto phy = ueDev->
GetPhy(0);
531 auto spectrumPhy = phy->GetSpectrumPhy();
532 spectrumPhy->SetActivePanel(panelIndex);
539 auto phy = ueDev->
GetPhy(0);
540 auto spectrumPhy = phy->GetSpectrumPhy();
541 for (uint8_t i = 0; i < spectrumPhy->GetNumPanels(); i++)
543 if (spectrumPhy->GetPanelByIndex(i) == spectrumPhy->GetAntenna())
548 NS_ABORT_MSG(
"Missed the antenna panel");
Ptr< const NetDevice > GetUeDevice() const
Get UE device for which initial association is required.
static TypeId GetTypeId()
Get the type ID.
void SetNumMainInterfererGnb(uint8_t numInterfere)
Set number of main interferer gNBs.
Ptr< NetDevice > GetAssociatedGnb() const
Get the gNB associated gNB with the UE.
void SetUeActivePanel(int8_t panelIndex) const
Set the active panel for the UE device in NrSpectrumPhy.
double GetAssociatedRsrp() const
Get RSRP of associated gNB.
std::vector< double > GetColBeamAngles() const
Get col angles of the beam used.
size_t GetNumIntfGnbsByRelRsrp(const std::vector< double > cumSumIntf, const double relRsrpThreshold, const double totalInterference) const
Get the number of interference gNB based on Relative RSRP value.
void SetPrimaryCarrier(double index)
Set the primary BWP or carrier.
double GetCarrierFrequency() const
Get carrier frequency.
void SetUeDevice(const Ptr< NetDevice > &ueDev)
Set UE device for which initial association is required.
uint8_t GetUeActivePanel() const
Get the index of the active panel for the UE device in NrSpectrumPhy.
void SetHandoffMargin(double margin)
Set hand off margin in dB.
void SetColBeamAngles(std::vector< double > colVect)
Set column beam angles.
NetDeviceContainer GetInterferingGnbs() const
Get the gNBs which are main interferer with the UE.
std::pair< Ptr< NetDevice >, double > FindAssociatedGnb()
Find the gNB associated with the UE.
bool CheckNumBeamsAllowed() const
Check whether number of beams is corresponds to standard.
void InitializeIntfSet(uint16_t numIntfs, bool useRelRsrp, double relRsrpThreshold)
Create a container of gNBs forming a main interfering set with the UE.
double GetTotalInterference(const std::vector< double > &cumSumIntf) const
Calculate total interference based on RSRP values from gNBs.
std::vector< double > GetInterference(const std::vector< uint16_t > &idxVal) const
Calculate the cumulative sum of RSRP values from gNBs.
double GetPrimaryCarrier() const
Get the primary BWP or carrier.
void SetRowBeamAngles(std::vector< double > rowVect)
Set row beam angles.
uint8_t GetNumMainInterfererGnb() const
Get number of main interferer gNBs.
NrAnglePair GetBestBfv(uint64_t gnbId) const
Get the best beam from a given gNB to the UE.
void SetGnbDevices(const NetDeviceContainer &gnbDevices)
Set gnb devices among which association is done.
void SetStartSsbRb(uint16_t startSsb)
Set start RB for SSB.
double GetHandoffMargin() const
Get handoff margin.
double GetMaxRsrp(uint64_t gnbId) const
Get the max RSRP from a given gNB.
double GetRelativeRsrpRatio() const
Get relative RSRP of remaining gNBs to that of the main one.
std::vector< double > GetRowBeamAngles() const
Get row angles of the beam used.
void SetNumSsbRb(uint16_t numSsbRb)
Set number of RBs for association.
static Ptr< SpectrumValue > CreateTxPowerSpectralDensity(double powerTx, const std::vector< int > &rbIndexVector, const Ptr< const SpectrumModel > &txSm, enum PowerAllocationType allocationType)
Create SpectrumValue that will represent transmit power spectral density, and assuming that all RBs a...
The User Equipment NetDevice.
Ptr< NrUePhy > GetPhy(uint8_t index) const
Obtain a pointer to the PHY at the index specified.
Angle pair in degrees for the row and column angle of beam direction for uniform planar array NrIniti...
LocalSearchParams struct format to keep ChannelParams, Mobilities, and AntennaArrayModels of UE and g...