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