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;
173 dlHarqPrcStatus.resize(8, 0);
176 dlHarqProcessesTimer.resize(8, 0);
179 dlHarqdci.resize(8);
180 m_dlHarqProcessesDciBuffer[params.m_rnti] = dlHarqdci;
182 dlHarqRlcPdu.resize(2);
183 dlHarqRlcPdu.at(0).resize(8);
184 dlHarqRlcPdu.at(1).resize(8);
186 m_ulHarqCurrentProcessId[params.m_rnti] = 0;
188 ulHarqPrcStatus.resize(8, 0);
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
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;
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 {
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
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
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;
497
499 for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
500 {
501 if (*it)
502 {
504 }
505 }
506
508
509 // update UL HARQ proc id
510 for (auto itProcId = m_ulHarqCurrentProcessId.begin();
512 itProcId++)
513 {
514 (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
515 }
516
517 // RACH Allocation
518 std::vector<bool> ulRbMap;
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 {
532 {
535 }
536 tmpMinBandwidth = 0;
537 }
538 else
539 {
540 if (tmpMinBandwidth == 0)
541 {
542 tmpFfrRbStartOffset = index;
543 }
545 }
546 index++;
547 }
548
550 {
553 }
554
556 uint16_t rbStart = 0;
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) &&
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
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);
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);
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
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);
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;
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");
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));
799 }
800 dci.m_rbBitmap = rbgMask;
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
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
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));
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);
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 =
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();
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
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 {
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);
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);
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
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;
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
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 {
1696 }
1697 }
1698
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);
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);
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);
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 =
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 }
1863 {
1864 // limit to physical resources last resource assignment
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;
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);
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 }
1912 allocated = true;
1913 break;
1914 }
1915 rbAllocated++;
1917 {
1918 // limit to physical resources last resource assignment
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);
1993 UpdateUlRlcBufferInfo(uldci.m_rnti, uldci.m_tbSize);
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);
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 }
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);
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;
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 {
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;
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
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);
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);
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 {
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
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...
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.
Definition ptr.h:66
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
#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
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#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
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< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
Vector of the 8 HARQ processes per UE.
@ SUCCESS
constexpr uint32_t HARQ_DL_TIMEOUT
HARQ DL timeout.
constexpr uint32_t HARQ_PROC_NUM
Number of HARQ processes.
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector.
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
static const int PssType0AllocationRbg[4]
PSS type 0 allocation RBG.
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector.
See section 4.3.8 buildDataListElement.
See section 4.3.10 buildRARListElement.
See section 4.3.1 dlDciListElement.
std::vector< uint8_t > m_rv
Redundancy version.
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.
Parameters of the SCHED_UL_CONFIG_IND primitive.
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.
Time flowStart
flow start time