5#define NS_LOG_APPEND_CONTEXT \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11#include "nr-gnb-phy.h"
13#include "beam-manager.h"
14#include "nr-ch-access-manager.h"
15#include "nr-gnb-net-device.h"
16#include "nr-net-device.h"
17#include "nr-ue-net-device.h"
20#include "ns3/double.h"
23#include "ns3/node-list.h"
25#include "ns3/object-vector.h"
26#include "ns3/pointer.h"
27#include "ns3/uinteger.h"
33#include <unordered_set>
39NS_LOG_COMPONENT_DEFINE(
"NrGnbPhy");
41NS_OBJECT_ENSURE_REGISTERED(NrGnbPhy);
47 NS_LOG_FUNCTION(
this);
59 NS_LOG_FUNCTION(
this);
60 delete m_gnbCphySapProvider;
68NrGnbPhy::EnableCsiRs()
77 TypeId(
"ns3::NrGnbPhy")
79 .AddConstructor<NrGnbPhy>()
80 .AddAttribute(
"RbOverhead",
81 "Overhead when calculating the usable RB number",
84 MakeDoubleChecker<double>(0, 0.5))
85 .AddAttribute(
"TxPower",
86 "Transmission power in dBm",
89 MakeDoubleChecker<double>())
92 "Loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver."
93 " According to Wikipedia (http://en.wikipedia.org/wiki/Noise_figure), this is "
94 "\"the difference in decibels (dB) between"
95 " the noise output of the actual receiver to the noise output of an "
96 " ideal receiver with the same overall gain and bandwidth when the receivers "
97 " are connected to sources at the standard noise temperature T0.\" "
98 "In this model, we consider T0 = 290K.",
101 MakeDoubleChecker<double>())
103 "PowerAllocationType",
104 "Defines the type of the power allocation. Currently are supported "
105 "two types: \"UniformPowerAllocBw\", which is a uniform power allocation over all "
106 "bandwidth (over all RBs), and \"UniformPowerAllocUsed\", which is a uniform "
107 "power allocation over used (active) RBs. By default is set a uniform power "
108 "allocation over used RBs .",
109 EnumValue(NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_USED),
110 MakeEnumAccessor<NrSpectrumValueHelper::PowerAllocationType>(
113 MakeEnumChecker(NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_BW,
114 "UniformPowerAllocBw",
115 NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_USED,
116 "UniformPowerAllocUsed"))
117 .AddAttribute(
"SpectrumPhy",
118 "The downlink NrSpectrumPhy associated to this NrPhy",
122 MakePointerChecker<NrSpectrumPhy>())
123 .AddTraceSource(
"UlSinrTrace",
124 "UL SINR statistics.",
125 MakeTraceSourceAccessor(&NrGnbPhy::m_ulSinrTrace),
126 "ns3::UlSinr::TracedCallback")
127 .AddTraceSource(
"GnbPhyRxedCtrlMsgsTrace",
128 "Gnb PHY Rxed Control Messages Traces.",
129 MakeTraceSourceAccessor(&NrGnbPhy::m_phyRxedCtrlMsgsTrace),
130 "ns3::NrPhyRxTrace::RxedGnbPhyCtrlMsgsTracedCallback")
131 .AddTraceSource(
"GnbPhyTxedCtrlMsgsTrace",
132 "Gnb PHY Txed Control Messages Traces.",
133 MakeTraceSourceAccessor(&NrGnbPhy::m_phyTxedCtrlMsgsTrace),
134 "ns3::NrPhyRxTrace::TxedGnbPhyCtrlMsgsTracedCallback")
135 .AddAttribute(
"N0Delay",
136 "Minimum processing delay needed to decode DL DCI and decode DL data",
139 MakeUintegerChecker<uint32_t>(0, 1))
140 .AddAttribute(
"N1Delay",
141 "Minimum processing delay (UE side) from the end of DL Data reception to "
142 "the earliest possible start of the corresponding ACK/NACK transmission",
145 MakeUintegerChecker<uint32_t>(0, 4))
146 .AddAttribute(
"N2Delay",
147 "Minimum processing delay needed to decode UL DCI and prepare UL data",
150 MakeUintegerChecker<uint32_t>(0, 4))
151 .AddAttribute(
"TbDecodeLatency",
152 "Transport block decode latency",
153 TimeValue(MicroSeconds(100)),
156 .AddAttribute(
"Numerology",
157 "The 3GPP numerology to be used",
160 MakeUintegerChecker<uint16_t>())
163 "Number of symbols in one slot",
166 MakeUintegerChecker<uint16_t>())
167 .AddAttribute(
"Pattern",
169 StringValue(
"F|F|F|F|F|F|F|F|F|F|"),
174 "Defines the type of the CSI-RS model to use. Currently the user can select "
175 "either: CsiRsPerUe or CsiRsPerBeam. CsiRsPerUe means that CSI-RS signals will be "
176 "transmitted towards a specific "
177 "UE periodically. CsiRsPerBeam means that the CSI-RS will be transmitted using a "
178 "predefined set of beams.",
186 .AddAttribute(
"CsiRsPeriodicity",
187 "Default CSI periodicity in the number of slots",
191 MakeUintegerChecker<uint16_t>())
192 .AddTraceSource(
"SlotDataStats",
193 "Data statistics for the current slot: SfnSf, active UE, used RE, "
194 "used symbols, available RBs, available symbols, bwp ID, cell ID",
195 MakeTraceSourceAccessor(&NrGnbPhy::m_phySlotDataStats),
196 "ns3::NrGnbPhy::SlotStatsTracedCallback")
197 .AddTraceSource(
"SlotCtrlStats",
198 "Ctrl statistics for the current slot: SfnSf, active UE, used RE, "
199 "used symbols, available RBs, available symbols, bwp ID, cell ID",
200 MakeTraceSourceAccessor(&NrGnbPhy::m_phySlotCtrlStats),
201 "ns3::NrGnbPhy::SlotStatsTracedCallback")
204 "Resource Block used for data: SfnSf, symbol, RB PHY map, bwp ID, cell ID",
205 MakeTraceSourceAccessor(&NrGnbPhy::m_rbStatistics),
206 "ns3::NrGnbPhy::RBStatsTracedCallback");
219 return m_currentSlot;
229modulo(
int n, uint32_t m)
233 return static_cast<uint32_t
>(n) % m;
241 return static_cast<uint32_t
>(n);
259ReturnHarqSlot(
const std::vector<LteNrTddSlotType>& pattern, uint32_t pos, uint32_t n1)
261 int32_t k1 =
static_cast<int32_t
>(n1);
263 uint32_t index = modulo(
static_cast<int>(pos) + k1,
static_cast<uint32_t
>(pattern.size()));
268 index = modulo(
static_cast<int>(pos) + k1,
static_cast<uint32_t
>(pattern.size()));
269 NS_ASSERT(index < pattern.size());
277 uint32_t indexDci{0};
290ReturnDciSlot(
const std::vector<LteNrTddSlotType>& pattern, uint32_t pos, uint32_t n)
294 ret.indexDci = modulo(
static_cast<int>(pos) -
static_cast<int>(ret.k),
295 static_cast<uint32_t
>(pattern.size()));
300 ret.indexDci = modulo(
static_cast<int>(pos) -
static_cast<int>(ret.k),
301 static_cast<uint32_t
>(pattern.size()));
302 NS_ASSERT(ret.indexDci < pattern.size());
319GenerateDciMaps(
const std::vector<LteNrTddSlotType>& pattern,
320 std::map<uint32_t, std::vector<uint32_t>>* toSend,
321 std::map<uint32_t, std::vector<uint32_t>>* generate,
324 uint32_t l1l2CtrlLatency)
326 auto dciSlot = ReturnDciSlot(pattern, pos, n);
328 modulo(
static_cast<int>(dciSlot.indexDci) -
static_cast<int>(l1l2CtrlLatency),
329 static_cast<uint32_t
>(pattern.size()));
330 uint32_t kWithCtrlLatency =
static_cast<uint32_t
>(dciSlot.k) + l1l2CtrlLatency;
332 (*toSend)[dciSlot.indexDci].push_back(
static_cast<uint32_t
>(dciSlot.k));
333 (*generate)[indexGen].push_back(kWithCtrlLatency);
337NrGnbPhy::GenerateStructuresFromPattern(
const std::vector<LteNrTddSlotType>& pattern,
338 std::map<uint32_t, std::vector<uint32_t>>* toSendDl,
339 std::map<uint32_t, std::vector<uint32_t>>* toSendUl,
340 std::map<uint32_t, std::vector<uint32_t>>* generateDl,
341 std::map<uint32_t, std::vector<uint32_t>>* generateUl,
342 std::map<uint32_t, uint32_t>* dlHarqfbPosition,
346 uint32_t l1l2CtrlLatency)
348 const uint32_t n =
static_cast<uint32_t
>(pattern.size());
351 std::vector<LteNrTddSlotType> fddGenerationPattern;
361 const std::vector<LteNrTddSlotType>* generationPattern;
365 generationPattern = &pattern;
369 generationPattern = &fddGenerationPattern;
372 for (uint32_t i = 0; i < n; i++)
376 GenerateDciMaps(*generationPattern, toSendUl, generateUl, i, n2, l1l2CtrlLatency);
381 GenerateDciMaps(*generationPattern, toSendDl, generateDl, i, n0, l1l2CtrlLatency);
383 int32_t k1 = ReturnHarqSlot(*generationPattern, i, n1);
384 (*dlHarqfbPosition).insert(std::make_pair(i, k1));
388 GenerateDciMaps(*generationPattern, toSendDl, generateDl, i, n0, l1l2CtrlLatency);
389 GenerateDciMaps(*generationPattern, toSendUl, generateUl, i, n2, l1l2CtrlLatency);
391 int32_t k1 = ReturnHarqSlot(*generationPattern, i, n1);
392 (*dlHarqfbPosition).insert(std::make_pair(i, k1));
417 for (
auto& list : (*generateUl))
419 std::stable_sort(list.second.begin(), list.second.end());
422 for (
auto& list : (*generateDl))
424 std::stable_sort(list.second.begin(), list.second.end());
429NrGnbPhy::PushDlAllocation(
const SfnSf& sfnSf)
const
431 NS_LOG_FUNCTION(
this);
432 NS_ASSERT(m_phySapUser);
435 VarTtiAllocInfo dlCtrlVarTti(dci);
437 SlotAllocInfo slotAllocInfo = SlotAllocInfo(sfnSf);
439 slotAllocInfo.m_numSymAlloc = dlCtrlVarTti.m_dci->m_numSym;
441 slotAllocInfo.m_varTtiAllocInfo.emplace_back(dlCtrlVarTti);
447NrGnbPhy::PushUlAllocation(
const SfnSf& sfnSf)
const
449 NS_LOG_FUNCTION(
this);
450 NS_ASSERT(m_phySapUser);
453 VarTtiAllocInfo ulCtrlVarTti(dci);
455 SlotAllocInfo slotAllocInfo = SlotAllocInfo(sfnSf);
457 slotAllocInfo.m_numSymAlloc = ulCtrlVarTti.m_dci->m_numSym;
459 slotAllocInfo.m_varTtiAllocInfo.emplace_back(ulCtrlVarTti);
465NrGnbPhy::SetTddPattern(
const std::vector<LteNrTddSlotType>& pattern)
467 NS_LOG_FUNCTION(
this);
469 std::stringstream ss;
471 for (
const auto& v : pattern)
475 NS_LOG_INFO(
"Set pattern : " << ss.str());
479 m_generateDl.clear();
480 m_generateUl.clear();
483 m_dlHarqfbPosition.clear();
485 GenerateStructuresFromPattern(pattern,
500 NS_LOG_FUNCTION(
this);
501 Simulator::ScheduleWithContext(nodeId,
503 &NrGnbPhy::StartEventLoop,
511NrGnbPhy::StartEventLoop(uint16_t frame, uint8_t subframe, uint16_t slot)
513 NS_LOG_FUNCTION(
this);
514 NS_LOG_DEBUG(
"PHY starting. Configuration: "
516 <<
"\t TxPower: " <<
m_txPower <<
" dBm" << std::endl
518 <<
"\t N0: " << m_n0Delay << std::endl
519 <<
"\t N1: " << m_n1Delay << std::endl
520 <<
"\t N2: " << m_n2Delay << std::endl
525 <<
"\t Pattern: " <<
GetPattern() << std::endl
526 <<
"Attached to physical channel: " << std::endl
532 StartSlot(startSlot);
538 NS_LOG_FUNCTION(
this);
539 m_gnbCphySapUser = s;
545 NS_LOG_FUNCTION(
this);
546 return m_gnbCphySapProvider;
556NrGnbPhy::GetNrFhPhySapUser()
603 NS_LOG_FUNCTION(
this);
611 NS_LOG_FUNCTION(
this);
613 for (
const auto& i : m_deviceMap)
615 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
616 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
618 if (ueRnti == rnti && DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
630 NS_LOG_FUNCTION(
this);
631 NS_ASSERT(cam !=
nullptr);
633 m_cam->SetAccessGrantedCallback(
634 std::bind(&NrGnbPhy::ChannelAccessGranted,
this, std::placeholders::_1));
635 m_cam->SetAccessDeniedCallback(std::bind(&NrGnbPhy::ChannelAccessLost,
this));
638Ptr<NrChAccessManager>
641 NS_LOG_FUNCTION(
this);
669 auto scaling = double(rbIndexVector.size()) / double(nTotalAllocRbs);
670 for (
auto it = txPsd->ValuesBegin(); it != txPsd->ValuesEnd(); it++)
686 NS_LOG_FUNCTION(
this);
691 Ptr<NrMibMessage> mibMsg = Create<NrMibMessage>();
700 NS_LOG_FUNCTION(
this);
701 Ptr<NrSib1Message> msg = Create<NrSib1Message>();
702 msg->SetSib1(m_sib1);
708NrGnbPhy::CallMacForSlotIndication(
const SfnSf& currentSlot)
710 NS_LOG_FUNCTION(
this);
711 NS_ASSERT(!m_generateDl.empty() || !m_generateUl.empty());
715 uint64_t currentSlotN = currentSlot.Normalize() %
m_tddPattern.size();
717 NS_LOG_DEBUG(
"Start Slot " << currentSlot <<
". In position " << currentSlotN
718 <<
" there is a slot of type " <<
m_tddPattern[currentSlotN]);
720 for (
const auto& k2WithLatency : m_generateUl[currentSlotN])
722 SfnSf targetSlot = currentSlot;
723 targetSlot.Add(k2WithLatency);
725 uint64_t pos = targetSlot.Normalize() %
m_tddPattern.size();
727 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" generate UL for " << targetSlot
733 for (
const auto& k0WithLatency : m_generateDl[currentSlotN])
735 SfnSf targetSlot = currentSlot;
736 targetSlot.Add(k0WithLatency);
738 uint64_t pos = targetSlot.Normalize() %
m_tddPattern.size();
740 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" generate DL for " << targetSlot
748NrGnbPhy::StartSlot(
const SfnSf& startSlot)
750 NS_LOG_FUNCTION(
this);
751 NS_ASSERT(m_channelStatus != TO_LOSE);
753 m_currentSlot = startSlot;
754 m_lastSlotStart = Simulator::Now();
756 Simulator::Schedule(
GetSlotPeriod(), &NrGnbPhy::EndSlot,
this);
766 NS_LOG_WARN(
"No allocation for the current slot. Using an empty one");
772 if (m_currentSlot.
GetSlot() == 0)
774 bool mibOrSib =
false;
787 VarTtiAllocInfo dlCtrlSlot(m_phySapUser->
GetDlCtrlDci());
794 if (m_channelStatus == GRANTED)
796 NS_LOG_INFO(
"Channel granted");
797 CallMacForSlotIndication(m_currentSlot);
802 bool hasUlDci =
false;
803 SfnSf ulSfn = m_currentSlot;
811 hasUlDci = ulSlot.ContainsDataAllocation() || ulSlot.ContainsUlCtrlAllocation() ||
812 ulSlot.ContainsUlMsg3Allocation();
823 if (m_channelStatus == NONE)
825 NS_LOG_INFO(
"Channel not granted, request the channel");
826 m_channelStatus = REQUESTED;
827 m_cam->RequestAccess();
828 if (m_channelStatus == GRANTED)
832 NS_LOG_INFO(
"Channel granted; asking MAC for SlotIndication for the future and "
833 "then start the slot");
834 CallMacForSlotIndication(m_currentSlot);
842 auto newSfnSf = slotAllocCopy.
m_sfnSf;
844 NS_LOG_INFO(
"Queueing allocation in front for " << newSfnSf);
847 NS_LOG_INFO(
"Reason: Current slot allocation has data");
851 NS_LOG_INFO(
"Reason: CTRL message list is not empty");
860 NS_LOG_INFO(
"Empty slot, but asking MAC for SlotIndication for the future, maybe there "
862 CallMacForSlotIndication(m_currentSlot);
875 NS_LOG_INFO(
"Schedule UL CTRL at " << start);
876 Simulator::Schedule(start, &NrGnbPhy::UlCtrl,
this, alloc.m_dci);
882 NS_LOG_INFO(
"Schedule UL SRS at " << start);
883 Simulator::Schedule(start, &NrGnbPhy::UlSrs,
this, alloc.m_dci);
891NrGnbPhy::DoCheckOrReleaseChannel()
893 NS_LOG_FUNCTION(
this);
895 NS_ASSERT(m_channelStatus == GRANTED);
900 uint8_t lastDlSymbol = 0;
907 std::max(lastDlSymbol,
908 static_cast<uint8_t
>(dci.m_dci->m_symStart + dci.m_dci->m_numSym));
916 NS_LOG_LOGIC(
"Last symbol of data: " << +lastDlSymbol
917 <<
", to the end of slot we still have "
919 <<
" us, so we're going to lose the channel");
920 m_channelStatus = TO_LOSE;
924 NS_LOG_LOGIC(
"Last symbol of data: " << +lastDlSymbol
925 <<
", to the end of slot we still have "
927 <<
" us, so we're NOT going to lose the channel");
932NrGnbPhy::RetrievePrepareEncodeCtrlMsgs()
934 NS_LOG_FUNCTION(
this);
937 ctrlMsgs.merge(RetrieveMsgsFromDCIs(m_currentSlot));
946 for (
const auto& msg : ctrlMsgs)
954NrGnbPhy::GenerateAllocationStatistics(
const SlotAllocInfo& allocInfo)
const
956 NS_LOG_FUNCTION(
this);
957 std::unordered_set<uint16_t> activeUe;
959 uint32_t dataReg = 0;
960 uint32_t ctrlReg = 0;
961 uint32_t dataSym = 0;
962 uint32_t ctrlSym = 0;
964 int lastSymStart = -1;
965 uint32_t symUsed = 0;
967 for (
const auto& allocation : allocInfo.m_varTtiAllocInfo)
969 uint32_t rbg = std::count(allocation.m_dci->m_rbgBitmask.begin(),
970 allocation.m_dci->m_rbgBitmask.end(),
974 if (allocation.m_dci->m_rnti != 0)
976 activeUe.insert(allocation.m_dci->m_rnti);
979 NS_ASSERT(lastSymStart <= allocation.m_dci->m_symStart);
981 auto rbgUsed = (rbg *
GetNumRbPerRbg()) * allocation.m_dci->m_numSym;
992 if (lastSymStart != allocation.m_dci->m_symStart)
994 symUsed += allocation.m_dci->m_numSym;
999 dataSym += allocation.m_dci->m_numSym;
1003 ctrlSym += allocation.m_dci->m_numSym;
1007 lastSymStart = allocation.m_dci->m_symStart;
1010 NS_ASSERT_MSG(symUsed == allocInfo.m_numSymAlloc,
1011 "Allocated " << +allocInfo.m_numSymAlloc <<
" but only " << symUsed
1012 <<
" written in stats");
1014 m_phySlotDataStats(allocInfo.m_sfnSf,
1022 m_phySlotCtrlStats(allocInfo.m_sfnSf,
1033NrGnbPhy::DoStartSlot()
1035 NS_LOG_FUNCTION(
this);
1041 NS_LOG_DEBUG(
"Start Slot " << m_currentSlot <<
" of type " <<
m_tddPattern[currentSlotN]);
1052 DoCheckOrReleaseChannel();
1054 RetrievePrepareEncodeCtrlMsgs();
1062NrGnbPhy::PrepareRbgAllocationMap(
const std::deque<VarTtiAllocInfo>& allocations)
1064 NS_LOG_FUNCTION(
this);
1067 m_rbgAllocationPerSym.clear();
1070 for (
const auto& allocation : allocations)
1078 StoreRBGAllocation(&m_rbgAllocationPerSym, allocation.m_dci);
1082 StoreRBGAllocation(&m_rbgAllocationPerSymDataStat, allocation.m_dci);
1086 for (
const auto& s : m_rbgAllocationPerSymDataStat)
1088 auto& rbgAllocation = s.second;
1089 m_rbStatistics(m_currentSlot,
1096 m_rbgAllocationPerSymDataStat.clear();
1100NrGnbPhy::FillTheEvent()
1102 NS_LOG_FUNCTION(
this);
1104 uint8_t lastSymStart = 0;
1107 NS_ASSERT(lastSymStart <= allocation.m_dci->m_symStart);
1110 Simulator::Schedule(varTtiStart, &NrGnbPhy::StartVarTti,
this, allocation.m_dci);
1111 lastSymStart = allocation.m_dci->m_symStart;
1113 NS_LOG_INFO(
"Scheduled allocation " << *(allocation.m_dci) <<
" at " << varTtiStart);
1120NrGnbPhy::StoreRBGAllocation(std::unordered_map<uint8_t, std::vector<bool>>* map,
1121 const std::shared_ptr<DciInfoElementTdma>& dci)
const
1123 NS_LOG_FUNCTION(
this);
1125 auto itAlloc = map->find(dci->m_symStart);
1126 if (itAlloc == map->end())
1128 itAlloc = map->insert(std::make_pair(dci->m_symStart, dci->m_rbgBitmask)).first;
1132 auto& existingRBGBitmask = itAlloc->second;
1133 NS_ASSERT(existingRBGBitmask.size() == dci->m_rbgBitmask.size());
1134 for (uint32_t i = 0; i < existingRBGBitmask.size(); ++i)
1136 existingRBGBitmask.at(i) = existingRBGBitmask.at(i) || dci->m_rbgBitmask.at(i);
1141std::list<Ptr<NrControlMessage>>
1142NrGnbPhy::RetrieveDciFromAllocation(
const SlotAllocInfo& alloc,
1147 NS_LOG_FUNCTION(
this);
1148 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1150 if (!alloc.m_buildRarList.empty())
1152 Ptr<NrRarMessage> ulMsg3DciMsg = Create<NrRarMessage>();
1153 for (
const auto& rarIt : alloc.m_buildRarList)
1155 NrRarMessage::Rar rar{};
1157 NS_ASSERT(rarIt.raPreambleId != 255);
1158 rar.rarPayload = rarIt;
1159 rar.rarPayload.k2Delay = kDelay;
1160 ulMsg3DciMsg->AddRar(rar);
1162 NS_LOG_INFO(
"In slot " << m_currentSlot <<
" PHY retrieves the RAR message for RNTI "
1163 << rar.rarPayload.ulMsg3Dci->m_rnti <<
" RA preamble Id "
1164 << +rar.rarPayload.raPreambleId <<
" at:" << Simulator::Now()
1165 <<
" for slot:" << alloc.m_sfnSf <<
" kDelay:" << kDelay
1166 <<
"k1Delay:" << k1Delay);
1167 ulMsg3DciMsg->SetSourceBwp(
GetBwpId());
1171 ctrlMsgs.push_back(ulMsg3DciMsg);
1175 for (
const auto& dlAlloc : alloc.m_varTtiAllocInfo)
1180 && dlAlloc.m_dci->m_format == format)
1182 auto& dciElem = dlAlloc.m_dci;
1183 NS_ASSERT(dciElem->m_format == format);
1185 "symStart: " <<
static_cast<uint32_t
>(dciElem->m_symStart)
1186 <<
" numSym: " <<
static_cast<uint32_t
>(dciElem->m_numSym)
1190 NS_LOG_INFO(
"Send DCI to RNTI " << dciElem->m_rnti <<
" from sym "
1191 << +dciElem->m_symStart <<
" to "
1192 << +dciElem->m_symStart + dciElem->m_numSym);
1194 Ptr<NrControlMessage> msg;
1198 Ptr<NrDlDciMessage> dciMsg = Create<NrDlDciMessage>(dciElem);
1201 dciMsg->SetKDelay(kDelay);
1202 dciMsg->SetK1Delay(k1Delay);
1207 Ptr<NrUlDciMessage> dciMsg = Create<NrUlDciMessage>(dciElem);
1210 dciMsg->SetKDelay(kDelay);
1214 ctrlMsgs.push_back(msg);
1221std::list<Ptr<NrControlMessage>>
1222NrGnbPhy::RetrieveMsgsFromDCIs(
const SfnSf& currentSlot)
1224 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1225 uint64_t currentSlotN = currentSlot.Normalize() %
m_tddPattern.size();
1227 uint32_t k1delay = m_dlHarqfbPosition[currentSlotN];
1230 for (
const auto& k0delay : m_toSendDl[currentSlotN])
1232 SfnSf targetSlot = currentSlot;
1234 targetSlot.Add(k0delay);
1236 if (targetSlot == currentSlot)
1238 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send DL DCI for the same slot");
1247 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send DL DCI for " << targetSlot);
1256 NS_LOG_DEBUG(
"No allocation found for slot " << targetSlot);
1260 for (
const auto& k2delay : m_toSendUl[currentSlotN])
1262 SfnSf targetSlot = currentSlot;
1264 targetSlot.Add(k2delay);
1266 if (targetSlot == currentSlot)
1268 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send UL DCI for the same slot");
1277 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send UL DCI for " << targetSlot);
1286 NS_LOG_DEBUG(
"No allocation found for slot " << targetSlot);
1294NrGnbPhy::DlCtrl(
const std::shared_ptr<DciInfoElementTdma>& dci)
1296 NS_LOG_FUNCTION(
this);
1298 NS_LOG_DEBUG(
"Starting DL CTRL TTI at symbol " << +m_currSymStart <<
" to "
1299 << +m_currSymStart + dci->m_numSym);
1304 bool transmitCsiRs =
false;
1308 uint16_t currentCsiRsOffset = m_currentSlot.
Normalize() % m_csiRsPeriodicity;
1309 if (TimeToTransmitCsiRs(currentCsiRsOffset))
1311 varTtiPeriod = ScheduleCsiRs(varTtiPeriod, currentCsiRsOffset);
1312 transmitCsiRs =
true;
1319 NS_LOG_DEBUG(
"gNB TXing DL CTRL with "
1320 <<
m_ctrlMsgs.size() <<
" msgs, frame " << m_currentSlot <<
" symbols "
1321 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1322 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1323 << Simulator::Now() <<
" end "
1324 << Simulator::Now() + varTtiPeriod - NanoSeconds(1.0));
1327 Ptr<NrControlMessage> msg = m_ctrlMsg;
1328 m_phyTxedCtrlMsgsTrace(m_currentSlot,
GetCellId(), dci->m_rnti,
GetBwpId(), msg);
1331 SendCtrlChannels(varTtiPeriod -
1336 NS_LOG_DEBUG(
"No messages to send, skipping");
1339 return varTtiPeriod;
1343NrGnbPhy::TimeToTransmitCsiRs(uint16_t currentOffset)
const
1345 if (!m_csiRsOffsetToUes.contains(currentOffset))
1351 return !m_csiRsOffsetToUes.at(currentOffset).empty();
1356NrGnbPhy::TransmitCsiRsPerUe(Ptr<NrUeNetDevice> ueDev)
1358 NS_LOG_FUNCTION(
this);
1360 uint64_t rnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1362 NS_LOG_DEBUG(
"Transmitting CSI-RS towards UE with IMSI : " << ueDev->GetImsi() <<
" at slot:"
1368NrGnbPhy::ScheduleCsiRs(Time ctrlVarTti, uint16_t currentOffset)
1371 "Should have finished transmission of CTRL already.");
1377 ctrlVarTti -= m_deviceMap.size() * NanoSeconds(2);
1379 uint16_t ueCounter = 0;
1380 for (
auto& i : m_csiRsOffsetToUes.at(currentOffset))
1382 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1383 Simulator::Schedule(ctrlVarTti + NanoSeconds(2.0) * ueCounter,
1384 &NrGnbPhy::TransmitCsiRsPerUe,
1395NrGnbPhy::UlCtrl(
const std::shared_ptr<DciInfoElementTdma>& dci)
1397 NS_LOG_FUNCTION(
this);
1399 NS_LOG_DEBUG(
"Starting UL CTRL TTI at symbol " << +m_currSymStart <<
" to "
1400 << +m_currSymStart + dci->m_numSym);
1404 NS_LOG_DEBUG(
"gNB RXng UL CTRL frame "
1405 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1406 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1407 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1408 return varTtiPeriod;
1412NrGnbPhy::DlData(
const std::shared_ptr<DciInfoElementTdma>& dci)
1414 NS_LOG_FUNCTION(
this);
1415 NS_LOG_DEBUG(
"Starting DL DATA TTI at symbol " << +m_currSymStart <<
" to "
1416 << +m_currSymStart + dci->m_numSym <<
" for "
1421 Ptr<PacketBurst> pktBurst =
GetPacketBurst(m_currentSlot, dci->m_symStart, dci->m_rnti);
1423 if (!pktBurst || pktBurst->GetNPackets() == 0)
1427 return varTtiPeriod;
1430 NS_LOG_INFO(
"gNB TXing DL DATA frame "
1431 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1432 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1433 << Simulator::Now() + NanoSeconds(1) <<
" end "
1434 << Simulator::Now() + varTtiPeriod - NanoSeconds(2.0));
1436 Simulator::Schedule(NanoSeconds(1.0),
1437 &NrGnbPhy::SendDataChannels,
1440 varTtiPeriod - NanoSeconds(2.0),
1443 return varTtiPeriod;
1447NrGnbPhy::UlData(
const std::shared_ptr<DciInfoElementTdma>& dci)
1449 NS_LOG_FUNCTION(
this);
1451 NS_LOG_DEBUG(
"Starting UL DATA TTI at symbol " << +m_currSymStart <<
" to "
1452 << +m_currSymStart + dci->m_numSym);
1470 for (
auto& i : m_deviceMap)
1472 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1473 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1474 if (dci->m_rnti == ueRnti)
1480 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1495 NS_LOG_INFO(
"GNB RXing UL DATA frame "
1496 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1497 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1498 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1499 return varTtiPeriod;
1505 m_spectrumPhy->GetBeamManager()->ChangeBeamformingVector(dev);
1511 m_spectrumPhy->GetBeamManager()->ChangeToQuasiOmniBeamformingVector();
1515NrGnbPhy::UlSrs(
const std::shared_ptr<DciInfoElementTdma>& dci)
1517 NS_LOG_FUNCTION(
this);
1519 NS_LOG_DEBUG(
"Starting UL SRS TTI at symbol " << +m_currSymStart <<
" to "
1520 << +m_currSymStart + dci->m_numSym);
1530 for (
auto& i : m_deviceMap)
1532 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1533 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(0)))->GetRnti();
1534 if (dci->m_rnti == ueRnti)
1540 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1554 NS_LOG_WARN(
"The UE for which is scheduled this SRS does not have yet initialized RNTI. "
1555 "RAR message was not received yet.");
1558 NS_LOG_INFO(
"GNB RXing UL SRS frame "
1559 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1560 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1561 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1562 return varTtiPeriod;
1566NrGnbPhy::StartVarTti(
const std::shared_ptr<DciInfoElementTdma>& dci)
1568 NS_LOG_FUNCTION(
this);
1569 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1573 m_currSymStart = dci->m_symStart;
1581 varTtiPeriod = DlCtrl(dci);
1585 varTtiPeriod = UlCtrl(dci);
1592 varTtiPeriod = DlData(dci);
1596 varTtiPeriod = UlData(dci);
1602 varTtiPeriod = UlSrs(dci);
1605 Simulator::Schedule(varTtiPeriod, &NrGnbPhy::EndVarTti,
this, dci);
1609NrGnbPhy::EndVarTti(
const std::shared_ptr<DciInfoElementTdma>& lastDci)
1611 NS_LOG_FUNCTION(
this << Simulator::Now().GetSeconds());
1613 NS_LOG_DEBUG(
"DCI started at symbol "
1614 <<
static_cast<uint32_t
>(lastDci->m_symStart) <<
" which lasted for "
1615 <<
static_cast<uint32_t
>(lastDci->m_numSym) <<
" symbols finished");
1621 NS_LOG_FUNCTION(
this);
1623 Time slotStart = m_lastSlotStart +
GetSlotPeriod() - Simulator::Now();
1625 if (m_channelStatus == TO_LOSE)
1627 NS_LOG_INFO(
"Release the channel because we did not have any data to maintain the grant");
1628 m_channelStatus = NONE;
1629 m_channelLostTimer.Cancel();
1632 NS_LOG_DEBUG(
"Slot started at " << m_lastSlotStart <<
" ended");
1636 NS_LOG_DEBUG(
"End slot notified from PHY");
1640 m_currentSlot.
Add(1);
1641 Simulator::Schedule(slotStart, &NrGnbPhy::StartSlot,
this, m_currentSlot);
1645NrGnbPhy::SendDataChannels(
const Ptr<PacketBurst>& pb,
1646 const Time& varTtiPeriod,
1647 const std::shared_ptr<DciInfoElementTdma>& dci)
1649 NS_LOG_FUNCTION(
this);
1654 if (Simulator::Now() > m_lastBfChange)
1657 "Cannot change analog BF after TX has started");
1658 m_lastBfChange = Simulator::Now();
1660 for (
auto& i : m_deviceMap)
1662 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1663 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1664 if (dci->m_rnti == ueRnti)
1666 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1687 NS_ASSERT(m_rbgAllocationPerSym.find(dci->m_symStart) != m_rbgAllocationPerSym.end());
1688 auto nTotalAllocRbs =
1692 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1693 m_spectrumPhy->StartTxDataFrames(pb, ctrlMsgs, dci, varTtiPeriod);
1697NrGnbPhy::SendCtrlChannels(
const Time& varTtiPeriod)
1699 NS_LOG_FUNCTION(
this <<
"Send Ctrl");
1701 std::vector<int> fullBwRb(
GetRbNum());
1703 for (uint32_t i = 0; i < fullBwRb.size(); ++i)
1705 fullBwRb[i] =
static_cast<int>(i);
1717 auto rng = std::default_random_engine{};
1718 std::shuffle(std::begin(fhCtrlMsgs), std::end(fhCtrlMsgs), rng);
1720 for (
auto ctrlIt = fhCtrlMsgs.begin(); ctrlIt != fhCtrlMsgs.end(); )
1722 Ptr<NrControlMessage> msg = (*ctrlIt);
1725 auto dciMsg = DynamicCast<NrDlDciMessage>(msg);
1726 auto dciInfoElem = dciMsg->GetDciInfoElement();
1727 long rbgAssigned = std::count(dciInfoElem->m_rbgBitmask.begin(),
1728 dciInfoElem->m_rbgBitmask.end(),
1733 rbgAssigned * dciInfoElem->m_numSym,
1734 dciInfoElem->m_rank) == 0)
1737 ctrlIt = fhCtrlMsgs.erase(ctrlIt);
1746 dciInfoElem->m_numSym,
1747 dciInfoElem->m_rank);
1771 NS_LOG_FUNCTION(
this);
1773 if (m_csiRsOffsetToUes.empty())
1775 NS_ABORT_MSG_UNLESS(m_csiRsPeriodicity %
m_tddPattern.size() == 0,
1776 "CSI-RS periodicity should be a multiply of TDD pattern size");
1778 uint8_t repetitions = m_csiRsPeriodicity /
m_tddPattern.size();
1780 for (uint8_t round = 0; round < repetitions; ++round)
1783 for (
size_t index = 0; index <
m_tddPattern.size(); index++)
1787 m_csiRsOffsetToUes[
m_tddPattern.size() * round + index] =
1788 std::set<Ptr<NrUeNetDevice>>();
1794 size_t lastAssignedOffset = m_csiRsOffsetToUes.begin()->second.size();
1797 for (
auto& i : m_csiRsOffsetToUes)
1799 if (i.second.size() < lastAssignedOffset)
1801 i.second.emplace(ueDevice);
1802 NS_LOG_DEBUG(
"Assigning CSI-RS offset for UE with IMSI: " << ueDevice->GetImsi());
1805 lastAssignedOffset = i.second.size();
1809 NS_LOG_DEBUG(
"Assigning CSI-RS offset for UE with IMSI: " << ueDevice->GetImsi());
1810 m_csiRsOffsetToUes.begin()->second.emplace(ueDevice);
1816 NS_LOG_FUNCTION(
this << imsi);
1817 std::set<uint64_t>::iterator it;
1818 it = m_ueAttached.find(imsi);
1820 if (it == m_ueAttached.end())
1822 m_ueAttached.insert(imsi);
1823 m_deviceMap.push_back(ueDevice);
1833 NS_LOG_ERROR(
"Programming error...UE already attached");
1841 Simulator::ScheduleWithContext(
m_netDevice->GetNode()->GetId(),
1851 NS_LOG_FUNCTION(
this << sinr);
1853 Values::const_iterator it;
1855 ulcqi.
m_ulCqi.m_type = UlCqiInfo::PUSCH;
1856 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
1862 ulcqi.
m_ulCqi.m_sinr.push_back(
1870 ulcqi.
m_sfnSf = m_currentSlot;
1872 SpectrumValue newSinr = sinr;
1873 m_ulSinrTrace(0, newSinr, newSinr);
1880 NS_LOG_FUNCTION(
this);
1884 Ptr<NrDlCqiMessage> dlcqi = DynamicCast<NrDlCqiMessage>(msg);
1888 NS_LOG_INFO(
"Received DL_CQI for RNTI: " << dlcqiLE.
m_rnti <<
" in slot " << m_currentSlot);
1894 NS_LOG_INFO(
"received RACH_PREAMBLE");
1896 Ptr<NrRachPreambleMessage> rachPreamble = DynamicCast<NrRachPreambleMessage>(msg);
1898 NS_LOG_INFO(
"Received RACH Preamble in slot " << m_currentSlot);
1903 Ptr<NrDlHarqFeedbackMessage> dlharqMsg = DynamicCast<NrDlHarqFeedbackMessage>(msg);
1904 DlHarqInfo dlharq = dlharqMsg->GetDlHarqFeedback();
1905 if (m_ueAttachedRnti.find(dlharq.
m_rnti) != m_ueAttachedRnti.end())
1909 NS_LOG_INFO(
"Received DL_HARQ for RNTI: " << dlharq.
m_rnti <<
" in slot "
1926NrGnbPhy::DoSetBandwidth(uint16_t ulBandwidth, uint16_t dlBandwidth)
1928 NS_LOG_FUNCTION(
this << +ulBandwidth << +dlBandwidth);
1929 NS_ASSERT(ulBandwidth == dlBandwidth);
1934NrGnbPhy::DoSetEarfcn(uint16_t ulEarfcn, uint16_t dlEarfcn)
1936 NS_LOG_FUNCTION(
this << ulEarfcn << dlEarfcn);
1940NrGnbPhy::DoAddUe([[maybe_unused]] uint16_t rnti)
1942 NS_LOG_FUNCTION(
this << rnti);
1943 std::set<uint16_t>::iterator it;
1944 it = m_ueAttachedRnti.find(rnti);
1945 if (it == m_ueAttachedRnti.end())
1947 m_ueAttachedRnti.insert(rnti);
1952NrGnbPhy::DoRemoveUe(uint16_t rnti)
1954 NS_LOG_FUNCTION(
this << rnti);
1956 std::set<uint16_t>::iterator it = m_ueAttachedRnti.find(rnti);
1957 if (it != m_ueAttachedRnti.end())
1959 m_ueAttachedRnti.erase(it);
1963 NS_FATAL_ERROR(
"Impossible to remove UE, not attached!");
1968NrGnbPhy::DoSetPa(uint16_t rnti,
double pa)
1970 NS_LOG_FUNCTION(
this << rnti << pa);
1974NrGnbPhy::DoSetTransmissionMode(uint16_t rnti, uint8_t txMode)
1976 NS_LOG_FUNCTION(
this << rnti << +txMode);
1981NrGnbPhy::DoSetSrsConfigurationIndex(uint16_t rnti, uint16_t srcCi)
1983 NS_LOG_FUNCTION(
this << rnti << srcCi);
1987NrGnbPhy::DoSetMasterInformationBlock([[maybe_unused]] NrRrcSap::MasterInformationBlock mib)
1989 NS_LOG_FUNCTION(
this);
1993NrGnbPhy::DoSetSystemInformationBlockType1(NrRrcSap::SystemInformationBlockType1 sib1)
1995 NS_LOG_FUNCTION(
this);
2002 NS_LOG_FUNCTION(
this);
2015 NS_LOG_FUNCTION(
this);
2017 if (m_ueAttachedRnti.find(mes.
m_rnti) != m_ueAttachedRnti.end())
2019 NS_LOG_INFO(
"Received UL HARQ feedback " << mes.
IsReceivedOk()
2020 <<
" and forwarding to the scheduler");
2028 NS_LOG_FUNCTION(
this);
2030 static std::unordered_map<std::string, LteNrTddSlotType> lookupTable = {
2037 std::vector<LteNrTddSlotType> vector;
2038 std::stringstream ss(pattern);
2040 std::vector<std::string> extracted;
2042 while (std::getline(ss, token,
'|'))
2044 extracted.push_back(token);
2047 for (
const auto& v : extracted)
2049 if (lookupTable.find(v) == lookupTable.end())
2051 NS_FATAL_ERROR(
"Pattern type " << v <<
" not valid. Valid values are: DL UL F S");
2053 vector.push_back(lookupTable[v]);
2056 SetTddPattern(vector);
2068 NS_LOG_FUNCTION(
this);
2075 m_csiRsModel = csiRsModel;
2081 return m_csiRsModel;
2087 m_csiRsPeriodicity = csiRsPeriodicity;
2093 return m_csiRsPeriodicity;
2097NrGnbPhy::ChannelAccessGranted(
const Time& time)
2099 NS_LOG_FUNCTION(
this);
2103 NS_LOG_INFO(
"Channel granted for less than the slot time. Ignoring the grant.");
2104 m_channelStatus = NONE;
2108 m_channelStatus = GRANTED;
2110 Time toNextSlot = m_lastSlotStart +
GetSlotPeriod() - Simulator::Now();
2111 Time grant = time - toNextSlot;
2112 int64_t slotGranted = grant.GetNanoSeconds() /
GetSlotPeriod().GetNanoSeconds();
2114 NS_LOG_INFO(
"Channel access granted for " << time <<
", which corresponds to " << slotGranted
2116 <<
". We lost " << toNextSlot);
2117 NS_ASSERT(!m_channelLostTimer.IsPending());
2119 if (slotGranted < 1)
2123 m_channelLostTimer = Simulator::Schedule(
GetSlotPeriod() * slotGranted - NanoSeconds(1),
2124 &NrGnbPhy::ChannelAccessLost,
2129NrGnbPhy::ChannelAccessLost()
2131 NS_LOG_FUNCTION(
this);
2132 NS_LOG_INFO(
"Channel access lost");
2133 m_channelStatus = NONE;
Representation of a beam id.
Template for the implementation of the NrFhPhySapUser as a member of an owner class of type C to whic...
@ DL_HARQ
DL HARQ feedback.
@ RACH_PREAMBLE
Random Access Preamble.
@ DL_DCI
The resources allocation map from the BS to the attached UEs (DL)
@ Dropping
Drop DCI + DATA at the PHY Layer.
Service Access Point (SAP) offered by the FhControl instance to the gnb PHY instance.
void GenerateDataCqiReport(const SpectrumValue &sinr)
Generate a DL CQI report.
void SetN1Delay(uint32_t delay)
: Set the minimum processing delay (in slots) to decode DL Data and send Harq feedback.
NrGnbCphySapProvider * GetGnbCphySapProvider()
Get the C PHY SAP provider.
void ChangeToQuasiOmniBeamformingVector()
void ReportUlHarqFeedback(const UlHarqInfo &mes)
Get the HARQ feedback from NrSpectrumPhy and forward it to the scheduler.
int8_t DoGetReferenceSignalPower() const
Get the power of the gnb.
Ptr< NrChAccessManager > GetCam() const
Get the channel access manager for the PHY.
void DoDispose() override
DoDispose method inherited from Object.
bool DoesFhAllocationFit(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank) const
Returns a boolean indicating whether the current allocation can fit in the available FH bandwidth.
void SetPrimary()
Set this PHY as primary.
void SetN0Delay(uint32_t delay)
: Set the minimum processing delay (in slots) to decode DL DCI and decode DL data....
void ScheduleStartEventLoop(uint32_t nodeId, uint16_t frame, uint8_t subframe, uint16_t slot) override
Start the ue Event Loop.
~NrGnbPhy() override
~NrGnbPhy
const SfnSf & GetCurrentSfnSf() const override
Get the current SfnSf.
void AssignCsiRsOffset(const Ptr< NrUeNetDevice > &ueDevice)
void SetCsiRsModel(enum CsiRsModel csiRsModel)
Set the CSI-RS model.
void SetCam(const Ptr< NrChAccessManager > &s)
Set the channel access manager interface for this instance of the PHY.
CsiRsModel
CSI-RS model to be used.
@ CSI_RS_PER_UE
CSI-RS per UE periodically.
@ CSI_RS_PER_BEAM
CSI-RS per beam periodically.
void SetSubChannels(const std::vector< int > &rbIndexVector, size_t nTotalAllocRbs)
Set the Tx power spectral density based on the RB index vector.
BeamId GetBeamId(uint16_t rnti) const override
Get the BeamId for the selected user.
void SetGnbCphySapUser(NrGnbCphySapUser *s)
Set the C PHY SAP user.
bool RegisterUe(uint64_t imsi, const Ptr< NrUeNetDevice > &ueDevice)
Add the UE to the list of this gnb UEs.
NrFhPhySapProvider * m_nrFhPhySapProvider
FH Control SAP provider.
void SetCsiRsPeriodicity(uint16_t csiRsPeriodicity)
void SetPattern(const std::string &pattern)
Set the pattern that the gnb will utilize.
void SetN2Delay(uint32_t delay)
: Set the minimum processing delay (in slots) to decode UL DCI and prepare UL data.
NrGnbPhy()
NrGnbPhy constructor. Please use the other one.
uint32_t GetN2Delay() const
: Get the minimum processing delay (in slots) to decode UL DCI and prepare UL data
uint32_t GetN1Delay() const
: Get the minimum processing delay (in slots) to decode DL Data and send Harq feedback
void PhyDataPacketReceived(const Ptr< Packet > &p)
Receive a PHY data packet.
void PhyCtrlMessagesReceived(const Ptr< NrControlMessage > &msg)
Receive a list of CTRL messages.
void SetTxPower(double pow)
Set the transmission power for the UE.
uint16_t GetCsiRsPeriodicity() const
Retrieve CSI-RS periodicity.
enum CsiRsModel GetCsiRsModel() const
Gets the CSI-RS model in use.
double GetTxPower() const override
Retrieve the TX power of the gNB.
void SetPhySapUser(NrGnbPhySapUser *ptr)
Install the PHY SAP user (which is in this case the MAC)
NrFhPhySapUser * m_nrFhPhySapUser
FH Control SAP user.
uint32_t GetN0Delay() const
: Get the minimum processing delay (in slots) to decode DL DCI and decode DL Data
uint32_t GetNumRbPerRbg() const override
Retrieve the number of RB per RBG.
std::string GetPattern() const
Retrieve the currently installed pattern.
void ChangeBeamformingVector(Ptr< NrNetDevice > dev)
static TypeId GetTypeId()
Get Type id.
SAP interface between the gNB PHY and the gNB MAC.
virtual void ReceiveControlMessage(Ptr< NrControlMessage > msg)=0
Receive SendNrControlMessage (PDCCH map, CQI feedbacks) using the ideal control channel.
virtual void SlotUlIndication(const SfnSf &sfn, LteNrTddSlotType slotType)=0
Trigger MAC layer to generate an UL slot for the SfnSf indicated.
virtual void ReceivePhyPdu(Ptr< Packet > p)=0
Notify the MAC of the reception of a new PHY-PDU.
virtual void UlCqiReport(NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi)=0
Returns to MAC level the UL-CQI evaluated.
virtual void UlHarqFeedback(UlHarqInfo params)=0
Notify the HARQ on the UL transmission status.
virtual void SetCurrentSfn(const SfnSf &sfn)=0
Set the current Sfn. The state machine has advanced by one slot.
virtual uint32_t GetNumRbPerRbg() const =0
PHY requests information from MAC. While MAC normally act as user of PHY services,...
virtual uint8_t GetDlCtrlSymbols() const =0
Retrieve the DL CTRL symbols.
virtual void ReceiveRachPreamble(uint32_t raId)=0
Notify the reception of a RACH preamble on the PRACH.
virtual void SlotDlIndication(const SfnSf &sfn, LteNrTddSlotType slotType)=0
Trigger MAC layer to generate a DL slot for the SfnSf indicated.
virtual std::shared_ptr< DciInfoElementTdma > GetUlCtrlDci() const =0
Retrieve a dci for a UL CTRL allocation.
virtual std::shared_ptr< DciInfoElementTdma > GetDlCtrlDci() const =0
Retrieve a dci for a DL CTRL allocation.
The base class for gNb and UE physical layer.
Time GetSymbolPeriod() const
Get SymbolPeriod.
Ptr< NrSpectrumPhy > m_spectrumPhy
Pointer to the (owned) spectrum phy.
SlotAllocInfo RetrieveSlotAllocInfo()
Get the head for the slot allocation info, and delete it from the internal list.
uint16_t GetCellId() const
uint16_t GetNumerology() const
Get the configured numerology.
Ptr< NrSpectrumPhy > GetSpectrumPhy() const
Retrieve the SpectrumPhy pointer.
void EncodeCtrlMsg(const Ptr< NrControlMessage > &msg)
Take the control messages, and put it in a list that will be sent at the first occasion.
void SetNumerology(uint16_t numerology)
Set GNB or UE numerology.
virtual void SetTbDecodeLatency(const Time &us)
Configures TB decode latency.
std::list< Ptr< NrControlMessage > > m_ctrlMsgs
CTRL messages to be sent.
void SetRbOverhead(double oh)
Set the bandwidth overhead for calculating the usable RB number.
Ptr< PacketBurst > GetPacketBurst(SfnSf sf, uint8_t sym, uint16_t rnti)
Retrieve the PacketBurst at the slot/symbol specified.
void SetPowerAllocationType(enum NrSpectrumValueHelper::PowerAllocationType powerAllocationType)
Set power allocation type. There are currently supported two types: one that distributes uniformly en...
static std::string GetPattern(const std::vector< LteNrTddSlotType > &pattern)
Get a string representation of a pattern.
Time GetSlotPeriod() const
Get the slot period.
virtual std::list< Ptr< NrControlMessage > > PopCurrentSlotCtrlMsgs()
Extract and return the message list that is at the beginning of the queue.
SlotAllocInfo m_currSlotAllocInfo
Current slot allocation.
enum NrSpectrumValueHelper::PowerAllocationType GetPowerAllocationType() const
Get the power allocation type.
void EnqueueCtrlMsgNow(const Ptr< NrControlMessage > &msg)
Enqueue a CTRL message without considering L1L2CtrlLatency.
uint32_t GetChannelBandwidth() const
Retrieve the channel bandwidth, in Hz.
virtual Time GetTbDecodeLatency() const
Returns Transport Block decode latency.
SlotAllocInfo & PeekSlotAllocInfo(const SfnSf &sfnsf)
Peek the SlotAllocInfo at the SfnSf specified.
double GetCentralFrequency() const
Retrieve the frequency (in Hz) of this PHY's channel.
double m_noiseFigure
Noise figure (attribute)
void SetSymbolsPerSlot(uint16_t symbolsPerSlot)
Set the number of symbol per slot.
double GetNoiseFigure() const
Get the NoiseFigure value.
void SetNoiseFigure(double d)
Set the NoiseFigure value.
double m_txPower
Transmission power (attribute)
void InitializeMessageList()
Initialize the message list.
Ptr< SpectrumValue > GetTxPowerSpectralDensity(const std::vector< int > &rbIndexVector)
void SetChannelBandwidth(uint16_t bandwidth)
Function to set the channel bandwidth, used also by child classes, i.e., see functions DoSetDlBanwidt...
uint16_t GetBwpId() const
void PushFrontSlotAllocInfo(const SfnSf &newSfnSf, const SlotAllocInfo &slotAllocInfo)
Store the slot allocation info at the front.
Ptr< NrNetDevice > m_netDevice
Pointer to the owner netDevice.
uint32_t GetL1L2CtrlLatency() const
bool HasDlSlot() const
Go through the current pattern and see if at least one slot is DL, F or S.
bool SlotAllocInfoExists(const SfnSf &sfnsf) const
Check if the SlotAllocationInfo for that slot exists.
uint32_t GetSymbolsPerSlot() const
Get the number of symbols in a slot.
std::vector< LteNrTddSlotType > m_tddPattern
Pattern.
NrPhySapProvider * m_phySapProvider
Pointer to the MAC.
double GetRbOverhead() const
Get the bandwidth overhead used when calculating the usable RB number.
bool HasUlSlot() const
Go through the current pattern and see if at least one slot is UL, F or S.
uint32_t GetRbNum() const
Get the number of Resource block configured.
std::vector< int > FromRBGBitmaskToRBAssignment(const std::vector< bool > rbgBitmask) const
Transform a MAC-made vector of RBG to a PHY-ready vector of SINR indices.
static bool IsTdd(const std::vector< LteNrTddSlotType > &pattern)
Check if a pattern is TDD.
void DoDispose() override
DoDispose method inherited from Object.
virtual void SetSlotAllocInfo(const SlotAllocInfo &slotAllocInfo)=0
Set a SlotAllocInfo inside the PHY allocations.
uint8_t GetSubframe() const
GetSubframe.
uint64_t Normalize() const
Normalize the SfnSf in slot number.
void Add(uint32_t slotN)
Add to this SfnSf a number of slot indicated by the first parameter.
uint8_t GetSlot() const
GetSlot.
@ F
DL CTRL + DL DATA + UL DATA + UL CTRL.
@ S
DL CTRL + DL 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)
DciFormat
Format of the DCI.
A struct that contains info for the DL HARQ.
The SchedUlCqiInfoReqParameters struct.
struct UlCqiInfo m_ulCqi
UL CQI.
uint8_t m_symStart
Sym start of the transmission to which this CQI refers to.
SfnSf m_sfnSf
SfnSf of this allocation.
bool ContainsDlCtrlAllocation() const
uint32_t m_numSymAlloc
Number of allocated symbols.
bool ContainsDataAllocation() const
Check if we have data allocations.
bool ContainsUlMsg3Allocation() const
Check if we have UL MSG3 allocations.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations
A struct that contains info for the UL HARQ.
bool IsReceivedOk() const override