A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
pss-ff-mac-scheduler.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Marco Miozzo <marco.miozzo@cttc.es>
7 * Modification: Dizhi Zhou <dizhi.zhou@gmail.com> // modify codes related to downlink scheduler
8 */
9
11
12#include "lte-amc.h"
14
15#include <ns3/boolean.h>
16#include <ns3/log.h>
17#include <ns3/math.h>
18#include <ns3/pointer.h>
19#include <ns3/simulator.h>
20#include <ns3/string.h>
21
22#include <algorithm>
23#include <cfloat>
24#include <set>
25
26namespace ns3
27{
28
29NS_LOG_COMPONENT_DEFINE("PssFfMacScheduler");
30
31/// PSS type 0 allocation RBG
32static const int PssType0AllocationRbg[4] = {
33 10, // RBG size 1
34 26, // RBG size 2
35 63, // RBG size 3
36 110, // RBG size 4
37}; // see table 7.1.6.1-1 of 36.213
38
39NS_OBJECT_ENSURE_REGISTERED(PssFfMacScheduler);
40
42 : m_cschedSapUser(nullptr),
43 m_schedSapUser(nullptr),
44 m_timeWindow(99.0),
45 m_nextRntiUl(0)
46{
50 m_ffrSapProvider = nullptr;
52}
53
58
59void
74
77{
78 static TypeId tid =
79 TypeId("ns3::PssFfMacScheduler")
81 .SetGroupName("Lte")
82 .AddConstructor<PssFfMacScheduler>()
83 .AddAttribute("CqiTimerThreshold",
84 "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
85 UintegerValue(1000),
88 .AddAttribute("PssFdSchedulerType",
89 "FD scheduler in PSS (default value is PFsch)",
90 StringValue("PFsch"),
93 .AddAttribute("nMux",
94 "The number of UE selected by TD scheduler (default value is 0)",
98 .AddAttribute("HarqEnabled",
99 "Activate/Deactivate the HARQ [by default is active].",
100 BooleanValue(true),
103 .AddAttribute("UlGrantMcs",
104 "The MCS of the UL grant, must be [0..15] (default 0)",
105 UintegerValue(0),
108 return tid;
109}
110
111void
116
117void
122
128
134
135void
140
146
147void
159
160void
163{
164 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
165 << (uint16_t)params.m_transmissionMode);
166 auto it = m_uesTxMode.find(params.m_rnti);
167 if (it == m_uesTxMode.end())
168 {
169 m_uesTxMode[params.m_rnti] = params.m_transmissionMode;
170 // generate HARQ buffers
171 m_dlHarqCurrentProcessId[params.m_rnti] = 0;
172 DlHarqProcessesStatus_t dlHarqPrcStatus;
173 dlHarqPrcStatus.resize(8, 0);
174 m_dlHarqProcessesStatus[params.m_rnti] = dlHarqPrcStatus;
175 DlHarqProcessesTimer_t dlHarqProcessesTimer;
176 dlHarqProcessesTimer.resize(8, 0);
177 m_dlHarqProcessesTimer[params.m_rnti] = dlHarqProcessesTimer;
179 dlHarqdci.resize(8);
180 m_dlHarqProcessesDciBuffer[params.m_rnti] = dlHarqdci;
181 DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
182 dlHarqRlcPdu.resize(2);
183 dlHarqRlcPdu.at(0).resize(8);
184 dlHarqRlcPdu.at(1).resize(8);
185 m_dlHarqProcessesRlcPduListBuffer[params.m_rnti] = dlHarqRlcPdu;
186 m_ulHarqCurrentProcessId[params.m_rnti] = 0;
187 UlHarqProcessesStatus_t ulHarqPrcStatus;
188 ulHarqPrcStatus.resize(8, 0);
189 m_ulHarqProcessesStatus[params.m_rnti] = ulHarqPrcStatus;
191 ulHarqdci.resize(8);
192 m_ulHarqProcessesDciBuffer[params.m_rnti] = ulHarqdci;
193 }
194 else
195 {
196 (*it).second = params.m_transmissionMode;
197 }
198}
199
200void
203{
204 NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
205
206 for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
207 {
208 auto it = m_flowStatsDl.find(params.m_rnti);
209
210 if (it == m_flowStatsDl.end())
211 {
212 double tbrDlInBytes =
213 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
214 double tbrUlInBytes =
215 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
216
217 pssFlowPerf_t flowStatsDl;
218 flowStatsDl.flowStart = Simulator::Now();
219 flowStatsDl.totalBytesTransmitted = 0;
220 flowStatsDl.lastTtiBytesTransmitted = 0;
221 flowStatsDl.lastAveragedThroughput = 1;
222 flowStatsDl.secondLastAveragedThroughput = 1;
223 flowStatsDl.targetThroughput = tbrDlInBytes;
224 m_flowStatsDl[params.m_rnti] = flowStatsDl;
225 pssFlowPerf_t flowStatsUl;
226 flowStatsUl.flowStart = Simulator::Now();
227 flowStatsUl.totalBytesTransmitted = 0;
228 flowStatsUl.lastTtiBytesTransmitted = 0;
229 flowStatsUl.lastAveragedThroughput = 1;
230 flowStatsUl.secondLastAveragedThroughput = 1;
231 flowStatsUl.targetThroughput = tbrUlInBytes;
232 m_flowStatsUl[params.m_rnti] = flowStatsUl;
233 }
234 else
235 {
236 // update GBR from UeManager::SetupDataRadioBearer ()
237 double tbrDlInBytes =
238 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
239 double tbrUlInBytes =
240 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
241 m_flowStatsDl[(*it).first].targetThroughput = tbrDlInBytes;
242 m_flowStatsUl[(*it).first].targetThroughput = tbrUlInBytes;
243 }
244 }
245}
246
247void
250{
251 NS_LOG_FUNCTION(this);
252 for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
253 {
254 auto it = m_rlcBufferReq.begin();
255 while (it != m_rlcBufferReq.end())
256 {
257 if (((*it).first.m_rnti == params.m_rnti) &&
258 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
259 {
260 auto temp = it;
261 it++;
262 m_rlcBufferReq.erase(temp);
263 }
264 else
265 {
266 it++;
267 }
268 }
269 }
270}
271
272void
275{
276 NS_LOG_FUNCTION(this);
277
278 m_uesTxMode.erase(params.m_rnti);
279 m_dlHarqCurrentProcessId.erase(params.m_rnti);
280 m_dlHarqProcessesStatus.erase(params.m_rnti);
281 m_dlHarqProcessesTimer.erase(params.m_rnti);
282 m_dlHarqProcessesDciBuffer.erase(params.m_rnti);
283 m_dlHarqProcessesRlcPduListBuffer.erase(params.m_rnti);
284 m_ulHarqCurrentProcessId.erase(params.m_rnti);
285 m_ulHarqProcessesStatus.erase(params.m_rnti);
286 m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
287 m_flowStatsDl.erase(params.m_rnti);
288 m_flowStatsUl.erase(params.m_rnti);
289 m_ceBsrRxed.erase(params.m_rnti);
290 auto it = m_rlcBufferReq.begin();
291 while (it != m_rlcBufferReq.end())
292 {
293 if ((*it).first.m_rnti == params.m_rnti)
294 {
295 auto temp = it;
296 it++;
297 m_rlcBufferReq.erase(temp);
298 }
299 else
300 {
301 it++;
302 }
303 }
304 if (m_nextRntiUl == params.m_rnti)
305 {
306 m_nextRntiUl = 0;
307 }
308}
309
310void
313{
314 NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
315 // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
316
317 LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
318
319 auto it = m_rlcBufferReq.find(flow);
320
321 if (it == m_rlcBufferReq.end())
322 {
323 m_rlcBufferReq[flow] = params;
324 }
325 else
326 {
327 (*it).second = params;
328 }
329}
330
331void
338
339void
346
347int
349{
350 for (int i = 0; i < 4; i++)
351 {
352 if (dlbandwidth < PssType0AllocationRbg[i])
353 {
354 return i + 1;
355 }
356 }
357
358 return -1;
359}
360
361unsigned int
363{
364 unsigned int lcActive = 0;
365 for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
366 {
367 if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
368 ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
369 ((*it).second.m_rlcStatusPduSize > 0)))
370 {
371 lcActive++;
372 }
373 if ((*it).first.m_rnti > rnti)
374 {
375 break;
376 }
377 }
378 return lcActive;
379}
380
381bool
383{
384 NS_LOG_FUNCTION(this << rnti);
385
386 auto it = m_dlHarqCurrentProcessId.find(rnti);
387 if (it == m_dlHarqCurrentProcessId.end())
388 {
389 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
390 }
391 auto itStat = m_dlHarqProcessesStatus.find(rnti);
392 if (itStat == m_dlHarqProcessesStatus.end())
393 {
394 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
395 }
396 uint8_t i = (*it).second;
397 do
398 {
399 i = (i + 1) % HARQ_PROC_NUM;
400 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
401
402 return (*itStat).second.at(i) == 0;
403}
404
405uint8_t
407{
408 NS_LOG_FUNCTION(this << rnti);
409
410 if (!m_harqOn)
411 {
412 return 0;
413 }
414
415 auto it = m_dlHarqCurrentProcessId.find(rnti);
416 if (it == m_dlHarqCurrentProcessId.end())
417 {
418 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
419 }
420 auto itStat = m_dlHarqProcessesStatus.find(rnti);
421 if (itStat == m_dlHarqProcessesStatus.end())
422 {
423 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
424 }
425 uint8_t i = (*it).second;
426 do
427 {
428 i = (i + 1) % HARQ_PROC_NUM;
429 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
430 if ((*itStat).second.at(i) == 0)
431 {
432 (*it).second = i;
433 (*itStat).second.at(i) = 1;
434 }
435 else
436 {
437 NS_FATAL_ERROR("No HARQ process available for RNTI "
438 << rnti << " check before update with HarqProcessAvailability");
439 }
440
441 return (*it).second;
442}
443
444void
446{
447 NS_LOG_FUNCTION(this);
448
449 for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
450 itTimers++)
451 {
452 for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
453 {
454 if ((*itTimers).second.at(i) == HARQ_DL_TIMEOUT)
455 {
456 // reset HARQ process
457
458 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
459 auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
460 if (itStat == m_dlHarqProcessesStatus.end())
461 {
462 NS_FATAL_ERROR("No Process Id Status found for this RNTI "
463 << (*itTimers).first);
464 }
465 (*itStat).second.at(i) = 0;
466 (*itTimers).second.at(i) = 0;
467 }
468 else
469 {
470 (*itTimers).second.at(i)++;
471 }
472 }
473 }
474}
475
476void
479{
480 NS_LOG_FUNCTION(this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
481 << (0xF & params.m_sfnSf));
482 // API generated by RLC for triggering the scheduling of a DL subframe
483
484 // evaluate the relative channel quality indicator for each UE per each RBG
485 // (since we are using allocation type 0 the small unit of allocation is RBG)
486 // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
487
489
491 int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
492 std::map<uint16_t, std::vector<uint16_t>> allocationMap; // RBs map per RNTI
493 std::vector<bool> rbgMap; // global RBGs map
494 uint16_t rbgAllocatedNum = 0;
495 std::set<uint16_t> rntiAllocated;
496 rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
497
499 for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
500 {
501 if (*it)
502 {
503 rbgAllocatedNum++;
504 }
505 }
506
508
509 // update UL HARQ proc id
510 for (auto itProcId = m_ulHarqCurrentProcessId.begin();
511 itProcId != m_ulHarqCurrentProcessId.end();
512 itProcId++)
513 {
514 (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
515 }
516
517 // RACH Allocation
518 std::vector<bool> ulRbMap;
519 ulRbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
521 uint8_t maxContinuousUlBandwidth = 0;
522 uint8_t tmpMinBandwidth = 0;
523 uint16_t ffrRbStartOffset = 0;
524 uint16_t tmpFfrRbStartOffset = 0;
525 uint16_t index = 0;
526
527 for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
528 {
529 if (*it)
530 {
531 if (tmpMinBandwidth > maxContinuousUlBandwidth)
532 {
533 maxContinuousUlBandwidth = tmpMinBandwidth;
534 ffrRbStartOffset = tmpFfrRbStartOffset;
535 }
536 tmpMinBandwidth = 0;
537 }
538 else
539 {
540 if (tmpMinBandwidth == 0)
541 {
542 tmpFfrRbStartOffset = index;
543 }
544 tmpMinBandwidth++;
545 }
546 index++;
547 }
548
549 if (tmpMinBandwidth > maxContinuousUlBandwidth)
550 {
551 maxContinuousUlBandwidth = tmpMinBandwidth;
552 ffrRbStartOffset = tmpFfrRbStartOffset;
553 }
554
556 uint16_t rbStart = 0;
557 rbStart = ffrRbStartOffset;
558 for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
559 {
561 (*itRach).m_estimatedSize,
562 " Default UL Grant MCS does not allow to send RACH messages");
564 newRar.m_rnti = (*itRach).m_rnti;
565 // DL-RACH Allocation
566 // Ideal: no needs of configuring m_dci
567 // UL-RACH Allocation
568 newRar.m_grant.m_rnti = newRar.m_rnti;
569 newRar.m_grant.m_mcs = m_ulGrantMcs;
570 uint16_t rbLen = 1;
571 uint16_t tbSizeBits = 0;
572 // find lowest TB size that fits UL grant estimated size
573 while ((tbSizeBits < (*itRach).m_estimatedSize) &&
574 (rbStart + rbLen < (ffrRbStartOffset + maxContinuousUlBandwidth)))
575 {
576 rbLen++;
577 tbSizeBits = m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, rbLen);
578 }
579 if (tbSizeBits < (*itRach).m_estimatedSize)
580 {
581 // no more allocation space: finish allocation
582 break;
583 }
584 newRar.m_grant.m_rbStart = rbStart;
585 newRar.m_grant.m_rbLen = rbLen;
586 newRar.m_grant.m_tbSize = tbSizeBits / 8;
587 newRar.m_grant.m_hopping = false;
588 newRar.m_grant.m_tpc = 0;
589 newRar.m_grant.m_cqiRequest = false;
590 newRar.m_grant.m_ulDelay = false;
591 NS_LOG_INFO(this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart "
592 << rbStart << " rbLen " << rbLen << " MCS " << (uint16_t)m_ulGrantMcs
593 << " tbSize " << newRar.m_grant.m_tbSize);
594 for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
595 {
596 m_rachAllocationMap.at(i) = (*itRach).m_rnti;
597 }
598
599 if (m_harqOn)
600 {
601 // generate UL-DCI for HARQ retransmissions
602 UlDciListElement_s uldci;
603 uldci.m_rnti = newRar.m_rnti;
604 uldci.m_rbLen = rbLen;
605 uldci.m_rbStart = rbStart;
606 uldci.m_mcs = m_ulGrantMcs;
607 uldci.m_tbSize = tbSizeBits / 8;
608 uldci.m_ndi = 1;
609 uldci.m_cceIndex = 0;
610 uldci.m_aggrLevel = 1;
611 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
612 uldci.m_hopping = false;
613 uldci.m_n2Dmrs = 0;
614 uldci.m_tpc = 0; // no power control
615 uldci.m_cqiRequest = false; // only period CQI at this stage
616 uldci.m_ulIndex = 0; // TDD parameter
617 uldci.m_dai = 1; // TDD parameter
618 uldci.m_freqHopping = 0;
619 uldci.m_pdcchPowerOffset = 0; // not used
620
621 uint8_t harqId = 0;
622 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
623 if (itProcId == m_ulHarqCurrentProcessId.end())
624 {
625 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
626 }
627 harqId = (*itProcId).second;
628 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
629 if (itDci == m_ulHarqProcessesDciBuffer.end())
630 {
631 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
632 << uldci.m_rnti);
633 }
634 (*itDci).second.at(harqId) = uldci;
635 }
636
637 rbStart = rbStart + rbLen;
638 ret.m_buildRarList.push_back(newRar);
639 }
640 m_rachList.clear();
641
642 // Process DL HARQ feedback
644 // retrieve past HARQ retx buffered
645 if (!m_dlInfoListBuffered.empty())
646 {
647 if (!params.m_dlInfoList.empty())
648 {
649 NS_LOG_INFO(this << " Received DL-HARQ feedback");
651 params.m_dlInfoList.begin(),
652 params.m_dlInfoList.end());
653 }
654 }
655 else
656 {
657 if (!params.m_dlInfoList.empty())
658 {
659 m_dlInfoListBuffered = params.m_dlInfoList;
660 }
661 }
662 if (!m_harqOn)
663 {
664 // Ignore HARQ feedback
665 m_dlInfoListBuffered.clear();
666 }
667 std::vector<DlInfoListElement_s> dlInfoListUntxed;
668 for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
669 {
670 auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
671 if (itRnti != rntiAllocated.end())
672 {
673 // RNTI already allocated for retx
674 continue;
675 }
676 auto nLayers = m_dlInfoListBuffered.at(i).m_harqStatus.size();
677 std::vector<bool> retx;
678 NS_LOG_INFO(this << " Processing DLHARQ feedback");
679 if (nLayers == 1)
680 {
681 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
683 retx.push_back(false);
684 }
685 else
686 {
687 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
689 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
691 }
692 if (retx.at(0) || retx.at(1))
693 {
694 // retrieve HARQ process information
695 uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
696 uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
697 NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
698 auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
699 if (itHarq == m_dlHarqProcessesDciBuffer.end())
700 {
701 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
702 }
703
704 DlDciListElement_s dci = (*itHarq).second.at(harqId);
705 int rv = 0;
706 if (dci.m_rv.size() == 1)
707 {
708 rv = dci.m_rv.at(0);
709 }
710 else
711 {
712 rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
713 }
714
715 if (rv == 3)
716 {
717 // maximum number of retx reached -> drop process
718 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
719 auto it = m_dlHarqProcessesStatus.find(rnti);
720 if (it == m_dlHarqProcessesStatus.end())
721 {
722 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
723 << m_dlInfoListBuffered.at(i).m_rnti);
724 }
725 it->second.at(harqId) = 0;
726 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
727 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
728 {
729 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
730 << m_dlInfoListBuffered.at(i).m_rnti);
731 }
732 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
733 {
734 (*itRlcPdu).second.at(k).at(harqId).clear();
735 }
736 continue;
737 }
738 // check the feasibility of retransmitting on the same RBGs
739 // translate the DCI to Spectrum framework
740 std::vector<int> dciRbg;
741 uint32_t mask = 0x1;
742 NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
743 for (int j = 0; j < 32; j++)
744 {
745 if (((dci.m_rbBitmap & mask) >> j) == 1)
746 {
747 dciRbg.push_back(j);
748 NS_LOG_INFO("\t" << j);
749 }
750 mask = (mask << 1);
751 }
752 bool free = true;
753 for (std::size_t j = 0; j < dciRbg.size(); j++)
754 {
755 if (rbgMap.at(dciRbg.at(j)))
756 {
757 free = false;
758 break;
759 }
760 }
761 if (free)
762 {
763 // use the same RBGs for the retx
764 // reserve RBGs
765 for (std::size_t j = 0; j < dciRbg.size(); j++)
766 {
767 rbgMap.at(dciRbg.at(j)) = true;
768 NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
769 rbgAllocatedNum++;
770 }
771
772 NS_LOG_INFO(this << " Send retx in the same RBGs");
773 }
774 else
775 {
776 // find RBGs for sending HARQ retx
777 uint8_t j = 0;
778 uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % rbgNum;
779 uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
780 std::vector<bool> rbgMapCopy = rbgMap;
781 while ((j < dciRbg.size()) && (startRbg != rbgId))
782 {
783 if (!rbgMapCopy.at(rbgId))
784 {
785 rbgMapCopy.at(rbgId) = true;
786 dciRbg.at(j) = rbgId;
787 j++;
788 }
789 rbgId = (rbgId + 1) % rbgNum;
790 }
791 if (j == dciRbg.size())
792 {
793 // find new RBGs -> update DCI map
794 uint32_t rbgMask = 0;
795 for (std::size_t k = 0; k < dciRbg.size(); k++)
796 {
797 rbgMask = rbgMask + (0x1 << dciRbg.at(k));
798 rbgAllocatedNum++;
799 }
800 dci.m_rbBitmap = rbgMask;
801 rbgMap = rbgMapCopy;
802 NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
803 }
804 else
805 {
806 // HARQ retx cannot be performed on this TTI -> store it
807 dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
808 NS_LOG_INFO(this << " No resource for this retx -> buffer it");
809 }
810 }
811 // retrieve RLC PDU list for retx TBsize and update DCI
813 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
814 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
815 {
816 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
817 }
818 for (std::size_t j = 0; j < nLayers; j++)
819 {
820 if (retx.at(j))
821 {
822 if (j >= dci.m_ndi.size())
823 {
824 // for avoiding errors in MIMO transient phases
825 dci.m_ndi.push_back(0);
826 dci.m_rv.push_back(0);
827 dci.m_mcs.push_back(0);
828 dci.m_tbsSize.push_back(0);
829 NS_LOG_INFO(this << " layer " << (uint16_t)j
830 << " no txed (MIMO transition)");
831 }
832 else
833 {
834 dci.m_ndi.at(j) = 0;
835 dci.m_rv.at(j)++;
836 (*itHarq).second.at(harqId).m_rv.at(j)++;
837 NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
838 << (uint16_t)dci.m_rv.at(j));
839 }
840 }
841 else
842 {
843 // empty TB of layer j
844 dci.m_ndi.at(j) = 0;
845 dci.m_rv.at(j) = 0;
846 dci.m_mcs.at(j) = 0;
847 dci.m_tbsSize.at(j) = 0;
848 NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
849 }
850 }
851 for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
852 {
853 std::vector<RlcPduListElement_s> rlcPduListPerLc;
854 for (std::size_t j = 0; j < nLayers; j++)
855 {
856 if (retx.at(j))
857 {
858 if (j < dci.m_ndi.size())
859 {
860 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
861 << dci.m_tbsSize.at(j));
862 rlcPduListPerLc.push_back(
863 (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
864 }
865 }
866 else
867 { // if no retx needed on layer j, push an RlcPduListElement_s object with
868 // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
869 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
870 RlcPduListElement_s emptyElement;
871 emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
872 .second.at(j)
873 .at(dci.m_harqProcess)
874 .at(k)
875 .m_logicalChannelIdentity;
876 emptyElement.m_size = 0;
877 rlcPduListPerLc.push_back(emptyElement);
878 }
879 }
880
881 if (!rlcPduListPerLc.empty())
882 {
883 newEl.m_rlcPduList.push_back(rlcPduListPerLc);
884 }
885 }
886 newEl.m_rnti = rnti;
887 newEl.m_dci = dci;
888 (*itHarq).second.at(harqId).m_rv = dci.m_rv;
889 // refresh timer
890 auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
891 if (itHarqTimer == m_dlHarqProcessesTimer.end())
892 {
893 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
894 }
895 (*itHarqTimer).second.at(harqId) = 0;
896 ret.m_buildDataList.push_back(newEl);
897 rntiAllocated.insert(rnti);
898 }
899 else
900 {
901 // update HARQ process status
902 NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
903 auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
904 if (it == m_dlHarqProcessesStatus.end())
905 {
906 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
907 << m_dlInfoListBuffered.at(i).m_rnti);
908 }
909 (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
910 auto itRlcPdu =
912 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
913 {
914 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
915 << m_dlInfoListBuffered.at(i).m_rnti);
916 }
917 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
918 {
919 (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
920 }
921 }
922 }
923 m_dlInfoListBuffered.clear();
924 m_dlInfoListBuffered = dlInfoListUntxed;
925
926 if (rbgAllocatedNum == rbgNum)
927 {
928 // all the RBGs are already allocated -> exit
929 if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
930 {
932 }
933 return;
934 }
935
936 std::map<uint16_t, pssFlowPerf_t> tdUeSet; // the result of TD scheduler
937
938 // schedulability check
939 std::map<uint16_t, pssFlowPerf_t> ueSet;
940 for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
941 {
942 if (LcActivePerFlow((*it).first) > 0)
943 {
944 ueSet[(*it).first] = (*it).second;
945 }
946 }
947
948 if (!ueSet.empty())
949 { // has data in RLC buffer
950
951 // Time Domain scheduler
952 std::vector<std::pair<double, uint16_t>> ueSet1;
953 std::vector<std::pair<double, uint16_t>> ueSet2;
954 for (auto it = ueSet.begin(); it != ueSet.end(); it++)
955 {
956 auto itRnti = rntiAllocated.find((*it).first);
957 if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
958 {
959 // UE already allocated for HARQ or without HARQ process available -> drop it
960 if (itRnti != rntiAllocated.end())
961 {
962 NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx" << (uint16_t)(*it).first);
963 }
964 if (!HarqProcessAvailability((*it).first))
965 {
966 NS_LOG_DEBUG(this << " RNTI discarded for HARQ id" << (uint16_t)(*it).first);
967 }
968 continue;
969 }
970
971 double metric = 0.0;
972 if ((*it).second.lastAveragedThroughput < (*it).second.targetThroughput)
973 {
974 // calculate TD BET metric
975 metric = 1 / (*it).second.lastAveragedThroughput;
976
977 // check first what are channel conditions for this UE, if CQI!=0
978 auto itCqi = m_p10CqiRxed.find((*it).first);
979 auto itTxMode = m_uesTxMode.find((*it).first);
980 if (itTxMode == m_uesTxMode.end())
981 {
982 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
983 }
984 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
985
986 uint8_t cqiSum = 0;
987 for (uint8_t j = 0; j < nLayer; j++)
988 {
989 if (itCqi == m_p10CqiRxed.end())
990 {
991 cqiSum += 1; // no info on this user -> lowest MCS
992 }
993 else
994 {
995 cqiSum = (*itCqi).second;
996 }
997 }
998 if (cqiSum != 0)
999 {
1000 ueSet1.emplace_back(metric, (*it).first);
1001 }
1002 }
1003 else
1004 {
1005 // calculate TD PF metric
1006 auto itCqi = m_p10CqiRxed.find((*it).first);
1007 auto itTxMode = m_uesTxMode.find((*it).first);
1008 if (itTxMode == m_uesTxMode.end())
1009 {
1010 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1011 }
1012 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1013 uint8_t wbCqi = 0;
1014 if (itCqi == m_p10CqiRxed.end())
1015 {
1016 wbCqi = 1; // start with lowest value
1017 }
1018 else
1019 {
1020 wbCqi = (*itCqi).second;
1021 }
1022
1023 if (wbCqi > 0)
1024 {
1025 if (LcActivePerFlow((*it).first) > 0)
1026 {
1027 // this UE has data to transmit
1028 double achievableRate = 0.0;
1029 for (uint8_t k = 0; k < nLayer; k++)
1030 {
1031 uint8_t mcs = 0;
1032 mcs = m_amc->GetMcsFromCqi(wbCqi);
1033 achievableRate += ((m_amc->GetDlTbSizeFromMcs(mcs, rbgSize) / 8) /
1034 0.001); // = TB size / TTI
1035 }
1036
1037 metric = achievableRate / (*it).second.lastAveragedThroughput;
1038 }
1039 ueSet2.emplace_back(metric, (*it).first);
1040 } // end of wbCqi
1041 }
1042 } // end of ueSet
1043
1044 if (!ueSet1.empty() || !ueSet2.empty())
1045 {
1046 // sorting UE in ueSet1 and ueSet1 in descending order based on their metric value
1047 std::sort(ueSet1.rbegin(), ueSet1.rend());
1048 std::sort(ueSet2.rbegin(), ueSet2.rend());
1049
1050 // select UE set for frequency domain scheduler
1051 uint32_t nMux;
1052 if (m_nMux > 0)
1053 {
1054 nMux = m_nMux;
1055 }
1056 else
1057 {
1058 // select half number of UE
1059 if (ueSet1.size() + ueSet2.size() <= 2)
1060 {
1061 nMux = 1;
1062 }
1063 else
1064 {
1065 // TD scheduler only transfers half selected UE per RTT to TD scheduler
1066 nMux = (int)((ueSet1.size() + ueSet2.size()) / 2);
1067 }
1068 }
1069
1070 for (auto itSet = ueSet1.begin(); itSet != ueSet1.end() && nMux != 0; itSet++)
1071 {
1072 auto itUe = m_flowStatsDl.find((*itSet).second);
1073 tdUeSet[(*itUe).first] = (*itUe).second;
1074 nMux--;
1075 }
1076
1077 for (auto itSet = ueSet2.begin(); itSet != ueSet2.end() && nMux != 0; itSet++)
1078 {
1079 auto itUe = m_flowStatsDl.find((*itSet).second);
1080 tdUeSet[(*itUe).first] = (*itUe).second;
1081 nMux--;
1082 }
1083
1084 if (m_fdSchedulerType == "CoItA")
1085 {
1086 // FD scheduler: Carrier over Interference to Average (CoItA)
1087 std::map<uint16_t, uint8_t> sbCqiSum;
1088 for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
1089 {
1090 uint8_t sum = 0;
1091 for (int i = 0; i < rbgNum; i++)
1092 {
1093 auto itCqi = m_a30CqiRxed.find((*it).first);
1094 auto itTxMode = m_uesTxMode.find((*it).first);
1095 if (itTxMode == m_uesTxMode.end())
1096 {
1097 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1098 }
1099 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1100 std::vector<uint8_t> sbCqis;
1101 if (itCqi == m_a30CqiRxed.end())
1102 {
1103 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1104 }
1105 else
1106 {
1107 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1108 }
1109
1110 uint8_t cqi1 = sbCqis.at(0);
1111 uint8_t cqi2 = 0;
1112 if (sbCqis.size() > 1)
1113 {
1114 cqi2 = sbCqis.at(1);
1115 }
1116
1117 uint8_t sbCqi = 0;
1118 if ((cqi1 > 0) ||
1119 (cqi2 >
1120 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1121 {
1122 for (uint8_t k = 0; k < nLayer; k++)
1123 {
1124 if (sbCqis.size() > k)
1125 {
1126 sbCqi = sbCqis.at(k);
1127 }
1128 else
1129 {
1130 // no info on this subband
1131 sbCqi = 0;
1132 }
1133 sum += sbCqi;
1134 }
1135 } // end if cqi
1136 } // end of rbgNum
1137
1138 sbCqiSum[(*it).first] = sum;
1139 } // end tdUeSet
1140
1141 for (int i = 0; i < rbgNum; i++)
1142 {
1143 if (rbgMap.at(i))
1144 {
1145 continue;
1146 }
1147
1148 auto itMax = tdUeSet.end();
1149 double metricMax = 0.0;
1150 for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
1151 {
1152 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
1153 {
1154 continue;
1155 }
1156
1157 // calculate PF weight
1158 double weight =
1159 (*it).second.targetThroughput / (*it).second.lastAveragedThroughput;
1160 if (weight < 1.0)
1161 {
1162 weight = 1.0;
1163 }
1164
1165 auto itSbCqiSum = sbCqiSum.find((*it).first);
1166
1167 auto itCqi = m_a30CqiRxed.find((*it).first);
1168 auto itTxMode = m_uesTxMode.find((*it).first);
1169 if (itTxMode == m_uesTxMode.end())
1170 {
1171 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1172 }
1173 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1174 std::vector<uint8_t> sbCqis;
1175 if (itCqi == m_a30CqiRxed.end())
1176 {
1177 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1178 }
1179 else
1180 {
1181 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1182 }
1183
1184 uint8_t cqi1 = sbCqis.at(0);
1185 uint8_t cqi2 = 0;
1186 if (sbCqis.size() > 1)
1187 {
1188 cqi2 = sbCqis.at(1);
1189 }
1190
1191 uint8_t sbCqi = 0;
1192 double colMetric = 0.0;
1193 if ((cqi1 > 0) ||
1194 (cqi2 >
1195 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1196 {
1197 for (uint8_t k = 0; k < nLayer; k++)
1198 {
1199 if (sbCqis.size() > k)
1200 {
1201 sbCqi = sbCqis.at(k);
1202 }
1203 else
1204 {
1205 // no info on this subband
1206 sbCqi = 0;
1207 }
1208 colMetric += (double)sbCqi / (double)(*itSbCqiSum).second;
1209 }
1210 } // end if cqi
1211
1212 double metric = 0.0;
1213 if (colMetric != 0)
1214 {
1215 metric = weight * colMetric;
1216 }
1217 else
1218 {
1219 metric = 1;
1220 }
1221
1222 if (metric > metricMax)
1223 {
1224 metricMax = metric;
1225 itMax = it;
1226 }
1227 } // end of tdUeSet
1228
1229 if (itMax == tdUeSet.end())
1230 {
1231 // no UE available for downlink
1232 }
1233 else
1234 {
1235 allocationMap[(*itMax).first].push_back(i);
1236 rbgMap.at(i) = true;
1237 }
1238 } // end of rbgNum
1239
1240 } // end of CoIta
1241
1242 if (m_fdSchedulerType == "PFsch")
1243 {
1244 // FD scheduler: Proportional Fair scheduled (PFsch)
1245 for (int i = 0; i < rbgNum; i++)
1246 {
1247 if (rbgMap.at(i))
1248 {
1249 continue;
1250 }
1251
1252 auto itMax = tdUeSet.end();
1253 double metricMax = 0.0;
1254 for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
1255 {
1256 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
1257 {
1258 continue;
1259 }
1260 // calculate PF weight
1261 double weight =
1262 (*it).second.targetThroughput / (*it).second.lastAveragedThroughput;
1263 if (weight < 1.0)
1264 {
1265 weight = 1.0;
1266 }
1267
1268 auto itCqi = m_a30CqiRxed.find((*it).first);
1269 auto itTxMode = m_uesTxMode.find((*it).first);
1270 if (itTxMode == m_uesTxMode.end())
1271 {
1272 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1273 }
1274 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1275 std::vector<uint8_t> sbCqis;
1276 if (itCqi == m_a30CqiRxed.end())
1277 {
1278 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1279 }
1280 else
1281 {
1282 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1283 }
1284
1285 uint8_t cqi1 = sbCqis.at(0);
1286 uint8_t cqi2 = 0;
1287 if (sbCqis.size() > 1)
1288 {
1289 cqi2 = sbCqis.at(1);
1290 }
1291
1292 double schMetric = 0.0;
1293 if ((cqi1 > 0) ||
1294 (cqi2 >
1295 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1296 {
1297 double achievableRate = 0.0;
1298 for (uint8_t k = 0; k < nLayer; k++)
1299 {
1300 uint8_t mcs = 0;
1301 if (sbCqis.size() > k)
1302 {
1303 mcs = m_amc->GetMcsFromCqi(sbCqis.at(k));
1304 }
1305 else
1306 {
1307 // no info on this subband -> worst MCS
1308 mcs = 0;
1309 }
1310 achievableRate += ((m_amc->GetDlTbSizeFromMcs(mcs, rbgSize) / 8) /
1311 0.001); // = TB size / TTI
1312 }
1313 schMetric = achievableRate / (*it).second.secondLastAveragedThroughput;
1314 } // end if cqi
1315
1316 double metric = 0.0;
1317 metric = weight * schMetric;
1318
1319 if (metric > metricMax)
1320 {
1321 metricMax = metric;
1322 itMax = it;
1323 }
1324 } // end of tdUeSet
1325
1326 if (itMax == tdUeSet.end())
1327 {
1328 // no UE available for downlink
1329 }
1330 else
1331 {
1332 allocationMap[(*itMax).first].push_back(i);
1333 rbgMap.at(i) = true;
1334 }
1335
1336 } // end of rbgNum
1337
1338 } // end of PFsch
1339
1340 } // end if ueSet1 || ueSet2
1341
1342 } // end if ueSet
1343
1344 // reset TTI stats of users
1345 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1346 {
1347 (*itStats).second.lastTtiBytesTransmitted = 0;
1348 }
1349
1350 // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1351 // creating the correspondent DCIs
1352 auto itMap = allocationMap.begin();
1353 while (itMap != allocationMap.end())
1354 {
1355 // create new BuildDataListElement_s for this LC
1357 newEl.m_rnti = (*itMap).first;
1358 // create the DlDciListElement_s
1359 DlDciListElement_s newDci;
1360 newDci.m_rnti = (*itMap).first;
1361 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1362
1363 uint16_t lcActives = LcActivePerFlow((*itMap).first);
1364 NS_LOG_INFO(this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1365 if (lcActives == 0)
1366 {
1367 // Set to max value, to avoid divide by 0 below
1368 lcActives = (uint16_t)65535; // UINT16_MAX;
1369 }
1370 uint16_t RbgPerRnti = (*itMap).second.size();
1371 auto itCqi = m_a30CqiRxed.find((*itMap).first);
1372 auto itTxMode = m_uesTxMode.find((*itMap).first);
1373 if (itTxMode == m_uesTxMode.end())
1374 {
1375 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
1376 }
1377 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1378 std::vector<uint8_t> worstCqi(2, 15);
1379 if (itCqi != m_a30CqiRxed.end())
1380 {
1381 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1382 {
1383 if ((*itCqi).second.m_higherLayerSelected.size() > (*itMap).second.at(k))
1384 {
1385 NS_LOG_INFO(this << " RBG " << (*itMap).second.at(k) << " CQI "
1386 << (uint16_t)((*itCqi)
1387 .second.m_higherLayerSelected
1388 .at((*itMap).second.at(k))
1389 .m_sbCqi.at(0)));
1390 for (uint8_t j = 0; j < nLayer; j++)
1391 {
1392 if ((*itCqi)
1393 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1394 .m_sbCqi.size() > j)
1395 {
1396 if (((*itCqi)
1397 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1398 .m_sbCqi.at(j)) < worstCqi.at(j))
1399 {
1400 worstCqi.at(j) =
1401 ((*itCqi)
1402 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1403 .m_sbCqi.at(j));
1404 }
1405 }
1406 else
1407 {
1408 // no CQI for this layer of this suband -> worst one
1409 worstCqi.at(j) = 1;
1410 }
1411 }
1412 }
1413 else
1414 {
1415 for (uint8_t j = 0; j < nLayer; j++)
1416 {
1417 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1418 }
1419 }
1420 }
1421 }
1422 else
1423 {
1424 for (uint8_t j = 0; j < nLayer; j++)
1425 {
1426 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1427 }
1428 }
1429 for (uint8_t j = 0; j < nLayer; j++)
1430 {
1431 NS_LOG_INFO(this << " Layer " << (uint16_t)j << " CQI selected "
1432 << (uint16_t)worstCqi.at(j));
1433 }
1434 uint32_t bytesTxed = 0;
1435 for (uint8_t j = 0; j < nLayer; j++)
1436 {
1437 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
1438 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
1439 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1440 newDci.m_tbsSize.push_back(tbSize);
1441 NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
1442 << m_amc->GetMcsFromCqi(worstCqi.at(j)));
1443 bytesTxed += tbSize;
1444 }
1445
1446 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1447 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1448 uint32_t rbgMask = 0;
1449 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1450 {
1451 rbgMask = rbgMask + (0x1 << (*itMap).second.at(k));
1452 NS_LOG_INFO(this << " Allocated RBG " << (*itMap).second.at(k));
1453 }
1454 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1455
1456 // create the rlc PDUs -> equally divide resources among actives LCs
1457 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1458 {
1459 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1460 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1461 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1462 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1463 {
1464 std::vector<RlcPduListElement_s> newRlcPduLe;
1465 for (uint8_t j = 0; j < nLayer; j++)
1466 {
1467 RlcPduListElement_s newRlcEl;
1468 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1469 newRlcEl.m_size = newDci.m_tbsSize.at(j) / lcActives;
1470 NS_LOG_INFO(this << " LCID " << (uint32_t)newRlcEl.m_logicalChannelIdentity
1471 << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1472 newRlcPduLe.push_back(newRlcEl);
1474 newRlcEl.m_logicalChannelIdentity,
1475 newRlcEl.m_size);
1476 if (m_harqOn)
1477 {
1478 // store RLC PDU list for HARQ
1479 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1480 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1481 {
1482 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1483 << (*itMap).first);
1484 }
1485 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1486 }
1487 }
1488 newEl.m_rlcPduList.push_back(newRlcPduLe);
1489 }
1490 if ((*itBufReq).first.m_rnti > (*itMap).first)
1491 {
1492 break;
1493 }
1494 }
1495 for (uint8_t j = 0; j < nLayer; j++)
1496 {
1497 newDci.m_ndi.push_back(1);
1498 newDci.m_rv.push_back(0);
1499 }
1500
1501 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1502
1503 newEl.m_dci = newDci;
1504
1505 if (m_harqOn)
1506 {
1507 // store DCI for HARQ
1508 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1509 if (itDci == m_dlHarqProcessesDciBuffer.end())
1510 {
1511 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1512 << newEl.m_rnti);
1513 }
1514 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1515 // refresh timer
1516 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1517 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1518 {
1519 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1520 }
1521 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1522 }
1523
1524 // ...more parameters -> ignored in this version
1525
1526 ret.m_buildDataList.push_back(newEl);
1527 // update UE stats
1528 auto it = m_flowStatsDl.find((*itMap).first);
1529 if (it != m_flowStatsDl.end())
1530 {
1531 (*it).second.lastTtiBytesTransmitted = bytesTxed;
1532 NS_LOG_INFO(this << " UE total bytes txed " << (*it).second.lastTtiBytesTransmitted);
1533 }
1534 else
1535 {
1536 NS_FATAL_ERROR(this << " No Stats for this allocated UE");
1537 }
1538
1539 itMap++;
1540 } // end while allocation
1541 ret.m_nrOfPdcchOfdmSymbols = 1; /// \todo check correct value according the DCIs txed
1542
1543 // update UEs stats
1544 NS_LOG_INFO(this << " Update UEs statistics");
1545 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1546 {
1547 auto itUeScheduleted = tdUeSet.end();
1548 itUeScheduleted = tdUeSet.find((*itStats).first);
1549 if (itUeScheduleted != tdUeSet.end())
1550 {
1551 (*itStats).second.secondLastAveragedThroughput =
1552 ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) +
1553 ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1554 }
1555
1556 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1557 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
1558 // Evolution, Ed Wiley)
1559 (*itStats).second.lastAveragedThroughput =
1560 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
1561 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1562 (*itStats).second.lastTtiBytesTransmitted = 0;
1563 }
1564
1566}
1567
1568void
1571{
1572 NS_LOG_FUNCTION(this);
1573
1574 m_rachList = params.m_rachList;
1575}
1576
1577void
1580{
1581 NS_LOG_FUNCTION(this);
1583
1584 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1585 {
1586 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1587 {
1588 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1589 << " reported");
1590 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1591 auto it = m_p10CqiRxed.find(rnti);
1592 if (it == m_p10CqiRxed.end())
1593 {
1594 // create the new entry
1595 m_p10CqiRxed[rnti] =
1596 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1597 // generate correspondent timer
1599 }
1600 else
1601 {
1602 // update the CQI value and refresh correspondent timer
1603 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1604 // update correspondent timer
1605 auto itTimers = m_p10CqiTimers.find(rnti);
1606 (*itTimers).second = m_cqiTimersThreshold;
1607 }
1608 }
1609 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1610 {
1611 // subband CQI reporting high layer configured
1612 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1613 auto it = m_a30CqiRxed.find(rnti);
1614 if (it == m_a30CqiRxed.end())
1615 {
1616 // create the new entry
1617 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1619 }
1620 else
1621 {
1622 // update the CQI value and refresh correspondent timer
1623 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1624 auto itTimers = m_a30CqiTimers.find(rnti);
1625 (*itTimers).second = m_cqiTimersThreshold;
1626 }
1627 }
1628 else
1629 {
1630 NS_LOG_ERROR(this << " CQI type unknown");
1631 }
1632 }
1633}
1634
1635double
1636PssFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1637{
1638 auto itCqi = m_ueCqi.find(rnti);
1639 if (itCqi == m_ueCqi.end())
1640 {
1641 // no cqi info about this UE
1642 return NO_SINR;
1643 }
1644 else
1645 {
1646 // take the average SINR value among the available
1647 double sinrSum = 0;
1648 unsigned int sinrNum = 0;
1649 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1650 {
1651 double sinr = (*itCqi).second.at(i);
1652 if (sinr != NO_SINR)
1653 {
1654 sinrSum += sinr;
1655 sinrNum++;
1656 }
1657 }
1658 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1659 // store the value
1660 (*itCqi).second.at(rb) = estimatedSinr;
1661 return estimatedSinr;
1662 }
1663}
1664
1665void
1668{
1669 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1670 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1671
1674
1675 // Generate RBs map
1677 std::vector<bool> rbMap;
1678 uint16_t rbAllocatedNum = 0;
1679 std::set<uint16_t> rntiAllocated;
1680 std::vector<uint16_t> rbgAllocationMap;
1681 // update with RACH allocation map
1682 rbgAllocationMap = m_rachAllocationMap;
1683 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1684 m_rachAllocationMap.clear();
1686
1687 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1688
1690
1691 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1692 {
1693 if (*it)
1694 {
1695 rbAllocatedNum++;
1696 }
1697 }
1698
1699 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1700 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1701
1702 // remove RACH allocation
1703 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1704 {
1705 if (rbgAllocationMap.at(i) != 0)
1706 {
1707 rbMap.at(i) = true;
1708 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1709 }
1710 }
1711
1712 if (m_harqOn)
1713 {
1714 // Process UL HARQ feedback
1715 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1716 {
1717 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1718 {
1719 // retx correspondent block: retrieve the UL-DCI
1720 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1721 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1722 if (itProcId == m_ulHarqCurrentProcessId.end())
1723 {
1724 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1725 }
1726 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1727 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1728 << " i " << i << " size " << params.m_ulInfoList.size());
1729 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1730 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1731 {
1732 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1733 continue;
1734 }
1735 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1736 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1737 if (itStat == m_ulHarqProcessesStatus.end())
1738 {
1739 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1740 }
1741 if ((*itStat).second.at(harqId) >= 3)
1742 {
1743 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1744 continue;
1745 }
1746 bool free = true;
1747 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1748 {
1749 if (rbMap.at(j))
1750 {
1751 free = false;
1752 NS_LOG_INFO(this << " BUSY " << j);
1753 }
1754 }
1755 if (free)
1756 {
1757 // retx on the same RBs
1758 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1759 {
1760 rbMap.at(j) = true;
1761 rbgAllocationMap.at(j) = dci.m_rnti;
1762 NS_LOG_INFO("\tRB " << j);
1763 rbAllocatedNum++;
1764 }
1765 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1766 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1767 << (*itStat).second.at(harqId) + 1);
1768 }
1769 else
1770 {
1771 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1772 continue;
1773 }
1774 dci.m_ndi = 0;
1775 // Update HARQ buffers with new HarqId
1776 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1777 (*itStat).second.at(harqId) = 0;
1778 (*itHarq).second.at((*itProcId).second) = dci;
1779 ret.m_dciList.push_back(dci);
1780 rntiAllocated.insert(dci.m_rnti);
1781 }
1782 else
1783 {
1784 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1785 << params.m_ulInfoList.at(i).m_rnti);
1786 }
1787 }
1788 }
1789
1790 std::map<uint16_t, uint32_t>::iterator it;
1791 int nflows = 0;
1792
1793 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1794 {
1795 auto itRnti = rntiAllocated.find((*it).first);
1796 // select UEs with queues not empty and not yet allocated for HARQ
1797 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1798 {
1799 nflows++;
1800 }
1801 }
1802
1803 if (nflows == 0)
1804 {
1805 if (!ret.m_dciList.empty())
1806 {
1807 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1809 }
1810
1811 return; // no flows to be scheduled
1812 }
1813
1814 // Divide the remaining resources equally among the active users starting from the subsequent
1815 // one served last scheduling trigger
1816 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1817 uint16_t rbPerFlow =
1818 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1819
1820 if (rbPerFlow < 3)
1821 {
1822 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1823 // >= 7 bytes
1824 }
1825 int rbAllocated = 0;
1826
1827 if (m_nextRntiUl != 0)
1828 {
1829 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1830 {
1831 if ((*it).first == m_nextRntiUl)
1832 {
1833 break;
1834 }
1835 }
1836 if (it == m_ceBsrRxed.end())
1837 {
1838 NS_LOG_ERROR(this << " no user found");
1839 }
1840 }
1841 else
1842 {
1843 it = m_ceBsrRxed.begin();
1844 m_nextRntiUl = (*it).first;
1845 }
1846 do
1847 {
1848 auto itRnti = rntiAllocated.find((*it).first);
1849 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1850 {
1851 // UE already allocated for UL-HARQ -> skip it
1852 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
1853 << (*it).first);
1854 it++;
1855 if (it == m_ceBsrRxed.end())
1856 {
1857 // restart from the first
1858 it = m_ceBsrRxed.begin();
1859 }
1860 continue;
1861 }
1862 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1863 {
1864 // limit to physical resources last resource assignment
1865 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1866 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1867 if (rbPerFlow < 3)
1868 {
1869 // terminate allocation
1870 rbPerFlow = 0;
1871 }
1872 }
1873
1874 rbAllocated = 0;
1875 UlDciListElement_s uldci;
1876 uldci.m_rnti = (*it).first;
1877 uldci.m_rbLen = rbPerFlow;
1878 bool allocated = false;
1879 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
1880 << " flows " << nflows);
1881 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
1882 (rbPerFlow != 0))
1883 {
1884 // check availability
1885 bool free = true;
1886 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1887 {
1888 if (rbMap.at(j))
1889 {
1890 free = false;
1891 break;
1892 }
1893 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
1894 {
1895 free = false;
1896 break;
1897 }
1898 }
1899 if (free)
1900 {
1901 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
1902 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1903 uldci.m_rbStart = rbAllocated;
1904
1905 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1906 {
1907 rbMap.at(j) = true;
1908 // store info on allocation for managing ul-cqi interpretation
1909 rbgAllocationMap.at(j) = (*it).first;
1910 }
1911 rbAllocated += rbPerFlow;
1912 allocated = true;
1913 break;
1914 }
1915 rbAllocated++;
1916 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1917 {
1918 // limit to physical resources last resource assignment
1919 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1920 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1921 if (rbPerFlow < 3)
1922 {
1923 // terminate allocation
1924 rbPerFlow = 0;
1925 }
1926 }
1927 }
1928 if (!allocated)
1929 {
1930 // unable to allocate new resource: finish scheduling
1931 // m_nextRntiUl = (*it).first;
1932 // if (ret.m_dciList.size () > 0)
1933 // {
1934 // m_schedSapUser->SchedUlConfigInd (ret);
1935 // }
1936 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
1937 break;
1938 }
1939
1940 auto itCqi = m_ueCqi.find((*it).first);
1941 int cqi = 0;
1942 if (itCqi == m_ueCqi.end())
1943 {
1944 // no cqi info about this UE
1945 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1946 }
1947 else
1948 {
1949 // take the lowest CQI value (worst RB)
1950 NS_ABORT_MSG_IF((*itCqi).second.empty(),
1951 "CQI of RNTI = " << (*it).first << " has expired");
1952 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
1953 if (minSinr == NO_SINR)
1954 {
1955 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
1956 }
1957 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1958 {
1959 double sinr = (*itCqi).second.at(i);
1960 if (sinr == NO_SINR)
1961 {
1962 sinr = EstimateUlSinr((*it).first, i);
1963 }
1964 if (sinr < minSinr)
1965 {
1966 minSinr = sinr;
1967 }
1968 }
1969
1970 // translate SINR -> cqi: WILD ACK: same as DL
1971 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
1972 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
1973 if (cqi == 0)
1974 {
1975 it++;
1976 if (it == m_ceBsrRxed.end())
1977 {
1978 // restart from the first
1979 it = m_ceBsrRxed.begin();
1980 }
1981 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
1982 // remove UE from allocation map
1983 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1984 {
1985 rbgAllocationMap.at(i) = 0;
1986 }
1987 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1988 }
1989 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
1990 }
1991
1992 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
1994 uldci.m_ndi = 1;
1995 uldci.m_cceIndex = 0;
1996 uldci.m_aggrLevel = 1;
1997 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1998 uldci.m_hopping = false;
1999 uldci.m_n2Dmrs = 0;
2000 uldci.m_tpc = 0; // no power control
2001 uldci.m_cqiRequest = false; // only period CQI at this stage
2002 uldci.m_ulIndex = 0; // TDD parameter
2003 uldci.m_dai = 1; // TDD parameter
2004 uldci.m_freqHopping = 0;
2005 uldci.m_pdcchPowerOffset = 0; // not used
2006 ret.m_dciList.push_back(uldci);
2007 // store DCI for HARQ_PERIOD
2008 uint8_t harqId = 0;
2009 if (m_harqOn)
2010 {
2011 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
2012 if (itProcId == m_ulHarqCurrentProcessId.end())
2013 {
2014 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
2015 }
2016 harqId = (*itProcId).second;
2017 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
2018 if (itDci == m_ulHarqProcessesDciBuffer.end())
2019 {
2020 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
2021 << uldci.m_rnti);
2022 }
2023 (*itDci).second.at(harqId) = uldci;
2024 // Update HARQ process status (RV 0)
2025 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
2026 if (itStat == m_ulHarqProcessesStatus.end())
2027 {
2028 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
2029 << uldci.m_rnti);
2030 }
2031 (*itStat).second.at(harqId) = 0;
2032 }
2033
2034 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
2035 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
2036 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
2037 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
2038 << (uint16_t)harqId);
2039
2040 it++;
2041 if (it == m_ceBsrRxed.end())
2042 {
2043 // restart from the first
2044 it = m_ceBsrRxed.begin();
2045 }
2046 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2047 {
2048 // Stop allocation: no more PRBs
2049 m_nextRntiUl = (*it).first;
2050 break;
2051 }
2052 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
2053
2054 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
2056}
2057
2058void
2064
2065void
2071
2072void
2075{
2076 NS_LOG_FUNCTION(this);
2077
2078 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
2079 {
2080 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
2081 {
2082 // buffer status report
2083 // note that this scheduler does not differentiate the
2084 // allocation according to which LCGs have more/less bytes
2085 // to send.
2086 // Hence the BSR of different LCGs are just summed up to get
2087 // a total queue size that is used for allocation purposes.
2088
2089 uint32_t buffer = 0;
2090 for (uint8_t lcg = 0; lcg < 4; ++lcg)
2091 {
2092 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
2093 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
2094 }
2095
2096 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
2097 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
2098 auto it = m_ceBsrRxed.find(rnti);
2099 if (it == m_ceBsrRxed.end())
2100 {
2101 // create the new entry
2102 m_ceBsrRxed[rnti] = buffer;
2103 }
2104 else
2105 {
2106 // update the buffer size value
2107 (*it).second = buffer;
2108 }
2109 }
2110 }
2111}
2112
2113void
2116{
2117 NS_LOG_FUNCTION(this);
2118 // retrieve the allocation for this subframe
2119 switch (m_ulCqiFilter)
2120 {
2122 // filter all the CQIs that are not SRS based
2123 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2124 {
2125 return;
2126 }
2127 }
2128 break;
2130 // filter all the CQIs that are not SRS based
2131 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2132 {
2133 return;
2134 }
2135 }
2136 break;
2137 default:
2138 NS_FATAL_ERROR("Unknown UL CQI type");
2139 }
2140
2141 switch (params.m_ulCqi.m_type)
2142 {
2143 case UlCqi_s::PUSCH: {
2144 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
2145 << " subframe no. " << (0xF & params.m_sfnSf));
2146 auto itMap = m_allocationMaps.find(params.m_sfnSf);
2147 if (itMap == m_allocationMaps.end())
2148 {
2149 return;
2150 }
2151 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
2152 {
2153 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2154 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
2155 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
2156 if (itCqi == m_ueCqi.end())
2157 {
2158 // create a new entry
2159 std::vector<double> newCqi;
2160 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2161 {
2162 if (i == j)
2163 {
2164 newCqi.push_back(sinr);
2165 }
2166 else
2167 {
2168 // initialize with NO_SINR value.
2169 newCqi.push_back(NO_SINR);
2170 }
2171 }
2172 m_ueCqi[(*itMap).second.at(i)] = newCqi;
2173 // generate correspondent timer
2174 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
2175 }
2176 else
2177 {
2178 // update the value
2179 (*itCqi).second.at(i) = sinr;
2180 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
2181 << sinr);
2182 // update correspondent timer
2183 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
2184 (*itTimers).second = m_cqiTimersThreshold;
2185 }
2186 }
2187 // remove obsolete info on allocation
2188 m_allocationMaps.erase(itMap);
2189 }
2190 break;
2191 case UlCqi_s::SRS: {
2192 // get the RNTI from vendor specific parameters
2193 uint16_t rnti = 0;
2194 NS_ASSERT(!params.m_vendorSpecificList.empty());
2195 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
2196 {
2197 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
2198 {
2199 Ptr<SrsCqiRntiVsp> vsp =
2200 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
2201 rnti = vsp->GetRnti();
2202 }
2203 }
2204 auto itCqi = m_ueCqi.find(rnti);
2205 if (itCqi == m_ueCqi.end())
2206 {
2207 // create a new entry
2208 std::vector<double> newCqi;
2209 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2210 {
2211 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2212 newCqi.push_back(sinr);
2213 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
2214 << sinr);
2215 }
2216 m_ueCqi[rnti] = newCqi;
2217 // generate correspondent timer
2219 }
2220 else
2221 {
2222 // update the values
2223 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2224 {
2225 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2226 (*itCqi).second.at(j) = sinr;
2227 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
2228 << sinr);
2229 }
2230 // update correspondent timer
2231 auto itTimers = m_ueCqiTimers.find(rnti);
2232 (*itTimers).second = m_cqiTimersThreshold;
2233 }
2234 }
2235 break;
2236 case UlCqi_s::PUCCH_1:
2237 case UlCqi_s::PUCCH_2:
2238 case UlCqi_s::PRACH: {
2239 NS_FATAL_ERROR("PssFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2240 }
2241 break;
2242 default:
2243 NS_FATAL_ERROR("Unknown type of UL-CQI");
2244 }
2245}
2246
2247void
2249{
2250 // refresh DL CQI P01 Map
2251 auto itP10 = m_p10CqiTimers.begin();
2252 while (itP10 != m_p10CqiTimers.end())
2253 {
2254 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
2255 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2256 if ((*itP10).second == 0)
2257 {
2258 // delete correspondent entries
2259 auto itMap = m_p10CqiRxed.find((*itP10).first);
2260 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
2261 " Does not find CQI report for user " << (*itP10).first);
2262 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
2263 m_p10CqiRxed.erase(itMap);
2264 auto temp = itP10;
2265 itP10++;
2266 m_p10CqiTimers.erase(temp);
2267 }
2268 else
2269 {
2270 (*itP10).second--;
2271 itP10++;
2272 }
2273 }
2274
2275 // refresh DL CQI A30 Map
2276 auto itA30 = m_a30CqiTimers.begin();
2277 while (itA30 != m_a30CqiTimers.end())
2278 {
2279 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
2280 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2281 if ((*itA30).second == 0)
2282 {
2283 // delete correspondent entries
2284 auto itMap = m_a30CqiRxed.find((*itA30).first);
2285 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2286 " Does not find CQI report for user " << (*itA30).first);
2287 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2288 m_a30CqiRxed.erase(itMap);
2289 auto temp = itA30;
2290 itA30++;
2291 m_a30CqiTimers.erase(temp);
2292 }
2293 else
2294 {
2295 (*itA30).second--;
2296 itA30++;
2297 }
2298 }
2299}
2300
2301void
2303{
2304 // refresh UL CQI Map
2305 auto itUl = m_ueCqiTimers.begin();
2306 while (itUl != m_ueCqiTimers.end())
2307 {
2308 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2309 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2310 if ((*itUl).second == 0)
2311 {
2312 // delete correspondent entries
2313 auto itMap = m_ueCqi.find((*itUl).first);
2314 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2315 " Does not find CQI report for user " << (*itUl).first);
2316 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2317 (*itMap).second.clear();
2318 m_ueCqi.erase(itMap);
2319 auto temp = itUl;
2320 itUl++;
2321 m_ueCqiTimers.erase(temp);
2322 }
2323 else
2324 {
2325 (*itUl).second--;
2326 itUl++;
2327 }
2328 }
2329}
2330
2331void
2332PssFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2333{
2334 LteFlowId_t flow(rnti, lcid);
2335 auto it = m_rlcBufferReq.find(flow);
2336 if (it != m_rlcBufferReq.end())
2337 {
2338 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2339 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2340 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2341 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2342 // Update queues: RLC tx order Status, ReTx, Tx
2343 // Update status queue
2344 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2345 {
2346 (*it).second.m_rlcStatusPduSize = 0;
2347 }
2348 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2349 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2350 {
2351 (*it).second.m_rlcRetransmissionQueueSize = 0;
2352 }
2353 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2354 {
2355 uint32_t rlcOverhead;
2356 if (lcid == 1)
2357 {
2358 // for SRB1 (using RLC AM) it's better to
2359 // overestimate RLC overhead rather than
2360 // underestimate it and risk unneeded
2361 // segmentation which increases delay
2362 rlcOverhead = 4;
2363 }
2364 else
2365 {
2366 // minimum RLC overhead due to header
2367 rlcOverhead = 2;
2368 }
2369 // update transmission queue
2370 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2371 {
2372 (*it).second.m_rlcTransmissionQueueSize = 0;
2373 }
2374 else
2375 {
2376 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2377 }
2378 }
2379 }
2380 else
2381 {
2382 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2383 }
2384}
2385
2386void
2387PssFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2388{
2389 size = size - 2; // remove the minimum RLC overhead
2390 auto it = m_ceBsrRxed.find(rnti);
2391 if (it != m_ceBsrRxed.end())
2392 {
2393 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2394 if ((*it).second >= size)
2395 {
2396 (*it).second -= size;
2397 }
2398 else
2399 {
2400 (*it).second = 0;
2401 }
2402 }
2403 else
2404 {
2405 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2406 }
2407}
2408
2409void
2411{
2412 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2414 params.m_rnti = rnti;
2415 params.m_transmissionMode = txMode;
2417}
2418
2419} // namespace ns3
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
Provides the CSCHED SAP.
FfMacCschedSapUser class.
virtual void CschedUeConfigCnf(const CschedUeConfigCnfParameters &params)=0
CSCHED_UE_CONFIG_CNF.
virtual void CschedUeConfigUpdateInd(const CschedUeConfigUpdateIndParameters &params)=0
CSCHED_UE_UPDATE_IND.
Provides the SCHED SAP.
FfMacSchedSapUser class.
virtual void SchedUlConfigInd(const SchedUlConfigIndParameters &params)=0
SCHED_UL_CONFIG_IND.
virtual void SchedDlConfigInd(const SchedDlConfigIndParameters &params)=0
SCHED_DL_CONFIG_IND.
This abstract base class identifies the interface by means of which the helper object can plug on the...
UlCqiFilter_t m_ulCqiFilter
UL CQI filter.
static double fpS11dot3toDouble(uint16_t val)
Convert from fixed point S11.3 notation to double.
Service Access Point (SAP) offered by the Frequency Reuse algorithm instance to the MAC Scheduler ins...
Definition lte-ffr-sap.h:29
virtual uint8_t GetTpc(uint16_t rnti)=0
GetTpc.
virtual std::vector< bool > GetAvailableUlRbg()=0
Get vector of available RB in UL for this Cell.
virtual void ReportUlCqiInfo(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)=0
ReportUlCqiInfo.
virtual bool IsUlRbgAvailableForUe(int i, uint16_t rnti)=0
Check if UE can be served on i-th RB in UL.
virtual void ReportDlCqiInfo(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)=0
ReportDlCqiInfo.
virtual std::vector< bool > GetAvailableDlRbg()=0
Get vector of available RBG in DL for this Cell.
virtual uint16_t GetMinContinuousUlBandwidth()=0
Get the minimum continuous Ul bandwidth.
virtual bool IsDlRbgAvailableForUe(int i, uint16_t rnti)=0
Check if UE can be served on i-th RB in DL.
Service Access Point (SAP) offered by the eNodeB RRC instance to the Frequency Reuse algorithm instan...
Template for the implementation of the LteFfrSapUser as a member of an owner class of type C to which...
Implements the SCHED SAP and CSCHED SAP for a Priority Set scheduler.
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process status.
void DoDispose() override
Destructor implementation.
void DoSchedDlCqiInfoReq(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CQI info request function.
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL SINR function.
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE's timers on DL CQI P01 received.
std::vector< RachListElement_s > m_rachList
RACH list.
bool HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI buffer.
void DoCschedLcReleaseReq(const FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
CSched LC release request function.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE's buffer status reports received.
LteFfrSapUser * GetLteFfrSapUser() override
FfMacSchedSapProvider * GetFfMacSchedSapProvider() override
void DoSchedDlPagingBufferReq(const FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL paging buffer request function.
FfMacCschedSapProvider * m_cschedSapProvider
CSched SAP provider.
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE's DL CQI A30 received.
void DoSchedUlSrInfoReq(const FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL SR info request function.
friend class MemberSchedSapProvider< PssFfMacScheduler >
allow MemberSchedSapProvider<PssFfMacScheduler> class friend access
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE's DL CQI P01 received.
void DoSchedDlMacBufferReq(const FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC buffer request function.
unsigned int LcActivePerFlow(uint16_t rnti)
Get LC active flow function.
void DoSchedUlCqiInfoReq(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CQI info request function.
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
static TypeId GetTypeId()
Get the type ID.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0)
void DoSchedDlRachInfoReq(const FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH info request function.
void RefreshDlCqiMaps()
Refresh DL CQI maps function.
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE's LC info.
void DoCschedCellConfigReq(const FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
CSched cell config request function.
std::map< uint16_t, std::vector< uint16_t > > m_allocationMaps
Map of previous allocated UE per RBG (used to retrieve info from UL-CQI)
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
uint32_t m_nMux
TD scheduler selects nMux UEs and transfer them to FD scheduler.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
HARQ retx buffered.
void SetFfMacCschedSapUser(FfMacCschedSapUser *s) override
set the user part of the FfMacCschedSap that this Scheduler will interact with.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
CSched cell config.
void DoCschedUeReleaseReq(const FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
CSched UE release request function.
void DoSchedDlRlcBufferReq(const FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC buffer request function.
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
~PssFfMacScheduler() override
Destructor.
std::string m_fdSchedulerType
FD scheduler type.
void RefreshUlCqiMaps()
Refresh UL CQI maps function.
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info function.
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
Update DL RLC buffer info function.
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs' UL-CQI per RBG.
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Transmission mode configuration update function.
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
DL HARQ process timer.
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
int GetRbgSize(int dlbandwidth)
Get RBG size function.
LteFfrSapProvider * m_ffrSapProvider
FFR SAP provider.
LteFfrSapUser * m_ffrSapUser
FFR SAP user.
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ current proess ID.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ process ID.
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
void DoCschedLcConfigReq(const FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
CSched LC config request function.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
FfMacSchedSapUser * m_schedSapUser
Sched SAP user.
FfMacCschedSapUser * m_cschedSapUser
CSched SAP user.
void DoSchedUlNoiseInterferenceReq(const FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL noise interference request function.
FfMacSchedSapProvider * m_schedSapProvider
Sched SAP provider.
friend class MemberCschedSapProvider< PssFfMacScheduler >
allow MemberCschedSapProvider<PssFfMacScheduler> class friend access
void DoSchedDlTriggerReq(const FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL trigger request function.
FfMacCschedSapProvider * GetFfMacCschedSapProvider() override
std::map< uint16_t, pssFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
void DoSchedUlTriggerReq(const FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL trigger request function.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
void DoCschedUeConfigReq(const FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
CSched UE config request function.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ ELC PDU list buffer.
void DoSchedUlMacCtrlInfoReq(const FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC control info request function.
std::map< uint16_t, pssFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis)
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE's timers on DL CQI A30 received.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs' timers on UL-CQI per RBG.
void SetFfMacSchedSapUser(FfMacSchedSapUser *s) override
set the user part of the FfMacSchedSap that this Scheduler will interact with.
void SetLteFfrSapProvider(LteFfrSapProvider *s) override
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Hold variables of type string.
Definition string.h:45
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define HARQ_PERIOD
Definition lte-common.h:19
#define SRS_CQI_RNTI_VSP
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector.
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
constexpr double NO_SINR
Value for SINR outside the range defined by FF-API, used to indicate that there is no CQI for this el...
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector.
@ SUCCESS
constexpr uint32_t HARQ_DL_TIMEOUT
HARQ DL timeout.
constexpr uint32_t HARQ_PROC_NUM
Number of HARQ processes.
Ptr< const AttributeChecker > MakeStringChecker()
Definition string.cc:19
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Definition string.h:46
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
Vector of the 8 HARQ processes per UE.
static const int PssType0AllocationRbg[4]
PSS type 0 allocation RBG.
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
See section 4.3.8 buildDataListElement.
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
RLC PDU list.
struct DlDciListElement_s m_dci
DCI.
See section 4.3.10 buildRARListElement.
See section 4.3.1 dlDciListElement.
std::vector< uint8_t > m_ndi
New data indicator.
uint8_t m_harqProcess
HARQ process.
uint32_t m_rbBitmap
RB bitmap.
std::vector< uint8_t > m_mcs
MCS.
uint8_t m_resAlloc
The type of resource allocation.
std::vector< uint16_t > m_tbsSize
The TBs size.
std::vector< uint8_t > m_rv
Redundancy version.
uint8_t m_tpc
Tx power control command.
Parameters of the CSCHED_LC_CONFIG_REQ primitive.
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
Parameters of the SCHED_UL_CQI_INFO_REQ primitive.
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
std::vector< BuildDataListElement_s > m_buildDataList
build data list
std::vector< BuildRarListElement_s > m_buildRarList
build rar list
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
Parameters of the SCHED_UL_CONFIG_IND primitive.
std::vector< UlDciListElement_s > m_dciList
DCI list.
LteFlowId structure.
Definition lte-common.h:32
See section 4.3.9 rlcPDU_ListElement.
uint8_t m_logicalChannelIdentity
logical channel identity
See section 4.3.2 ulDciListElement.
int8_t m_pdcchPowerOffset
CCH power offset.
int8_t m_tpc
Tx power control command.
uint8_t m_dai
DL assignment index.
uint8_t m_cceIndex
Control Channel Element index.
uint8_t m_ulIndex
UL index.
uint8_t m_ueTxAntennaSelection
UE antenna selection.
bool m_cqiRequest
CQI request.
uint8_t m_freqHopping
freq hopping
uint8_t m_aggrLevel
The aggregation level.
bool m_ulDelay
UL delay?
int8_t m_tpc
Tx power control command.
bool m_cqiRequest
CQI request?
bool m_hopping
hopping?
uint16_t m_tbSize
size
uint8_t m_rbLen
length
uint8_t m_mcs
MCS.
uint8_t m_rbStart
start
uint16_t m_rnti
RNTI.
double secondLastAveragedThroughput
Second last average throughput.
double lastAveragedThroughput
Past average throughput.
double targetThroughput
Target throughput.
Time flowStart
flow start time
unsigned int lastTtiBytesTransmitted
Total bytes send by eNB in last tti for this UE.
unsigned long totalBytesTransmitted
Total bytes send by eNb for this UE.