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