5G-LENA nr-v3.3-120-gdac69c56
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-ofdma.cc
1// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#define NS_LOG_APPEND_CONTEXT \
6 do \
7 { \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
9 } while (false);
10
11#include "nr-mac-scheduler-ofdma.h"
12
13#include "nr-fh-control.h"
14
15#include "ns3/log.h"
16
17#include <algorithm>
18#include <random>
19
20namespace ns3
21{
22NS_LOG_COMPONENT_DEFINE("NrMacSchedulerOfdma");
23NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerOfdma);
24
25TypeId
27{
28 static TypeId tid =
29 TypeId("ns3::NrMacSchedulerOfdma")
30 .SetParent<NrMacSchedulerTdma>()
31 .AddAttribute("SymPerBeamType",
32 "Type of symbol allocation per beam",
34 MakeEnumAccessor<SymPerBeamType>(&NrMacSchedulerOfdma::SetSymPerBeamType),
35 MakeEnumChecker<SymPerBeamType>(SymPerBeamType::LOAD_BASED,
36 "LOAD_BASED",
38 "ROUND_ROBIN",
40 "PROPORTIONAL_FAIR"))
41 .AddTraceSource(
42 "SymPerBeam",
43 "Number of assigned symbol per beam. Gets called every time an assignment is made",
44 MakeTraceSourceAccessor(&NrMacSchedulerOfdma::m_tracedValueSymPerBeam),
45 "ns3::TracedValueCallback::Uint32");
46 return tid;
47}
48
53
54void
55NrMacSchedulerOfdma::SetSymPerBeamType(SymPerBeamType type)
56{
57 m_symPerBeamType = type;
58 switch (m_symPerBeamType)
59 {
61 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamPF>(
62 [this]() { return m_dlAmc; },
63 std::bind_front(&NrMacSchedulerOfdma::GetBandwidthInRbg, this));
64 break;
66 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamRR>();
67 break;
69 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamLB>();
70 break;
71 default:
72 NS_ABORT_MSG("Invalid NrMacSchedulerOfdma::m_symPerBeamType");
73 }
74}
75
78 const NrMacSchedulerNs3::ActiveUeMap& activeDl) const
79{
80 BeamSymbolMap ret = m_symPerBeam->GetSymPerBeam(symAvail, activeDl);
81
82 // Ensure we have one entry per beam
83 for (const auto& [beam, ueVector] : activeDl)
84 {
85 if (ret.find(beam) == ret.end())
86 {
87 ret[beam] = 0;
88 }
89 }
90
91 // Trigger the trace source firing, using const_cast as we don't change
92 // the internal state of the class
93 for (const auto& v : ret)
94 {
95 const_cast<NrMacSchedulerOfdma*>(this)->m_tracedValueSymPerBeam = v.second;
96 }
97 return ret;
98}
99
100bool
101NrMacSchedulerOfdma::AdvanceToNextUeToSchedule(
102 std::vector<UePtrAndBufferReq>::iterator& schedInfoIt,
103 const std::vector<UePtrAndBufferReq>::iterator end,
104 uint32_t resourcesAssignable) const
105{
106 // Skip UEs which already have enough resources to transmit
107 while (schedInfoIt != end)
108 {
109 const uint32_t bufQueueSize = schedInfoIt->second;
110 if (schedInfoIt->first->m_dlTbSize >= std::max(bufQueueSize, 10U))
111 {
112 std::advance(schedInfoIt, 1);
113 }
114 else
115 {
117 m_nrFhSchedSapProvider->GetFhControlMethod() ==
119 !ShouldScheduleUeBasedOnFronthaul(schedInfoIt, resourcesAssignable))
120 {
121 std::advance(schedInfoIt, 1);
122 }
123 else
124 {
125 return true; // UE left to schedule
126 }
127 }
128 }
129 return false; // No UE left to schedule
130}
131
132bool
133NrMacSchedulerOfdma::ShouldScheduleUeBasedOnFronthaul(
134 const std::vector<UePtrAndBufferReq>::iterator& schedInfoIt,
135 uint32_t resourcesAssignable) const
136{
137 GetFirst GetUe;
138 uint32_t quantizationStep = resourcesAssignable;
139 uint32_t maxAssignable = m_nrFhSchedSapProvider->GetMaxRegAssignable(
140 GetBwpId(),
141 GetUe(*schedInfoIt)->m_dlMcs,
142 GetUe(*schedInfoIt)->m_rnti,
143 GetUe(*schedInfoIt)->m_dlRank); // maxAssignable is in REGs
144 // set a minimum of the maxAssignable equal to 5 RBGs
145 maxAssignable = std::max(maxAssignable, 5 * resourcesAssignable);
146
147 // the minimum allocation is one resource in freq, containing rbgAssignable
148 // in time (REGs)
149 return GetUe(*schedInfoIt)->m_dlRBG.size() + quantizationStep <= maxAssignable;
150}
151
152void
153NrMacSchedulerOfdma::AllocateCurrentResourceToUe(std::shared_ptr<NrMacSchedulerUeInfo> currentUe,
154 const uint32_t& currentRbg,
155 const uint32_t beamSym,
156 FTResources& assignedResources,
157 std::vector<bool>& availableRbgs)
158{
159 // Assign 1 RBG for each available symbols for the beam,
160 // and then update the count of available resources
161 auto& assignedRbgs = currentUe->m_dlRBG;
162 auto existingRbgs = assignedRbgs.size();
163 assignedRbgs.resize(assignedRbgs.size() + beamSym);
164 std::fill(assignedRbgs.begin() + existingRbgs, assignedRbgs.end(), currentRbg);
165 assignedResources.m_rbg++; // We increment one RBG
166
167 auto& assignedSymbols = currentUe->m_dlSym;
168 auto existingSymbols = assignedSymbols.size();
169 assignedSymbols.resize(assignedSymbols.size() + beamSym);
170 std::iota(assignedSymbols.begin() + existingSymbols, assignedSymbols.end(), 0);
171 assignedResources.m_sym = beamSym; // We keep beams per symbol fixed, since it depends on beam
172
173 availableRbgs.at(currentRbg) = false; // Mark RBG as occupied
174}
175
176void
177NrMacSchedulerOfdma::DeallocateCurrentResourceFromUe(
178 std::shared_ptr<NrMacSchedulerUeInfo> currentUe,
179 const uint32_t& currentRbg,
180 const uint32_t beamSym,
181 FTResources& assignedResources,
182 std::vector<bool>& availableRbgs)
183{
184 auto& assignedRbgs = currentUe->m_dlRBG;
185 auto& assignedSymbols = currentUe->m_dlSym;
186
187 assignedRbgs.resize(assignedRbgs.size() - beamSym);
188 assignedSymbols.resize(assignedSymbols.size() - beamSym);
189
190 NS_ASSERT_MSG(assignedResources.m_rbg > 0,
191 "Should have more than 0 resources allocated before deallocating");
192 assignedResources.m_rbg--; // We decrement the allocated RBGs
193 // We zero symbols allocated in case number of RBGs reaches 0
194 assignedResources.m_sym = assignedResources.m_rbg == 0 ? 0 : assignedResources.m_sym;
195 availableRbgs.at(currentRbg) = true;
196}
197
198bool
199NrMacSchedulerOfdma::AttemptAllocationOfCurrentResourceToUe(
200 std::vector<UePtrAndBufferReq>::iterator schedInfoIt,
201 std::set<uint32_t>& remainingRbgSet,
202 const uint32_t beamSym,
203 FTResources& assignedResources,
204 std::vector<bool>& availableRbgs) const
205{
206 auto currentUe = schedInfoIt->first;
207
208 uint32_t currentRbgPos = std::numeric_limits<uint32_t>::max();
209
210 // Use wideband information in case there is no sub-band feedback yet
211 if (currentUe->m_dlSbMcsInfo.empty() ||
213 {
214 currentRbgPos = *remainingRbgSet.begin();
215 }
216 else
217 {
218 // Find the best resource for UE among the available ones
219 int maxCqi = 0;
220 for (auto resourcePos : remainingRbgSet)
221 {
222 const auto resourceSb = currentUe->m_rbgToSb.at(resourcePos);
223 if (currentUe->m_dlSbMcsInfo.at(resourceSb).cqi > maxCqi)
224 {
225 currentRbgPos = resourcePos;
226 maxCqi = currentUe->m_dlSbMcsInfo.at(resourceSb).cqi;
227 }
228 }
229
230 // Do not schedule RBGs that are lower than 4 CQI than maximum
231 if (!currentUe->m_dlRBG.empty())
232 {
233 const auto bestCqi =
234 currentUe->m_dlSbMcsInfo.at(currentUe->m_rbgToSb.at(currentUe->m_dlRBG.at(0))).cqi;
235 if (maxCqi < bestCqi - 4)
236 {
237 return false;
238 }
239 }
240
241 // Do not schedule RBGs with sub-band CQI equals to zero
242 if (currentRbgPos == std::numeric_limits<uint32_t>::max())
243 {
244 return false;
245 }
246 }
247
248 AllocateCurrentResourceToUe(currentUe,
249 currentRbgPos,
250 beamSym,
251 assignedResources,
252 availableRbgs);
253 // Save previous tbSize to check if we need to undo this allocation because of a bad
254 // MCS
255 const auto previousTbSize = currentUe->m_dlTbSize;
256
257 AssignedDlResources(*schedInfoIt, FTResources(beamSym, beamSym), assignedResources);
258
259 // Check if the allocated RBG had a bad MCS and lowered our overall tbsize
260 const auto currentTbSize = currentUe->m_dlTbSize;
261 if (currentTbSize < previousTbSize * 0.99)
262 {
263 // Undo allocation
264 DeallocateCurrentResourceFromUe(currentUe,
265 currentRbgPos,
266 beamSym,
267 assignedResources,
268 availableRbgs);
269
270 // Update UE stats to go back to previous state
271 AssignedDlResources(*schedInfoIt, FTResources(beamSym, beamSym), assignedResources);
272 return false; // Unsuccessful allocation
273 }
274 remainingRbgSet.erase(currentRbgPos);
275 return true; // Successful allocation
276}
277
278void
279NrMacSchedulerOfdma::DeallocateResourcesDueToFronthaulConstraint(
280 const std::vector<UePtrAndBufferReq>& ueVector,
281 const uint32_t& beamSym,
282 FTResources& assignedResources,
283 std::vector<bool>& availableRbgs) const
284{
285 GetFirst GetUe;
286 std::vector<UePtrAndBufferReq> fhUeVector = ueVector;
287 auto rng = std::default_random_engine{};
288 std::shuffle(std::begin(fhUeVector), std::end(fhUeVector), rng);
289 for (auto schedInfoIt : fhUeVector)
290 {
291 const auto numAssignedResourcesToUe = GetUe(schedInfoIt)->m_dlRBG.size();
292 if (numAssignedResourcesToUe > 0) // UEs with an actual allocation
293 {
295 GetUe(schedInfoIt)->GetDlMcs(),
296 numAssignedResourcesToUe,
297 GetUe(schedInfoIt)->m_dlRank) == 0)
298 {
299 // remove allocation if the UE does not fit in the available FH
300 // capacity
301 while (!schedInfoIt.first->m_dlRBG.empty())
302 {
303 uint32_t resourceAssigned = schedInfoIt.first->m_dlRBG.back();
304 DeallocateCurrentResourceFromUe(schedInfoIt.first,
305 resourceAssigned,
306 beamSym,
307 assignedResources,
308 availableRbgs);
309 }
310 }
311 }
312 }
313}
314
341NrMacSchedulerOfdma::AssignDLRBG(uint32_t symAvail, const ActiveUeMap& activeDl) const
342{
343 NS_LOG_FUNCTION(this);
344
345 NS_LOG_DEBUG("# beams active flows: " << activeDl.size() << ", # sym: " << symAvail);
346
347 GetFirst GetBeamId;
348 GetSecond GetUeVector;
349 BeamSymbolMap symPerBeam = GetSymPerBeam(symAvail, activeDl);
350
351 // Iterate through the different beams
352 for (const auto& el : activeDl)
353 {
354 // Distribute the RBG evenly among UEs of the same beam
355 uint32_t beamSym = symPerBeam.at(GetBeamId(el));
356 std::vector<UePtrAndBufferReq> ueVector;
357 FTResources assignedResources(0, 0);
358 const std::vector<bool> dlNotchedRBGsMask = GetDlNotchedRbgMask();
359 std::vector<bool> availableRbgs = !dlNotchedRBGsMask.empty()
360 ? dlNotchedRBGsMask
361 : std::vector<bool>(GetBandwidthInRbg(), true);
362 std::set<uint32_t> remainingRbgSet;
363 for (size_t i = 0; i < availableRbgs.size(); i++)
364 {
365 if (availableRbgs.at(i))
366 {
367 remainingRbgSet.emplace(i);
368 }
369 }
370
371 NS_ASSERT(!remainingRbgSet.empty());
372
373 for (const auto& ue : GetUeVector(el))
374 {
375 ueVector.emplace_back(ue);
376 BeforeDlSched(ueVector.back(), FTResources(beamSym, beamSym));
377 }
378
379 // While there are resources to schedule
380 while (!remainingRbgSet.empty())
381 {
382 // Keep track if resources are being allocated. If not, then stop.
383 const auto prevRemaining = remainingRbgSet.size();
384
385 if (m_activeDlAi)
386 {
387 CallNotifyDlFn(ueVector);
388 }
389 // Sort UEs based on the selected scheduler policy (PF, RR, QoS, AI)
390 std::stable_sort(ueVector.begin(), ueVector.end(), GetUeCompareDlFn());
391
392 // Select the first UE
393 auto schedInfoIt = ueVector.begin();
394
395 // Advance schedInfoIt iterator to the next UE to schedule
396 while (AdvanceToNextUeToSchedule(schedInfoIt, ueVector.end(), beamSym))
397 {
398 // Try to allocate the resource to the current UE
399 // If it fails, try again for the next UE
400 if (!AttemptAllocationOfCurrentResourceToUe(schedInfoIt,
401 remainingRbgSet,
402 beamSym,
403 assignedResources,
404 availableRbgs))
405 {
406 std::advance(schedInfoIt, 1); // Get the next UE
407 continue;
408 }
409 // Update metrics
410 GetFirst GetUe;
411 NS_LOG_DEBUG("assignedResources " << GetUe(*schedInfoIt)->m_dlRBG.back()
412 << " DL RBG, spanned over " << beamSym
413 << " SYM, to UE " << GetUe(*schedInfoIt)->m_rnti);
414
415 // Update metrics for the unsuccessful UEs (who did not get any resource in this
416 // iteration)
417 for (auto& ue : ueVector)
418 {
419 if (GetUe(ue)->m_rnti != GetUe(*schedInfoIt)->m_rnti)
420 {
422 FTResources(beamSym, beamSym),
423 assignedResources);
424 }
425 }
426 break; // Successful allocation
427 }
428 // No more UEs to allocate in the current beam
429 if (prevRemaining == remainingRbgSet.size())
430 {
431 break;
432 }
433 }
434
436 {
437 if (m_nrFhSchedSapProvider->GetFhControlMethod() ==
439 {
440 GetFirst GetUe;
441 for (auto& schedInfoIt : GetUeVector(el)) // over all UEs with data
442 {
443 if (!GetUe(schedInfoIt)->m_dlRBG.empty()) // UEs with an actual allocation
444 {
445 uint8_t maxMcsAssignable = m_nrFhSchedSapProvider->GetMaxMcsAssignable(
446 GetBwpId(),
447 GetUe(schedInfoIt)->m_dlRBG.size(),
448 GetUe(schedInfoIt)->m_rnti,
449 GetUe(schedInfoIt)->m_dlRank); // max MCS index assignable
450
451 NS_LOG_DEBUG("UE " << GetUe(schedInfoIt)->m_rnti
452 << " MCS from sched: " << GetUe(schedInfoIt)->GetDlMcs()
453 << " FH max MCS: " << maxMcsAssignable);
454
455 GetUe(schedInfoIt)->m_fhMaxMcsAssignable =
456 std::min(GetUe(schedInfoIt)->GetDlMcs(), maxMcsAssignable);
457 }
458 }
459 }
460
464 {
465 DeallocateResourcesDueToFronthaulConstraint(ueVector,
466 beamSym,
467 assignedResources,
468 availableRbgs);
469 }
470 }
471 }
472
473 return symPerBeam;
474}
475
477NrMacSchedulerOfdma::AssignULRBG(uint32_t symAvail, const ActiveUeMap& activeUl) const
478{
479 NS_LOG_FUNCTION(this);
480
481 NS_LOG_DEBUG("# beams active flows: " << activeUl.size() << ", # sym: " << symAvail);
482
483 GetFirst GetBeamId;
484 GetSecond GetUeVector;
485 BeamSymbolMap symPerBeam = GetSymPerBeam(symAvail, activeUl);
486
487 // Iterate through the different beams
488 for (const auto& el : activeUl)
489 {
490 // Distribute the RBG evenly among UEs of the same beam
491 uint32_t beamSym = symPerBeam.at(GetBeamId(el));
492 std::vector<UePtrAndBufferReq> ueVector;
493 FTResources assigned(0, 0);
494 const std::vector<bool> ulNotchedRBGsMask = GetUlNotchedRbgMask();
495 uint32_t resources = !ulNotchedRBGsMask.empty()
496 ? std::count(ulNotchedRBGsMask.begin(), ulNotchedRBGsMask.end(), 1)
498 NS_ASSERT(resources > 0);
499
500 for (const auto& ue : GetUeVector(el))
501 {
502 ueVector.emplace_back(ue);
503 }
504
505 for (auto& ue : ueVector)
506 {
507 BeforeUlSched(ue, FTResources(beamSym * beamSym, beamSym));
508 }
509
510 while (resources > 0)
511 {
512 if (m_activeUlAi)
513 {
514 CallNotifyUlFn(ueVector);
515 }
516 GetFirst GetUe;
517 std::stable_sort(ueVector.begin(), ueVector.end(), GetUeCompareUlFn());
518 auto schedInfoIt = ueVector.begin();
519
520 // Ensure fairness: pass over UEs which already has enough resources to transmit
521 while (schedInfoIt != ueVector.end())
522 {
523 uint32_t bufQueueSize = schedInfoIt->second;
524 if (GetUe(*schedInfoIt)->m_ulTbSize >= std::max(bufQueueSize, 12U))
525 {
526 std::advance(schedInfoIt, 1);
527 }
528 else
529 {
530 break;
531 }
532 }
533
534 // In the case that all the UE already have their requirements fulfilled,
535 // then stop the beam processing and pass to the next
536 if (schedInfoIt == ueVector.end())
537 {
538 break;
539 }
540
541 // Assign 1 RBG for each available symbols for the beam,
542 // and then update the count of available resources
543 auto& assignedRbgs = GetUe(*schedInfoIt)->m_ulRBG;
544 auto existingRbgs = assignedRbgs.size();
545 assignedRbgs.resize(assignedRbgs.size() + beamSym);
546 std::fill(assignedRbgs.begin() + existingRbgs, assignedRbgs.end(), resources - 1);
547 assigned.m_rbg++;
548
549 auto& assignedSymbols = GetUe(*schedInfoIt)->m_ulSym;
550 auto existingSymbols = assignedSymbols.size();
551 assignedSymbols.resize(assignedSymbols.size() + beamSym);
552 std::iota(assignedSymbols.begin() + existingSymbols, assignedSymbols.end(), 0);
553 assigned.m_sym = beamSym;
554
555 resources -= 1; // Resources are RBG, so they do not consider the beamSym
556
557 // Update metrics
558 NS_LOG_DEBUG("Assigned " << assigned.m_rbg << " UL RBG, spanned over " << beamSym
559 << " SYM, to UE " << GetUe(*schedInfoIt)->m_rnti);
560 AssignedUlResources(*schedInfoIt, FTResources(beamSym, beamSym), assigned);
561
562 // Update metrics for the unsuccessful UEs (who did not get any resource in this
563 // iteration)
564 for (auto& ue : ueVector)
565 {
566 if (GetUe(ue)->m_rnti != GetUe(*schedInfoIt)->m_rnti)
567 {
568 NotAssignedUlResources(ue, FTResources(beamSym, beamSym), assigned);
569 }
570 }
571 }
572 }
573
574 return symPerBeam;
575}
576
586std::shared_ptr<DciInfoElementTdma>
588 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
589 uint32_t maxSym) const
590{
591 NS_LOG_FUNCTION(this);
592
593 auto dlMcs = ueInfo->GetDlMcs();
594 ueInfo->m_fhMaxMcsAssignable.reset(); // Erase value assigned when fronthaul control is enabled
595 uint32_t tbs = m_dlAmc->CalculateTbSize(dlMcs,
596 ueInfo->m_dlRank,
597 ueInfo->m_dlRBG.size() * GetNumRbPerRbg());
598 // NS_ASSERT_MSG(ueInfo->m_dlRBG.size() % maxSym == 0,
599 // " MaxSym " << maxSym << " RBG: " << ueInfo->m_dlRBG.size());
600 NS_ASSERT(ueInfo->m_dlRBG.size() <= maxSym * GetBandwidthInRbg());
601 NS_ASSERT(spoint->m_rbg < GetBandwidthInRbg());
602 NS_ASSERT(maxSym <= UINT8_MAX);
603
604 // 5 bytes for headers (3 mac header, 2 rlc header)
605 if (tbs < 10)
606 {
607 NS_LOG_DEBUG("While creating DCI for UE "
608 << ueInfo->m_rnti << " assigned "
609 << std::set<uint32_t>(ueInfo->m_dlRBG.begin(), ueInfo->m_dlRBG.end()).size()
610 << " DL RBG, but TBS < 10");
611 ueInfo->m_dlTbSize = 0;
612 return nullptr;
613 }
614
615 const auto rbgBitmask = CreateRbgBitmaskFromAllocatedRbgs(ueInfo->m_dlRBG);
616 std::ostringstream oss;
617 for (const auto& x : rbgBitmask)
618 {
619 oss << std::to_string(x) << " ";
620 }
621
622 NS_LOG_INFO("UE " << ueInfo->m_rnti << " assigned RBG from " << spoint->m_rbg << " with mask "
623 << oss.str() << " for " << static_cast<uint32_t>(maxSym) << " SYM.");
624
625 std::shared_ptr<DciInfoElementTdma> dci =
626 std::make_shared<DciInfoElementTdma>(ueInfo->m_rnti,
628 spoint->m_sym,
629 maxSym,
630 dlMcs,
631 ueInfo->m_dlRank,
632 ueInfo->m_dlPrecMats,
633 tbs,
634 1,
635 0,
637 GetBwpId(),
638 GetTpc());
639
640 dci->m_rbgBitmask = std::move(rbgBitmask);
641
642 NS_ASSERT(std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 0) !=
644
645 return dci;
646}
647
648std::shared_ptr<DciInfoElementTdma>
650 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
651 uint32_t maxSym) const
652{
653 NS_LOG_FUNCTION(this);
654
655 uint32_t tbs = m_ulAmc->CalculateTbSize(ueInfo->m_ulMcs,
656 ueInfo->m_ulRank,
657 ueInfo->m_ulRBG.size() * GetNumRbPerRbg());
658
659 // If is less than 12, i.e., 7 (3 mac header, 2 rlc header, 2 data) + 5 bytes for
660 // the SHORT_BSR. then we can't transmit any new data, so don't create dci.
661 if (tbs < 12)
662 {
663 NS_LOG_DEBUG("While creating UL DCI for UE "
664 << ueInfo->m_rnti << " assigned "
665 << std::set<uint32_t>(ueInfo->m_ulRBG.begin(), ueInfo->m_ulRBG.end()).size()
666 << " UL RBG, but TBS < 12");
667 return nullptr;
668 }
669
670 uint32_t RBGNum = ueInfo->m_ulRBG.size() / maxSym;
671 const auto rbgBitmask = CreateRbgBitmaskFromAllocatedRbgs(ueInfo->m_ulRBG);
672
673 NS_LOG_INFO("UE " << ueInfo->m_rnti << " assigned RBG from " << spoint->m_rbg << " to "
674 << spoint->m_rbg + RBGNum << " for " << static_cast<uint32_t>(maxSym)
675 << " SYM.");
676
677 NS_ASSERT(spoint->m_sym >= maxSym);
678 std::shared_ptr<DciInfoElementTdma> dci =
679 std::make_shared<DciInfoElementTdma>(ueInfo->m_rnti,
681 spoint->m_sym - maxSym,
682 maxSym,
683 ueInfo->m_ulMcs,
684 ueInfo->m_ulRank,
685 ueInfo->m_ulPrecMats,
686 tbs,
687 1,
688 0,
690 GetBwpId(),
691 GetTpc());
692
693 dci->m_rbgBitmask = std::move(rbgBitmask);
694
695 std::ostringstream oss;
696 for (auto x : dci->m_rbgBitmask)
697 {
698 oss << std::to_string(x) << " ";
699 }
700 NS_LOG_INFO("UE " << ueInfo->m_rnti << " DCI RBG mask: " << oss.str());
701
702 NS_ASSERT(std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 0) !=
704
705 return dci;
706}
707
708void
709NrMacSchedulerOfdma::ChangeDlBeam(PointInFTPlane* spoint, uint32_t symOfBeam) const
710{
711 spoint->m_rbg = 0;
712 spoint->m_sym += symOfBeam;
713}
714
715void
716NrMacSchedulerOfdma::ChangeUlBeam(PointInFTPlane* spoint, uint32_t symOfBeam) const
717{
718 spoint->m_rbg = 0;
719 spoint->m_sym -= symOfBeam;
720}
721
722uint8_t
724{
725 NS_LOG_FUNCTION(this);
726 return 1; // 1 is mapped to 0 for Accumulated mode, and to -1 in Absolute mode TS38.213
727 // Table 7.1.1-1
728}
729
730std::vector<bool>
731NrMacSchedulerOfdma::CreateRbgBitmaskFromAllocatedRbgs(
732 const std::vector<uint16_t>& allocatedRbgs) const
733{
734 std::vector<bool> rbgNotchedBitmask = GetDlNotchedRbgMask();
735 if (rbgNotchedBitmask.empty())
736 {
737 rbgNotchedBitmask = std::vector<bool>(GetBandwidthInRbg(), true);
738 }
739 std::vector<bool> rbgBitmask = std::vector<bool>(GetBandwidthInRbg(), false);
740
741 NS_ASSERT(rbgNotchedBitmask.size() == rbgBitmask.size());
742
743 // rbgBitmask is all 1s or have 1s in the place we are allowed to transmit.
744
745 for (auto rbg : allocatedRbgs)
746 {
747 NS_ASSERT_MSG(rbgNotchedBitmask.at(rbg), "Scheduled notched resource");
748 rbgBitmask.at(rbg) = true;
749 }
750 return rbgBitmask;
751}
752
753} // namespace ns3
@ Postponing
Postpone sending data (MAC Layer)
@ OptimizeRBs
Optimize RBs allocated.
@ OptimizeMcs
Optimize MCS.
Ptr< NrAmc > m_ulAmc
AMC pointer.
NrMacSchedulerUeInfo::McsCsiSource m_mcsCsiSource
CSI information source for DL MCS estimation.
NrFhSchedSapProvider * m_nrFhSchedSapProvider
FH Control SAP provider.
Ptr< NrAmc > m_dlAmc
AMC pointer.
bool m_activeUlAi
Flag for activating AI for uplink.
std::vector< bool > GetUlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the UL.
std::unordered_map< BeamId, uint32_t, BeamIdHash > BeamSymbolMap
Map between a BeamId and the symbol assigned to that beam.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
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...
bool m_activeDlAi
Flag for activating AI for downlink.
std::unordered_map< BeamId, std::vector< UePtrAndBufferReq >, BeamIdHash > ActiveUeMap
Map between a BeamId and a vector of UE (the UE are in that beam)
std::vector< bool > GetDlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the DL.
uint64_t GetNumRbPerRbg() const
Private function that is used to get the number of resource blocks per resource block group and also ...
uint8_t GetFhControlMethod() const
Get the FH Control Method.
PointInFTPlane FTResources
Represent an amount of RBG/symbols that can be, or is, assigned.
The base for all the OFDMA schedulers.
std::shared_ptr< DciInfoElementTdma > CreateDlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create the DL DCI in OFDMA mode.
void ChangeDlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const override
Advance the starting point by the number of symbols specified, resetting the RB count to 0.
NrMacSchedulerOfdma()
NrMacSchedulerOfdma constructor.
std::shared_ptr< DciInfoElementTdma > CreateUlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create a DCI for the specified UE for UL data.
NrMacSchedulerOfdma::BeamSymbolMap GetSymPerBeam(uint32_t symAvail, const ActiveUeMap &activeDl) const
Calculate the number of symbols to assign to each beam by calling using the technique selected in m_s...
BeamSymbolMap AssignULRBG(uint32_t symAvail, const ActiveUeMap &activeUl) const override
Assign the UL RBG to the active UE, and return the distribution of symbols per beam.
BeamSymbolMap AssignDLRBG(uint32_t symAvail, const ActiveUeMap &activeDl) const override
Assign the available DL RBG to the UEs.
@ ROUND_ROBIN
Distributes all symbols to the first active beam in the m_rrBeams queue.
@ PROPORTIONAL_FAIR
Distributes symbols to beams proportionally to mean achievable rate.
@ LOAD_BASED
Distributes symbols to beams proportionally to the buffer size of its users.
uint8_t GetTpc() const override
Returns TPC command.
static TypeId GetTypeId()
GetTypeId.
void ChangeUlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const override
Perform a custom operation on the starting point each time all the UE of an UL beam have been schedul...
The base for all the TDMA schedulers.
virtual std::function< bool(const NrMacSchedulerNs3::UePtrAndBufferReq &lhs, const NrMacSchedulerNs3::UePtrAndBufferReq &rhs)> GetUeCompareUlFn() const =0
Provide the comparison function to order the UE when scheduling UL.
virtual void AssignedUlResources(const UePtrAndBufferReq &ue, const FTResources &assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to it.
virtual std::function< bool(const NrMacSchedulerNs3::UePtrAndBufferReq &lhs, const NrMacSchedulerNs3::UePtrAndBufferReq &rhs)> GetUeCompareDlFn() const =0
Provide the comparison function to order the UE when scheduling DL.
virtual void NotAssignedUlResources(const UePtrAndBufferReq &ue, const FTResources &notAssigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (UL) has been assigned to other UE.
virtual void NotAssignedDlResources(const UePtrAndBufferReq &ue, const FTResources &notAssigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to other UE.
virtual void AssignedDlResources(const UePtrAndBufferReq &ue, const FTResources &assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to it.
virtual void BeforeUlSched(const UePtrAndBufferReq &ue, const FTResources &assignableInIteration) const =0
Prepare UE for the UL scheduling.
virtual void CallNotifyDlFn(const std::vector< UePtrAndBufferReq > &ueVector) const
Call the notify callback function in the OpenGymEnv class in the ns3-gym module for downlink.
virtual void CallNotifyUlFn(const std::vector< UePtrAndBufferReq > &ueVector) const
Call the notify callback function in the OpenGymEnv class in the ns3-gym module for uplink.
virtual void BeforeDlSched(const UePtrAndBufferReq &ue, const FTResources &assignableInIteration) const =0
Prepare UE for the DL scheduling.
@ DATA
Used for DL/UL DATA.
Point in the Frequency/Time plane.
uint32_t m_rbg
Represent the starting RBG.
uint8_t m_sym
Represent the starting symbol.