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 (see table 7.1.6.1-1 of 36.213)
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};
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 }
1041 }
1042 }
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 }
1136 }
1137
1138 sbCqiSum[(*it).first] = sum;
1139 }
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 }
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 }
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 }
1239 }
1240
1241 if (m_fdSchedulerType == "PFsch")
1242 {
1243 // FD scheduler: Proportional Fair scheduled (PFsch)
1244 for (int i = 0; i < rbgNum; i++)
1245 {
1246 if (rbgMap.at(i))
1247 {
1248 continue;
1249 }
1250
1251 auto itMax = tdUeSet.end();
1252 double metricMax = 0.0;
1253 for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
1254 {
1255 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
1256 {
1257 continue;
1258 }
1259 // calculate PF weight
1260 double weight =
1261 (*it).second.targetThroughput / (*it).second.lastAveragedThroughput;
1262 if (weight < 1.0)
1263 {
1264 weight = 1.0;
1265 }
1266
1267 auto itCqi = m_a30CqiRxed.find((*it).first);
1268 auto itTxMode = m_uesTxMode.find((*it).first);
1269 if (itTxMode == m_uesTxMode.end())
1270 {
1271 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1272 }
1273 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1274 std::vector<uint8_t> sbCqis;
1275 if (itCqi == m_a30CqiRxed.end())
1276 {
1277 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1278 }
1279 else
1280 {
1281 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1282 }
1283
1284 uint8_t cqi1 = sbCqis.at(0);
1285 uint8_t cqi2 = 0;
1286 if (sbCqis.size() > 1)
1287 {
1288 cqi2 = sbCqis.at(1);
1289 }
1290
1291 double schMetric = 0.0;
1292 if ((cqi1 > 0) ||
1293 (cqi2 >
1294 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1295 {
1296 double achievableRate = 0.0;
1297 for (uint8_t k = 0; k < nLayer; k++)
1298 {
1299 uint8_t mcs = 0;
1300 if (sbCqis.size() > k)
1301 {
1302 mcs = m_amc->GetMcsFromCqi(sbCqis.at(k));
1303 }
1304 else
1305 {
1306 // no info on this subband -> worst MCS
1307 mcs = 0;
1308 }
1309 achievableRate += ((m_amc->GetDlTbSizeFromMcs(mcs, rbgSize) / 8) /
1310 0.001); // = TB size / TTI
1311 }
1312 schMetric = achievableRate / (*it).second.secondLastAveragedThroughput;
1313 }
1314
1315 double metric = 0.0;
1316 metric = weight * schMetric;
1317
1318 if (metric > metricMax)
1319 {
1320 metricMax = metric;
1321 itMax = it;
1322 }
1323 }
1324
1325 if (itMax == tdUeSet.end())
1326 {
1327 // no UE available for downlink
1328 }
1329 else
1330 {
1331 allocationMap[(*itMax).first].push_back(i);
1332 rbgMap.at(i) = true;
1333 }
1334 }
1335 }
1336 }
1337 }
1338
1339 // reset TTI stats of users
1340 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1341 {
1342 (*itStats).second.lastTtiBytesTransmitted = 0;
1343 }
1344
1345 // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1346 // creating the correspondent DCIs
1347 auto itMap = allocationMap.begin();
1348 while (itMap != allocationMap.end())
1349 {
1350 // create new BuildDataListElement_s for this LC
1352 newEl.m_rnti = (*itMap).first;
1353 // create the DlDciListElement_s
1354 DlDciListElement_s newDci;
1355 newDci.m_rnti = (*itMap).first;
1356 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1357
1358 uint16_t lcActives = LcActivePerFlow((*itMap).first);
1359 NS_LOG_INFO(this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1360 if (lcActives == 0)
1361 {
1362 // Set to max value, to avoid divide by 0 below
1363 lcActives = (uint16_t)65535; // UINT16_MAX;
1364 }
1365 uint16_t RbgPerRnti = (*itMap).second.size();
1366 auto itCqi = m_a30CqiRxed.find((*itMap).first);
1367 auto itTxMode = m_uesTxMode.find((*itMap).first);
1368 if (itTxMode == m_uesTxMode.end())
1369 {
1370 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
1371 }
1372 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1373 std::vector<uint8_t> worstCqi(2, 15);
1374 if (itCqi != m_a30CqiRxed.end())
1375 {
1376 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1377 {
1378 if ((*itCqi).second.m_higherLayerSelected.size() > (*itMap).second.at(k))
1379 {
1380 NS_LOG_INFO(this << " RBG " << (*itMap).second.at(k) << " CQI "
1381 << (uint16_t)((*itCqi)
1382 .second.m_higherLayerSelected
1383 .at((*itMap).second.at(k))
1384 .m_sbCqi.at(0)));
1385 for (uint8_t j = 0; j < nLayer; j++)
1386 {
1387 if ((*itCqi)
1388 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1389 .m_sbCqi.size() > j)
1390 {
1391 if (((*itCqi)
1392 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1393 .m_sbCqi.at(j)) < worstCqi.at(j))
1394 {
1395 worstCqi.at(j) =
1396 ((*itCqi)
1397 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1398 .m_sbCqi.at(j));
1399 }
1400 }
1401 else
1402 {
1403 // no CQI for this layer of this suband -> worst one
1404 worstCqi.at(j) = 1;
1405 }
1406 }
1407 }
1408 else
1409 {
1410 for (uint8_t j = 0; j < nLayer; j++)
1411 {
1412 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1413 }
1414 }
1415 }
1416 }
1417 else
1418 {
1419 for (uint8_t j = 0; j < nLayer; j++)
1420 {
1421 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1422 }
1423 }
1424 for (uint8_t j = 0; j < nLayer; j++)
1425 {
1426 NS_LOG_INFO(this << " Layer " << (uint16_t)j << " CQI selected "
1427 << (uint16_t)worstCqi.at(j));
1428 }
1429 uint32_t bytesTxed = 0;
1430 for (uint8_t j = 0; j < nLayer; j++)
1431 {
1432 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
1433 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
1434 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1435 newDci.m_tbsSize.push_back(tbSize);
1436 NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
1437 << m_amc->GetMcsFromCqi(worstCqi.at(j)));
1438 bytesTxed += tbSize;
1439 }
1440
1441 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1442 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1443 uint32_t rbgMask = 0;
1444 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1445 {
1446 rbgMask = rbgMask + (0x1 << (*itMap).second.at(k));
1447 NS_LOG_INFO(this << " Allocated RBG " << (*itMap).second.at(k));
1448 }
1449 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1450
1451 // create the rlc PDUs -> equally divide resources among actives LCs
1452 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1453 {
1454 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1455 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1456 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1457 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1458 {
1459 std::vector<RlcPduListElement_s> newRlcPduLe;
1460 for (uint8_t j = 0; j < nLayer; j++)
1461 {
1462 RlcPduListElement_s newRlcEl;
1463 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1464 newRlcEl.m_size = newDci.m_tbsSize.at(j) / lcActives;
1465 NS_LOG_INFO(this << " LCID " << (uint32_t)newRlcEl.m_logicalChannelIdentity
1466 << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1467 newRlcPduLe.push_back(newRlcEl);
1469 newRlcEl.m_logicalChannelIdentity,
1470 newRlcEl.m_size);
1471 if (m_harqOn)
1472 {
1473 // store RLC PDU list for HARQ
1474 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1475 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1476 {
1477 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1478 << (*itMap).first);
1479 }
1480 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1481 }
1482 }
1483 newEl.m_rlcPduList.push_back(newRlcPduLe);
1484 }
1485 if ((*itBufReq).first.m_rnti > (*itMap).first)
1486 {
1487 break;
1488 }
1489 }
1490 for (uint8_t j = 0; j < nLayer; j++)
1491 {
1492 newDci.m_ndi.push_back(1);
1493 newDci.m_rv.push_back(0);
1494 }
1495
1496 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1497
1498 newEl.m_dci = newDci;
1499
1500 if (m_harqOn)
1501 {
1502 // store DCI for HARQ
1503 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1504 if (itDci == m_dlHarqProcessesDciBuffer.end())
1505 {
1506 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1507 << newEl.m_rnti);
1508 }
1509 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1510 // refresh timer
1511 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1512 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1513 {
1514 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1515 }
1516 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1517 }
1518
1519 // ...more parameters -> ignored in this version
1520
1521 ret.m_buildDataList.push_back(newEl);
1522 // update UE stats
1523 auto it = m_flowStatsDl.find((*itMap).first);
1524 if (it != m_flowStatsDl.end())
1525 {
1526 (*it).second.lastTtiBytesTransmitted = bytesTxed;
1527 NS_LOG_INFO(this << " UE total bytes txed " << (*it).second.lastTtiBytesTransmitted);
1528 }
1529 else
1530 {
1531 NS_FATAL_ERROR(this << " No Stats for this allocated UE");
1532 }
1533
1534 itMap++;
1535 }
1536 ret.m_nrOfPdcchOfdmSymbols = 1; /// \todo check correct value according the DCIs txed
1537
1538 // update UEs stats
1539 NS_LOG_INFO(this << " Update UEs statistics");
1540 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1541 {
1542 auto itUeScheduleted = tdUeSet.end();
1543 itUeScheduleted = tdUeSet.find((*itStats).first);
1544 if (itUeScheduleted != tdUeSet.end())
1545 {
1546 (*itStats).second.secondLastAveragedThroughput =
1547 ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) +
1548 ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1549 }
1550
1551 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1552 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
1553 // Evolution, Ed Wiley)
1554 (*itStats).second.lastAveragedThroughput =
1555 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
1556 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1557 (*itStats).second.lastTtiBytesTransmitted = 0;
1558 }
1559
1561}
1562
1563void
1566{
1567 NS_LOG_FUNCTION(this);
1568
1569 m_rachList = params.m_rachList;
1570}
1571
1572void
1575{
1576 NS_LOG_FUNCTION(this);
1578
1579 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1580 {
1581 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1582 {
1583 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1584 << " reported");
1585 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1586 auto it = m_p10CqiRxed.find(rnti);
1587 if (it == m_p10CqiRxed.end())
1588 {
1589 // create the new entry
1590 m_p10CqiRxed[rnti] =
1591 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1592 // generate correspondent timer
1594 }
1595 else
1596 {
1597 // update the CQI value and refresh correspondent timer
1598 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1599 // update correspondent timer
1600 auto itTimers = m_p10CqiTimers.find(rnti);
1601 (*itTimers).second = m_cqiTimersThreshold;
1602 }
1603 }
1604 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1605 {
1606 // subband CQI reporting high layer configured
1607 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1608 auto it = m_a30CqiRxed.find(rnti);
1609 if (it == m_a30CqiRxed.end())
1610 {
1611 // create the new entry
1612 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1614 }
1615 else
1616 {
1617 // update the CQI value and refresh correspondent timer
1618 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1619 auto itTimers = m_a30CqiTimers.find(rnti);
1620 (*itTimers).second = m_cqiTimersThreshold;
1621 }
1622 }
1623 else
1624 {
1625 NS_LOG_ERROR(this << " CQI type unknown");
1626 }
1627 }
1628}
1629
1630double
1631PssFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1632{
1633 auto itCqi = m_ueCqi.find(rnti);
1634 if (itCqi == m_ueCqi.end())
1635 {
1636 // no cqi info about this UE
1637 return NO_SINR;
1638 }
1639 else
1640 {
1641 // take the average SINR value among the available
1642 double sinrSum = 0;
1643 unsigned int sinrNum = 0;
1644 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1645 {
1646 double sinr = (*itCqi).second.at(i);
1647 if (sinr != NO_SINR)
1648 {
1649 sinrSum += sinr;
1650 sinrNum++;
1651 }
1652 }
1653 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1654 // store the value
1655 (*itCqi).second.at(rb) = estimatedSinr;
1656 return estimatedSinr;
1657 }
1658}
1659
1660void
1663{
1664 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1665 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1666
1669
1670 // Generate RBs map
1672 std::vector<bool> rbMap;
1673 uint16_t rbAllocatedNum = 0;
1674 std::set<uint16_t> rntiAllocated;
1675 std::vector<uint16_t> rbgAllocationMap;
1676 // update with RACH allocation map
1677 rbgAllocationMap = m_rachAllocationMap;
1678 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1679 m_rachAllocationMap.clear();
1681
1682 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1683
1685
1686 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1687 {
1688 if (*it)
1689 {
1690 rbAllocatedNum++;
1691 }
1692 }
1693
1694 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1695 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1696
1697 // remove RACH allocation
1698 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1699 {
1700 if (rbgAllocationMap.at(i) != 0)
1701 {
1702 rbMap.at(i) = true;
1703 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1704 }
1705 }
1706
1707 if (m_harqOn)
1708 {
1709 // Process UL HARQ feedback
1710 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1711 {
1712 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1713 {
1714 // retx correspondent block: retrieve the UL-DCI
1715 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1716 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1717 if (itProcId == m_ulHarqCurrentProcessId.end())
1718 {
1719 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1720 }
1721 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1722 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1723 << " i " << i << " size " << params.m_ulInfoList.size());
1724 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1725 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1726 {
1727 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1728 continue;
1729 }
1730 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1731 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1732 if (itStat == m_ulHarqProcessesStatus.end())
1733 {
1734 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1735 }
1736 if ((*itStat).second.at(harqId) >= 3)
1737 {
1738 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1739 continue;
1740 }
1741 bool free = true;
1742 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1743 {
1744 if (rbMap.at(j))
1745 {
1746 free = false;
1747 NS_LOG_INFO(this << " BUSY " << j);
1748 }
1749 }
1750 if (free)
1751 {
1752 // retx on the same RBs
1753 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1754 {
1755 rbMap.at(j) = true;
1756 rbgAllocationMap.at(j) = dci.m_rnti;
1757 NS_LOG_INFO("\tRB " << j);
1758 rbAllocatedNum++;
1759 }
1760 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1761 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1762 << (*itStat).second.at(harqId) + 1);
1763 }
1764 else
1765 {
1766 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1767 continue;
1768 }
1769 dci.m_ndi = 0;
1770 // Update HARQ buffers with new HarqId
1771 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1772 (*itStat).second.at(harqId) = 0;
1773 (*itHarq).second.at((*itProcId).second) = dci;
1774 ret.m_dciList.push_back(dci);
1775 rntiAllocated.insert(dci.m_rnti);
1776 }
1777 else
1778 {
1779 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1780 << params.m_ulInfoList.at(i).m_rnti);
1781 }
1782 }
1783 }
1784
1785 std::map<uint16_t, uint32_t>::iterator it;
1786 int nflows = 0;
1787
1788 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1789 {
1790 auto itRnti = rntiAllocated.find((*it).first);
1791 // select UEs with queues not empty and not yet allocated for HARQ
1792 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1793 {
1794 nflows++;
1795 }
1796 }
1797
1798 if (nflows == 0)
1799 {
1800 if (!ret.m_dciList.empty())
1801 {
1802 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1804 }
1805
1806 return; // no flows to be scheduled
1807 }
1808
1809 // Divide the remaining resources equally among the active users starting from the subsequent
1810 // one served last scheduling trigger
1811 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1812 uint16_t rbPerFlow =
1813 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1814
1815 if (rbPerFlow < 3)
1816 {
1817 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1818 // >= 7 bytes
1819 }
1820 int rbAllocated = 0;
1821
1822 if (m_nextRntiUl != 0)
1823 {
1824 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1825 {
1826 if ((*it).first == m_nextRntiUl)
1827 {
1828 break;
1829 }
1830 }
1831 if (it == m_ceBsrRxed.end())
1832 {
1833 NS_LOG_ERROR(this << " no user found");
1834 }
1835 }
1836 else
1837 {
1838 it = m_ceBsrRxed.begin();
1839 m_nextRntiUl = (*it).first;
1840 }
1841 do
1842 {
1843 auto itRnti = rntiAllocated.find((*it).first);
1844 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1845 {
1846 // UE already allocated for UL-HARQ -> skip it
1847 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
1848 << (*it).first);
1849 it++;
1850 if (it == m_ceBsrRxed.end())
1851 {
1852 // restart from the first
1853 it = m_ceBsrRxed.begin();
1854 }
1855 continue;
1856 }
1857 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1858 {
1859 // limit to physical resources last resource assignment
1860 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1861 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1862 if (rbPerFlow < 3)
1863 {
1864 // terminate allocation
1865 rbPerFlow = 0;
1866 }
1867 }
1868
1869 rbAllocated = 0;
1870 UlDciListElement_s uldci;
1871 uldci.m_rnti = (*it).first;
1872 uldci.m_rbLen = rbPerFlow;
1873 bool allocated = false;
1874 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
1875 << " flows " << nflows);
1876 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
1877 (rbPerFlow != 0))
1878 {
1879 // check availability
1880 bool free = true;
1881 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1882 {
1883 if (rbMap.at(j))
1884 {
1885 free = false;
1886 break;
1887 }
1888 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
1889 {
1890 free = false;
1891 break;
1892 }
1893 }
1894 if (free)
1895 {
1896 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
1897 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1898 uldci.m_rbStart = rbAllocated;
1899
1900 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1901 {
1902 rbMap.at(j) = true;
1903 // store info on allocation for managing ul-cqi interpretation
1904 rbgAllocationMap.at(j) = (*it).first;
1905 }
1906 rbAllocated += rbPerFlow;
1907 allocated = true;
1908 break;
1909 }
1910 rbAllocated++;
1911 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1912 {
1913 // limit to physical resources last resource assignment
1914 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1915 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1916 if (rbPerFlow < 3)
1917 {
1918 // terminate allocation
1919 rbPerFlow = 0;
1920 }
1921 }
1922 }
1923 if (!allocated)
1924 {
1925 // unable to allocate new resource: finish scheduling
1926 // m_nextRntiUl = (*it).first;
1927 // if (ret.m_dciList.size () > 0)
1928 // {
1929 // m_schedSapUser->SchedUlConfigInd (ret);
1930 // }
1931 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
1932 break;
1933 }
1934
1935 auto itCqi = m_ueCqi.find((*it).first);
1936 int cqi = 0;
1937 if (itCqi == m_ueCqi.end())
1938 {
1939 // no cqi info about this UE
1940 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1941 }
1942 else
1943 {
1944 // take the lowest CQI value (worst RB)
1945 NS_ABORT_MSG_IF((*itCqi).second.empty(),
1946 "CQI of RNTI = " << (*it).first << " has expired");
1947 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
1948 if (minSinr == NO_SINR)
1949 {
1950 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
1951 }
1952 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1953 {
1954 double sinr = (*itCqi).second.at(i);
1955 if (sinr == NO_SINR)
1956 {
1957 sinr = EstimateUlSinr((*it).first, i);
1958 }
1959 if (sinr < minSinr)
1960 {
1961 minSinr = sinr;
1962 }
1963 }
1964
1965 // translate SINR -> cqi: WILD ACK: same as DL
1966 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
1967 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
1968 if (cqi == 0)
1969 {
1970 it++;
1971 if (it == m_ceBsrRxed.end())
1972 {
1973 // restart from the first
1974 it = m_ceBsrRxed.begin();
1975 }
1976 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
1977 // remove UE from allocation map
1978 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1979 {
1980 rbgAllocationMap.at(i) = 0;
1981 }
1982 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1983 }
1984 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
1985 }
1986
1987 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
1989 uldci.m_ndi = 1;
1990 uldci.m_cceIndex = 0;
1991 uldci.m_aggrLevel = 1;
1992 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1993 uldci.m_hopping = false;
1994 uldci.m_n2Dmrs = 0;
1995 uldci.m_tpc = 0; // no power control
1996 uldci.m_cqiRequest = false; // only period CQI at this stage
1997 uldci.m_ulIndex = 0; // TDD parameter
1998 uldci.m_dai = 1; // TDD parameter
1999 uldci.m_freqHopping = 0;
2000 uldci.m_pdcchPowerOffset = 0; // not used
2001 ret.m_dciList.push_back(uldci);
2002 // store DCI for HARQ_PERIOD
2003 uint8_t harqId = 0;
2004 if (m_harqOn)
2005 {
2006 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
2007 if (itProcId == m_ulHarqCurrentProcessId.end())
2008 {
2009 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
2010 }
2011 harqId = (*itProcId).second;
2012 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
2013 if (itDci == m_ulHarqProcessesDciBuffer.end())
2014 {
2015 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
2016 << uldci.m_rnti);
2017 }
2018 (*itDci).second.at(harqId) = uldci;
2019 // Update HARQ process status (RV 0)
2020 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
2021 if (itStat == m_ulHarqProcessesStatus.end())
2022 {
2023 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
2024 << uldci.m_rnti);
2025 }
2026 (*itStat).second.at(harqId) = 0;
2027 }
2028
2029 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
2030 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
2031 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
2032 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
2033 << (uint16_t)harqId);
2034
2035 it++;
2036 if (it == m_ceBsrRxed.end())
2037 {
2038 // restart from the first
2039 it = m_ceBsrRxed.begin();
2040 }
2041 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2042 {
2043 // Stop allocation: no more PRBs
2044 m_nextRntiUl = (*it).first;
2045 break;
2046 }
2047 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
2048
2049 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
2051}
2052
2053void
2059
2060void
2066
2067void
2070{
2071 NS_LOG_FUNCTION(this);
2072
2073 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
2074 {
2075 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
2076 {
2077 // buffer status report
2078 // note that this scheduler does not differentiate the
2079 // allocation according to which LCGs have more/less bytes
2080 // to send.
2081 // Hence the BSR of different LCGs are just summed up to get
2082 // a total queue size that is used for allocation purposes.
2083
2084 uint32_t buffer = 0;
2085 for (uint8_t lcg = 0; lcg < 4; ++lcg)
2086 {
2087 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
2088 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
2089 }
2090
2091 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
2092 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
2093 auto it = m_ceBsrRxed.find(rnti);
2094 if (it == m_ceBsrRxed.end())
2095 {
2096 // create the new entry
2097 m_ceBsrRxed[rnti] = buffer;
2098 }
2099 else
2100 {
2101 // update the buffer size value
2102 (*it).second = buffer;
2103 }
2104 }
2105 }
2106}
2107
2108void
2111{
2112 NS_LOG_FUNCTION(this);
2113 // retrieve the allocation for this subframe
2114 switch (m_ulCqiFilter)
2115 {
2117 // filter all the CQIs that are not SRS based
2118 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2119 {
2120 return;
2121 }
2122 }
2123 break;
2125 // filter all the CQIs that are not SRS based
2126 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2127 {
2128 return;
2129 }
2130 }
2131 break;
2132 default:
2133 NS_FATAL_ERROR("Unknown UL CQI type");
2134 }
2135
2136 switch (params.m_ulCqi.m_type)
2137 {
2138 case UlCqi_s::PUSCH: {
2139 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
2140 << " subframe no. " << (0xF & params.m_sfnSf));
2141 auto itMap = m_allocationMaps.find(params.m_sfnSf);
2142 if (itMap == m_allocationMaps.end())
2143 {
2144 return;
2145 }
2146 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
2147 {
2148 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2149 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
2150 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
2151 if (itCqi == m_ueCqi.end())
2152 {
2153 // create a new entry
2154 std::vector<double> newCqi;
2155 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2156 {
2157 if (i == j)
2158 {
2159 newCqi.push_back(sinr);
2160 }
2161 else
2162 {
2163 // initialize with NO_SINR value.
2164 newCqi.push_back(NO_SINR);
2165 }
2166 }
2167 m_ueCqi[(*itMap).second.at(i)] = newCqi;
2168 // generate correspondent timer
2169 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
2170 }
2171 else
2172 {
2173 // update the value
2174 (*itCqi).second.at(i) = sinr;
2175 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
2176 << sinr);
2177 // update correspondent timer
2178 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
2179 (*itTimers).second = m_cqiTimersThreshold;
2180 }
2181 }
2182 // remove obsolete info on allocation
2183 m_allocationMaps.erase(itMap);
2184 }
2185 break;
2186 case UlCqi_s::SRS: {
2187 // get the RNTI from vendor specific parameters
2188 uint16_t rnti = 0;
2189 NS_ASSERT(!params.m_vendorSpecificList.empty());
2190 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
2191 {
2192 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
2193 {
2194 Ptr<SrsCqiRntiVsp> vsp =
2195 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
2196 rnti = vsp->GetRnti();
2197 }
2198 }
2199 auto itCqi = m_ueCqi.find(rnti);
2200 if (itCqi == m_ueCqi.end())
2201 {
2202 // create a new entry
2203 std::vector<double> newCqi;
2204 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2205 {
2206 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2207 newCqi.push_back(sinr);
2208 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
2209 << sinr);
2210 }
2211 m_ueCqi[rnti] = newCqi;
2212 // generate correspondent timer
2214 }
2215 else
2216 {
2217 // update the values
2218 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2219 {
2220 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2221 (*itCqi).second.at(j) = sinr;
2222 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
2223 << sinr);
2224 }
2225 // update correspondent timer
2226 auto itTimers = m_ueCqiTimers.find(rnti);
2227 (*itTimers).second = m_cqiTimersThreshold;
2228 }
2229 }
2230 break;
2231 case UlCqi_s::PUCCH_1:
2232 case UlCqi_s::PUCCH_2:
2233 case UlCqi_s::PRACH: {
2234 NS_FATAL_ERROR("PssFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2235 }
2236 break;
2237 default:
2238 NS_FATAL_ERROR("Unknown type of UL-CQI");
2239 }
2240}
2241
2242void
2244{
2245 // refresh DL CQI P01 Map
2246 auto itP10 = m_p10CqiTimers.begin();
2247 while (itP10 != m_p10CqiTimers.end())
2248 {
2249 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
2250 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2251 if ((*itP10).second == 0)
2252 {
2253 // delete correspondent entries
2254 auto itMap = m_p10CqiRxed.find((*itP10).first);
2255 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
2256 " Does not find CQI report for user " << (*itP10).first);
2257 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
2258 m_p10CqiRxed.erase(itMap);
2259 auto temp = itP10;
2260 itP10++;
2261 m_p10CqiTimers.erase(temp);
2262 }
2263 else
2264 {
2265 (*itP10).second--;
2266 itP10++;
2267 }
2268 }
2269
2270 // refresh DL CQI A30 Map
2271 auto itA30 = m_a30CqiTimers.begin();
2272 while (itA30 != m_a30CqiTimers.end())
2273 {
2274 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
2275 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2276 if ((*itA30).second == 0)
2277 {
2278 // delete correspondent entries
2279 auto itMap = m_a30CqiRxed.find((*itA30).first);
2280 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2281 " Does not find CQI report for user " << (*itA30).first);
2282 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2283 m_a30CqiRxed.erase(itMap);
2284 auto temp = itA30;
2285 itA30++;
2286 m_a30CqiTimers.erase(temp);
2287 }
2288 else
2289 {
2290 (*itA30).second--;
2291 itA30++;
2292 }
2293 }
2294}
2295
2296void
2298{
2299 // refresh UL CQI Map
2300 auto itUl = m_ueCqiTimers.begin();
2301 while (itUl != m_ueCqiTimers.end())
2302 {
2303 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2304 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2305 if ((*itUl).second == 0)
2306 {
2307 // delete correspondent entries
2308 auto itMap = m_ueCqi.find((*itUl).first);
2309 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2310 " Does not find CQI report for user " << (*itUl).first);
2311 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2312 (*itMap).second.clear();
2313 m_ueCqi.erase(itMap);
2314 auto temp = itUl;
2315 itUl++;
2316 m_ueCqiTimers.erase(temp);
2317 }
2318 else
2319 {
2320 (*itUl).second--;
2321 itUl++;
2322 }
2323 }
2324}
2325
2326void
2327PssFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2328{
2329 LteFlowId_t flow(rnti, lcid);
2330 auto it = m_rlcBufferReq.find(flow);
2331 if (it != m_rlcBufferReq.end())
2332 {
2333 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2334 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2335 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2336 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2337 // Update queues: RLC tx order Status, ReTx, Tx
2338 // Update status queue
2339 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2340 {
2341 (*it).second.m_rlcStatusPduSize = 0;
2342 }
2343 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2344 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2345 {
2346 (*it).second.m_rlcRetransmissionQueueSize = 0;
2347 }
2348 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2349 {
2350 uint32_t rlcOverhead;
2351 if (lcid == 1)
2352 {
2353 // for SRB1 (using RLC AM) it's better to
2354 // overestimate RLC overhead rather than
2355 // underestimate it and risk unneeded
2356 // segmentation which increases delay
2357 rlcOverhead = 4;
2358 }
2359 else
2360 {
2361 // minimum RLC overhead due to header
2362 rlcOverhead = 2;
2363 }
2364 // update transmission queue
2365 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2366 {
2367 (*it).second.m_rlcTransmissionQueueSize = 0;
2368 }
2369 else
2370 {
2371 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2372 }
2373 }
2374 }
2375 else
2376 {
2377 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2378 }
2379}
2380
2381void
2382PssFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2383{
2384 size = size - 2; // remove the minimum RLC overhead
2385 auto it = m_ceBsrRxed.find(rnti);
2386 if (it != m_ceBsrRxed.end())
2387 {
2388 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2389 if ((*it).second >= size)
2390 {
2391 (*it).second -= size;
2392 }
2393 else
2394 {
2395 (*it).second = 0;
2396 }
2397 }
2398 else
2399 {
2400 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2401 }
2402}
2403
2404void
2406{
2407 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2409 params.m_rnti = rnti;
2410 params.m_transmissionMode = txMode;
2412}
2413
2414} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
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:49
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
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeChecker > MakeStringChecker()
Definition string.cc:19
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition string.h:46
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#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.
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector.
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...
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.
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
Vector of the 8 HARQ processes per UE.
static const int PssType0AllocationRbg[4]
PSS type 0 allocation RBG (see table 7.1.6.1-1 of 36.213)
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.