5G-LENA nr-v3.1-69-g2dd513a7
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-ue-phy.cc
1// Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2// Copyright (c) 2015 NYU WIRELESS, Tandon School of Engineering, New York University
3// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4//
5// SPDX-License-Identifier: GPL-2.0-only
6
7#define NS_LOG_APPEND_CONTEXT \
8 do \
9 { \
10 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11 } while (false);
12
13#include "nr-ue-phy.h"
14
15#include "beam-manager.h"
16#include "nr-ch-access-manager.h"
17#include "nr-radio-bearer-tag.h"
18#include "nr-ue-net-device.h"
19#include "nr-ue-power-control.h"
20
21#include <ns3/boolean.h>
22#include <ns3/double.h>
23#include <ns3/enum.h>
24#include <ns3/log.h>
25#include <ns3/node.h>
26#include <ns3/pointer.h>
27#include <ns3/simulator.h>
28
29#include <algorithm>
30#include <cfloat>
31
32namespace ns3
33{
34
35const Time NR_DEFAULT_PMI_INTERVAL_WB{MilliSeconds(10)}; // Wideband PMI update interval
36const Time NR_DEFAULT_PMI_INTERVAL_SB{MilliSeconds(2)}; // Subband PMI update interval
37
38NS_LOG_COMPONENT_DEFINE("NrUePhy");
39NS_OBJECT_ENSURE_REGISTERED(NrUePhy);
40
42{
43 NS_LOG_FUNCTION(this);
44 m_wbCqiLast = Simulator::Now();
45 m_ueCphySapProvider = new MemberNrUeCphySapProvider<NrUePhy>(this);
46 m_powerControl = CreateObject<NrUePowerControl>(this);
47 m_isConnected = false;
48 Simulator::Schedule(m_ueMeasurementsFilterPeriod, &NrUePhy::ReportUeMeasurements, this);
49}
50
52{
53 NS_LOG_FUNCTION(this);
54}
55
56void
58{
59 NS_LOG_FUNCTION(this);
60 delete m_ueCphySapProvider;
61 if (m_powerControl)
62 {
63 m_powerControl->Dispose();
64 m_powerControl = nullptr;
65 }
66 if (m_cam)
67 {
68 m_cam->Dispose();
69 m_cam = nullptr;
70 }
72}
73
74TypeId
76{
77 static TypeId tid =
78 TypeId("ns3::NrUePhy")
79 .SetParent<NrPhy>()
80 .AddConstructor<NrUePhy>()
81 .AddAttribute("TxPower",
82 "Transmission power in dBm",
83 DoubleValue(2.0),
84 MakeDoubleAccessor(&NrUePhy::m_txPower),
85 MakeDoubleChecker<double>())
86 .AddAttribute(
87 "NoiseFigure",
88 "Loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver."
89 " According to Wikipedia (http://en.wikipedia.org/wiki/Noise_figure), this is "
90 "\"the difference in decibels (dB) between"
91 " the noise output of the actual receiver to the noise output of an "
92 " ideal receiver with the same overall gain and bandwidth when the receivers "
93 " are connected to sources at the standard noise temperature T0.\" "
94 "In this model, we consider T0 = 290K.",
95 DoubleValue(5.0), // nr code from NYU and UniPd assumed in the code the value of
96 // 5dB, that is why we configure the default value to that
97 MakeDoubleAccessor(&NrPhy::SetNoiseFigure, &NrPhy::GetNoiseFigure),
98 MakeDoubleChecker<double>())
99 .AddAttribute(
100 "PowerAllocationType",
101 "Defines the type of the power allocation. Currently are supported "
102 "two types: \"UniformPowerAllocBw\", which is a uniform power allocation over all "
103 "bandwidth (over all RBs), and \"UniformPowerAllocBw\", which is a uniform "
104 "power allocation over used (active) RBs. By default is set a uniform power "
105 "allocation over used RBs .",
106 EnumValue(NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_USED),
107 MakeEnumAccessor<NrSpectrumValueHelper::PowerAllocationType>(
110 MakeEnumChecker(NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_BW,
111 "UniformPowerAllocBw",
112 NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_USED,
113 "UniformPowerAllocUsed"))
114 .AddAttribute("SpectrumPhy",
115 "The SpectrumPhy associated to this NrPhy",
116 TypeId::ATTR_GET,
117 PointerValue(),
118 MakePointerAccessor(&NrPhy::GetSpectrumPhy),
119 MakePointerChecker<NrSpectrumPhy>())
120 .AddAttribute("LBTThresholdForCtrl",
121 "After a DL/UL transmission, if we have less than this value to send the "
122 "UL CTRL, we consider the channel as granted",
123 TimeValue(MicroSeconds(25)),
124 MakeTimeAccessor(&NrUePhy::m_lbtThresholdForCtrl),
125 MakeTimeChecker())
126 .AddAttribute("TbDecodeLatency",
127 "Transport block decode latency",
128 TimeValue(MicroSeconds(100)),
130 MakeTimeChecker())
131 .AddAttribute("EnableUplinkPowerControl",
132 "If true, Uplink Power Control will be enabled.",
133 BooleanValue(false),
134 MakeBooleanAccessor(&NrUePhy::SetEnableUplinkPowerControl),
135 MakeBooleanChecker())
136 .AddAttribute("WbPmiUpdateInterval",
137 "Wideband PMI update interval",
138 TimeValue(NR_DEFAULT_PMI_INTERVAL_WB),
139 MakeTimeAccessor(&NrUePhy::m_wbPmiUpdateInterval),
140 MakeTimeChecker())
141 .AddAttribute("SbPmiUpdateInterval",
142 "Subband PMI update interval",
143 TimeValue(NR_DEFAULT_PMI_INTERVAL_SB),
144 MakeTimeAccessor(&NrUePhy::m_sbPmiUpdateInterval),
145 MakeTimeChecker())
146 .AddTraceSource("DlDataSinr",
147 "DL DATA SINR statistics.",
148 MakeTraceSourceAccessor(&NrUePhy::m_dlDataSinrTrace),
149 "ns3::NrUePhy::DlDataSinrTracedCallback")
150 .AddTraceSource("DlCtrlSinr",
151 "Report the SINR computed for DL CTRL",
152 MakeTraceSourceAccessor(&NrUePhy::m_dlCtrlSinrTrace),
153 "ns3::NrUePhy::DlCtrlSinrTracedCallback")
154 .AddAttribute("UeMeasurementsFilterPeriod",
155 "Time period for reporting UE measurements, i.e., the"
156 "length of layer-1 filtering.",
157 TimeValue(MilliSeconds(200)),
158 MakeTimeAccessor(&NrUePhy::m_ueMeasurementsFilterPeriod),
159 MakeTimeChecker())
160 .AddTraceSource("ReportUplinkTbSize",
161 "Report allocated uplink TB size for trace.",
162 MakeTraceSourceAccessor(&NrUePhy::m_reportUlTbSize),
163 "ns3::UlTbSize::TracedCallback")
164 .AddTraceSource("ReportDownlinkTbSize",
165 "Report allocated downlink TB size for trace.",
166 MakeTraceSourceAccessor(&NrUePhy::m_reportDlTbSize),
167 "ns3::DlTbSize::TracedCallback")
168 .AddTraceSource("ReportRsrp",
169 "RSRP statistics.",
170 MakeTraceSourceAccessor(&NrUePhy::m_reportRsrpTrace),
171 "ns3::CurrentRsrp::TracedCallback")
172 .AddTraceSource("UePhyRxedCtrlMsgsTrace",
173 "Ue PHY Control Messages Traces.",
174 MakeTraceSourceAccessor(&NrUePhy::m_phyRxedCtrlMsgsTrace),
175 "ns3::NrPhyRxTrace::RxedUePhyCtrlMsgsTracedCallback")
176 .AddTraceSource("UePhyTxedCtrlMsgsTrace",
177 "Ue PHY Control Messages Traces.",
178 MakeTraceSourceAccessor(&NrUePhy::m_phyTxedCtrlMsgsTrace),
179 "ns3::NrPhyRxTrace::TxedUePhyCtrlMsgsTracedCallback")
180 .AddTraceSource("UePhyRxedDlDciTrace",
181 "Ue PHY DL DCI Traces.",
182 MakeTraceSourceAccessor(&NrUePhy::m_phyUeRxedDlDciTrace),
183 "ns3::NrPhyRxTrace::RxedUePhyDlDciTracedCallback")
184 .AddTraceSource("UePhyTxedHarqFeedbackTrace",
185 "Ue PHY DL HARQ Feedback Traces.",
186 MakeTraceSourceAccessor(&NrUePhy::m_phyUeTxedHarqFeedbackTrace),
187 "ns3::NrPhyRxTrace::TxedUePhyHarqFeedbackTracedCallback")
188 .AddTraceSource("ReportPowerSpectralDensity",
189 "Power Spectral Density data.",
190 MakeTraceSourceAccessor(&NrUePhy::m_reportPowerSpectralDensity),
191 "ns3::NrUePhy::PowerSpectralDensityTracedCallback")
192 .AddTraceSource("ReportUeMeasurements",
193 "Report UE measurements RSRP (dBm) and RSRQ (dB).",
194 MakeTraceSourceAccessor(&NrUePhy::m_reportUeMeasurements),
195 "ns3::NrUePhy::RsrpRsrqTracedCallback")
196 .AddAttribute("EnableRlfDetection",
197 "If true, RLF detection will be enabled.",
198 BooleanValue(true),
199 MakeBooleanAccessor(&NrUePhy::m_enableRlfDetection),
200 MakeBooleanChecker());
201 return tid;
202}
203
204void
205NrUePhy::ChannelAccessGranted([[maybe_unused]] const Time& time)
206{
207 NS_LOG_FUNCTION(this);
208 // That will be granted only till the end of the slot
209 m_channelStatus = GRANTED;
210}
211
212void
213NrUePhy::ChannelAccessDenied()
214{
215 NS_LOG_FUNCTION(this);
216 m_channelStatus = NONE;
217}
218
219void
221{
222 NS_LOG_FUNCTION(this);
223 m_ueCphySapUser = s;
224}
225
228{
229 NS_LOG_FUNCTION(this);
230 return (m_ueCphySapProvider);
231}
232
233void
234NrUePhy::SetEnableUplinkPowerControl(bool enable)
235{
236 m_enableUplinkPowerControl = enable;
237}
238
239void
241{
242 m_txPower = pow;
243 m_powerControl->SetTxPower(pow);
244}
245
246double
248{
249 return m_txPower;
250}
251
252double
254{
255 return m_rsrp;
256}
257
258Ptr<NrUePowerControl>
260{
261 NS_LOG_FUNCTION(this);
262 return m_powerControl;
263}
264
265void
266NrUePhy::SetUplinkPowerControl(Ptr<NrUePowerControl> pc)
267{
268 m_powerControl = pc;
269}
270
271void
272NrUePhy::SetDlAmc(const Ptr<const NrAmc>& amc)
273{
274 m_amc = amc;
275
276 if (m_pmSearch)
277 {
278 m_pmSearch->SetAmc(amc);
279 }
280}
281
282void
283NrUePhy::SetSubChannelsForTransmission(const std::vector<int>& mask, uint32_t numSym)
284{
285 Ptr<SpectrumValue> txPsd = GetTxPowerSpectralDensity(mask);
286 NS_ASSERT(txPsd);
287
288 m_reportPowerSpectralDensity(m_currentSlot,
289 txPsd,
290 numSym * GetSymbolPeriod(),
291 m_rnti,
292 m_imsi,
293 GetBwpId(),
294 GetCellId());
295 m_spectrumPhy->SetTxPowerSpectralDensity(txPsd);
296}
297
298void
299NrUePhy::DoSendControlMessage(Ptr<NrControlMessage> msg)
300{
301 NS_LOG_FUNCTION(this << msg);
303}
304
305void
306NrUePhy::DoSendControlMessageNow(Ptr<NrControlMessage> msg)
307{
308 NS_LOG_FUNCTION(this << msg);
310}
311
312void
313NrUePhy::ProcessDataDci(const SfnSf& ulSfnSf,
314 const std::shared_ptr<DciInfoElementTdma>& dciInfoElem)
315{
316 NS_LOG_FUNCTION(this);
317
318 NS_LOG_DEBUG("UE" << m_rnti << " UL-DCI received for slot " << ulSfnSf << " symStart "
319 << static_cast<uint32_t>(dciInfoElem->m_symStart) << " numSym "
320 << static_cast<uint32_t>(dciInfoElem->m_numSym) << " tbs "
321 << dciInfoElem->m_tbSize << " harqId "
322 << static_cast<uint32_t>(dciInfoElem->m_harqProcess));
323
324 if (ulSfnSf == m_currentSlot)
325 {
326 InsertAllocation(dciInfoElem);
327 }
328 else
329 {
330 InsertFutureAllocation(ulSfnSf, dciInfoElem);
331 }
332}
333
334void
335NrUePhy::SendRachPreamble(uint32_t PreambleId, uint32_t Rnti)
336{
337 NS_LOG_FUNCTION(this << PreambleId);
338 m_raPreambleId = PreambleId;
339 Ptr<NrRachPreambleMessage> msg = Create<NrRachPreambleMessage>();
340 msg->SetSourceBwp(GetBwpId());
341 msg->SetRapId(PreambleId);
343}
344
345void
346NrUePhy::ProcessSrsDci(const SfnSf& ulSfnSf, const std::shared_ptr<DciInfoElementTdma>& dciInfoElem)
347{
348 NS_LOG_FUNCTION(this);
349 // Instruct PHY for transmitting the SRS
350 if (ulSfnSf == m_currentSlot)
351 {
352 InsertAllocation(dciInfoElem);
353 }
354 else
355 {
356 InsertFutureAllocation(ulSfnSf, dciInfoElem);
357 }
358}
359
360void
362{
363 NS_LOG_FUNCTION(this);
364
366 DoSetCellId(bwpId);
367}
368
369void
370NrUePhy::SetUlCtrlSyms(uint8_t ulCtrlSyms)
371{
372 m_ulCtrlSyms = ulCtrlSyms;
373}
374
375void
376NrUePhy::SetDlCtrlSyms(uint8_t dlCtrlSyms)
377{
378 m_dlCtrlSyms = dlCtrlSyms;
379}
380
381void
382NrUePhy::SetNumRbPerRbg(uint32_t numRbPerRbg)
383{
384 m_numRbPerRbg = numRbPerRbg;
385}
386
387void
388NrUePhy::SetPattern(const std::string& pattern)
389{
390 NS_LOG_FUNCTION(this);
391
392 static std::unordered_map<std::string, LteNrTddSlotType> lookupTable = {
393 {"DL", LteNrTddSlotType::DL},
394 {"UL", LteNrTddSlotType::UL},
395 {"S", LteNrTddSlotType::S},
396 {"F", LteNrTddSlotType::F},
397 };
398
399 std::vector<LteNrTddSlotType> vector;
400 std::stringstream ss(pattern);
401 std::string token;
402 std::vector<std::string> extracted;
403
404 while (std::getline(ss, token, '|'))
405 {
406 extracted.push_back(token);
407 }
408
409 vector.reserve(extracted.size());
410 for (const auto& v : extracted)
411 {
412 vector.push_back(lookupTable[v]);
413 }
414
415 m_tddPattern = vector;
416}
417
418uint32_t
420{
421 return m_numRbPerRbg;
422}
423
424double
425NrUePhy::ComputeAvgSinr(const SpectrumValue& sinr)
426{
427 // averaged SINR among RBs
428 double sum = 0.0;
429 uint16_t rbNum = 0;
430 Values::const_iterator it;
431
432 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
433 {
434 sum += (*it);
435 rbNum++;
436 }
437
438 double avrgSinr = (rbNum > 0) ? (sum / rbNum) : DBL_MAX;
439
440 return avrgSinr;
441}
442
443void
444NrUePhy::InsertAllocation(const std::shared_ptr<DciInfoElementTdma>& dci)
445{
446 NS_LOG_FUNCTION(this);
447
448 VarTtiAllocInfo varTtiInfo(dci);
449 m_currSlotAllocInfo.m_varTtiAllocInfo.push_back(varTtiInfo);
450 std::stable_sort(m_currSlotAllocInfo.m_varTtiAllocInfo.begin(),
452}
453
454void
455NrUePhy::InsertFutureAllocation(const SfnSf& sfnSf, const std::shared_ptr<DciInfoElementTdma>& dci)
456{
457 NS_LOG_FUNCTION(this);
458
459 VarTtiAllocInfo varTtiInfo(dci);
460 if (SlotAllocInfoExists(sfnSf))
461 {
462 auto& ulSlot = PeekSlotAllocInfo(sfnSf);
463 ulSlot.m_varTtiAllocInfo.push_back(varTtiInfo);
464 std::stable_sort(ulSlot.m_varTtiAllocInfo.begin(), ulSlot.m_varTtiAllocInfo.end());
465 }
466 else
467 {
468 SlotAllocInfo slotAllocInfo = SlotAllocInfo(sfnSf);
469 slotAllocInfo.m_varTtiAllocInfo.push_back(varTtiInfo);
470 PushBackSlotAllocInfo(slotAllocInfo);
471 }
472}
473
474void
475NrUePhy::PhyCtrlMessagesReceived(const Ptr<NrControlMessage>& msg)
476{
477 NS_LOG_FUNCTION(this);
478
479 if (msg->GetMessageType() == NrControlMessage::DL_DCI)
480 {
481 auto dciMsg = DynamicCast<NrDlDciMessage>(msg);
482 auto dciInfoElem = dciMsg->GetDciInfoElement();
483
484 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
485
486 if (dciInfoElem->m_rnti != 0 && dciInfoElem->m_rnti != m_rnti)
487 {
488 return; // DCI not for me
489 }
490
491 SfnSf dciSfn = m_currentSlot;
492 uint32_t k0Delay = dciMsg->GetKDelay();
493 dciSfn.Add(k0Delay);
494
495 NS_LOG_DEBUG("UE" << m_rnti << " DL-DCI received for slot " << dciSfn << " symStart "
496 << static_cast<uint32_t>(dciInfoElem->m_symStart) << " numSym "
497 << static_cast<uint32_t>(dciInfoElem->m_numSym) << " tbs "
498 << dciInfoElem->m_tbSize << " harqId "
499 << static_cast<uint32_t>(dciInfoElem->m_harqProcess));
500
501 /* BIG ASSUMPTION: We assume that K0 is always 0 */
502
503 auto it = m_harqIdToK1Map.find(dciInfoElem->m_harqProcess);
504 if (it != m_harqIdToK1Map.end())
505 {
506 m_harqIdToK1Map.erase(m_harqIdToK1Map.find(dciInfoElem->m_harqProcess));
507 }
508
509 m_harqIdToK1Map.insert(std::make_pair(dciInfoElem->m_harqProcess, dciMsg->GetK1Delay()));
510
511 m_phyUeRxedDlDciTrace(m_currentSlot,
512 GetCellId(),
513 m_rnti,
514 GetBwpId(),
515 dciInfoElem->m_harqProcess,
516 dciMsg->GetK1Delay());
517
518 InsertAllocation(dciInfoElem);
519
520 m_phySapUser->ReceiveControlMessage(msg);
521
522 if (m_enableUplinkPowerControl)
523 {
524 m_powerControl->ReportTpcPusch(dciInfoElem->m_tpc);
525 m_powerControl->ReportTpcPucch(dciInfoElem->m_tpc);
526 }
527 }
528 else if (msg->GetMessageType() == NrControlMessage::UL_DCI)
529 {
530 auto dciMsg = DynamicCast<NrUlDciMessage>(msg);
531 auto dciInfoElem = dciMsg->GetDciInfoElement();
532
533 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
534
535 if (dciInfoElem->m_rnti != 0 && dciInfoElem->m_rnti != m_rnti)
536 {
537 return; // DCI not for me
538 }
539
540 SfnSf ulSfnSf = m_currentSlot;
541 uint32_t k2Delay = dciMsg->GetKDelay();
542 ulSfnSf.Add(k2Delay);
543
544 if (dciInfoElem->m_type == DciInfoElementTdma::DATA)
545 {
546 ProcessDataDci(ulSfnSf, dciInfoElem);
547 m_phySapUser->ReceiveControlMessage(msg);
548 }
549 else if (dciInfoElem->m_type == DciInfoElementTdma::SRS)
550 {
551 ProcessSrsDci(ulSfnSf, dciInfoElem);
552 // Do not pass the DCI to MAC
553 }
554 }
555 else if (msg->GetMessageType() == NrControlMessage::MIB)
556 {
557 NS_LOG_DEBUG("received MIB");
558 Ptr<NrMibMessage> msg2 = DynamicCast<NrMibMessage>(msg);
559 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
560 m_ueCphySapUser->RecvMasterInformationBlock(GetCellId(), msg2->GetMib());
561 }
562 else if (msg->GetMessageType() == NrControlMessage::SIB1)
563 {
564 Ptr<NrSib1Message> msg2 = DynamicCast<NrSib1Message>(msg);
565 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
566 m_ueCphySapUser->RecvSystemInformationBlockType1(GetCellId(), msg2->GetSib1());
567 }
568 else if (msg->GetMessageType() == NrControlMessage::RAR)
569 {
570 Ptr<NrRarMessage> rarMsg = DynamicCast<NrRarMessage>(msg);
571
572 ProcessRar(rarMsg);
573 }
574 else
575 {
576 NS_LOG_INFO("Message type not recognized " << msg->GetMessageType());
577 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
578 m_phySapUser->ReceiveControlMessage(msg);
579 }
580}
581
582void
583NrUePhy::ProcessRar(const Ptr<NrRarMessage>& rarMsg)
584{
585 NS_LOG_FUNCTION(this);
586 bool myRar = false;
587 {
588 for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
589 {
590 NS_LOG_INFO("Received RAR in slot" << m_currentSlot << " with RA preamble ID: "
591 << std::to_string(it->rarPayload.raPreambleId));
592 if (it->rarPayload.raPreambleId == m_raPreambleId)
593 {
594 NS_LOG_INFO("Received RAR with RA preamble ID:" << +it->rarPayload.raPreambleId
595 << " current RA preamble ID is :"
596 << m_raPreambleId);
597 // insert allocation
598 SfnSf ulSfnSf = m_currentSlot;
599 uint32_t k2Delay = it->rarPayload.k2Delay;
600 ulSfnSf.Add(k2Delay);
601 NS_LOG_DEBUG("Insert RAR UL DCI allocation for " << ulSfnSf);
602 ProcessDataDci(ulSfnSf, (*it).rarPayload.ulMsg3Dci);
603 myRar = true;
604 // notify MAC and above about transmission opportunity
605 m_phySapUser->ReceiveControlMessage(rarMsg);
606 // fire CTRL msg trace
607 m_phyRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), rarMsg);
608 // reset RACH variables with out of range values
609 m_raPreambleId = 255;
610 }
611 }
612 if (!myRar)
613 {
614 NS_LOG_DEBUG("Skipping RAR, does not contain preamble ID."
615 << "\n My preamble id: " << std::to_string(m_raPreambleId) << " found:");
616 for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
617 {
618 NS_LOG_DEBUG("rapId: " << std::to_string(it->rapId));
619 }
620 }
621 }
622}
623
624void
625NrUePhy::TryToPerformLbt()
626{
627 NS_LOG_FUNCTION(this);
628 uint8_t ulCtrlSymStart = 0;
629 uint8_t ulCtrlNumSym = 0;
630
631 for (const auto& alloc : m_currSlotAllocInfo.m_varTtiAllocInfo)
632 {
633 if (alloc.m_dci->m_type == DciInfoElementTdma::CTRL &&
634 alloc.m_dci->m_format == DciInfoElementTdma::UL)
635 {
636 ulCtrlSymStart = alloc.m_dci->m_symStart;
637 ulCtrlNumSym = alloc.m_dci->m_numSym;
638 break;
639 }
640 }
641
642 if (ulCtrlNumSym != 0)
643 {
644 // We have an UL CTRL symbol scheduled and we have to transmit CTRLs..
645 // .. so we check that we have at least 25 us between the latest DCI,
646 // or we have to schedule an LBT event.
647
648 Time limit = m_lastSlotStart + GetSlotPeriod() -
649 ((GetSymbolsPerSlot() - ulCtrlSymStart) * GetSymbolPeriod()) -
650 m_lbtThresholdForCtrl;
651
652 for (const auto& alloc : m_currSlotAllocInfo.m_varTtiAllocInfo)
653 {
654 int64_t symbolPeriod = GetSymbolPeriod().GetMicroSeconds();
655 int64_t dciEndsAt = m_lastSlotStart.GetMicroSeconds() +
656 ((alloc.m_dci->m_numSym + alloc.m_dci->m_symStart) * symbolPeriod);
657
658 if (alloc.m_dci->m_type != DciInfoElementTdma::DATA &&
659 alloc.m_dci->m_type != DciInfoElementTdma::MSG3)
660 {
661 continue;
662 }
663
664 if (limit.GetMicroSeconds() < dciEndsAt)
665 {
666 NS_LOG_INFO("This data DCI ends at "
667 << MicroSeconds(dciEndsAt)
668 << " which is inside the LBT shared COT (the limit is " << limit
669 << "). No need for LBT");
670 m_lbtEvent.Cancel(); // Forget any LBT we previously set, because of the new
671 // DCI information
672 m_channelStatus = GRANTED;
673 }
674 else
675 {
676 NS_LOG_INFO("This data DCI starts at "
677 << +alloc.m_dci->m_symStart << " for " << +alloc.m_dci->m_numSym
678 << " ends at " << MicroSeconds(dciEndsAt)
679 << " which is outside the LBT shared COT (the limit is " << limit
680 << ").");
681 }
682 }
683 if (m_channelStatus != GRANTED)
684 {
685 Time sched = m_lastSlotStart - Simulator::Now() + (GetSymbolPeriod() * ulCtrlSymStart) -
686 MicroSeconds(25);
687 NS_LOG_DEBUG("Scheduling an LBT for sending the UL CTRL at "
688 << Simulator::Now() + sched);
689 m_lbtEvent.Cancel();
690 m_lbtEvent = Simulator::Schedule(sched, &NrUePhy::RequestAccess, this);
691 }
692 else
693 {
694 NS_LOG_DEBUG("Not scheduling LBT: the UE has a channel status that is GRANTED");
695 }
696 }
697 else
698 {
699 NS_LOG_INFO("Not scheduling LBT; the UE has no UL CTRL symbols available");
700 }
701}
702
703void
704NrUePhy::RequestAccess()
705{
706 NS_LOG_FUNCTION(this);
707 NS_LOG_DEBUG("Request access because we have to transmit UL CTRL");
708 m_cam->RequestAccess(); // This will put the m_channelStatus to granted when
709 // the channel will be granted.
710}
711
712void
713NrUePhy::PushCtrlAllocations(const SfnSf currentSfnSf)
714{
715 NS_LOG_FUNCTION(this);
716
717 // The UE does not know anything from the GNB yet, so listen on the default
718 // bandwidth.
719 std::vector<uint8_t> rbgBitmask(GetRbNum(), 1);
720
721 // The UE still doesn't know the TDD pattern, so just add a DL CTRL
722 if (m_tddPattern.empty())
723 {
724 NS_LOG_INFO("TDD Pattern unknown, insert DL CTRL at the beginning of the slot");
725 VarTtiAllocInfo dlCtrlSlot(std::make_shared<DciInfoElementTdma>(0,
726 m_dlCtrlSyms,
729 rbgBitmask));
730 m_currSlotAllocInfo.m_varTtiAllocInfo.push_front(dlCtrlSlot);
731 return;
732 }
733
734 uint64_t currentSlotN = currentSfnSf.Normalize() % m_tddPattern.size();
735
736 if (m_tddPattern[currentSlotN] < LteNrTddSlotType::UL)
737 {
738 NS_LOG_DEBUG("The current TDD pattern indicates that we are in a "
739 << m_tddPattern[currentSlotN]
740 << " slot, so insert DL CTRL at the beginning of the slot");
741 VarTtiAllocInfo dlCtrlSlot(std::make_shared<DciInfoElementTdma>(0,
742 m_dlCtrlSyms,
745 rbgBitmask));
746 m_currSlotAllocInfo.m_varTtiAllocInfo.push_front(dlCtrlSlot);
747 }
748 if (m_tddPattern[currentSlotN] > LteNrTddSlotType::DL)
749 {
750 NS_LOG_DEBUG("The current TDD pattern indicates that we are in a "
751 << m_tddPattern[currentSlotN]
752 << " slot, so insert UL CTRL at the end of the slot");
753 VarTtiAllocInfo ulCtrlSlot(
754 std::make_shared<DciInfoElementTdma>(GetSymbolsPerSlot() - m_ulCtrlSyms,
755 m_ulCtrlSyms,
758 rbgBitmask));
759 m_currSlotAllocInfo.m_varTtiAllocInfo.push_back(ulCtrlSlot);
760 }
761}
762
763void
764NrUePhy::StartSlot(const SfnSf& s)
765{
766 NS_LOG_FUNCTION(this);
767 m_currentSlot = s;
768 m_lastSlotStart = Simulator::Now();
769
770 // Call MAC before doing anything in PHY
771 m_phySapUser->SlotIndication(m_currentSlot); // trigger mac
772
773 // update the current slot object, and insert DL/UL CTRL allocations depending on the TDD
774 // pattern
775 if (SlotAllocInfoExists(m_currentSlot))
776 {
778 }
779 else
780 {
781 m_currSlotAllocInfo = SlotAllocInfo(m_currentSlot);
782 }
783
784 PushCtrlAllocations(m_currentSlot);
785
786 NS_ASSERT(m_currSlotAllocInfo.m_sfnSf == m_currentSlot);
787
788 NS_LOG_DEBUG("UE " << m_rnti << " start slot " << m_currSlotAllocInfo.m_sfnSf
789 << " composed by the following allocations, total "
791 for (const auto& alloc : m_currSlotAllocInfo.m_varTtiAllocInfo)
792 {
793 std::string direction;
794 std::string type;
795
796 if (alloc.m_dci->m_format == DciInfoElementTdma::UL)
797 {
798 direction = "UL";
799 }
800 else
801 {
802 direction = "DL";
803 }
804
805 switch (alloc.m_dci->m_type)
806 {
808 type = "SRS";
809 NS_LOG_DEBUG("Allocation from sym "
810 << static_cast<uint32_t>(alloc.m_dci->m_symStart) << " to sym "
811 << static_cast<uint32_t>(alloc.m_dci->m_numSym + alloc.m_dci->m_symStart)
812 << " direction " << direction << " type " << type);
813 break;
815 type = "DATA";
816 NS_LOG_INFO("Allocation from sym "
817 << static_cast<uint32_t>(alloc.m_dci->m_symStart) << " to sym "
818 << static_cast<uint32_t>(alloc.m_dci->m_numSym + alloc.m_dci->m_symStart)
819 << " direction " << direction << " type " << type);
820 break;
822 type = "CTRL";
823 NS_LOG_DEBUG("Allocation from sym "
824 << static_cast<uint32_t>(alloc.m_dci->m_symStart) << " to sym "
825 << static_cast<uint32_t>(alloc.m_dci->m_numSym + alloc.m_dci->m_symStart)
826 << " direction " << direction << " type " << type);
827 break;
829 type = "MSG3";
830 NS_LOG_DEBUG("Allocation from sym "
831 << static_cast<uint32_t>(alloc.m_dci->m_symStart) << " to sym "
832 << static_cast<uint32_t>(alloc.m_dci->m_numSym + alloc.m_dci->m_symStart)
833 << " direction " << direction << " type " << type);
834 break;
835 default:
836 NS_LOG_ERROR("Unknown type DciInfoElementTdma::VarTtiType " << alloc.m_dci->m_type);
837 }
838 }
839
840 TryToPerformLbt();
841
842 VarTtiAllocInfo allocation = m_currSlotAllocInfo.m_varTtiAllocInfo.front();
844
845 auto nextVarTtiStart = GetSymbolPeriod() * allocation.m_dci->m_symStart;
846
847 auto ctrlMsgs = PopCurrentSlotCtrlMsgs();
848 if (m_netDevice)
849 {
850 DynamicCast<NrUeNetDevice>(m_netDevice)->RouteOutgoingCtrlMsgs(ctrlMsgs, GetBwpId());
851 }
852 else
853 {
854 // No netDevice (that could happen in tests) so just redirect them to us
855 for (const auto& msg : ctrlMsgs)
856 {
857 EncodeCtrlMsg(msg);
858 }
859 }
860
861 Simulator::Schedule(nextVarTtiStart, &NrUePhy::StartVarTti, this, allocation.m_dci);
862}
863
864Time
865NrUePhy::DlCtrl(const std::shared_ptr<DciInfoElementTdma>& dci)
866{
867 NS_LOG_FUNCTION(this);
868
869 Time varTtiDuration = GetSymbolPeriod() * dci->m_numSym;
870
871 NS_LOG_DEBUG("UE" << m_rnti
872 << " RXing DL CTRL frame for"
873 " symbols "
874 << +dci->m_symStart << "-" << +(dci->m_symStart + dci->m_numSym - 1)
875 << "\t start " << Simulator::Now() << " end "
876 << (Simulator::Now() + varTtiDuration));
877
878 m_tryToPerformLbt = true;
879
880 return varTtiDuration;
881}
882
883Time
884NrUePhy::UlSrs(const std::shared_ptr<DciInfoElementTdma>& dci)
885{
886 NS_LOG_FUNCTION(this);
887
888 std::vector<int> channelRbs;
889 for (uint32_t i = 0; i < GetRbNum(); i++)
890 {
891 channelRbs.push_back(static_cast<int>(i));
892 }
893 SetSubChannelsForTransmission(channelRbs, dci->m_numSym);
894
895 std::list<Ptr<NrControlMessage>> srsMsg;
896 Ptr<NrSrsMessage> srs = Create<NrSrsMessage>();
897 srs->SetSourceBwp(GetBwpId());
898 srsMsg.emplace_back(srs);
899 Time varTtiDuration = GetSymbolPeriod() * dci->m_numSym;
900
901 m_phyTxedCtrlMsgsTrace(m_currentSlot, GetCellId(), dci->m_rnti, GetBwpId(), *srsMsg.begin());
902 m_spectrumPhy->StartTxUlControlFrames(srsMsg, varTtiDuration - NanoSeconds(1.0));
903
904 NS_LOG_DEBUG("UE" << m_rnti << " TXing UL SRS frame for symbols " << +dci->m_symStart << "-"
905 << +(dci->m_symStart + dci->m_numSym - 1) << "\t start " << Simulator::Now()
906 << " end " << (Simulator::Now() + varTtiDuration - NanoSeconds(1.0)));
907
908 ChannelAccessDenied(); // Reset the channel status
909 return varTtiDuration;
910}
911
912Time
913NrUePhy::UlCtrl(const std::shared_ptr<DciInfoElementTdma>& dci)
914{
915 NS_LOG_FUNCTION(this);
916
917 Time varTtiDuration = GetSymbolPeriod() * dci->m_numSym;
918
919 if (m_ctrlMsgs.empty())
920 {
921 NS_LOG_DEBUG("UE" << m_rnti << " reserved space for UL CTRL frame for symbols "
922 << +dci->m_symStart << "-" << +(dci->m_symStart + dci->m_numSym - 1)
923 << "\t start " << Simulator::Now() << " end "
924 << (Simulator::Now() + varTtiDuration - NanoSeconds(1.0))
925 << " but no data to transmit");
926 m_cam->Cancel();
927 return varTtiDuration;
928 }
929 else if (m_channelStatus != GRANTED)
930 {
931 NS_LOG_INFO("UE" << m_rnti << " has to transmit CTRL but channel not granted");
932 m_cam->Cancel();
933 return varTtiDuration;
934 }
935
936 for (const auto& msg : m_ctrlMsgs)
937 {
938 m_phyTxedCtrlMsgsTrace(m_currentSlot, GetCellId(), dci->m_rnti, GetBwpId(), msg);
939
940 if (msg->GetMessageType() == NrControlMessage::DL_HARQ)
941 {
942 Ptr<NrDlHarqFeedbackMessage> harqMsg = DynamicCast<NrDlHarqFeedbackMessage>(msg);
943 uint8_t harqId = harqMsg->GetDlHarqFeedback().m_harqProcessId;
944
945 auto it = m_harqIdToK1Map.find(harqId);
946 if (it != m_harqIdToK1Map.end())
947 {
948 m_phyUeTxedHarqFeedbackTrace(m_currentSlot,
949 GetCellId(),
950 m_rnti,
951 GetBwpId(),
952 static_cast<uint32_t>(harqId),
953 it->second);
954 }
955 }
956 }
957
958 std::vector<int> channelRbs;
959 for (uint32_t i = 0; i < GetRbNum(); i++)
960 {
961 channelRbs.push_back(static_cast<int>(i));
962 }
963
964 if (m_enableUplinkPowerControl)
965 {
966 m_txPower = m_powerControl->GetPucchTxPower(channelRbs.size());
967 }
968 SetSubChannelsForTransmission(channelRbs, dci->m_numSym);
969
970 NS_LOG_DEBUG("UE" << m_rnti << " TXing UL CTRL frame for symbols " << +dci->m_symStart << "-"
971 << +(dci->m_symStart + dci->m_numSym - 1) << "\t start " << Simulator::Now()
972 << " end " << (Simulator::Now() + varTtiDuration - NanoSeconds(1.0)));
973
974 SendCtrlChannels(varTtiDuration - NanoSeconds(1.0));
975
976 ChannelAccessDenied(); // Reset the channel status
977 return varTtiDuration;
978}
979
980Time
981NrUePhy::DlData(const std::shared_ptr<DciInfoElementTdma>& dci)
982{
983 NS_LOG_FUNCTION(this);
984
985 m_receptionEnabled = true;
986 Time varTtiDuration = GetSymbolPeriod() * dci->m_numSym;
987 NS_ASSERT(dci->m_rnti == m_rnti);
988 m_spectrumPhy->AddExpectedTb({dci->m_ndi,
989 dci->m_tbSize,
990 dci->m_mcs,
991 dci->m_rank,
992 dci->m_rnti,
993 FromRBGBitmaskToRBAssignment(dci->m_rbgBitmask),
994 dci->m_harqProcess,
995 dci->m_rv,
996 true,
997 dci->m_symStart,
998 dci->m_numSym,
999 m_currentSlot});
1000 m_reportDlTbSize(m_netDevice->GetObject<NrUeNetDevice>()->GetImsi(), dci->m_tbSize);
1001 NS_LOG_INFO("UE" << m_rnti << " RXing DL DATA frame for symbols " << +dci->m_symStart << "-"
1002 << +(dci->m_symStart + dci->m_numSym - 1) << " num of rbg assigned: "
1003 << FromRBGBitmaskToRBAssignment(dci->m_rbgBitmask).size()
1004 << ". RX will take place for " << varTtiDuration);
1005
1006 return varTtiDuration;
1007}
1008
1009Time
1010NrUePhy::UlData(const std::shared_ptr<DciInfoElementTdma>& dci)
1011{
1012 NS_LOG_FUNCTION(this);
1013 if (m_enableUplinkPowerControl)
1014 {
1015 m_txPower = m_powerControl->GetPuschTxPower(
1016 (FromRBGBitmaskToRBAssignment(dci->m_rbgBitmask)).size());
1017 }
1018 SetSubChannelsForTransmission(FromRBGBitmaskToRBAssignment(dci->m_rbgBitmask), dci->m_numSym);
1019 Time varTtiDuration = GetSymbolPeriod() * dci->m_numSym;
1020 std::list<Ptr<NrControlMessage>> ctrlMsg;
1021 Ptr<PacketBurst> pktBurst = GetPacketBurst(m_currentSlot, dci->m_symStart, dci->m_rnti);
1022 if (pktBurst && pktBurst->GetNPackets() > 0)
1023 {
1024 std::list<Ptr<Packet>> pkts = pktBurst->GetPackets();
1025 NrRadioBearerTag bearerTag;
1026 if (!pkts.front()->PeekPacketTag(bearerTag))
1027 {
1028 NS_FATAL_ERROR("No radio bearer tag");
1029 }
1030 }
1031 else
1032 {
1033 // put an error, as something is wrong. The UE should not be scheduled
1034 // if there is no data for him...
1035 if (dci->m_type != DciInfoElementTdma::MSG3)
1036 {
1037 NS_FATAL_ERROR("The UE " << dci->m_rnti << " has been scheduled without data");
1038 }
1039 else
1040 {
1041 NS_LOG_WARN("Not sending MSG3. Probably in RRC IDEAL mode.");
1042 return varTtiDuration;
1043 }
1044 }
1045 m_reportUlTbSize(m_netDevice->GetObject<NrUeNetDevice>()->GetImsi(), dci->m_tbSize);
1046
1047 NS_LOG_DEBUG("UE" << m_rnti << " TXing UL DATA frame for"
1048 << " symbols " << +dci->m_symStart << "-"
1049 << +(dci->m_symStart + dci->m_numSym - 1) << "\t start " << Simulator::Now()
1050 << " end " << (Simulator::Now() + varTtiDuration));
1051
1052 Simulator::Schedule(NanoSeconds(1.0),
1053 &NrUePhy::SendDataChannels,
1054 this,
1055 pktBurst,
1056 ctrlMsg,
1057 dci,
1058 varTtiDuration - NanoSeconds(2.0));
1059 return varTtiDuration;
1060}
1061
1062void
1063NrUePhy::StartVarTti(const std::shared_ptr<DciInfoElementTdma>& dci)
1064{
1065 NS_LOG_FUNCTION(this);
1066 Time varTtiDuration;
1067
1068 m_currTbs = dci->m_tbSize;
1069 m_receptionEnabled = false;
1070
1071 if (dci->m_type == DciInfoElementTdma::CTRL && dci->m_format == DciInfoElementTdma::DL)
1072 {
1073 varTtiDuration = DlCtrl(dci);
1074 }
1075 else if (dci->m_type == DciInfoElementTdma::CTRL && dci->m_format == DciInfoElementTdma::UL)
1076 {
1077 varTtiDuration = UlCtrl(dci);
1078 }
1079 else if (dci->m_type == DciInfoElementTdma::SRS && dci->m_format == DciInfoElementTdma::UL)
1080 {
1081 varTtiDuration = UlSrs(dci);
1082 }
1083 else if (dci->m_type == DciInfoElementTdma::DATA && dci->m_format == DciInfoElementTdma::DL)
1084 {
1085 varTtiDuration = DlData(dci);
1086 }
1087 else if ((dci->m_type == DciInfoElementTdma::DATA || dci->m_type == DciInfoElementTdma::MSG3) &&
1088 dci->m_format == DciInfoElementTdma::UL)
1089 {
1090 varTtiDuration = UlData(dci);
1091 }
1092
1093 Simulator::Schedule(varTtiDuration, &NrUePhy::EndVarTti, this, dci);
1094}
1095
1096void
1097NrUePhy::EndVarTti(const std::shared_ptr<DciInfoElementTdma>& dci)
1098{
1099 NS_LOG_FUNCTION(this);
1100 NS_LOG_DEBUG("DCI started at symbol "
1101 << static_cast<uint32_t>(dci->m_symStart) << " which lasted for "
1102 << static_cast<uint32_t>(dci->m_numSym) << " symbols finished");
1103
1104 if (m_tryToPerformLbt)
1105 {
1106 TryToPerformLbt();
1107 m_tryToPerformLbt = false;
1108 }
1109
1111 {
1112 // end of slot
1113 m_currentSlot.Add(1);
1114
1115 Simulator::Schedule(m_lastSlotStart + GetSlotPeriod() - Simulator::Now(),
1116 &NrUePhy::StartSlot,
1117 this,
1118 m_currentSlot);
1119 }
1120 else
1121 {
1122 VarTtiAllocInfo allocation = m_currSlotAllocInfo.m_varTtiAllocInfo.front();
1124
1125 Time nextVarTtiStart = GetSymbolPeriod() * allocation.m_dci->m_symStart;
1126
1127 Simulator::Schedule(nextVarTtiStart + m_lastSlotStart - Simulator::Now(),
1128 &NrUePhy::StartVarTti,
1129 this,
1130 allocation.m_dci);
1131 }
1132
1133 m_receptionEnabled = false;
1134}
1135
1136void
1138{
1139 Simulator::ScheduleWithContext(m_netDevice->GetNode()->GetId(),
1142 m_phySapUser,
1143 p);
1144 // m_phySapUser->ReceivePhyPdu (p);
1145}
1146
1147void
1148NrUePhy::SendDataChannels(const Ptr<PacketBurst>& pb,
1149 const std::list<Ptr<NrControlMessage>>& ctrlMsg,
1150 const std::shared_ptr<DciInfoElementTdma>& dci,
1151 const Time& duration)
1152{
1153 if (pb->GetNPackets() > 0)
1154 {
1155 NrRadioBearerTag tag;
1156 if (!pb->GetPackets().front()->PeekPacketTag(tag))
1157 {
1158 NS_FATAL_ERROR("No radio bearer tag");
1159 }
1160 }
1161
1162 m_spectrumPhy->StartTxDataFrames(pb, ctrlMsg, dci, duration);
1163}
1164
1165void
1166NrUePhy::SendCtrlChannels(Time duration)
1167{
1168 m_spectrumPhy->StartTxUlControlFrames(m_ctrlMsgs, duration);
1169 m_ctrlMsgs.clear();
1170}
1171
1172Ptr<NrDlCqiMessage>
1173NrUePhy::CreateDlCqiFeedbackMessage(const SpectrumValue& sinr)
1174{
1175 NS_LOG_FUNCTION(this);
1176 // Create DL CQI CTRL message
1177 Ptr<NrDlCqiMessage> msg = Create<NrDlCqiMessage>();
1178 msg->SetSourceBwp(GetBwpId());
1179 DlCqiInfo dlcqi;
1180
1181 dlcqi.m_rnti = m_rnti;
1182 dlcqi.m_cqiType = DlCqiInfo::WB;
1183
1184 std::vector<int> cqi;
1185 dlcqi.m_wbCqi = ComputeCqi(sinr);
1186 msg->SetDlCqi(dlcqi);
1187 return msg;
1188}
1189
1190void
1191NrUePhy::GenerateDlCqiReport(const SpectrumValue& sinr)
1192{
1193 NS_LOG_FUNCTION(this);
1194 // Not totally sure what this is about. We have to check.
1195 if (m_ulConfigured && (m_rnti > 0) && m_receptionEnabled)
1196 {
1197 m_dlDataSinrTrace(GetCellId(), m_rnti, ComputeAvgSinr(sinr), GetBwpId());
1198
1199 if (Simulator::Now() > m_wbCqiLast)
1200 {
1201 Ptr<NrDlCqiMessage> msg = CreateDlCqiFeedbackMessage(sinr);
1202
1203 if (msg)
1204 {
1205 DoSendControlMessage(msg);
1206 }
1207 }
1208 }
1209}
1210
1211void
1213{
1214 NS_LOG_FUNCTION(this);
1215 // get the feedback from NrSpectrumPhy and send it through ideal PUCCH to gNB
1216 Ptr<NrDlHarqFeedbackMessage> msg = Create<NrDlHarqFeedbackMessage>();
1217 msg->SetSourceBwp(GetBwpId());
1218 msg->SetDlHarqFeedback(m);
1219
1220 auto k1It = m_harqIdToK1Map.find(m.m_harqProcessId);
1221
1222 NS_LOG_DEBUG("ReceiveNrDlHarqFeedback"
1223 << " Harq Process " << static_cast<uint32_t>(k1It->first)
1224 << " K1: " << k1It->second << " Frame " << m_currentSlot);
1225
1226 Time event = m_lastSlotStart + (GetSlotPeriod() * k1It->second);
1227 if (event <= Simulator::Now())
1228 {
1229 Simulator::ScheduleNow(&NrUePhy::DoSendControlMessageNow, this, msg);
1230 }
1231 else
1232 {
1233 Simulator::Schedule(event - Simulator::Now(), &NrUePhy::DoSendControlMessageNow, this, msg);
1234 }
1235}
1236
1237void
1238NrUePhy::SetCam(const Ptr<NrChAccessManager>& cam)
1239{
1240 NS_LOG_FUNCTION(this);
1241 NS_ASSERT(cam != nullptr);
1242 m_cam = cam;
1243 m_cam->SetAccessGrantedCallback(
1244 std::bind(&NrUePhy::ChannelAccessGranted, this, std::placeholders::_1));
1245 m_cam->SetAccessDeniedCallback(std::bind(&NrUePhy::ChannelAccessDenied, this));
1246}
1247
1248const SfnSf&
1250{
1251 return m_currentSlot;
1252}
1253
1254uint16_t
1256{
1257 return m_rnti;
1258}
1259
1260void
1261NrUePhy::DoReset()
1262{
1263 NS_LOG_FUNCTION(this);
1264 m_raPreambleId = 255; // value out of range
1265 m_isConnected = false;
1266}
1267
1268void
1269NrUePhy::DoStartCellSearch(uint16_t dlEarfcn)
1270{
1271 NS_LOG_FUNCTION(this << dlEarfcn);
1272 DoSetInitialBandwidth();
1273}
1274
1275void
1276NrUePhy::DoSynchronizeWithGnb(uint16_t cellId, uint16_t dlEarfcn)
1277{
1278 NS_LOG_FUNCTION(this << cellId << dlEarfcn);
1279 DoSynchronizeWithGnb(cellId);
1280}
1281
1282void
1283NrUePhy::DoSetPa(double pa)
1284{
1285 NS_LOG_FUNCTION(this << pa);
1286}
1287
1288void
1289NrUePhy::DoSetRsrpFilterCoefficient(uint8_t rsrpFilterCoefficient)
1290{
1291 NS_LOG_FUNCTION(this << +rsrpFilterCoefficient);
1292}
1293
1294void
1295NrUePhy::DoSynchronizeWithGnb(uint16_t cellId)
1296{
1297 NS_LOG_FUNCTION(this << cellId);
1298 DoSetCellId(cellId);
1299 DoSetInitialBandwidth();
1300}
1301
1302BeamId
1303NrUePhy::GetBeamId([[maybe_unused]] uint16_t rnti) const
1304{
1305 NS_LOG_FUNCTION(this);
1306 // That's a bad specification: the UE PHY doesn't know anything about its beam id.
1307 NS_FATAL_ERROR("ERROR");
1308}
1309
1310void
1311NrUePhy::ScheduleStartEventLoop(uint32_t nodeId, uint16_t frame, uint8_t subframe, uint16_t slot)
1312{
1313 NS_LOG_FUNCTION(this);
1314 Simulator::ScheduleWithContext(nodeId,
1315 MilliSeconds(0),
1316 &NrUePhy::StartEventLoop,
1317 this,
1318 frame,
1319 subframe,
1320 slot);
1321}
1322
1323void
1324NrUePhy::ReportRsReceivedPower(const SpectrumValue& rsReceivedPower)
1325{
1326 NS_LOG_FUNCTION(this << rsReceivedPower);
1327 m_rsrp = 10 * log10(Integral(rsReceivedPower)) + 30;
1328 NS_LOG_DEBUG("RSRP value updated: " << m_rsrp << " dBm");
1329
1330 if (m_enableUplinkPowerControl)
1331 {
1332 m_powerControl->SetLoggingInfo(GetCellId(), m_rnti);
1333 m_powerControl->SetRsrp(m_rsrp);
1334 }
1335}
1336
1337void
1338NrUePhy::ReceivePss(uint16_t cellId, const Ptr<SpectrumValue>& p)
1339{
1340 NS_LOG_FUNCTION(this);
1341
1342 double sum = 0.0;
1343 uint16_t nRB = 0;
1344
1345 uint32_t subcarrierSpacing;
1346 subcarrierSpacing = 15000 * static_cast<uint32_t>(std::pow(2, GetNumerology()));
1347
1348 Values::const_iterator itPi;
1349 for (itPi = p->ConstValuesBegin(); itPi != p->ConstValuesEnd(); itPi++)
1350 {
1351 // convert PSD [W/Hz] to linear power [W] for the single RE
1352 double powerTxW = (*itPi) * subcarrierSpacing;
1353 sum += powerTxW;
1354 nRB++;
1355 }
1356
1357 // measure instantaneous RSRP now (in dBm)
1358 double rsrp = 10 * log10(1000 * (sum / static_cast<double>(nRB)));
1359
1360 NS_LOG_DEBUG("RSRP value updated: " << rsrp << " dBm"
1361 << " for Cell Id: " << cellId << " RNTI: " << m_rnti);
1362
1363 // store RSRP measurements
1364 std::map<uint16_t, UeMeasurementsElement>::iterator itMeasMap =
1365 m_ueMeasurementsMap.find(cellId);
1366 if (itMeasMap == m_ueMeasurementsMap.end())
1367 {
1368 // insert new entry
1369 UeMeasurementsElement newEl;
1370 newEl.rsrpSum = rsrp;
1371 newEl.rsrpNum = 1;
1372 newEl.rsrqSum = 0;
1373 newEl.rsrqNum = 0;
1374
1375 NS_LOG_DEBUG("New RSRP entry for Cell Id: " << cellId << " RNTI: " << m_rnti
1376 << " RSRP: " << newEl.rsrpSum << " dBm"
1377 << " number of entries: " << +newEl.rsrpNum);
1378
1379 m_ueMeasurementsMap.insert(std::pair<uint16_t, UeMeasurementsElement>(cellId, newEl));
1380 }
1381 else
1382 {
1383 (*itMeasMap).second.rsrpSum += rsrp;
1384 (*itMeasMap).second.rsrpNum++;
1385
1386 NS_LOG_DEBUG("Update RSRP entry for Cell Id: "
1387 << cellId << " RNTI: " << m_rnti
1388 << " RSRP Sum: " << (*itMeasMap).second.rsrpSum << " dBm"
1389 << " number of entries: " << +((*itMeasMap).second.rsrpNum));
1390 }
1391}
1392
1393void
1394NrUePhy::ReportUeMeasurements()
1395{
1396 NS_LOG_FUNCTION(this);
1397
1399
1400 std::map<uint16_t, UeMeasurementsElement>::iterator it;
1401 for (it = m_ueMeasurementsMap.begin(); it != m_ueMeasurementsMap.end(); it++)
1402 {
1403 double avg_rsrp;
1404 double avg_rsrq = 0;
1405 if ((*it).second.rsrpNum != 0)
1406 {
1407 avg_rsrp = (*it).second.rsrpSum / static_cast<double>((*it).second.rsrpNum);
1408 }
1409 else
1410 {
1411 NS_LOG_WARN(" RSRP nSamples is zero!");
1412 avg_rsrp = 0;
1413 }
1414
1415 NS_LOG_DEBUG(" Report UE Measurements for CellId "
1416 << (*it).first << " Reporting UE " << m_rnti << " Av. RSRP " << avg_rsrp
1417 << " (nSamples " << +((*it).second.rsrpNum) << ")"
1418 << " BwpID " << GetBwpId());
1419
1420 m_reportRsrpTrace(GetCellId(), m_imsi, m_rnti, avg_rsrp, GetBwpId());
1421
1422 // trigger RLF detection only when UE has an active RRC connection
1423 // and RLF detection attribute is set to true
1424 if (m_isConnected && m_enableRlfDetection)
1425 {
1426 double avrgSinrForRlf = ComputeAvgSinr(m_ctrlSinrForRlf);
1427 RlfDetection(10 * log10(avrgSinrForRlf));
1428 }
1429
1430 NrUeCphySapUser::UeMeasurementsElement newEl;
1431 newEl.m_cellId = (*it).first;
1432 newEl.m_rsrp = avg_rsrp;
1433 newEl.m_rsrq = avg_rsrq; // LEAVE IT 0 FOR THE MOMENT
1434 ret.m_ueMeasurementsList.push_back(newEl);
1436
1437 m_reportUeMeasurements(m_rnti,
1438 (*it).first,
1439 avg_rsrp,
1440 avg_rsrq,
1441 (*it).first == GetCellId(),
1443 }
1444
1445 // report to RRC
1446 m_ueCphySapUser->ReportUeMeasurements(ret);
1447
1448 m_ueMeasurementsMap.clear();
1449 Simulator::Schedule(m_ueMeasurementsFilterPeriod, &NrUePhy::ReportUeMeasurements, this);
1450}
1451
1452void
1453NrUePhy::ReportDlCtrlSinr(const SpectrumValue& sinr)
1454{
1455 NS_LOG_FUNCTION(this);
1456 uint32_t rbUsed = 0;
1457 double sinrSum = 0.0;
1458
1459 for (uint32_t i = 0; i < sinr.GetValuesN(); i++)
1460 {
1461 double currentSinr = sinr.ValuesAt(i);
1462 if (currentSinr != 0)
1463 {
1464 rbUsed++;
1465 sinrSum += currentSinr;
1466 }
1467 }
1468
1469 NS_ASSERT(rbUsed);
1470 m_dlCtrlSinrTrace(GetCellId(), m_rnti, sinrSum / rbUsed, GetBwpId());
1471}
1472
1473uint8_t
1474NrUePhy::ComputeCqi(const SpectrumValue& sinr)
1475{
1476 NS_LOG_FUNCTION(this);
1477 uint8_t mcs; // it is initialized by AMC in the following call
1478 uint8_t wbCqi = m_amc->CreateCqiFeedbackWbTdma(sinr, mcs);
1479 return wbCqi;
1480}
1481
1482void
1483NrUePhy::StartEventLoop(uint16_t frame, uint8_t subframe, uint16_t slot)
1484{
1485 NS_LOG_FUNCTION(this);
1486
1487 if (GetChannelBandwidth() == 0)
1488 {
1489 NS_LOG_INFO("Initial bandwidth not set, configuring the default one for Cell ID: "
1490 << GetCellId() << ", RNTI: " << GetRnti() << ", BWP ID: " << GetBwpId());
1491 DoSetInitialBandwidth();
1492 }
1493
1494 NS_LOG_INFO("PHY starting. Configuration: "
1495 << std::endl
1496 << "\t TxPower: " << m_txPower << " dBm" << std::endl
1497 << "\t NoiseFigure: " << m_noiseFigure << std::endl
1498 << "\t TbDecodeLatency: " << GetTbDecodeLatency().GetMicroSeconds() << " us "
1499 << std::endl
1500 << "\t Numerology: " << GetNumerology() << std::endl
1501 << "\t SymbolsPerSlot: " << GetSymbolsPerSlot() << std::endl
1502 << "\t Pattern: " << NrPhy::GetPattern(m_tddPattern) << std::endl
1503 << "Attached to physical channel: " << std::endl
1504 << "\t Channel bandwidth: " << GetChannelBandwidth() << " Hz" << std::endl
1505 << "\t Channel central freq: " << GetCentralFrequency() << " Hz" << std::endl
1506 << "\t Num. RB: " << GetRbNum());
1507 SfnSf startSlot(frame, subframe, slot, GetNumerology());
1508 StartSlot(startSlot);
1509}
1510
1511void
1512NrUePhy::DoSetInitialBandwidth()
1513{
1514 NS_LOG_FUNCTION(this);
1515 // configure initial bandwidth to 6 RBs, numerology 0
1516 double initialBandwidthHz =
1518 // divided by 100*1000 because the parameter should be in 100KHz
1519 uint16_t initialBandwidthIn100KHz = ceil(initialBandwidthHz / (100 * 1000));
1520 // account for overhead that will be reduced when determining real BW
1521 uint16_t initialBandwidthWithOverhead = initialBandwidthIn100KHz / (1 - GetRbOverhead());
1522
1523 NS_ABORT_MSG_IF(initialBandwidthWithOverhead == 0,
1524 " Initial bandwidth could not be set. Parameters provided are: "
1525 "\n dlBandwidthInRBNum = "
1526 << 6 << "\n m_subcarrierSpacing = " << GetSubcarrierSpacing()
1527 << "\n NrSpectrumValueHelper::SUBCARRIERS_PER_RB = "
1529 << "\n m_rbOh = " << GetRbOverhead());
1530
1531 DoSetDlBandwidth(initialBandwidthWithOverhead);
1532}
1533
1534uint16_t
1535NrUePhy::DoGetCellId()
1536{
1537 return GetCellId();
1538}
1539
1540uint32_t
1541NrUePhy::DoGetDlEarfcn()
1542{
1543 // TBD See how to get rid of this function in future
1544 // Added for the compatibility with 810 MR to LTE.
1545 NS_LOG_FUNCTION(this);
1546 NS_LOG_WARN("DoGetDlEarfcn function is called. This function should be removed in future once "
1547 "NR has its own RRC.");
1548 return 0;
1549}
1550
1551void
1552NrUePhy::DoSetDlBandwidth(uint16_t dlBandwidth)
1553{
1554 NS_LOG_FUNCTION(this << +dlBandwidth);
1555
1556 SetChannelBandwidth(dlBandwidth);
1557
1558 NS_LOG_DEBUG("PHY reconfiguring. Result: "
1559 << std::endl
1560 << "\t TxPower: " << m_txPower << " dBm" << std::endl
1561 << "\t NoiseFigure: " << m_noiseFigure << std::endl
1562 << "\t TbDecodeLatency: " << GetTbDecodeLatency().GetMicroSeconds() << " us "
1563 << std::endl
1564 << "\t Numerology: " << GetNumerology() << std::endl
1565 << "\t SymbolsPerSlot: " << GetSymbolsPerSlot() << std::endl
1566 << "\t Pattern: " << NrPhy::GetPattern(m_tddPattern) << std::endl
1567 << "Attached to physical channel: " << std::endl
1568 << "\t Channel bandwidth: " << GetChannelBandwidth() << " Hz" << std::endl
1569 << "\t Channel central freq: " << GetCentralFrequency() << " Hz" << std::endl
1570 << "\t Num. RB: " << GetRbNum());
1571}
1572
1573void
1574NrUePhy::DoConfigureUplink(uint16_t ulEarfcn, uint8_t ulBandwidth)
1575{
1576 NS_LOG_FUNCTION(this << ulEarfcn << +ulBandwidth);
1577 // Ignore this; should be equal to dlBandwidth
1578 m_ulConfigured = true;
1579}
1580
1581void
1582NrUePhy::DoConfigureReferenceSignalPower(int8_t referenceSignalPower)
1583{
1584 NS_LOG_FUNCTION(this << referenceSignalPower);
1585 m_powerControl->ConfigureReferenceSignalPower(referenceSignalPower);
1586}
1587
1588void
1589NrUePhy::DoSetRnti(uint16_t rnti)
1590{
1591 NS_LOG_FUNCTION(this << rnti);
1592 GetSpectrumPhy()->SetRnti(rnti);
1593 m_rnti = rnti;
1594}
1595
1596void
1597NrUePhy::DoSetTransmissionMode(uint8_t txMode)
1598{
1599 NS_LOG_FUNCTION(this << +txMode);
1600}
1601
1602void
1603NrUePhy::DoSetSrsConfigurationIndex(uint16_t srcCi)
1604{
1605 NS_LOG_FUNCTION(this << srcCi);
1606}
1607
1608void
1610{
1611 m_phySapUser = ptr;
1612}
1613
1614void
1615NrUePhy::DoNotifyConnectionSuccessful()
1616{
1622 if (GetBwpId() == 0)
1623 {
1624 m_isConnected = true;
1625 // Initialize the parameters for radio link failure detection
1626 InitializeRlfParams();
1627 }
1628}
1629
1630void
1631NrUePhy::DoResetPhyAfterRlf()
1632{
1633 NS_LOG_FUNCTION(this);
1634 // m_spectrumPhy->m_harqPhyModule->ClearDlHarqBuffer(m_rnti); // flush HARQ buffers
1635 DoReset();
1636}
1637
1638void
1639NrUePhy::DoResetRlfParams()
1640{
1641 NS_LOG_FUNCTION(this);
1642 InitializeRlfParams();
1643}
1644
1645void
1646NrUePhy::DoStartInSyncDetection()
1647{
1648 NS_LOG_FUNCTION(this);
1649 // indicates that the downlink radio link quality has to be monitored for in-sync indications
1650 m_downlinkInSync = false;
1651}
1652
1653void
1654NrUePhy::InitializeRlfParams()
1655{
1656 NS_LOG_FUNCTION(this);
1657 m_numOfSubframes = 0;
1658 m_sinrDbFrame = 0;
1659 m_numOfFrames = 0;
1660 m_downlinkInSync = true;
1661}
1662
1663void
1664NrUePhy::RlfDetection(double sinrDb)
1665{
1666 NS_LOG_FUNCTION(this << sinrDb);
1667 m_sinrDbFrame += sinrDb;
1668 m_numOfSubframes++;
1669 NS_LOG_LOGIC("No of Subframes: " << m_numOfSubframes
1670 << " UE synchronized: " << m_downlinkInSync);
1671 // check for out_of_sync indications first when UE is both DL and UL synchronized
1672 // m_downlinkInSync=true indicates that the evaluation is for out-of-sync indications
1673 if (m_downlinkInSync && m_numOfSubframes == 10)
1674 {
1679 if ((m_sinrDbFrame / m_numOfSubframes) < m_qOut)
1680 {
1681 m_numOfFrames++; // increment the counter if a frame cannot be decoded
1682 NS_LOG_LOGIC("No of Frames which cannot be decoded: " << m_numOfFrames);
1683 }
1684 else
1685 {
1691 NS_LOG_INFO("Resetting frame counter at phy. Current value = " << m_numOfFrames);
1692 m_numOfFrames = 0;
1693 // Also reset the sync indicator counter at RRC
1694 m_ueCphySapUser->ResetSyncIndicationCounter();
1695 }
1696 m_numOfSubframes = 0;
1697 m_sinrDbFrame = 0;
1698 }
1704 if (m_downlinkInSync && (m_numOfFrames * 10) == m_numOfQoutEvalSf)
1705 {
1706 NS_LOG_LOGIC("At " << Simulator::Now().As(Time::MS)
1707 << " ms UE PHY sending out of sync indication to UE RRC layer");
1708 m_ueCphySapUser->NotifyOutOfSync();
1709 m_numOfFrames = 0;
1710 }
1711 // check for in_sync indications when T310 timer is started
1712 // m_downlinkInSync=false indicates that the evaluation is for in-sync indications
1713 if (!m_downlinkInSync && m_numOfSubframes == 10)
1714 {
1720 if ((m_sinrDbFrame / m_numOfSubframes) > m_qIn)
1721 {
1722 m_numOfFrames++; // increment the counter if a frame can be decoded
1723 NS_LOG_LOGIC("No of Frames successfully decoded: " << m_numOfFrames);
1724 }
1725 else
1726 {
1732 m_numOfFrames = 0;
1733 // Also reset the sync indicator counter at RRC
1734 m_ueCphySapUser->ResetSyncIndicationCounter();
1735 }
1736 m_numOfSubframes = 0;
1737 m_sinrDbFrame = 0;
1738 }
1743 if (!m_downlinkInSync && (m_numOfFrames * 10) == m_numOfQinEvalSf)
1744 {
1745 NS_LOG_LOGIC("At " << Simulator::Now().As(Time::MS)
1746 << " ms UE PHY sending in sync indication to UE RRC layer");
1747 m_ueCphySapUser->NotifyInSync();
1748 m_numOfFrames = 0;
1749 }
1750}
1751
1752void
1753NrUePhy::DoSetImsi(uint64_t imsi)
1754{
1755 NS_LOG_FUNCTION(this);
1756 m_imsi = imsi;
1757}
1758
1759void
1760NrUePhy::GenerateDlCqiReportMimo(const std::vector<MimoSignalChunk>& mimoChunks)
1761{
1762 NS_LOG_FUNCTION(this);
1763 // Adopted from NrUePhy::GenerateDlCqiReport: CQI feedback requires properly configured UE
1764 if (!m_ulConfigured || (m_rnti == 0))
1765 {
1766 return;
1767 }
1768 // Adopted from NrUePhy::GenerateDlCqiReport: Do not send feedback if this UE was not
1769 // receiving downlink data (was not scheduled)
1770 if (!m_receptionEnabled)
1771 {
1772 return;
1773 }
1774
1775 // Combine multiple signal chunks into a single channel matrix and interference covariance
1776 auto rxSignal = NrMimoSignal{mimoChunks};
1777
1778 // Determine if an update to wideband or subband PMI is needed and possible
1779 auto pmiUpdateParams = CheckUpdatePmi();
1780
1781 // Create DL CQI message for CQI, PMI, and RI. PMI values are updated only if specified by
1782 // pmiUpdateParams, otherwise assume same PMI values as during last CQI feedback
1783 auto cqi = m_pmSearch->CreateCqiFeedbackMimo(rxSignal, pmiUpdateParams);
1784 auto dlcqi = DlCqiInfo{
1785 .m_rnti = m_rnti,
1786 .m_ri = cqi.m_rank,
1787 .m_cqiType = cqi.m_cqiType,
1788 .m_wbCqi = cqi.m_wbCqi,
1789 .m_wbPmi = cqi.m_wbPmi,
1790 .m_sbCqis = cqi.m_sbCqis,
1791 .m_sbPmis = cqi.m_sbPmis,
1792 .m_mcs = cqi.m_mcs,
1793 .m_optPrecMat = cqi.m_optPrecMat,
1794 };
1795
1796 auto msg = Create<NrDlCqiMessage>();
1797 msg->SetSourceBwp(GetBwpId());
1798 msg->SetDlCqi(dlcqi);
1799
1800 DoSendControlMessage(msg);
1801}
1802
1805{
1806 // This implementation only checks if sufficient time has passed since the last update.
1807 // TODO: Improve following logic that defines when to update wideband and/or
1808 // subband PMIs for two-stage codebooks. The algorithm must allow managing the computational
1809 // complexity of PMI updates, and take into account availability of PUCCH/PUSCH resources for
1810 // sending PMI.
1811 auto pmiUpdate = NrPmSearch::PmiUpdate{};
1812 auto now = Simulator::Now();
1813 if (now > m_wbPmiLastUpdate + m_wbPmiUpdateInterval)
1814 {
1815 pmiUpdate.updateWb = true;
1816 m_wbPmiLastUpdate = now;
1817 }
1818 if (now > m_sbPmiLastUpdate + m_sbPmiUpdateInterval)
1819 {
1820 pmiUpdate.updateSb = true;
1821 m_sbPmiLastUpdate = now;
1822 }
1823 return pmiUpdate;
1824}
1825
1826void
1827NrUePhy::SetPmSearch(Ptr<NrPmSearch> pmSearch)
1828{
1829 m_pmSearch = pmSearch;
1830 NS_ASSERT(m_amc);
1831 m_pmSearch->SetAmc(m_amc);
1832}
1833
1834Ptr<NrPmSearch>
1836{
1837 return m_pmSearch;
1838}
1839
1840} // namespace ns3
@ UL_DCI
The resources allocation map from the BS to the attached UEs (UL)
@ DL_HARQ
DL HARQ feedback.
@ MIB
Master Information Block.
@ RAR
Random Access Response.
@ SIB1
System Information Block Type 1.
@ DL_DCI
The resources allocation map from the BS to the attached UEs (DL)
The base class for gNb and UE physical layer.
Definition nr-phy.h:67
Time GetSymbolPeriod() const
Get SymbolPeriod.
Definition nr-phy.cc:849
Ptr< NrSpectrumPhy > m_spectrumPhy
Pointer to the (owned) spectrum phy.
Definition nr-phy.h:554
SlotAllocInfo RetrieveSlotAllocInfo()
Get the head for the slot allocation info, and delete it from the internal list.
Definition nr-phy.cc:779
uint16_t GetCellId() const
Definition nr-phy.cc:648
uint16_t GetNumerology() const
Get the configured numerology.
Definition nr-phy.cc:280
Ptr< NrSpectrumPhy > GetSpectrumPhy() const
Retrieve the SpectrumPhy pointer.
Definition nr-phy.cc:660
void EncodeCtrlMsg(const Ptr< NrControlMessage > &msg)
Take the control messages, and put it in a list that will be sent at the first occasion.
Definition nr-phy.cc:460
virtual void SetTbDecodeLatency(const Time &us)
Configures TB decode latency.
Definition nr-phy.cc:873
std::list< Ptr< NrControlMessage > > m_ctrlMsgs
CTRL messages to be sent.
Definition nr-phy.h:567
void PushBackSlotAllocInfo(const SlotAllocInfo &slotAllocInfo)
Store the slot allocation info.
Definition nr-phy.cc:673
Ptr< PacketBurst > GetPacketBurst(SfnSf sf, uint8_t sym, uint16_t rnti)
Retrieve the PacketBurst at the slot/symbol specified.
Definition nr-phy.cc:355
void SetPowerAllocationType(enum NrSpectrumValueHelper::PowerAllocationType powerAllocationType)
Set power allocation type. There are currently supported two types: one that distributes uniformly en...
Definition nr-phy.cc:423
static std::string GetPattern(const std::vector< LteNrTddSlotType > &pattern)
Get a string representation of a pattern.
Definition nr-phy.cc:404
Time GetSlotPeriod() const
Get the slot period.
Definition nr-phy.cc:312
virtual std::list< Ptr< NrControlMessage > > PopCurrentSlotCtrlMsgs()
Extract and return the message list that is at the beginning of the queue.
Definition nr-phy.cc:601
SlotAllocInfo m_currSlotAllocInfo
Current slot allocation.
Definition nr-phy.h:562
enum NrSpectrumValueHelper::PowerAllocationType GetPowerAllocationType() const
Get the power allocation type.
Definition nr-phy.cc:429
void EnqueueCtrlMsgNow(const Ptr< NrControlMessage > &msg)
Enqueue a CTRL message without considering L1L2CtrlLatency.
Definition nr-phy.cc:443
uint32_t GetChannelBandwidth() const
Retrieve the channel bandwidth, in Hz.
Definition nr-phy.cc:511
virtual Time GetTbDecodeLatency() const
Returns Transport Block decode latency.
Definition nr-phy.cc:879
SlotAllocInfo & PeekSlotAllocInfo(const SfnSf &sfnsf)
Peek the SlotAllocInfo at the SfnSf specified.
Definition nr-phy.cc:808
double GetCentralFrequency() const
Retrieve the frequency (in Hz) of this PHY's channel.
Definition nr-phy.cc:396
double m_noiseFigure
Noise figure (attribute)
Definition nr-phy.h:557
uint32_t m_raPreambleId
Preamble ID.
Definition nr-phy.h:566
double GetNoiseFigure() const
Get the NoiseFigure value.
Definition nr-phy.cc:867
void SetNoiseFigure(double d)
Set the NoiseFigure value.
Definition nr-phy.cc:856
double m_txPower
Transmission power (attribute)
Definition nr-phy.h:556
void InitializeMessageList()
Initialize the message list.
Definition nr-phy.cc:589
Ptr< SpectrumValue > GetTxPowerSpectralDensity(const std::vector< int > &rbIndexVector)
Definition nr-phy.cc:385
void SetChannelBandwidth(uint16_t bandwidth)
Function to set the channel bandwidth, used also by child classes, i.e., see functions DoSetDlBanwidt...
Definition nr-phy.cc:233
uint16_t GetBwpId() const
Definition nr-phy.cc:642
std::vector< int > FromRBGBitmaskToRBAssignment(const std::vector< uint8_t > rbgBitmask) const
Transform a MAC-made vector of RBG to a PHY-ready vector of SINR indices.
Definition nr-phy.cc:165
Ptr< NrNetDevice > m_netDevice
Pointer to the owner netDevice.
Definition nr-phy.h:553
bool SlotAllocInfoExists(const SfnSf &sfnsf) const
Check if the SlotAllocationInfo for that slot exists.
Definition nr-phy.cc:764
uint32_t GetSubcarrierSpacing() const
Retrieve the subcarrier spacing in Hz. Subcarrier spacing is updated when the numerology is being upd...
Definition nr-phy.cc:518
uint32_t GetSymbolsPerSlot() const
Get the number of symbols in a slot.
Definition nr-phy.cc:306
std::vector< LteNrTddSlotType > m_tddPattern
Pattern.
Definition nr-phy.h:569
double GetRbOverhead() const
Get the bandwidth overhead used when calculating the usable RB number.
Definition nr-phy.cc:300
uint32_t GetRbNum() const
Get the number of Resource block configured.
Definition nr-phy.cc:505
void EnqueueCtrlMessage(const Ptr< NrControlMessage > &m)
Enqueue a ctrl message, keeping in consideration L1L2CtrlDelay.
Definition nr-phy.cc:435
void DoDispose() override
DoDispose method inherited from Object.
Definition nr-phy.cc:200
void DoSetCellId(uint16_t cellId)
Set the cell ID.
Definition nr-phy.cc:319
Tag used to define the RNTI and LC id for each MAC packet transmitted.
static const uint8_t SUBCARRIERS_PER_RB
subcarriers per resource block
virtual void ReportUeMeasurements(UeMeasurementsParameters params)=0
Send a report of RSRP and RSRQ values perceived from PSS by the PHY entity (after applying layer-1 fi...
virtual void ResetSyncIndicationCounter()=0
Reset the sync indication counter.
virtual void RecvSystemInformationBlockType1(uint16_t cellId, NrRrcSap::SystemInformationBlockType1 sib1)=0
Relay an SIB1 message from the PHY entity to the RRC layer.
virtual void RecvMasterInformationBlock(uint16_t cellId, NrRrcSap::MasterInformationBlock mib)=0
Relay an MIB message from the PHY entity to the RRC layer.
virtual void NotifyOutOfSync()=0
Send an out of sync indication to UE RRC.
virtual void NotifyInSync()=0
Send an in sync indication to UE RRC.
void SetUplinkPowerControl(Ptr< NrUePowerControl > pc)
Allow configuration of uplink power control algorithm. E.g. necessary in FDD, when measurements are r...
Definition nr-ue-phy.cc:266
void SetPhySapUser(NrUePhySapUser *ptr)
Install the PHY sap user (AKA the UE MAC)
void ScheduleStartEventLoop(uint32_t nodeId, uint16_t frame, uint8_t subframe, uint16_t slot) override
Start the ue Event Loop.
void ReceivePss(uint16_t cellId, const Ptr< SpectrumValue > &p)
Receive PSS and calculate RSRQ in dBm.
void EnqueueDlHarqFeedback(const DlHarqInfo &m)
Get the HARQ feedback (on the transmission) from NrSpectrumPhy and send it through ideal PUCCH to gNB...
void SetTxPower(double pow)
Set the transmission power for the UE.
Definition nr-ue-phy.cc:240
NrUePhy()
NrUePhy default constructor.
Definition nr-ue-phy.cc:41
void SetNumRbPerRbg(uint32_t numRbPerRbg)
Function that sets the number of RBs per RBG. This function will be soon deprecated,...
Definition nr-ue-phy.cc:382
BeamId GetBeamId(uint16_t rnti) const override
Get the beam id for the specified user.
~NrUePhy() override
~NrUePhy
Definition nr-ue-phy.cc:51
Ptr< NrPmSearch > GetPmSearch() const
Get the precoding matrix search engine.
NrPmSearch::PmiUpdate CheckUpdatePmi()
Check if updates to wideband and/or subband PMI are necessary. This function is used to limit the fre...
void SetPmSearch(Ptr< NrPmSearch > pmSearch)
Set the precoding matrix search engine.
uint32_t GetNumRbPerRbg() const override
Protected function that is used to get the number of resource blocks per resource block group.
Definition nr-ue-phy.cc:419
NrUeCphySapProvider * GetUeCphySapProvider() __attribute__((warn_unused_result))
Retrieve the pointer for the C PHY SAP provider (AKA the PHY interface towards the RRC)
Definition nr-ue-phy.cc:227
uint8_t ComputeCqi(const SpectrumValue &sinr)
Compute the CQI based on the SINR.
void SetDlAmc(const Ptr< const NrAmc > &amc)
Set the AMC pointer from the GNB.
Definition nr-ue-phy.cc:272
double GetTxPower() const override
Retrieve the TX power of the UE.
Definition nr-ue-phy.cc:247
void SetDlCtrlSyms(uint8_t dlCtrlSyms)
Set the number of DL CTRL symbols.
Definition nr-ue-phy.cc:376
double GetRsrp() const
Returns the latest measured RSRP value Called by NrUePowerControl.
Definition nr-ue-phy.cc:253
void DoDispose() override
DoDispose method inherited from Object.
Definition nr-ue-phy.cc:57
Ptr< NrUePowerControl > GetUplinkPowerControl() const
Get NR uplink power control entity.
Definition nr-ue-phy.cc:259
void GenerateDlCqiReport(const SpectrumValue &sinr)
Generate a DL CQI report.
void SetCam(const Ptr< NrChAccessManager > &cam)
Set the channel access manager interface for this instance of the PHY.
void SetPattern(const std::string &pattern)
Set the UE pattern.
Definition nr-ue-phy.cc:388
void GenerateDlCqiReportMimo(const std::vector< MimoSignalChunk > &mimoChunks)
Generate DL CQI, PMI, and RI (channel quality precoding matrix and rank indicators)
void SetUlCtrlSyms(uint8_t ulCtrlSyms)
Set the number of UL CTRL symbols.
Definition nr-ue-phy.cc:370
uint16_t GetRnti() const __attribute__((warn_unused_result))
Get the current RNTI of the user.
void RegisterToGnb(uint16_t bwpId)
Register the UE to a certain Gnb.
Definition nr-ue-phy.cc:361
const SfnSf & GetCurrentSfnSf() const override
Get the current SfnSf.
void SetUeCphySapUser(NrUeCphySapUser *s)
Install ue C PHY SAP user (AKA the PHY interface towards the RRC)
Definition nr-ue-phy.cc:220
void PhyCtrlMessagesReceived(const Ptr< NrControlMessage > &msg)
Receive a list of CTRL messages.
Definition nr-ue-phy.cc:475
void ReportDlCtrlSinr(const SpectrumValue &sinr)
Called when DlCtrlSinr is fired.
void PhyDataPacketReceived(const Ptr< Packet > &p)
Receive a PHY data packet.
void ReportRsReceivedPower(const SpectrumValue &power)
Called when rsReceivedPower is fired.
static TypeId GetTypeId()
Get the object TypeId.
Definition nr-ue-phy.cc:75
SAP interface between the UE PHY and the UE MAC.
Definition nr-phy-sap.h:264
virtual void ReceiveControlMessage(Ptr< NrControlMessage > msg)=0
Receive SendNrControlMessage (PDCCH map, CQI feedbacks) using the ideal control channel.
virtual void ReceivePhyPdu(Ptr< Packet > p)=0
Notify the MAC of the reception of a new PHY-PDU.
virtual void SlotIndication(SfnSf s)=0
Trigger the indication of a new slot for the MAC.
The SfnSf class.
Definition sfnsf.h:32
void Add(uint32_t slotN)
Add to this SfnSf a number of slot indicated by the first parameter.
Definition sfnsf.cc:117
@ F
DL CTRL + DL DATA + UL DATA + UL CTRL.
@ S
DL CTRL + DL DATA + UL CTRL.
@ DL
DL CTRL + DL DATA.
@ UL
UL DATA + UL CTRL.
@ CTRL
Used for DL/UL CTRL.
@ DATA
Used for DL/UL DATA.
@ SRS
Used for SRS (it would be like DCI format 2_3)
The DlCqiInfo struct.
enum ns3::DlCqiInfo::DlCqiType WB
The type of the CQI.
uint16_t m_rnti
The RNTI.
A struct that contains info for the DL HARQ.
uint8_t m_harqProcessId
ProcessId.
Helper struct for processing and storing received signals for use in CSI feedback.
Parameters that define if PMI should be updated or if previous PMI values are used.
UeMeasurementsParameters structure.
std::vector< UeMeasurementsElement > m_ueMeasurementsList
UE measurement list.
uint8_t m_componentCarrierId
component carrier ID
SfnSf m_sfnSf
SfnSf of this allocation.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations