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