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();
1068NrGnbPhy::PrepareRbgAllocationMap(
const std::deque<VarTtiAllocInfo>& allocations)
1070 NS_LOG_FUNCTION(
this);
1073 m_rbgAllocationPerSym.clear();
1076 for (
const auto& allocation : allocations)
1084 StoreRBGAllocation(&m_rbgAllocationPerSym, allocation.m_dci);
1088 StoreRBGAllocation(&m_rbgAllocationPerSymDataStat, allocation.m_dci);
1092 for (
const auto& s : m_rbgAllocationPerSymDataStat)
1094 auto& rbgAllocation = s.second;
1095 m_rbStatistics(m_currentSlot,
1102 m_rbgAllocationPerSymDataStat.clear();
1106NrGnbPhy::HandleFhDropping()
1108 NS_LOG_FUNCTION(
this);
1109 NS_LOG_DEBUG(
"Dropping FH control messages that do not fit in the available FH BW");
1110 std::vector<size_t> indexesToDelete;
1112 std::iota(shuffledIndexes.begin(), shuffledIndexes.end(), 0);
1114 auto rng = std::default_random_engine{};
1115 std::shuffle(shuffledIndexes.begin(), shuffledIndexes.end(), rng);
1117 for (
size_t index : shuffledIndexes)
1119 std::shared_ptr<DciInfoElementTdma> dci =
1122 NS_ASSERT(dci !=
nullptr);
1125 NS_LOG_DEBUG(
"Checking DCI " << *dci <<
" for FH allocation fit");
1129 long rbgAssigned = std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 1);
1133 rbgAssigned * dci->m_numSym,
1136 NS_LOG_DEBUG(
"Dropping DCI " << *dci <<
" because it does not fit in FH BW");
1137 indexesToDelete.push_back(index);
1150 NS_LOG_DEBUG(
"Skipping non-DL CTRL DCI " << *dci);
1156 std::sort(indexesToDelete.begin(), indexesToDelete.end());
1159 for (
auto it = indexesToDelete.rbegin(); it != indexesToDelete.rend(); ++it)
1167NrGnbPhy::FillTheEvent()
1169 NS_LOG_FUNCTION(
this);
1171 uint8_t lastSymStart = 0;
1174 NS_ASSERT(lastSymStart <= allocation.m_dci->m_symStart);
1177 Simulator::Schedule(varTtiStart, &NrGnbPhy::StartVarTti,
this, allocation.m_dci);
1178 lastSymStart = allocation.m_dci->m_symStart;
1180 NS_LOG_INFO(
"Scheduled allocation " << *(allocation.m_dci) <<
" at " << varTtiStart);
1187NrGnbPhy::StoreRBGAllocation(std::unordered_map<uint8_t, std::vector<bool>>* map,
1188 const std::shared_ptr<DciInfoElementTdma>& dci)
const
1190 NS_LOG_FUNCTION(
this);
1192 auto itAlloc = map->find(dci->m_symStart);
1193 if (itAlloc == map->end())
1195 itAlloc = map->insert(std::make_pair(dci->m_symStart, dci->m_rbgBitmask)).first;
1199 auto& existingRBGBitmask = itAlloc->second;
1200 NS_ASSERT(existingRBGBitmask.size() == dci->m_rbgBitmask.size());
1201 for (uint32_t i = 0; i < existingRBGBitmask.size(); ++i)
1203 existingRBGBitmask.at(i) = existingRBGBitmask.at(i) || dci->m_rbgBitmask.at(i);
1208std::list<Ptr<NrControlMessage>>
1209NrGnbPhy::RetrieveDciFromAllocation(
const SlotAllocInfo& alloc,
1214 NS_LOG_FUNCTION(
this);
1215 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1217 if (!alloc.m_buildRarList.empty())
1219 Ptr<NrRarMessage> ulMsg3DciMsg = Create<NrRarMessage>();
1220 for (
const auto& rarIt : alloc.m_buildRarList)
1222 NrRarMessage::Rar rar{};
1224 NS_ASSERT(rarIt.raPreambleId != 255);
1225 rar.rarPayload = rarIt;
1226 rar.rarPayload.k2Delay = kDelay;
1227 ulMsg3DciMsg->AddRar(rar);
1229 NS_LOG_INFO(
"In slot " << m_currentSlot <<
" PHY retrieves the RAR message for RNTI "
1230 << rar.rarPayload.ulMsg3Dci->m_rnti <<
" RA preamble Id "
1231 << +rar.rarPayload.raPreambleId <<
" at:" << Simulator::Now()
1232 <<
" for slot:" << alloc.m_sfnSf <<
" kDelay:" << kDelay
1233 <<
"k1Delay:" << k1Delay);
1234 ulMsg3DciMsg->SetSourceBwp(
GetBwpId());
1238 ctrlMsgs.push_back(ulMsg3DciMsg);
1242 for (
const auto& dlAlloc : alloc.m_varTtiAllocInfo)
1247 && dlAlloc.m_dci->m_format == format)
1249 auto& dciElem = dlAlloc.m_dci;
1250 NS_ASSERT(dciElem->m_format == format);
1252 "symStart: " <<
static_cast<uint32_t
>(dciElem->m_symStart)
1253 <<
" numSym: " <<
static_cast<uint32_t
>(dciElem->m_numSym)
1257 NS_LOG_INFO(
"Send DCI to RNTI " << dciElem->m_rnti <<
" from sym "
1258 << +dciElem->m_symStart <<
" to "
1259 << +dciElem->m_symStart + dciElem->m_numSym);
1261 Ptr<NrControlMessage> msg;
1265 Ptr<NrDlDciMessage> dciMsg = Create<NrDlDciMessage>(dciElem);
1268 dciMsg->SetKDelay(kDelay);
1269 dciMsg->SetK1Delay(k1Delay);
1274 Ptr<NrUlDciMessage> dciMsg = Create<NrUlDciMessage>(dciElem);
1277 dciMsg->SetKDelay(kDelay);
1281 ctrlMsgs.push_back(msg);
1288std::list<Ptr<NrControlMessage>>
1289NrGnbPhy::RetrieveMsgsFromDCIs(
const SfnSf& currentSlot)
1291 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1292 uint64_t currentSlotN = currentSlot.Normalize() %
m_tddPattern.size();
1294 uint32_t k1delay = m_dlHarqfbPosition[currentSlotN];
1297 for (
const auto& k0delay : m_toSendDl[currentSlotN])
1299 SfnSf targetSlot = currentSlot;
1301 targetSlot.Add(k0delay);
1303 if (targetSlot == currentSlot)
1305 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send DL DCI for the same slot");
1314 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send DL DCI for " << targetSlot);
1323 NS_LOG_DEBUG(
"No allocation found for slot " << targetSlot);
1327 for (
const auto& k2delay : m_toSendUl[currentSlotN])
1329 SfnSf targetSlot = currentSlot;
1331 targetSlot.Add(k2delay);
1333 if (targetSlot == currentSlot)
1335 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send UL DCI for the same slot");
1344 NS_LOG_DEBUG(
" in slot " << currentSlot <<
" send UL DCI for " << targetSlot);
1353 NS_LOG_DEBUG(
"No allocation found for slot " << targetSlot);
1361NrGnbPhy::DlCtrl(
const std::shared_ptr<DciInfoElementTdma>& dci)
1363 NS_LOG_FUNCTION(
this);
1365 NS_LOG_DEBUG(
"Starting DL CTRL TTI at symbol " << +m_currSymStart <<
" to "
1366 << +m_currSymStart + dci->m_numSym);
1371 bool transmitCsiRs =
false;
1375 uint16_t currentCsiRsOffset = m_currentSlot.
Normalize() % m_csiRsPeriodicity;
1376 if (TimeToTransmitCsiRs(currentCsiRsOffset))
1378 varTtiPeriod = ScheduleCsiRs(varTtiPeriod, currentCsiRsOffset);
1379 transmitCsiRs =
true;
1386 NS_LOG_DEBUG(
"gNB TXing DL CTRL with "
1387 <<
m_ctrlMsgs.size() <<
" msgs, frame " << m_currentSlot <<
" symbols "
1388 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1389 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1390 << Simulator::Now() <<
" end "
1391 << Simulator::Now() + varTtiPeriod - NanoSeconds(1.0));
1394 Ptr<NrControlMessage> msg = m_ctrlMsg;
1395 m_phyTxedCtrlMsgsTrace(m_currentSlot,
GetCellId(), dci->m_rnti,
GetBwpId(), msg);
1398 SendCtrlChannels(varTtiPeriod -
1403 NS_LOG_DEBUG(
"No messages to send, skipping");
1406 return varTtiPeriod;
1410NrGnbPhy::TimeToTransmitCsiRs(uint16_t currentOffset)
const
1412 if (!m_csiRsOffsetToUes.contains(currentOffset))
1418 return !m_csiRsOffsetToUes.at(currentOffset).empty();
1423NrGnbPhy::TransmitCsiRsPerUe(Ptr<NrUeNetDevice> ueDev)
1425 NS_LOG_FUNCTION(
this);
1427 uint64_t rnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1429 NS_LOG_DEBUG(
"Transmitting CSI-RS towards UE with IMSI : " << ueDev->GetImsi() <<
" at slot:"
1435NrGnbPhy::ScheduleCsiRs(Time ctrlVarTti, uint16_t currentOffset)
1438 "Should have finished transmission of CTRL already.");
1444 ctrlVarTti -= m_deviceMap.size() * NanoSeconds(2);
1446 uint16_t ueCounter = 0;
1447 for (
auto& i : m_csiRsOffsetToUes.at(currentOffset))
1449 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1450 Simulator::Schedule(ctrlVarTti + NanoSeconds(2.0) * ueCounter,
1451 &NrGnbPhy::TransmitCsiRsPerUe,
1462NrGnbPhy::UlCtrl(
const std::shared_ptr<DciInfoElementTdma>& dci)
1464 NS_LOG_FUNCTION(
this);
1466 NS_LOG_DEBUG(
"Starting UL CTRL TTI at symbol " << +m_currSymStart <<
" to "
1467 << +m_currSymStart + dci->m_numSym);
1471 NS_LOG_DEBUG(
"gNB RXng UL CTRL frame "
1472 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1473 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1474 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1475 return varTtiPeriod;
1479NrGnbPhy::DlData(
const std::shared_ptr<DciInfoElementTdma>& dci)
1481 NS_LOG_FUNCTION(
this);
1482 NS_LOG_DEBUG(
"Starting DL DATA TTI at symbol " << +m_currSymStart <<
" to "
1483 << +m_currSymStart + dci->m_numSym <<
" for "
1488 Ptr<PacketBurst> pktBurst =
GetPacketBurst(m_currentSlot, dci->m_symStart, dci->m_rnti);
1490 if (!pktBurst || pktBurst->GetNPackets() == 0)
1494 return varTtiPeriod;
1497 NS_LOG_INFO(
"gNB TXing DL DATA frame "
1498 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1499 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1500 << Simulator::Now() + NanoSeconds(1) <<
" end "
1501 << Simulator::Now() + varTtiPeriod - NanoSeconds(2.0));
1503 Simulator::Schedule(NanoSeconds(1.0),
1504 &NrGnbPhy::SendDataChannels,
1507 varTtiPeriod - NanoSeconds(2.0),
1510 return varTtiPeriod;
1514NrGnbPhy::UlData(
const std::shared_ptr<DciInfoElementTdma>& dci)
1516 NS_LOG_FUNCTION(
this);
1518 NS_LOG_DEBUG(
"Starting UL DATA TTI at symbol " << +m_currSymStart <<
" to "
1519 << +m_currSymStart + dci->m_numSym);
1537 for (
auto& i : m_deviceMap)
1539 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1540 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1541 if (dci->m_rnti == ueRnti)
1548 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1563 NS_LOG_INFO(
"GNB RXing UL DATA frame "
1564 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1565 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1566 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1567 return varTtiPeriod;
1576 beamManager->ChangeBeamformingVector(dev);
1586 beamManager->ChangeToQuasiOmniBeamformingVector();
1591NrGnbPhy::UlSrs(
const std::shared_ptr<DciInfoElementTdma>& dci)
1593 NS_LOG_FUNCTION(
this);
1595 NS_LOG_DEBUG(
"Starting UL SRS TTI at symbol " << +m_currSymStart <<
" to "
1596 << +m_currSymStart + dci->m_numSym);
1606 for (
auto& i : m_deviceMap)
1608 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1609 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(0)))->GetRnti();
1610 if (dci->m_rnti == ueRnti)
1617 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1631 NS_LOG_WARN(
"The UE for which is scheduled this SRS does not have yet initialized RNTI. "
1632 "RAR message was not received yet.");
1635 NS_LOG_INFO(
"GNB RXing UL SRS frame "
1636 << m_currentSlot <<
" symbols " <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1637 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym - 1) <<
" start "
1638 << Simulator::Now() <<
" end " << Simulator::Now() + varTtiPeriod);
1639 return varTtiPeriod;
1643NrGnbPhy::StartVarTti(
const std::shared_ptr<DciInfoElementTdma>& dci)
1645 NS_LOG_FUNCTION(
this);
1646 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1650 m_currSymStart = dci->m_symStart;
1658 varTtiPeriod = DlCtrl(dci);
1662 varTtiPeriod = UlCtrl(dci);
1669 varTtiPeriod = DlData(dci);
1673 varTtiPeriod = UlData(dci);
1679 varTtiPeriod = UlSrs(dci);
1682 Simulator::Schedule(varTtiPeriod, &NrGnbPhy::EndVarTti,
this, dci);
1686NrGnbPhy::EndVarTti(
const std::shared_ptr<DciInfoElementTdma>& lastDci)
1688 NS_LOG_FUNCTION(
this << Simulator::Now().GetSeconds());
1690 NS_LOG_DEBUG(
"DCI started at symbol "
1691 <<
static_cast<uint32_t
>(lastDci->m_symStart) <<
" which lasted for "
1692 <<
static_cast<uint32_t
>(lastDci->m_numSym) <<
" symbols finished");
1698 NS_LOG_FUNCTION(
this);
1700 Time slotStart = m_lastSlotStart +
GetSlotPeriod() - Simulator::Now();
1702 if (m_channelStatus == TO_LOSE)
1704 NS_LOG_INFO(
"Release the channel because we did not have any data to maintain the grant");
1705 m_channelStatus = NONE;
1706 m_channelLostTimer.Cancel();
1709 NS_LOG_DEBUG(
"Slot started at " << m_lastSlotStart <<
" ended");
1713 NS_LOG_DEBUG(
"End slot notified from PHY");
1717 m_currentSlot.
Add(1);
1718 Simulator::Schedule(slotStart, &NrGnbPhy::StartSlot,
this, m_currentSlot);
1722NrGnbPhy::SendDataChannels(
const Ptr<PacketBurst>& pb,
1723 const Time& varTtiPeriod,
1724 const std::shared_ptr<DciInfoElementTdma>& dci)
1726 NS_LOG_FUNCTION(
this);
1731 if (Simulator::Now() > m_lastBfChange)
1734 "Cannot change analog BF after TX has started");
1735 m_lastBfChange = Simulator::Now();
1737 for (
auto& i : m_deviceMap)
1739 Ptr<NrUeNetDevice> ueDev = DynamicCast<NrUeNetDevice>(i);
1740 uint64_t ueRnti = (DynamicCast<NrUePhy>(ueDev->GetPhy(
GetBwpId())))->GetRnti();
1741 if (dci->m_rnti == ueRnti)
1743 if (DynamicCast<UniformPlanarArray>(
m_spectrumPhy->GetAntenna()))
1764 NS_ASSERT(m_rbgAllocationPerSym.find(dci->m_symStart) != m_rbgAllocationPerSym.end());
1765 auto nTotalAllocRbs =
1769 std::list<Ptr<NrControlMessage>> ctrlMsgs;
1770 m_spectrumPhy->StartTxDataFrames(pb, ctrlMsgs, dci, varTtiPeriod);
1774NrGnbPhy::SendCtrlChannels(
const Time& varTtiPeriod)
1776 NS_LOG_FUNCTION(
this <<
"Send Ctrl");
1778 std::vector<int> fullBwRb(
GetRbNum());
1780 for (uint32_t i = 0; i < fullBwRb.size(); ++i)
1782 fullBwRb[i] =
static_cast<int>(i);
1797 NS_LOG_FUNCTION(
this);
1799 if (m_csiRsOffsetToUes.empty())
1801 NS_ABORT_MSG_UNLESS(m_csiRsPeriodicity %
m_tddPattern.size() == 0,
1802 "CSI-RS periodicity should be a multiply of TDD pattern size");
1804 uint8_t repetitions = m_csiRsPeriodicity /
m_tddPattern.size();
1806 for (uint8_t round = 0; round < repetitions; ++round)
1809 for (
size_t index = 0; index <
m_tddPattern.size(); index++)
1813 m_csiRsOffsetToUes[
m_tddPattern.size() * round + index] =
1814 std::set<Ptr<NrUeNetDevice>>();
1820 size_t lastAssignedOffset = m_csiRsOffsetToUes.begin()->second.size();
1823 for (
auto& i : m_csiRsOffsetToUes)
1825 if (i.second.size() < lastAssignedOffset)
1827 i.second.emplace(ueDevice);
1828 NS_LOG_DEBUG(
"Assigning CSI-RS offset for UE with IMSI: " << ueDevice->GetImsi());
1831 lastAssignedOffset = i.second.size();
1835 NS_LOG_DEBUG(
"Assigning CSI-RS offset for UE with IMSI: " << ueDevice->GetImsi());
1836 m_csiRsOffsetToUes.begin()->second.emplace(ueDevice);
1842 NS_LOG_FUNCTION(
this << imsi);
1843 std::set<uint64_t>::iterator it;
1844 it = m_ueAttached.find(imsi);
1846 if (it == m_ueAttached.end())
1848 m_ueAttached.insert(imsi);
1849 m_deviceMap.push_back(ueDevice);
1859 NS_LOG_ERROR(
"Programming error...UE already attached");
1867 Simulator::ScheduleWithContext(
m_netDevice->GetNode()->GetId(),
1877 NS_LOG_FUNCTION(
this << sinr);
1879 Values::const_iterator it;
1881 ulcqi.
m_ulCqi.m_type = UlCqiInfo::PUSCH;
1882 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
1888 ulcqi.
m_ulCqi.m_sinr.push_back(
1896 ulcqi.
m_sfnSf = m_currentSlot;
1898 SpectrumValue newSinr = sinr;
1899 m_ulSinrTrace(0, newSinr, newSinr);
1906 NS_LOG_FUNCTION(
this);
1910 Ptr<NrDlCqiMessage> dlcqi = DynamicCast<NrDlCqiMessage>(msg);
1914 NS_LOG_INFO(
"Received DL_CQI for RNTI: " << dlcqiLE.
m_rnti <<
" in slot " << m_currentSlot);
1920 NS_LOG_INFO(
"received RACH_PREAMBLE");
1922 Ptr<NrRachPreambleMessage> rachPreamble = DynamicCast<NrRachPreambleMessage>(msg);
1924 NS_LOG_INFO(
"Received RACH Preamble in slot " << m_currentSlot);
1929 Ptr<NrDlHarqFeedbackMessage> dlharqMsg = DynamicCast<NrDlHarqFeedbackMessage>(msg);
1930 DlHarqInfo dlharq = dlharqMsg->GetDlHarqFeedback();
1931 if (m_ueAttachedRnti.find(dlharq.
m_rnti) != m_ueAttachedRnti.end())
1935 NS_LOG_INFO(
"Received DL_HARQ for RNTI: " << dlharq.
m_rnti <<
" in slot "
1952NrGnbPhy::DoSetBandwidth(uint16_t ulBandwidth, uint16_t dlBandwidth)
1954 NS_LOG_FUNCTION(
this << +ulBandwidth << +dlBandwidth);
1955 NS_ASSERT(ulBandwidth == dlBandwidth);
1960NrGnbPhy::DoSetEarfcn(uint16_t ulEarfcn, uint16_t dlEarfcn)
1962 NS_LOG_FUNCTION(
this << ulEarfcn << dlEarfcn);
1966NrGnbPhy::DoAddUe([[maybe_unused]] uint16_t rnti)
1968 NS_LOG_FUNCTION(
this << rnti);
1969 std::set<uint16_t>::iterator it;
1970 it = m_ueAttachedRnti.find(rnti);
1971 if (it == m_ueAttachedRnti.end())
1973 m_ueAttachedRnti.insert(rnti);
1978NrGnbPhy::DoRemoveUe(uint16_t rnti)
1980 NS_LOG_FUNCTION(
this << rnti);
1982 std::set<uint16_t>::iterator it = m_ueAttachedRnti.find(rnti);
1983 if (it != m_ueAttachedRnti.end())
1985 m_ueAttachedRnti.erase(it);
1989 NS_FATAL_ERROR(
"Impossible to remove UE, not attached!");
1994NrGnbPhy::DoSetPa(uint16_t rnti,
double pa)
1996 NS_LOG_FUNCTION(
this << rnti << pa);
2000NrGnbPhy::DoSetTransmissionMode(uint16_t rnti, uint8_t txMode)
2002 NS_LOG_FUNCTION(
this << rnti << +txMode);
2007NrGnbPhy::DoSetSrsConfigurationIndex(uint16_t rnti, uint16_t srcCi)
2009 NS_LOG_FUNCTION(
this << rnti << srcCi);
2013NrGnbPhy::DoSetMasterInformationBlock([[maybe_unused]] NrRrcSap::MasterInformationBlock mib)
2015 NS_LOG_FUNCTION(
this);
2019NrGnbPhy::DoSetSystemInformationBlockType1(NrRrcSap::SystemInformationBlockType1 sib1)
2021 NS_LOG_FUNCTION(
this);
2028 NS_LOG_FUNCTION(
this);
2041 NS_LOG_FUNCTION(
this);
2043 if (m_ueAttachedRnti.find(mes.
m_rnti) != m_ueAttachedRnti.end())
2045 NS_LOG_INFO(
"Received UL HARQ feedback " << mes.
IsReceivedOk()
2046 <<
" and forwarding to the scheduler");
2054 NS_LOG_FUNCTION(
this);
2056 static std::unordered_map<std::string, LteNrTddSlotType> lookupTable = {
2063 std::vector<LteNrTddSlotType> vector;
2064 std::stringstream ss(pattern);
2066 std::vector<std::string> extracted;
2068 while (std::getline(ss, token,
'|'))
2070 extracted.push_back(token);
2073 for (
const auto& v : extracted)
2075 if (lookupTable.find(v) == lookupTable.end())
2077 NS_FATAL_ERROR(
"Pattern type " << v <<
" not valid. Valid values are: DL UL F S");
2079 vector.push_back(lookupTable[v]);
2082 SetTddPattern(vector);
2094 NS_LOG_FUNCTION(
this);
2101 m_csiRsModel = csiRsModel;
2107 return m_csiRsModel;
2113 m_csiRsPeriodicity = csiRsPeriodicity;
2119 return m_csiRsPeriodicity;
2123NrGnbPhy::ChannelAccessGranted(
const Time& time)
2125 NS_LOG_FUNCTION(
this);
2129 NS_LOG_INFO(
"Channel granted for less than the slot time. Ignoring the grant.");
2130 m_channelStatus = NONE;
2134 m_channelStatus = GRANTED;
2136 Time toNextSlot = m_lastSlotStart +
GetSlotPeriod() - Simulator::Now();
2137 Time grant = time - toNextSlot;
2138 int64_t slotGranted = grant.GetNanoSeconds() /
GetSlotPeriod().GetNanoSeconds();
2140 NS_LOG_INFO(
"Channel access granted for " << time <<
", which corresponds to " << slotGranted
2142 <<
". We lost " << toNextSlot);
2143 NS_ASSERT(!m_channelLostTimer.IsPending());
2145 if (slotGranted < 1)
2149 m_channelLostTimer = Simulator::Schedule(
GetSlotPeriod() * slotGranted - NanoSeconds(1),
2150 &NrGnbPhy::ChannelAccessLost,
2155NrGnbPhy::ChannelAccessLost()
2157 NS_LOG_FUNCTION(
this);
2158 NS_LOG_INFO(
"Channel access lost");
2159 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.
@ 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