5#define NS_LOG_APPEND_CONTEXT \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11#include "nr-mac-scheduler-ns3.h"
13#include "nr-fh-control.h"
14#include "nr-mac-scheduler-harq-rr.h"
15#include "nr-mac-scheduler-lc-rr.h"
16#include "nr-mac-scheduler-srs-default.h"
17#include "nr-mac-short-bsr-ce.h"
19#include "ns3/boolean.h"
21#include "ns3/integer.h"
23#include "ns3/pointer.h"
24#include "ns3/uinteger.h"
28#include <unordered_set>
33NS_LOG_COMPONENT_DEFINE(
"NrMacSchedulerNs3");
34NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerNs3);
39 NS_LOG_FUNCTION_NOARGS();
42 m_schedHarq = std::make_unique<NrMacSchedulerHarqRr>();
46 m_schedHarq->InstallGetFhControlMethodFn(
48 m_schedHarq->InstallDoesFhAllocationFitFn(
53 m_cqiManagement.InstallGetNrAmcDlFn([
this]() {
return m_dlAmc; });
54 m_cqiManagement.InstallGetNrAmcUlFn([
this]() {
return m_ulAmc; });
55 m_cqiManagement.InstallGetStartMcsDlFn([
this]() {
return m_startMcsDl; });
56 m_cqiManagement.InstallGetStartMcsUlFn([
this]() {
return m_startMcsUl; });
59 m_schedulerSrs = CreateObject<NrMacSchedulerSrsDefault>();
88 NS_LOG_FUNCTION(
this);
95 NS_LOG_FUNCTION(
this);
102 NS_LOG_FUNCTION(
this << stream);
103 return m_schedulerSrs->AssignStreams(stream);
110 TypeId(
"ns3::NrMacSchedulerNs3")
112 .AddAttribute(
"CqiTimerThreshold",
113 "The time while a CQI is valid",
114 TimeValue(Seconds(1)),
118 .AddAttribute(
"FixedMcsDl",
119 "Fix MCS to value set in StartingMcsDl",
123 MakeBooleanChecker())
124 .AddAttribute(
"FixedMcsUl",
125 "Fix MCS to value set in StartingMcsUl",
129 MakeBooleanChecker())
130 .AddAttribute(
"StartingMcsDl",
131 "Starting MCS for DL",
135 MakeUintegerChecker<uint8_t>())
136 .AddAttribute(
"StartingMcsUl",
137 "Starting MCS for UL",
141 MakeUintegerChecker<uint8_t>())
142 .AddAttribute(
"DlCtrlSymbols",
143 "Number of symbols allocated for DL CTRL",
147 MakeUintegerChecker<uint8_t>())
148 .AddAttribute(
"UlCtrlSymbols",
149 "Number of symbols allocated for UL CTRL",
153 MakeUintegerChecker<uint8_t>())
154 .AddAttribute(
"SrsSymbols",
155 "Number of symbols allocated for UL SRS",
159 MakeUintegerChecker<uint8_t>())
160 .AddAttribute(
"EnableSrsInUlSlots",
161 "Denotes whether the SRSs will be transmitted only in F slots"
162 "or both in F and UL slots. If False, SRS is transmitted only"
163 "in F slots, if True in both (F/UL)",
167 MakeBooleanChecker())
168 .AddAttribute(
"EnableSrsInFSlots",
169 "Denotes whether the SRSs will be transmitted in F slots"
170 "If true, it can be transmitted in F slots, otherwise "
175 MakeBooleanChecker())
176 .AddAttribute(
"DlAmc",
177 "The DL AMC of this scheduler",
180 MakePointerChecker<NrAmc>())
181 .AddAttribute(
"UlAmc",
182 "The UL AMC of this scheduler",
185 MakePointerChecker<NrAmc>())
186 .AddAttribute(
"MaxDlMcs",
187 "Maximum MCS index for DL",
191 MakeIntegerChecker<int8_t>(-1, 30))
192 .AddAttribute(
"EnableHarqReTx",
193 "If true, it would set the max HARQ ReTx to 3; otherwise it set it to 0",
197 MakeBooleanChecker())
199 "SchedLcAlgorithmType",
200 "Type of the scheduling algorithm that assigns bytes to the different LCs.",
205 .AddAttribute(
"RachUlGrantMcs",
206 "The MCS of the RACH UL grant, must be [0..15] (default 0)",
209 MakeUintegerChecker<uint8_t>())
212 "Choose which CSI information is used to estimate DL MCS(default AVG_MCS)",
214 MakeEnumAccessor<NrMacSchedulerUeInfo::McsCsiSource>(
216 MakeEnumChecker<NrMacSchedulerUeInfo::McsCsiSource>(
225 .AddTraceSource(
"CsiFeedbackReceived",
226 "Received CSI feedback post-processed by the scheduler CQI management",
227 MakeTraceSourceAccessor(&NrMacSchedulerNs3::m_csiFeedbackReceived),
228 "ns3::NrMacSchedulerNs3::CsiFeedbackReceived::TracedCallback");
243 NS_LOG_FUNCTION(
this);
246 m_startMcsDl =
static_cast<uint8_t
>(mcs);
247 m_startMcsUl =
static_cast<uint8_t
>(mcs);
254 NS_LOG_FUNCTION(
this);
262 NS_LOG_FUNCTION(
this);
263 m_cqiTimersThreshold = v;
269 NS_LOG_FUNCTION(
this);
270 return m_cqiTimersThreshold;
276 NS_LOG_FUNCTION(
this);
283 NS_LOG_FUNCTION(
this);
290 NS_LOG_FUNCTION(
this);
297 NS_LOG_FUNCTION(
this);
304 NS_LOG_FUNCTION(
this);
311 NS_LOG_FUNCTION(
this);
318 NS_LOG_FUNCTION(
this);
325 NS_LOG_FUNCTION(
this);
332 m_rachUlGrantMcs = v;
338 NS_LOG_FUNCTION(
this);
339 ObjectFactory factory;
340 m_schedLcType = type;
342 factory.SetTypeId(m_schedLcType);
343 m_schedLc = DynamicCast<NrMacSchedulerLcAlgorithm>(factory.Create());
344 NS_ASSERT(m_schedLc !=
nullptr);
350 NS_LOG_FUNCTION(
this);
357 NS_LOG_FUNCTION(
this);
370 return m_dlCtrlSymbols;
382 NS_LOG_FUNCTION(
this);
383 m_dlNotchedRbgsMask = dlNotchedRbgsMask;
384 std::stringstream ss;
387 for (
const auto& x : m_dlNotchedRbgsMask)
391 NS_LOG_INFO(
"Set DL notched mask: " << ss.str());
397 return m_dlNotchedRbgsMask;
403 NS_LOG_FUNCTION(
this);
404 m_ulNotchedRbgsMask = ulNotchedRbgsMask;
405 std::stringstream ss;
408 for (
const auto& x : m_ulNotchedRbgsMask)
412 NS_LOG_INFO(
"Set UL notched mask: " << ss.str());
418 return m_ulNotchedRbgsMask;
424 m_srsCtrlSymbols = v;
430 return m_srsCtrlSymbols;
436 m_enableSrsInUlSlots = v;
442 return m_enableSrsInUlSlots;
448 m_enableSrsInFSlots = v;
454 return m_enableSrsInFSlots;
460 m_enableHarqReTx = enableFlag;
466 return m_enableHarqReTx;
485 const std::unordered_map<uint16_t, UePtr>& ueMap,
486 std::vector<DlHarqInfo>* dlHarqToRetransmit,
487 const std::vector<DlHarqInfo>& dlHarqFeedback,
490 NS_LOG_FUNCTION(
this);
491 return m_schedHarq->ScheduleDlHarq(startingPoint,
503 const std::unordered_map<uint16_t, UePtr>& ueMap,
504 std::vector<UlHarqInfo>* ulHarqToRetransmit,
505 const std::vector<UlHarqInfo>& ulHarqFeedback,
508 NS_LOG_FUNCTION(
this);
509 return m_schedHarq->ScheduleUlHarq(startingPoint,
520 NS_LOG_FUNCTION(
this);
521 m_schedHarq->SortDlHarq(activeDlHarq);
527 NS_LOG_FUNCTION(
this);
528 m_schedHarq->SortDlHarq(activeUlHarq);
534 return m_ulCtrlSymbols;
547 NS_LOG_FUNCTION(
this);
553 cnf.m_result = NrMacCschedSapUser::Result_e::SUCCESS;
570 NS_LOG_FUNCTION(
this <<
" RNTI " << params.m_rnti <<
" txMode "
571 <<
static_cast<uint32_t
>(params.m_transmissionMode));
573 auto itUe = m_ueMap.find(params.m_rnti);
575 if (itUe == m_ueMap.end())
579 UeInfoOf(*itUe)->m_dlHarq.SetMaxSize(
581 UeInfoOf(*itUe)->m_ulHarq.SetMaxSize(
583 UeInfoOf(*itUe)->m_dlMcs = m_startMcsDl;
584 UeInfoOf(*itUe)->m_startMcsDlUe = m_startMcsDl;
585 UeInfoOf(*itUe)->m_ulMcs = m_startMcsUl;
586 UeInfoOf(*itUe)->m_dlAmc =
m_dlAmc;
587 UeInfoOf(*itUe)->m_ulAmc =
m_ulAmc;
594 bool ret = m_schedulerSrs->IncreasePeriodicity(
600 UeInfoOf(*itUe)->m_srsPeriodicity =
602 UeInfoOf(*itUe)->m_srsOffset = srs.
m_offset;
605 NS_LOG_INFO(
"Creating user, beam " << params.
m_beamId <<
" and ue " << params.m_rnti
611 NS_LOG_LOGIC(
"Updating Beam for UE " << params.m_rnti <<
" beam " << params.
m_beamId);
612 UeInfoOf(*itUe)->m_beamId = params.
m_beamId;
627 NS_LOG_FUNCTION(
this <<
" Release RNTI " << params.m_rnti);
629 auto itUe = m_ueMap.find(params.m_rnti);
630 NS_ABORT_IF(itUe == m_ueMap.end());
632 m_schedulerSrs->RemoveUe(itUe->second->m_srsOffset);
638 NS_LOG_INFO(
"Release RNTI " << params.m_rnti);
660 NS_LOG_FUNCTION(
this);
661 return std::make_unique<NrMacSchedulerLC>(config);
677 NS_LOG_FUNCTION(
this);
698 NS_LOG_FUNCTION(
this <<
static_cast<uint32_t
>(params.m_rnti));
699 auto itUe = m_ueMap.find(params.m_rnti);
701 NS_ABORT_IF(itUe == m_ueMap.end());
703 for (
const auto& lcConfig : params.m_logicalChannelConfigList)
705 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_DL ||
706 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
708 auto itDl = UeInfoOf(*itUe)->m_dlLCG.find(lcConfig.m_logicalChannelGroup);
709 auto itDlEnd = UeInfoOf(*itUe)->m_dlLCG.end();
712 NS_LOG_DEBUG(
"Created DL LCG for UE "
713 << UeInfoOf(*itUe)->m_rnti
714 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
715 std::unique_ptr<NrMacSchedulerLCG> lcg =
CreateLCG(lcConfig);
716 itDl = UeInfoOf(*itUe)
717 ->m_dlLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
721 itDl->second->Insert(
CreateLC(lcConfig));
722 NS_LOG_DEBUG(
"Created DL LC for UE "
723 << UeInfoOf(*itUe)->m_rnti
724 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelIdentity)
725 <<
" in LCG " <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
727 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_UL ||
728 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
730 auto itUl = UeInfoOf(*itUe)->m_ulLCG.find(lcConfig.m_logicalChannelGroup);
731 auto itUlEnd = UeInfoOf(*itUe)->m_ulLCG.end();
734 NS_LOG_DEBUG(
"Created UL LCG for UE "
735 << UeInfoOf(*itUe)->m_rnti
736 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
737 std::unique_ptr<NrMacSchedulerLCG> lcg =
CreateLCG(lcConfig);
738 itUl = UeInfoOf(*itUe)
739 ->m_ulLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
745 if (itUl->second->NumOfLC() == 0)
747 itUl->second->Insert(
CreateLC(lcConfig));
748 NS_LOG_DEBUG(
"Created UL LC for UE "
749 << UeInfoOf(*itUe)->m_rnti
750 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelIdentity)
752 <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
766 NS_LOG_FUNCTION(
this);
768 for (
const auto& lcId : params.m_logicalChannelIdentity)
770 auto itUe = m_ueMap.find(params.m_rnti);
771 NS_ABORT_IF(itUe == m_ueMap.end());
772 itUe->second->ReleaseLC(lcId);
788 NS_LOG_FUNCTION(
this << params.
m_rnti
792 auto itUe = m_ueMap.find(params.
m_rnti);
793 NS_ABORT_IF(itUe == m_ueMap.end());
795 for (
const auto& lcg : UeInfoOf(*itUe)->m_dlLCG)
799 NS_LOG_INFO(
"Updating DL LC Info: " << params
800 <<
" in LCG: " <<
static_cast<uint32_t
>(lcg.first));
801 lcg.second->UpdateInfo(params);
807 lcg.second->GetTotalSize());
813 NS_FATAL_ERROR(
"The LC does not exist. Can't update");
826NrMacSchedulerNs3::BSRReceivedFromUe(
const MacCeElement& bsr)
828 NS_LOG_FUNCTION(
this);
829 NS_ASSERT(bsr.m_macCeType == MacCeElement::BSR);
831 auto itUe = m_ueMap.find(bsr.m_rnti);
832 NS_ABORT_IF(itUe == m_ueMap.end());
836 for (uint8_t lcg = 0; lcg < 4; ++lcg)
838 uint8_t bsrId = bsr.m_macCeValue.m_bufferStatus.at(lcg);
841 auto itLcg = UeInfoOf(*itUe)->m_ulLCG.find(lcg);
842 if (itLcg == UeInfoOf(*itUe)->m_ulLCG.end())
847 NS_LOG_DEBUG(
"BSR does not match an established lcg");
851 if (itLcg->second->GetTotalSize() > 0 || bufSize > 0)
853 NS_LOG_INFO(
"Updating UL LCG " <<
static_cast<uint32_t
>(lcg) <<
" for UE " << bsr.m_rnti
854 <<
" size " << bufSize);
857 itLcg->second->UpdateInfo(bufSize);
872 NS_LOG_FUNCTION(
this);
876 if (element.m_macCeType == MacCeElement::BSR)
878 BSRReceivedFromUe(element);
882 NS_LOG_INFO(
"Ignoring received CTRL message because it's not a BSR");
901 NS_LOG_FUNCTION(
this);
910 uint32_t expirationTime =
911 static_cast<uint32_t
>(m_cqiTimersThreshold.GetNanoSeconds() /
916 NS_ASSERT(m_ueMap.find(cqi.m_rnti) != m_ueMap.end());
917 const std::shared_ptr<NrMacSchedulerUeInfo>& ue = m_ueMap.find(cqi.m_rnti)->second;
940 NS_LOG_FUNCTION(
this);
949 uint32_t expirationTime =
950 static_cast<uint32_t
>(m_cqiTimersThreshold.GetNanoSeconds() /
955 case UlCqiInfo::PUSCH: {
956 [[maybe_unused]]
bool found =
false;
960 NS_LOG_INFO(
"CQI for allocation: " << params.
m_sfnSf <<
" started at sym: " << +symStart
961 <<
" modified allocation " << ulSfnSf <<
" sym Start "
962 <<
static_cast<uint32_t
>(symStart));
964 auto itAlloc = m_ulAllocationMap.find(ulSfnSf.
GetEncoding());
965 NS_ASSERT_MSG(itAlloc != m_ulAllocationMap.end(),
"Can't find allocation for " << ulSfnSf);
966 std::vector<AllocElem>& ulAllocations = itAlloc->second.m_ulAllocations;
968 for (
auto it = ulAllocations.cbegin(); it != ulAllocations.cend(); )
970 const AllocElem& allocation = *(it);
971 if (allocation.m_symStart == symStart)
973 auto itUe = m_ueMap.find(allocation.m_rnti);
974 NS_ASSERT(itUe != m_ueMap.end());
975 NS_ASSERT(allocation.m_numSym > 0);
976 NS_ASSERT(allocation.m_tbs > 0);
982 allocation.m_rbgMask,
986 it = ulAllocations.erase(it);
995 if (ulAllocations.empty())
998 NS_LOG_INFO(
"Removing allocation for " << ulSfnSf);
999 m_ulAllocationMap.erase(itAlloc);
1004 NS_FATAL_ERROR(
"Unknown type of UL-CQI");
1021template <
typename T>
1023NrMacSchedulerNs3::MergeHARQ(std::vector<T>* existingFeedbacks,
1024 const std::vector<T>& inFeedbacks,
1025 const std::string& mode)
const
1027 NS_LOG_FUNCTION(
this);
1028 NS_LOG_INFO(
"To retransmit : " << existingFeedbacks->size() <<
" " << mode <<
" HARQ, received "
1029 << inFeedbacks.size() <<
" " << mode <<
" HARQ Feedback");
1030 uint64_t existingSize = existingFeedbacks->size();
1031 uint64_t inSize = inFeedbacks.size();
1032 existingFeedbacks->insert(existingFeedbacks->end(), inFeedbacks.begin(), inFeedbacks.end());
1033 NS_ASSERT(existingFeedbacks->size() == existingSize + inSize);
1035 auto ret = std::vector<T>(std::make_move_iterator(existingFeedbacks->begin()),
1036 std::make_move_iterator(existingFeedbacks->end()));
1037 existingFeedbacks->clear();
1059template <
typename T>
1061NrMacSchedulerNs3::ProcessHARQFeedbacks(
1062 std::vector<T>* harqInfo,
1063 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVectorFn,
1064 const std::string& direction)
const
1066 NS_LOG_FUNCTION(
this);
1067 uint32_t nackReceived = 0;
1070 for (
auto harqFeedbackIt = harqInfo->begin(); harqFeedbackIt != harqInfo->end();
1073 uint8_t harqId = harqFeedbackIt->m_harqProcessId;
1074 uint16_t rnti = harqFeedbackIt->m_rnti;
1075 NrMacHarqVector& ueHarqVector = GetHarqVectorFn(m_ueMap.find(rnti)->second);
1076 HarqProcess& ueProcess = ueHarqVector.Get(harqId);
1078 NS_LOG_INFO(
"Evaluating feedback: " << *harqFeedbackIt);
1079 if (!ueProcess.m_active)
1081 NS_LOG_INFO(
"UE " << rnti <<
" HARQ vector: " << ueHarqVector);
1082 NS_FATAL_ERROR(
"Received feedback for a process which is not active");
1084 NS_ABORT_IF(ueProcess.m_dciElement ==
nullptr);
1087 NS_ASSERT(ueProcess.m_dciElement->m_rv < 4);
1088 uint8_t maxHarqReTx = m_enableHarqReTx ? 3 : 0;
1090 if (harqFeedbackIt->IsReceivedOk() || ueProcess.m_dciElement->m_rv == maxHarqReTx)
1092 ueHarqVector.Erase(harqId);
1093 harqFeedbackIt = harqInfo->erase(harqFeedbackIt);
1094 NS_LOG_INFO(
"Erased processID " <<
static_cast<uint32_t
>(harqId) <<
" of UE " << rnti
1095 <<
" direction " << direction);
1097 else if (!harqFeedbackIt->IsReceivedOk())
1102 NS_LOG_INFO(
"NACK received for UE " <<
static_cast<uint32_t
>(rnti) <<
" process "
1103 <<
static_cast<uint32_t
>(harqId) <<
" direction "
1108 NS_ASSERT(harqInfo->size() == nackReceived);
1123NrMacSchedulerNs3::ResetExpiredHARQ(uint16_t rnti, NrMacHarqVector* harq)
1125 NS_LOG_FUNCTION(
this << harq);
1127 for (
auto harqIt = harq->Begin(); harqIt != harq->End(); ++harqIt)
1129 HarqProcess& process = harqIt->second;
1130 uint8_t processId = harqIt->first;
1140 NS_LOG_INFO(
"Updated process for UE " << rnti <<
" number "
1141 <<
static_cast<uint32_t
>(processId)
1142 <<
", resulting process: " << process);
1146 harq->Erase(processId);
1147 NS_LOG_INFO(
"Erased process for UE " << rnti <<
" number "
1148 <<
static_cast<uint32_t
>(processId)
1149 <<
" for time limits");
1163NrMacSchedulerNs3::PrependCtrlSym(uint8_t symStart,
1164 uint8_t numSymToAllocate,
1166 std::deque<VarTtiAllocInfo>* allocations)
const
1174 NS_ASSERT(allocations->empty());
1175 NS_ASSERT(symStart == 0);
1178 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1180 allocations->emplace_front(std::make_shared<DciInfoElementTdma>(sym,
1185 NS_LOG_INFO(
"Allocating CTRL symbol, type"
1186 << mode <<
" in TDMA. numSym=1, symStart=" <<
static_cast<uint32_t
>(sym)
1187 <<
" Remaining CTRL sym to allocate: " << sym - symStart);
1189 return symStart + numSymToAllocate;
1201NrMacSchedulerNs3::AppendCtrlSym(uint8_t symStart,
1202 uint8_t numSymToAllocate,
1204 std::deque<VarTtiAllocInfo>* allocations)
const
1211 NS_ASSERT(allocations->empty());
1212 NS_ASSERT(symStart == 0);
1215 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1217 allocations->emplace_back(std::make_shared<DciInfoElementTdma>(sym,
1222 NS_LOG_INFO(
"Allocating CTRL symbol, type"
1223 << mode <<
" in TDMA. numSym=1, symStart=" <<
static_cast<uint32_t
>(sym)
1224 <<
" Remaining CTRL sym to allocate: " << sym - symStart);
1226 return symStart + numSymToAllocate;
1240NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeDlHarq,
1241 const std::vector<DlHarqInfo>& dlHarqFeedback)
const
1243 NS_LOG_FUNCTION(
this);
1244 NS_ASSERT(activeDlHarq->empty());
1246 for (
const auto& feedback : dlHarqFeedback)
1248 uint16_t rnti = feedback.m_rnti;
1249 auto& schedInfo = m_ueMap.find(rnti)->second;
1250 auto beamIterator = activeDlHarq->find(schedInfo->m_beamId);
1252 if (beamIterator == activeDlHarq->end())
1254 std::vector<NrMacHarqVector::iterator> harqVector;
1255 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1257 harqVector.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1258 activeDlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1262 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1263 beamIterator->second.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1265 NS_LOG_INFO(
"Received feedback for UE " << rnti <<
" ID "
1266 <<
static_cast<uint32_t
>(feedback.m_harqProcessId)
1267 <<
" marked as active");
1268 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_status ==
1290NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeUlHarq,
1291 const std::vector<UlHarqInfo>& ulHarqFeedback)
const
1293 NS_LOG_FUNCTION(
this);
1295 for (
const auto& feedback : ulHarqFeedback)
1297 uint16_t rnti = feedback.m_rnti;
1298 auto& schedInfo = m_ueMap.find(rnti)->second;
1299 auto beamIterator = activeUlHarq->find(schedInfo->m_beamId);
1301 if (beamIterator == activeUlHarq->end())
1303 std::vector<NrMacHarqVector::iterator> harqVector;
1304 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1305 harqVector.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1306 activeUlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1310 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1311 beamIterator->second.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1330NrMacSchedulerNs3::ComputeActiveUe(ActiveUeMap* activeUe,
1331 const NrMacSchedulerUeInfo::GetLCGFn& GetLCGFn,
1332 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVector,
1333 const std::string& mode)
const
1335 NS_LOG_FUNCTION(
this);
1336 for (
const auto& ueInfo : m_ueMap)
1338 uint32_t totBuffer = 0;
1339 const auto& ue = ueInfo.second;
1342 for (
const auto& lcgInfo : GetLCGFn(ue))
1344 const auto& lcg = lcgInfo.second;
1345 if (lcg->GetTotalSize() > 0)
1347 NS_LOG_INFO(
"UE " << ue->m_rnti <<
" " << mode <<
" LCG "
1348 <<
static_cast<uint32_t
>(lcgInfo.first) <<
" bytes "
1349 << lcg->GetTotalSize());
1351 totBuffer += lcg->GetTotalSize();
1354 auto harqV = GetHarqVector(ue);
1356 if (totBuffer > 0 && harqV.CanInsert())
1358 auto it = activeUe->find(ue->m_beamId);
1359 if (it == activeUe->end())
1361 std::vector<std::pair<std::shared_ptr<NrMacSchedulerUeInfo>, uint32_t>> tmp;
1362 tmp.emplace_back(ue, totBuffer);
1363 activeUe->insert(std::make_pair(ue->m_beamId, tmp));
1367 it->second.emplace_back(ue, totBuffer);
1405NrMacSchedulerNs3::DoScheduleDlData(PointInFTPlane* spoint,
1407 const ActiveUeMap& activeDl,
1408 SlotAllocInfo* slotAlloc)
const
1410 NS_LOG_FUNCTION(
this << symAvail);
1411 NS_ASSERT(spoint->m_rbg == 0);
1414 uint8_t usedSym = 0;
1416 for (
const auto& beam : activeDl)
1418 uint32_t availableRBG =
1420 bool assigned =
false;
1421 std::unordered_set<uint8_t> symbStartDci;
1424 uint32_t allocSym = 0;
1426 NS_LOG_DEBUG(activeDl.size()
1427 <<
" active DL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1428 <<
" SYM, starts from RB " << spoint->m_rbg <<
" and symbol "
1429 <<
static_cast<uint32_t
>(spoint->m_sym) <<
" for a total of " << availableRBG
1432 if (symPerBeam.at(GetBeam(beam)) == 0)
1434 NS_LOG_INFO(
"No available symbols for this beam, continue");
1438 for (
const auto& ue : beam.second)
1440 if (ue.first->m_dlRBG.empty())
1442 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" does not have RBG assigned");
1446 std::shared_ptr<DciInfoElementTdma> dci =
1447 CreateDlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1461 NS_LOG_DEBUG(
"No DCI has been created, ignoring");
1462 ue.first->ResetDlMetric();
1468 if (symbStartDci.insert(dci->m_symStart).second)
1470 allocSym += dci->m_numSym;
1473 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" has " << ue.first->m_dlRBG.size()
1474 <<
" RBG assigned");
1477 <<
static_cast<uint32_t
>(dci->m_symStart)
1478 <<
" symEnd: " <<
static_cast<uint32_t
>(dci->m_numSym) <<
" symbols: "
1484 if (!ue.first->m_dlHarq.CanInsert())
1486 NS_LOG_INFO(
"Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1487 << ue.first->m_dlHarq);
1488 NS_FATAL_ERROR(
"UE " << ue.first->m_rnti <<
" does not have DL HARQ space");
1491 ue.first->m_dlHarq.Insert(&
id, harqProcess);
1492 ue.first->m_dlHarq.Get(
id).m_dciElement->m_harqProcess = id;
1496 auto distributedBytes =
1497 m_schedLc->AssignBytesToDlLC(ue.first->m_dlLCG,
1501 std::vector<std::vector<NrMacSchedulerLcAlgorithm::Assignation>> bytesPerLc(
1502 distributedBytes.size());
1504 for (std::size_t numLc = 0; numLc < distributedBytes.size(); numLc++)
1506 bytesPerLc.at(numLc).emplace_back(distributedBytes.at(numLc).m_lcg,
1507 distributedBytes.at(numLc).m_lcId,
1508 distributedBytes.at(numLc).m_bytes);
1511 VarTtiAllocInfo slotInfo(dci);
1513 NS_LOG_INFO(
"Assigned process ID " <<
static_cast<uint32_t
>(dci->m_harqProcess)
1514 <<
" to UE " << ue.first->m_rnti);
1515 NS_LOG_DEBUG(
" UE" << dci->m_rnti <<
" gets DL symbols "
1516 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1517 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym) <<
" tbs "
1518 << dci->m_tbSize <<
" mcs " <<
static_cast<uint32_t
>(dci->m_mcs)
1519 <<
" harqId " <<
static_cast<uint32_t
>(
id) <<
" rv "
1520 <<
static_cast<uint32_t
>(dci->m_rv));
1522 for (
const auto& byteDistribution : distributedBytes)
1524 NS_ASSERT(byteDistribution.m_bytes >= 3);
1525 uint8_t lcId = byteDistribution.m_lcId;
1526 uint8_t lcgId = byteDistribution.m_lcg;
1527 uint32_t bytes = byteDistribution.m_bytes - 3;
1529 RlcPduInfo newRlcPdu(lcId, bytes);
1530 HarqProcess& process = ue.first->m_dlHarq.Get(dci->m_harqProcess);
1532 slotInfo.m_rlcPduInfo.push_back(newRlcPdu);
1533 process.m_rlcPduInfo.push_back(newRlcPdu);
1535 ue.first->m_dlLCG.at(lcgId)->AssignedData(lcId, bytes,
"DL");
1537 NS_LOG_DEBUG(
"DL LCG " <<
static_cast<uint32_t
>(lcgId) <<
" LCID "
1538 <<
static_cast<uint32_t
>(lcId) <<
" got bytes "
1539 << newRlcPdu.m_size);
1542 NS_ABORT_IF(slotInfo.m_rlcPduInfo.empty());
1544 slotAlloc->m_varTtiAllocInfo.emplace_back(slotInfo);
1549 usedSym += allocSym;
1550 slotAlloc->m_numSymAlloc += allocSym;
1554 for (
auto& beam : activeDl)
1556 for (
auto& ue : beam.second)
1558 ue.first->ResetDlSchedInfo();
1562 NS_ASSERT(spoint->m_rbg == 0);
1603NrMacSchedulerNs3::DoScheduleUlData(PointInFTPlane* spoint,
1605 const ActiveUeMap& activeUl,
1606 SlotAllocInfo* slotAlloc)
const
1608 NS_LOG_FUNCTION(
this);
1609 NS_ASSERT(symAvail > 0 && !activeUl.empty());
1610 NS_ASSERT(spoint->m_rbg == 0);
1613 uint8_t usedSym = 0;
1616 for (
const auto& beam : activeUl)
1618 uint32_t availableRBG =
1620 bool assigned =
false;
1621 std::unordered_set<uint8_t> symbStartDci;
1624 uint32_t allocSym = 0;
1626 NS_LOG_DEBUG(activeUl.size()
1627 <<
" active UL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1628 <<
" SYM, starts from RBG " << spoint->m_rbg <<
" and symbol "
1629 <<
static_cast<uint32_t
>(spoint->m_sym) <<
" (going backward) for a total of "
1633 if (symPerBeam.at(GetBeam(beam)) == 0)
1635 NS_LOG_INFO(
"No available symbols for this beam, continue");
1639 for (
const auto& ue : beam.second)
1641 if (ue.first->m_ulRBG.empty())
1643 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" does not have RBG assigned");
1647 std::shared_ptr<DciInfoElementTdma> dci =
1648 CreateUlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1663 NS_LOG_DEBUG(
"No DCI has been created, ignoring");
1664 ue.first->ResetUlMetric();
1670 if (symbStartDci.insert(dci->m_symStart).second)
1672 allocSym += dci->m_numSym;
1675 if (!ue.first->m_ulHarq.CanInsert())
1677 NS_LOG_INFO(
"Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1678 << ue.first->m_ulHarq);
1679 NS_FATAL_ERROR(
"UE " << ue.first->m_rnti <<
" does not have UL HARQ space");
1684 ue.first->m_ulHarq.Insert(&
id, harqProcess);
1686 ue.first->m_ulHarq.Get(
id).m_dciElement->m_harqProcess = id;
1688 VarTtiAllocInfo slotInfo(dci);
1690 NS_LOG_INFO(
"Assigned process ID " <<
static_cast<uint32_t
>(dci->m_harqProcess)
1691 <<
" to UE " << ue.first->m_rnti);
1692 NS_LOG_DEBUG(
" UE" << dci->m_rnti <<
" gets UL symbols "
1693 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1694 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym) <<
" tbs "
1695 << dci->m_tbSize <<
" mcs " <<
static_cast<uint32_t
>(dci->m_mcs)
1696 <<
" harqId " <<
static_cast<uint32_t
>(
id) <<
" rv "
1697 <<
static_cast<uint32_t
>(dci->m_rv));
1699 auto distributedBytes = m_schedLc->AssignBytesToUlLC(ue.first->m_ulLCG, dci->m_tbSize);
1700 bool assignedToLC =
false;
1701 for (
const auto& byteDistribution : distributedBytes)
1703 assignedToLC =
true;
1704 ue.first->m_ulLCG.at(byteDistribution.m_lcg)
1705 ->AssignedData(byteDistribution.m_lcId, byteDistribution.m_bytes,
"UL");
1706 NS_LOG_DEBUG(
"UL LCG " <<
static_cast<uint32_t
>(byteDistribution.m_lcg)
1707 <<
" assigned bytes " << byteDistribution.m_bytes
1709 <<
static_cast<uint32_t
>(byteDistribution.m_lcId));
1711 NS_ASSERT(assignedToLC);
1712 slotAlloc->m_varTtiAllocInfo.emplace_front(slotInfo);
1717 usedSym += allocSym;
1718 slotAlloc->m_numSymAlloc += allocSym;
1722 for (
auto& beam : activeUl)
1724 for (
auto& ue : beam.second)
1726 ue.first->ResetUlSchedInfo();
1730 NS_ASSERT(spoint->m_rbg == 0);
1747NrMacSchedulerNs3::DoScheduleUlSr(PointInFTPlane* spoint,
const std::list<uint16_t>& rntiList)
const
1749 NS_LOG_FUNCTION(
this);
1750 NS_ASSERT(spoint->m_rbg == 0);
1752 for (
const auto& v : rntiList)
1754 for (
auto& ulLcg : NrMacSchedulerUeInfo::GetUlLCG(m_ueMap.at(v)))
1756 NS_LOG_DEBUG(
"Assigning 12 bytes to UE " << v <<
" because of a SR");
1757 ulLcg.second->UpdateInfo(12);
1801NrMacSchedulerNs3::ScheduleDl(
const NrMacSchedSapProvider::SchedDlTriggerReqParameters& params,
1802 const std::vector<DlHarqInfo>& dlHarqFeedback)
1804 NS_LOG_FUNCTION(
this);
1805 NS_LOG_INFO(
"Scheduling invoked for slot " << params.m_snfSf <<
" of type "
1806 << params.m_slotType);
1808 NrMacSchedSapUser::SchedConfigIndParameters dlSlot(params.m_snfSf);
1809 dlSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1811 auto ulAllocationIt =
1812 m_ulAllocationMap.find(params.m_snfSf.GetEncoding());
1813 if (ulAllocationIt == m_ulAllocationMap.end())
1816 m_ulAllocationMap.insert(std::make_pair(params.m_snfSf.GetEncoding(), SlotElem(0)))
1819 auto& ulAllocations = ulAllocationIt->second;
1825 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1826 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_dlCtrlSymbols;
1831 NS_LOG_INFO(
"S slot, adding UL CTRL");
1835 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1836 ulAllocations.m_totUlSym += m_ulCtrlSymbols;
1837 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1842 ComputeActiveHarq(&activeDlHarq, dlHarqFeedback);
1845 ComputeActiveUe(&activeDlUe,
1850 DoScheduleDl(dlHarqFeedback,
1855 &dlSlot.m_slotAllocInfo);
1862 NS_LOG_INFO(
"Removing UL allocation for slot " << params.m_snfSf <<
" size "
1863 << m_ulAllocationMap.size());
1864 m_ulAllocationMap.erase(ulAllocationIt);
1867 NS_LOG_INFO(
"Total DCI for DL : " << dlSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1868 <<
" including DL CTRL");
1876 Simulator::Schedule(NanoSeconds(1),
1877 &NrMacSchedulerNs3::CallNrFhControlForMapUpdate,
1879 dlSlot.m_slotAllocInfo.m_varTtiAllocInfo,
1924NrMacSchedulerNs3::ScheduleUl(
const NrMacSchedSapProvider::SchedUlTriggerReqParameters& params,
1925 const std::vector<UlHarqInfo>& ulHarqFeedback)
1927 NS_LOG_FUNCTION(
this);
1928 NS_LOG_INFO(
"Scheduling invoked for slot " << params.m_snfSf);
1930 NrMacSchedSapUser::SchedConfigIndParameters ulSlot(params.m_snfSf);
1931 ulSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1938 &ulSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1939 ulSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1942 DoScheduleUl(ulHarqFeedback, params.m_snfSf, &ulSlot.m_slotAllocInfo, params.m_slotType);
1944 NS_LOG_INFO(
"Total DCI for UL : " << ulSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1945 <<
" including UL CTRL");
1988NrMacSchedulerNs3::DoScheduleUl(
const std::vector<UlHarqInfo>& ulHarqFeedback,
1990 SlotAllocInfo* allocInfo,
1993 NS_LOG_FUNCTION(
this);
1995 NS_ASSERT(allocInfo->m_varTtiAllocInfo.size() == 1);
2000 dataSymPerSlot -= m_dlCtrlSymbols;
2004 ComputeActiveHarq(&activeUlHarq, ulHarqFeedback);
2009 PointInFTPlane ulAssignationStartPoint(0, lastSym);
2010 uint8_t ulSymAvail = dataSymPerSlot;
2013 m_ulAllocationMap.emplace(ulSfn.GetEncoding(), SlotElem(0));
2019 NS_ASSERT(m_srsCtrlSymbols <= ulSymAvail);
2020 uint8_t srsSym = DoScheduleSrs(&ulAssignationStartPoint, allocInfo);
2021 ulSymAvail -= srsSym;
2024 NS_LOG_DEBUG(
"Scheduling UL " << ulSfn <<
" UL HARQ to retransmit: " << ulHarqFeedback.size()
2025 <<
" Active Beams UL HARQ: " << activeUlHarq.size()
2026 <<
" starting from (" << +ulAssignationStartPoint.m_rbg <<
", "
2027 << +ulAssignationStartPoint.m_sym <<
")");
2030 uint8_t usedMsg3 = 0;
2031 if (!m_rachList.empty())
2033 usedMsg3 = DoScheduleUlMsg3(&ulAssignationStartPoint, ulSymAvail, allocInfo);
2034 NS_ASSERT_MSG(ulSymAvail >= usedMsg3,
2035 "Available: " << +ulSymAvail <<
" used by UL MSG3: " << +usedMsg3);
2036 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedMsg3)
2037 <<
" symbols for UL MSG3");
2038 ulSymAvail -= usedMsg3;
2039 allocInfo->m_numSymAlloc += usedMsg3;
2042 if (!activeUlHarq.empty())
2047 &m_ulHarqToRetransmit,
2050 NS_ASSERT_MSG(ulSymAvail >= usedHarq,
2051 "Available: " << +ulSymAvail <<
" used by HARQ: " << +usedHarq);
2052 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedHarq)
2053 <<
" symbols for UL HARQ retx");
2054 ulSymAvail -= usedHarq;
2057 NS_ASSERT(ulAssignationStartPoint.m_rbg == 0);
2059 if (ulSymAvail > 0 && !m_srList.empty())
2061 DoScheduleUlSr(&ulAssignationStartPoint, m_srList);
2066 ComputeActiveUe(&activeUlUe,
2071 GetSecond GetUeInfoList;
2072 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2074 for (
auto it = activeUlUe.begin(); it != activeUlUe.end(); )
2076 auto& ueInfos = GetUeInfoList(*it);
2077 for (
auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); )
2079 GetFirst GetUeInfoPtr;
2080 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2082 NS_LOG_INFO(
"Removed RNTI " << alloc.m_dci->m_rnti
2083 <<
" from active ue list "
2084 "because it has already an HARQ scheduled");
2085 ueInfos.erase(ueIt);
2093 if (!ueInfos.empty())
2099 activeUlUe.erase(it);
2105 if (ulSymAvail > 0 && !activeUlUe.empty())
2108 DoScheduleUlData(&ulAssignationStartPoint, ulSymAvail, activeUlUe, allocInfo);
2109 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedUl)
2110 <<
" symbols for UL data tx");
2111 ulSymAvail -= usedUl;
2114 std::vector<uint32_t> symToAl;
2115 symToAl.resize(15, 0);
2117 auto& totUlSym = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym;
2118 auto& allocations = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_ulAllocations;
2119 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2126 symToAl[alloc.m_dci->m_symStart] = alloc.m_dci->m_numSym;
2127 NS_LOG_INFO(
"UL Allocation. RNTI " << alloc.m_dci->m_rnti <<
", symStart "
2128 <<
static_cast<uint32_t
>(alloc.m_dci->m_symStart)
2129 <<
" numSym " << +alloc.m_dci->m_numSym);
2134 NS_LOG_INFO(
"Placed the above allocation in the CQI map");
2135 allocations.emplace_back(alloc.m_dci->m_rnti,
2136 alloc.m_dci->m_tbSize,
2137 alloc.m_dci->m_symStart,
2138 alloc.m_dci->m_numSym,
2140 alloc.m_dci->m_rank,
2141 alloc.m_dci->m_rbgBitmask);
2146 for (
const auto& v : symToAl)
2151 NS_ASSERT_MSG((dataSymPerSlot + m_ulCtrlSymbols) - ulSymAvail == totUlSym,
2152 "UL symbols available: "
2153 <<
static_cast<uint32_t
>(dataSymPerSlot + m_ulCtrlSymbols)
2154 <<
" UL symbols available at end of sched: "
2155 <<
static_cast<uint32_t
>(ulSymAvail)
2156 <<
" total of symbols registered in the allocation: "
2157 <<
static_cast<uint32_t
>(totUlSym) <<
" slot type " << type);
2159 NS_LOG_INFO(
"For the slot " << ulSfn <<
" registered a total of "
2160 <<
static_cast<uint32_t
>(totUlSym) <<
" symbols and "
2161 << allocations.size() <<
" data allocations, with a total of "
2162 << allocInfo->m_varTtiAllocInfo.size());
2163 NS_ASSERT(m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym == totUlSym);
2165 return dataSymPerSlot - ulSymAvail;
2169NrMacSchedulerNs3::DoScheduleSrs(PointInFTPlane* spoint, SlotAllocInfo* allocInfo)
2171 NS_LOG_FUNCTION(
this);
2176 if (m_ueMap.empty())
2185 uint32_t offset_UEx = m_srsSlotCounter % m_ueMap.begin()->second->m_srsPeriodicity;
2188 for (
const auto& ue : m_ueMap)
2190 if (ue.second->m_srsOffset == offset_UEx)
2192 rnti = ue.second->m_rnti;
2203 for (uint32_t i = 0; i < m_srsCtrlSymbols; ++i)
2207 NS_LOG_INFO(
"UE " << rnti <<
" assigned symbol " << +spoint->m_sym <<
" for SRS tx");
2216 Ptr<const ComplexMatrixArray> precMats{
nullptr};
2220 auto dci = std::make_shared<DciInfoElementTdma>(rnti,
2233 dci->m_rbgBitmask = rbgBitmask;
2235 allocInfo->m_numSymAlloc += 1;
2236 allocInfo->m_varTtiAllocInfo.emplace_front(dci);
2279 NS_LOG_FUNCTION(
this);
2294 uint8_t dlRank)
const
2296 NS_LOG_FUNCTION(
this);
2308NrMacSchedulerNs3::CallNrFhControlForMapUpdate(
2309 const std::deque<VarTtiAllocInfo>& allocation,
2310 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap)
2335NrMacSchedulerNs3::DoScheduleDl(
const std::vector<DlHarqInfo>& dlHarqFeedback,
2336 const ActiveHarqMap& activeDlHarq,
2337 ActiveUeMap* activeDlUe,
2338 const SfnSf& dlSfnSf,
2339 const SlotElem& ulAllocations,
2340 SlotAllocInfo* allocInfo)
2342 NS_LOG_FUNCTION(
this);
2343 NS_ASSERT(activeDlUe !=
nullptr);
2347 uint8_t dlSymAvail = dataSymPerSlot - ulAllocations.m_totUlSym;
2348 PointInFTPlane dlAssignationStartPoint(0, m_dlCtrlSymbols);
2350 NS_LOG_DEBUG(
"Scheduling DL for slot "
2351 << dlSfnSf <<
" DL HARQ to retransmit: " << dlHarqFeedback.size()
2352 <<
" Active Beams DL HARQ: " << activeDlHarq.size()
2353 <<
" sym available: " <<
static_cast<uint32_t
>(dlSymAvail) <<
" starting from sym "
2354 <<
static_cast<uint32_t
>(m_dlCtrlSymbols));
2356 if (!activeDlHarq.empty())
2362 &m_dlHarqToRetransmit,
2365 NS_ASSERT(dlSymAvail >= usedHarq);
2366 dlSymAvail -= usedHarq;
2369 GetSecond GetUeInfoList;
2371 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2373 for (
auto it = activeDlUe->begin(); it != activeDlUe->end(); )
2375 auto& ueInfos = GetUeInfoList(*it);
2376 for (
auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); )
2378 GetFirst GetUeInfoPtr;
2379 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2381 NS_LOG_INFO(
"Removed RNTI " << alloc.m_dci->m_rnti
2382 <<
" from active ue list "
2383 "because it has already an HARQ scheduled");
2384 ueInfos.erase(ueIt);
2392 if (!ueInfos.empty())
2398 activeDlUe->erase(it);
2404 NS_ASSERT(dlAssignationStartPoint.m_rbg == 0);
2406 if (dlSymAvail > 0 && !activeDlUe->empty())
2409 DoScheduleDlData(&dlAssignationStartPoint, dlSymAvail, *activeDlUe, allocInfo);
2410 NS_ASSERT(dlSymAvail >= usedDl);
2411 dlSymAvail -= usedDl;
2414 return (dataSymPerSlot - ulAllocations.m_totUlSym) - dlSymAvail;
2431 NS_LOG_FUNCTION(
this);
2437 for (
const auto& itUe : m_ueMap)
2439 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_dlHarq);
2443 std::vector<DlHarqInfo> dlHarqFeedback;
2448 uint64_t existingSize = m_dlHarqToRetransmit.size();
2451 dlHarqFeedback = MergeHARQ(&m_dlHarqToRetransmit, params.
m_dlHarqInfoList,
"DL");
2453 NS_ASSERT(m_dlHarqToRetransmit.empty());
2454 NS_ASSERT_MSG(existingSize + inSize == dlHarqFeedback.size(),
2455 " existing: " << existingSize <<
" received: " << inSize
2456 <<
" calculated: " << dlHarqFeedback.size());
2458 std::unordered_map<uint16_t, std::set<uint32_t>> feedbacksDup;
2465 for (
auto it = dlHarqFeedback.begin(); it != dlHarqFeedback.end(); )
2467 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2468 auto& process = ueInfo->m_dlHarq.Find(it->m_harqProcessId)->second;
2469 NS_LOG_INFO(
"Analyzing feedback for UE " << it->m_rnti <<
" process "
2470 <<
static_cast<uint32_t
>(it->m_harqProcessId));
2471 if (!process.m_active)
2473 NS_LOG_INFO(
"Feedback for UE " << it->m_rnti <<
" process "
2474 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2475 <<
" ignored because process is INACTIVE");
2476 it = dlHarqFeedback.erase(it);
2480 auto itDuplicated = feedbacksDup.find(it->m_rnti);
2481 if (itDuplicated == feedbacksDup.end())
2483 feedbacksDup.insert(std::make_pair(it->m_rnti, std::set<uint32_t>()));
2484 feedbacksDup.at(it->m_rnti).insert(it->m_harqProcessId);
2489 if (itDuplicated->second.find(it->m_harqProcessId) ==
2490 itDuplicated->second.end())
2492 itDuplicated->second.insert(it->m_harqProcessId);
2497 NS_LOG_INFO(
"Feedback for UE "
2498 << it->m_rnti <<
" process "
2499 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2500 <<
" ignored because is a duplicate of another feedback");
2501 it = dlHarqFeedback.erase(it);
2510 ScheduleDl(params, dlHarqFeedback);
2527 NS_LOG_FUNCTION(
this);
2533 for (
const auto& itUe : m_ueMap)
2535 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_ulHarq);
2539 std::vector<UlHarqInfo> ulHarqFeedback;
2543 uint64_t existingSize = m_ulHarqToRetransmit.size();
2546 ulHarqFeedback = MergeHARQ(&m_ulHarqToRetransmit, params.
m_ulHarqInfoList,
"UL");
2548 NS_ASSERT(m_ulHarqToRetransmit.empty());
2549 NS_ASSERT_MSG(existingSize + inSize == ulHarqFeedback.size(),
2550 " existing: " << existingSize <<
" received: " << inSize
2551 <<
" calculated: " << ulHarqFeedback.size());
2554 for (
auto it = ulHarqFeedback.begin(); it != ulHarqFeedback.end(); )
2556 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2557 auto& process = ueInfo->m_ulHarq.Find(it->m_harqProcessId)->second;
2558 if (!process.m_active)
2560 NS_LOG_INFO(
"Feedback for UE " << it->m_rnti <<
" process "
2561 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2562 <<
" ignored because process is INACTIVE");
2563 it = ulHarqFeedback.erase(it);
2574 ScheduleUl(params, ulHarqFeedback);
2587 NS_LOG_FUNCTION(
this);
2590 for (
const auto& ue : params.
m_srList)
2592 NS_LOG_INFO(
"UE " << ue <<
" asked for a SR ");
2594 auto it = std::find(m_srList.begin(), m_srList.end(), ue);
2595 if (it == m_srList.end())
2597 m_srList.push_back(ue);
2600 NS_ASSERT(m_srList.size() >= params.
m_srList.size());
2619NrMacSchedulerNs3::DoScheduleUlMsg3(PointInFTPlane* sPoint,
2623 NS_LOG_FUNCTION(
this);
2624 NS_ASSERT(sPoint->m_rbg == 0);
2626 uint8_t symAvailBeforeRach = symAvail;
2628 for (
const auto& rachReq : m_rachList)
2630 uint8_t allocSymbols = 0;
2631 uint16_t tbSizeBits = 0;
2634 while ((tbSizeBits < rachReq.m_estimatedSize) && (symAvail - allocSymbols > 0))
2638 GetUlAmc()->CalculateTbSize(m_rachUlGrantMcs,
2644 if (tbSizeBits < rachReq.m_estimatedSize)
2650 sPoint->m_sym -= allocSymbols;
2656 Ptr<const ComplexMatrixArray> precMats{
nullptr};
2657 std::shared_ptr<DciInfoElementTdma> ulMsg3Dci =
2658 std::make_shared<DciInfoElementTdma>(rachReq.m_rnti,
2674 ulMsg3Dci->m_rbgBitmask = rbgBitmask;
2675 symAvail -= allocSymbols;
2677 NS_LOG_INFO(
" UL grant allocated to RNTI "
2678 << ulMsg3Dci->m_rnti <<
" in slot: " << slotAlloc->
m_sfnSf <<
" symStart "
2679 << +ulMsg3Dci->m_symStart <<
" symEnd " << +ulMsg3Dci->m_numSym
2681 << (uint16_t) + ulMsg3Dci->m_mcs <<
" tbSize in bytes:" << +ulMsg3Dci->m_tbSize
2682 <<
" BWP index: " << +ulMsg3Dci->m_bwpIndex
2683 <<
" RBG bitmask:" << +ulMsg3Dci->m_rbgBitmask.size());
2685 VarTtiAllocInfo slotInfo(ulMsg3Dci);
2690 return (symAvailBeforeRach - symAvail);
Template for the implementation of the NrFhSchedSapUser as a member of an owner class of type C to wh...
@ Dropping
Drop DCI + DATA at the PHY Layer.
Service Access Point (SAP) offered by the FhControl instance to the MAC Scheduler instance.
Service Access Point (SAP) offered by the MAC Scheduler instance to the FhControl instance.
virtual uint32_t GetNumRbPerRbg() const =0
Get the number of RB per RBG.
virtual Time GetSlotPeriod() const =0
Get the slot period.
virtual uint16_t GetBwpId() const =0
Get the BWP ID.
virtual uint32_t GetSymbolsPerSlot() const =0
Get the Symbol per slot.
virtual void SchedConfigInd(const struct SchedConfigIndParameters ¶ms)=0
Install a scheduling decision.
virtual uint16_t GetCellId() const =0
Get the Cell ID.
virtual Ptr< const SpectrumModel > GetSpectrumModel() const =0
Get the SpectrumModel.
virtual void BuildRarList(SlotAllocInfo &slotAllocInfo)=0
Build RAR list from allocations and assign preamble IDs.
virtual uint8_t GetNumHarqProcess() const =0
Get the number of HARQ process.
void RefreshUlCqiMaps(const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &m_ueMap) const
Refresh the UL CQI for all the UE.
void InstallGetCellIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the cell id.
void RefreshDlCqiMaps(const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &m_ueMap) const
Refresh the DL CQI for all the UE.
void InstallGetBwpIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the bwp id.
void UlSBCQIReported(uint32_t expirationTime, uint32_t tbs, const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ¶ms, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, const std::vector< bool > &rbgMask, uint32_t numRbPerRbg, const Ptr< const SpectrumModel > &model) const
An UL SB CQI has been reported for the specified UE.
void DlCqiReported(const DlCqiInfo &info, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t expirationTime, int8_t maxDlMcs, uint16_t bandwidthInRbgs) const
A wideband CQI has been reported for the specified UE.
Interface for all the nr schedulers.
NrMacSchedSapUser * m_macSchedSapUser
SAP user.
NrMacCschedSapUser * m_macCschedSapUser
SAP User.
static TypeId GetTypeId()
Get the type ID.
bool IsSrsInUlSlots() const
Check if the UL slots are allowed for SRS transmission.
void DoCschedUeConfigReq(const NrMacCschedSapProvider::CschedUeConfigReqParameters ¶ms) override
Register an UE.
NrMacSchedulerNs3()
NrMacSchedulerNs3 default constructor.
uint8_t GetUlCtrlSyms() const override
Retrieve the number of UL ctrl symbols configured in the scheduler.
std::unordered_map< BeamId, HarqVectorIteratorList, BeamIdHash > ActiveHarqMap
Map between a beamID and the HARQ of that beam.
virtual std::shared_ptr< NrMacSchedulerUeInfo > CreateUeRepresentation(const NrMacCschedSapProvider::CschedUeConfigReqParameters ¶ms) const =0
Create an UE representation for the scheduler.
Ptr< NrAmc > m_ulAmc
AMC pointer.
bool IsHarqReTxEnable() const
Is HARQ ReTx enable function.
uint8_t GetStartMcsDl() const
Get the DL MCS starting value.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model....
void DoCschedUeReleaseReq(const NrMacCschedSapProvider::CschedUeReleaseReqParameters ¶ms) override
Release an UE.
void DoSchedUlTriggerReq(const NrMacSchedSapProvider::SchedUlTriggerReqParameters ¶ms) override
Decide how to fill the frequency/time of a UL slot.
NrMacSchedulerUeInfo::McsCsiSource m_mcsCsiSource
CSI information source for DL MCS estimation.
void SetSrsInFSlots(bool v)
Set if the F slots are allowed for SRS transmission.
virtual void ChangeDlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const =0
Perform a custom operation on the starting point each time all the UE of a DL beam have been schedule...
void SetRachUlGrantMcs(uint8_t v)
Sets the default RACH UL grant MCS.
virtual BeamSymbolMap AssignDLRBG(uint32_t symAvail, const ActiveUeMap &activeDl) const =0
Assign the DL RBG to the active UE, and return the distribution of symbols per beam.
virtual void SortUlHarq(ActiveHarqMap *activeUlHarq) const
Sort the UL HARQ retransmission.
NrFhSchedSapUser * GetNrFhSchedSapUser() override
void SetSrsCtrlSyms(uint8_t v)
Set the number of UL SRS symbols.
void DoCschedLcReleaseReq(const NrMacCschedSapProvider::CschedLcReleaseReqParameters ¶ms) override
Release a LC.
void SetFixedDlMcs(bool v)
Set if the MCS in DL is fixed (in case, it will take the starting value)
virtual void ChangeUlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const =0
Perform a custom operation on the starting point each time all the UE of an UL beam have been schedul...
NrFhSchedSapProvider * m_nrFhSchedSapProvider
FH Control SAP provider.
Ptr< NrAmc > m_dlAmc
AMC pointer.
bool IsSrsInFSlots() const
Check if the F slots are allowed for SRS transmission.
void SetUlCtrlSyms(uint8_t v)
Set the number of UL ctrl symbols.
uint8_t GetSrsCtrlSyms() const
Get the configured value for the SRS symbols.
virtual uint8_t ScheduleUlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const std::unordered_map< uint16_t, UePtr > &ueMap, std::vector< UlHarqInfo > *ulHarqToRetransmit, const std::vector< UlHarqInfo > &ulHarqFeedback, SlotAllocInfo *slotAlloc) const
Giving the input, append to slotAlloc the allocations for the DL HARQ retransmissions.
void InstallUlAmc(const Ptr< NrAmc > &ulAmc)
Install the AMC for the DL part.
Ptr< const NrAmc > GetDlAmc() const
Get the AMC for DL.
void SetSrsInUlSlots(bool v)
Set if the UL slots are allowed for SRS transmission (if True, UL and F slots may carry SRS,...
void SetStartMcsUl(uint8_t v)
Set the starting value for the UL MCS.
std::vector< bool > GetUlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the UL.
uint8_t GetStartMcsUl() const
Get the DL MCS starting value.
std::unordered_map< BeamId, uint32_t, BeamIdHash > BeamSymbolMap
Map between a BeamId and the symbol assigned to that beam.
void DoSchedSetMcs(uint32_t mcs) override
Set a fixed MCS.
void DoCschedLcConfigReq(const NrMacCschedSapProvider::CschedLcConfigReqParameters ¶ms) override
Configure a logical channel for a UE.
void DoSchedDlCqiInfoReq(const NrMacSchedSapProvider::SchedDlCqiInfoReqParameters ¶ms) override
Received a DL CQI message.
virtual std::shared_ptr< DciInfoElementTdma > CreateUlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const =0
Create a DCI for the specified UE for UL data.
void DoSchedUlCqiInfoReq(const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ¶ms) override
Received a UL CQI message.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
void DoCschedCellConfigReq(const NrMacCschedSapProvider::CschedCellConfigReqParameters ¶ms) override
Cell configuration.
void SetStartMcsDl(uint8_t v)
Set the starting value for the DL MCS.
void SetLcSched(const TypeId &type)
Set LC Scheduler Algorithm model type.
virtual BeamSymbolMap AssignULRBG(uint32_t symAvail, const ActiveUeMap &activeUl) const =0
Assign the UL RBG to the active UE, and return the distribution of symbols per beam.
NrFhSchedSapUser * m_nrFhSchedSapUser
FH Control SAP user.
static TypeId GetTypeId()
GetTypeId.
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 (wh...
Time GetCqiTimerThreshold() const
Get the CqiTimerThreshold.
void SetUlNotchedRbgMask(const std::vector< bool > &ulNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the UL.
std::unordered_map< BeamId, std::vector< UePtrAndBufferReq >, BeamIdHash > ActiveUeMap
Map between a BeamId and a vector of UE (the UE are in that beam)
bool IsUlMcsFixed() const
Check if the MCS in UL is fixed.
std::vector< bool > GetDlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the DL.
void InstallDlAmc(const Ptr< NrAmc > &dlAmc)
Install the AMC for the DL part.
~NrMacSchedulerNs3() override
NrMacSchedulerNs3 deconstructor.
virtual void SortDlHarq(ActiveHarqMap *activeDlHarq) const
Sort the DL HARQ retransmission.
void SetFixedUlMcs(bool v)
Set if the MCS in UL is fixed (in case, it will take the starting value)
virtual uint8_t GetTpc() const =0
Returns TPC command.
void DoSchedDlRlcBufferReq(const NrMacSchedSapProvider::SchedDlRlcBufferReqParameters ¶ms) override
RLC informs of DL data.
void DoSchedDlRachInfoReq(const NrMacSchedSapProvider::SchedDlRachInfoReqParameters ¶ms) override
RACH information.
void EnableHarqReTx(bool enableFlag)
Enable HARQ ReTx function.
virtual std::shared_ptr< DciInfoElementTdma > CreateDlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const =0
Create a DCI for the specified UE for DL data.
void DoSchedDlTriggerReq(const NrMacSchedSapProvider::SchedDlTriggerReqParameters ¶ms) override
Decide how to fill the frequency/time of a DL slot.
void SetNrFhSchedSapProvider(NrFhSchedSapProvider *s) override
void DoSchedUlMacCtrlInfoReq(const NrMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters ¶ms) override
Evaluate different types of control messages (only BSR for the moment)
virtual uint8_t ScheduleDlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const ActiveHarqMap &activeDlHarq, const std::unordered_map< uint16_t, UePtr > &ueMap, std::vector< DlHarqInfo > *dlHarqToRetransmit, const std::vector< DlHarqInfo > &dlHarqFeedback, SlotAllocInfo *slotAlloc) const
Giving the input, append to slotAlloc the allocations for the DL HARQ retransmissions.
virtual LCPtr CreateLC(const nr::LogicalChannelConfigListElement_s &config) const
Create a logical channel starting from a configuration.
uint16_t GetBandwidthInRbg() const
bool IsDlMcsFixed() const
Check if the MCS in DL is fixed.
virtual LCGPtr CreateLCG(const nr::LogicalChannelConfigListElement_s &config) const
Create a logical channel group starting from a configuration.
void DoSchedUlSrInfoReq(const NrMacSchedSapProvider::SchedUlSrInfoReqParameters ¶ms) override
Save the SR list into m_srList.
uint64_t GetNumRbPerRbg() const
Private function that is used to get the number of resource blocks per resource block group and also ...
uint16_t GetCellId() const
Get the cell id of this MAC.
void SetDlCtrlSyms(uint8_t v)
Set the number of DL ctrl symbols.
void SetMaxDlMcs(int8_t v)
Set the maximum index for the DL MCS.
Ptr< const NrAmc > GetUlAmc() const
Get the AMC for UL.
uint8_t GetFhControlMethod() const
Get the FH Control Method.
uint8_t GetDlCtrlSyms() const override
Retrieve the number of DL ctrl symbols configured in the scheduler.
int8_t GetMaxDlMcs() const
Get the maximum DL MCS index.
void SetCqiTimerThreshold(const Time &v)
Set the CqiTimerThreshold.
void SetDlNotchedRbgMask(const std::vector< bool > &dlNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the DL.
static std::unordered_map< uint8_t, LCGPtr > & GetUlLCG(const UePtr &ue)
GetUlLCG.
static NrMacHarqVector & GetUlHarqVector(const UePtr &ue)
GetUlHarqVector.
@ AVG_MCS
Estimate MCS based on the average MCS of allocated RBGs.
@ AVG_SPEC_EFF
Estimate MCS based on the average spectral efficiency of allocated RBGs.
@ AVG_SINR
Estimate MCS based on the average SINR of allocated RBGs.
@ WIDEBAND_MCS
Wideband MCS.
static std::unordered_map< uint8_t, LCGPtr > & GetDlLCG(const UePtr &ue)
GetDlLCG.
static NrMacHarqVector & GetDlHarqVector(const UePtr &ue)
GetDlHarqVector.
static uint64_t FromLevelToBytes(uint8_t bufferLevel)
Convert a buffer level into a buffer size.
uint64_t GetEncoding() const
Get encoding for this SfnSf.
std::unique_ptr< NrMacSchedulerLC > LCPtr
Unique pointer to an instance of NrMacSchedulerLC.
std::unique_ptr< NrMacSchedulerLCG > LCGPtr
LCGPtr unique pointer to a LCG.
LteNrTddSlotType
Available TDD slot types. Ordering is important.
@ 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.
@ RECEIVED_FEEDBACK
Received feedback (NACK)
@ WAITING_FEEDBACK
Data transmitted, waiting the feedback.
@ INACTIVE
Inactive process.
See section 4.3.14 macCEListElement.
uint16_t m_dlBandwidth
In number of RBG, created by MAC and passed to the scheduler.
uint16_t m_ulBandwidth
In number of RBG, created by MAC and passed to the scheduler.
The SchedDlCqiInfoReqParameters struct.
std::vector< struct DlCqiInfo > m_cqiList
cqi list
std::vector< struct nr::RachListElement_s > m_rachList
RACH list.
uint16_t m_rnti
The RNTI identifying the UE.
uint8_t m_logicalChannelIdentity
The logical channel ID, range: 0..10.
DL HARQ information to be used when scheduling UL data.
std::vector< struct DlHarqInfo > m_dlHarqInfoList
DL HARQ info list.
The SchedUlCqiInfoReqParameters struct.
struct UlCqiInfo m_ulCqi
UL CQI.
uint8_t m_symStart
Sym start of the transmission to which this CQI refers to.
The SchedUlMacCtrlInfoReqParameters struct.
std::vector< struct MacCeElement > m_macCeList
MacCeElement list.
SR received from MAC, to pass to schedulers.
std::vector< uint16_t > m_srList
List of RNTI which asked for a SR.
UL HARQ information to be used when scheduling UL data.
std::vector< struct UlHarqInfo > m_ulHarqInfoList
UL HARQ info list.
Point in the Frequency/Time plane.
Struct to indicate to the scheduler the periodicity and the offset, in slots.
uint32_t m_periodicity
The periodicity requested (in slot).
uint32_t m_offset
The offset requested (in slot).
bool m_isValid
Indicates if the values are valid.
The SlotAllocInfo struct.
SfnSf m_sfnSf
SfnSf of this allocation.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations
See section 4.3.4 logicalChannelConfigListElement.
uint8_t m_logicalChannelGroup
logical channel group