A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
fdbet-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> // original version
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/fdbet-ff-mac-scheduler.h>
29 #include <ns3/lte-vendor-specific-parameters.h>
30 
31 NS_LOG_COMPONENT_DEFINE ("FdBetFfMacScheduler");
32 
33 // value for SINR outside the range defined by LTE, used to indicate that there
34 // is no CQI for this element
35 #define NO_SINR -5000
36 
37 namespace ns3 {
38 
40  10, // RGB size 1
41  26, // RGB size 2
42  63, // RGB size 3
43  110 // RGB size 4
44 }; // see table 7.1.6.1-1 of 36.213
45 
46 NS_OBJECT_ENSURE_REGISTERED (FdBetFfMacScheduler);
47 
49 {
50 public:
52 
53  // inherited from FfMacCschedSapProvider
54  virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
55  virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
56  virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
57  virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
58  virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
59 
60 private:
63 };
64 
66 {
67 }
68 
70 {
71 }
72 
73 
74 void
76 {
78 }
79 
80 void
82 {
84 }
85 
86 
87 void
89 {
91 }
92 
93 void
95 {
97 }
98 
99 void
101 {
103 }
104 
105 
106 
107 
109 {
110 public:
112 
113  // inherited from FfMacSchedSapProvider
114  virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
115  virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
116  virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
117  virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
118  virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
119  virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
120  virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
121  virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
122  virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
123  virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
124  virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
125 
126 
127 private:
130 };
131 
132 
133 
135 {
136 }
137 
138 
140  : m_scheduler (scheduler)
141 {
142 }
143 
144 void
146 {
148 }
149 
150 void
152 {
154 }
155 
156 void
158 {
160 }
161 
162 void
164 {
166 }
167 
168 void
170 {
172 }
173 
174 void
176 {
178 }
179 
180 void
182 {
184 }
185 
186 void
188 {
190 }
191 
192 void
194 {
196 }
197 
198 void
200 {
202 }
203 
204 void
206 {
208 }
209 
210 
211 
212 
213 
215  : m_cschedSapUser (0),
216  m_schedSapUser (0),
217  m_timeWindow (99.0),
218  m_nextRntiUl (0)
219 {
220  m_amc = CreateObject <LteAmc> ();
223 }
224 
226 {
227  NS_LOG_FUNCTION (this);
228 }
229 
230 void
232 {
233  NS_LOG_FUNCTION (this);
234  delete m_cschedSapProvider;
235  delete m_schedSapProvider;
236 }
237 
238 TypeId
240 {
241  static TypeId tid = TypeId ("ns3::FdBetFfMacScheduler")
243  .AddConstructor<FdBetFfMacScheduler> ()
244  .AddAttribute ("CqiTimerThreshold",
245  "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
246  UintegerValue (1000),
247  MakeUintegerAccessor (&FdBetFfMacScheduler::m_cqiTimersThreshold),
248  MakeUintegerChecker<uint32_t> ())
249  ;
250  return tid;
251 }
252 
253 
254 
255 void
257 {
258  m_cschedSapUser = s;
259 }
260 
261 void
263 {
264  m_schedSapUser = s;
265 }
266 
269 {
270  return m_cschedSapProvider;
271 }
272 
275 {
276  return m_schedSapProvider;
277 }
278 
279 void
281 {
282  NS_LOG_FUNCTION (this);
283  // Read the subset of parameters used
284  m_cschedCellConfig = params;
286  cnf.m_result = SUCCESS;
288  return;
289 }
290 
291 void
293 {
294  NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
295  std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
296  if (it == m_uesTxMode.end ())
297  {
298  m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
299  }
300  else
301  {
302  (*it).second = params.m_transmissionMode;
303  }
304  return;
305 }
306 
307 void
309 {
310  NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
311 
312  std::map <uint16_t, fdbetsFlowPerf_t>::iterator it;
313  for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
314  {
315  it = m_flowStatsDl.find (params.m_rnti);
316 
317  if (it == m_flowStatsDl.end ())
318  {
319  fdbetsFlowPerf_t flowStatsDl;
320  flowStatsDl.flowStart = Simulator::Now ();
321  flowStatsDl.totalBytesTransmitted = 0;
322  flowStatsDl.lastTtiBytesTransmitted = 0;
323  flowStatsDl.lastAveragedThroughput = 1;
324  m_flowStatsDl.insert (std::pair<uint16_t, fdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
325  fdbetsFlowPerf_t flowStatsUl;
326  flowStatsUl.flowStart = Simulator::Now ();
327  flowStatsUl.totalBytesTransmitted = 0;
328  flowStatsUl.lastTtiBytesTransmitted = 0;
329  flowStatsUl.lastAveragedThroughput = 1;
330  m_flowStatsUl.insert (std::pair<uint16_t, fdbetsFlowPerf_t> (params.m_rnti, flowStatsUl));
331  }
332  else
333  {
334  NS_LOG_ERROR ("RNTI already exists");
335  }
336  }
337 
338  return;
339 }
340 
341 void
343 {
344  NS_FATAL_ERROR ("unimplemented");
345  return;
346 }
347 
348 void
350 {
351  NS_FATAL_ERROR ("unimplemented");
352  return;
353 }
354 
355 
356 void
358 {
359  NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
360  // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
361 
362  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
363 
364  LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
365 
366  it = m_rlcBufferReq.find (flow);
367 
368  if (it == m_rlcBufferReq.end ())
369  {
370  m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
371  }
372  else
373  {
374  (*it).second = params;
375  }
376 
377  return;
378 }
379 
380 void
382 {
383  NS_FATAL_ERROR ("unimplemented");
384  return;
385 }
386 
387 void
389 {
390  NS_FATAL_ERROR ("unimplemented");
391  return;
392 }
393 
394 int
396 {
397  for (int i = 0; i < 4; i++)
398  {
399  if (dlbandwidth < FdBetType0AllocationRbg[i])
400  {
401  return (i + 1);
402  }
403  }
404 
405  return (-1);
406 }
407 
408 
409 int
411 {
412  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
413  int lcActive = 0;
414  for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
415  {
416  if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
417  || ((*it).second.m_rlcRetransmissionQueueSize > 0)
418  || ((*it).second.m_rlcStatusPduSize > 0) ))
419  {
420  lcActive++;
421  }
422  if ((*it).first.m_rnti > rnti)
423  {
424  break;
425  }
426  }
427  return (lcActive);
428 
429 }
430 
431 void
433 {
434  NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
435  // API generated by RLC for triggering the scheduling of a DL subframe
436 
437 
438  // evaluate the relative channel quality indicator for each UE per each RBG
439  // (since we are using allocation type 0 the small unit of allocation is RBG)
440  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
441 
442  RefreshDlCqiMaps ();
443 
445  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
446  std::map <uint16_t, std::vector <uint16_t> > allocationMap;
447  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itFlow;
448  std::map <uint16_t, double> estAveThr; // store expected average throughput for UE
449  std::map <uint16_t, double>::iterator itMax = estAveThr.end ();
450  std::map <uint16_t, double>::iterator it;
451  std::map <uint16_t, int> rbgPerRntiLog; // record the number of RBG assigned to UE
452  double metricMax = 0.0;
453 
454  for (itFlow = m_flowStatsDl.begin (); itFlow != m_flowStatsDl.end (); itFlow++)
455  {
456  estAveThr.insert (std::pair <uint16_t, double> ((*itFlow).first, (*itFlow).second.lastAveragedThroughput));
457  }
458 
459  // Find UE with largest priority metric
460  for (it = estAveThr.begin (); it != estAveThr.end (); it++)
461  {
462  double metric = 1 / (*it).second;
463  if (metric > metricMax)
464  {
465  metricMax = metric;
466  itMax = it;
467  }
468  rbgPerRntiLog.insert (std::pair<uint16_t, int> ((*it).first, 1));
469  }
470 
471  // The scheduler tries the best to achieve the equal throughput among all UEs
472  int i = 0;
473  do
474  {
475  // allocate one RBG to current UE
476  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
477  std::vector <uint16_t> tempMap;
478  itMap = allocationMap.find ((*itMax).first);
479  if (itMap == allocationMap.end ())
480  {
481  tempMap.push_back (i);
482  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
483  }
484  else
485  {
486  (*itMap).second.push_back (i);
487  }
488 
489  // caculate expected throughput for current UE
490  std::map <uint16_t,uint8_t>::iterator itCqi;
491  itCqi = m_p10CqiRxed.find ((*itMax).first);
492  std::map <uint16_t,uint8_t>::iterator itTxMode;
493  itTxMode = m_uesTxMode.find ((*itMax).first);
494  if (itTxMode == m_uesTxMode.end ())
495  {
496  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMax).first);
497  }
498  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
499  std::vector <uint8_t> mcs;
500  for (uint8_t j = 0; j < nLayer; j++)
501  {
502  if (itCqi == m_p10CqiRxed.end ())
503  {
504  mcs.push_back (0); // no info on this user -> lowest MCS
505  }
506  else
507  {
508  mcs.push_back (m_amc->GetMcsFromCqi ((*itCqi).second));
509  }
510  }
511 
512  std::map <uint16_t,int>::iterator itRbgPerRntiLog;
513  itRbgPerRntiLog = rbgPerRntiLog.find ((*itMax).first);
514  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itPastAveThr;
515  itPastAveThr = m_flowStatsDl.find ((*itMax).first);
516  uint32_t bytesTxed = 0;
517  for (uint8_t j = 0; j < nLayer; j++)
518  {
519  int tbSize = (m_amc->GetTbSizeFromMcs (mcs.at (0), (*itRbgPerRntiLog).second * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
520  bytesTxed += tbSize;
521  }
522  double expectedAveThr = ((1.0 - (1.0 / m_timeWindow)) * (*itPastAveThr).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)(bytesTxed / 0.001));
523 
524  int rbgPerRnti = (*itRbgPerRntiLog).second;
525  rbgPerRnti++;
526  rbgPerRntiLog[(*itMax).first] = rbgPerRnti;
527  estAveThr[(*itMax).first] = expectedAveThr;
528 
529  // find new UE with largest priority metric
530  metricMax = 0.0;
531  for (it = estAveThr.begin (); it != estAveThr.end (); it++)
532  {
533  double metric = 1 / (*it).second;
534  if (metric > metricMax)
535  {
536  itMax = it;
537  metricMax = metric;
538  }
539  } // end for estAveThr
540 
541  i++;
542 
543  }
544  while ( i < rbgNum ); // end for RBGs
545 
546  // reset TTI stats of users
547  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
548  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
549  {
550  (*itStats).second.lastTtiBytesTransmitted = 0;
551  }
552 
553  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
554  // creating the correspondent DCIs
556  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
557  while (itMap != allocationMap.end ())
558  {
559  // create new BuildDataListElement_s for this LC
561  newEl.m_rnti = (*itMap).first;
562  // create the DlDciListElement_s
563  DlDciListElement_s newDci;
564  std::vector <struct RlcPduListElement_s> newRlcPduLe;
565  newDci.m_rnti = (*itMap).first;
566 
567  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
568  uint16_t rbgPerRnti = (*itMap).second.size ();
569  std::map <uint16_t,uint8_t>::iterator itCqi;
570  itCqi = m_p10CqiRxed.find ((*itMap).first);
571  std::map <uint16_t,uint8_t>::iterator itTxMode;
572  itTxMode = m_uesTxMode.find ((*itMap).first);
573  if (itTxMode == m_uesTxMode.end ())
574  {
575  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
576  }
577  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
578  uint32_t bytesTxed = 0;
579  for (uint8_t i = 0; i < nLayer; i++)
580  {
581  if (itCqi == m_p10CqiRxed.end ())
582  {
583  newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
584  }
585  else
586  {
587  newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
588  }
589  }
590 
591  for (uint8_t i = 0; i < nLayer; i++)
592  {
593  int tbSize = (m_amc->GetTbSizeFromMcs (newDci.m_mcs.at (0), rbgPerRnti * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
594  newDci.m_tbsSize.push_back (tbSize);
595  bytesTxed += tbSize;
596  }
597 
598  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
599  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
600  uint32_t rbgMask = 0;
601  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
602  {
603  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
604  }
605  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
606 
607  // create the rlc PDUs -> equally divide resources among actives LCs
608  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
609  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
610  {
611  if (((*itBufReq).first.m_rnti == (*itMap).first) &&
612  (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
613  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
614  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
615  {
616  for (uint8_t j = 0; j < nLayer; j++)
617  {
618  RlcPduListElement_s newRlcEl;
619  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
620  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
621  newRlcPduLe.push_back (newRlcEl);
622  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
623  }
624  }
625  if ((*itBufReq).first.m_rnti > (*itMap).first)
626  {
627  break;
628  }
629  }
630  newDci.m_ndi.push_back (1); // TBD (new data indicator)
631  newDci.m_rv.push_back (0); // TBD (redundancy version)
632 
633  newEl.m_dci = newDci;
634  // ...more parameters -> ingored in this version
635 
636  newEl.m_rlcPduList.push_back (newRlcPduLe);
637  ret.m_buildDataList.push_back (newEl);
638 
639  // update UE stats
640  std::map <uint16_t, fdbetsFlowPerf_t>::iterator it;
641  it = m_flowStatsDl.find ((*itMap).first);
642  if (it != m_flowStatsDl.end ())
643  {
644  (*it).second.lastTtiBytesTransmitted = bytesTxed;
645  }
646  else
647  {
648  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
649  }
650 
651  itMap++;
652 
653  } // end while allocation
654  ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
655 
656 
657  // update UEs stats
658  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
659  {
660  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
661  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
662  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
663  (*itStats).second.lastTtiBytesTransmitted = 0;
664 
665  }
666 
668 
669 
670  return;
671 }
672 
673 void
675 {
676  NS_FATAL_ERROR ("unimplemented");
677  return;
678 }
679 
680 void
682 {
683  NS_LOG_FUNCTION (this);
684 
685  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
686  {
687  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
688  {
689  // wideband CQI reporting
690  std::map <uint16_t,uint8_t>::iterator it;
691  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
692  it = m_p10CqiRxed.find (rnti);
693  if (it == m_p10CqiRxed.end ())
694  {
695  // create the new entry
696  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)
697  // generate correspondent timer
698  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
699  }
700  else
701  {
702  // update the CQI value and refresh correspondent timer
703  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
704  // update correspondent timer
705  std::map <uint16_t,uint32_t>::iterator itTimers;
706  itTimers = m_p10CqiTimers.find (rnti);
707  (*itTimers).second = m_cqiTimersThreshold;
708  }
709  }
710  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
711  {
712  // subband CQI reporting high layer configured
713  std::map <uint16_t,SbMeasResult_s>::iterator it;
714  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
715  it = m_a30CqiRxed.find (rnti);
716  if (it == m_a30CqiRxed.end ())
717  {
718  // create the new entry
719  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
720  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
721  }
722  else
723  {
724  // update the CQI value and refresh correspondent timer
725  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
726  std::map <uint16_t,uint32_t>::iterator itTimers;
727  itTimers = m_a30CqiTimers.find (rnti);
728  (*itTimers).second = m_cqiTimersThreshold;
729  }
730  }
731  else
732  {
733  NS_LOG_ERROR (this << " CQI type unknown");
734  }
735  }
736 
737  return;
738 }
739 
740 
741 double
742 FdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
743 {
744  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
745  if (itCqi == m_ueCqi.end ())
746  {
747  // no cqi info about this UE
748  return (NO_SINR);
749 
750  }
751  else
752  {
753  // take the average SINR value among the available
754  double sinrSum = 0;
755  int sinrNum = 0;
756  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
757  {
758  double sinr = (*itCqi).second.at (i);
759  if (sinr != NO_SINR)
760  {
761  sinrSum += sinr;
762  sinrNum++;
763  }
764  }
765  double estimatedSinr = sinrSum / (double)sinrNum;
766  // store the value
767  (*itCqi).second.at (rb) = estimatedSinr;
768  return (estimatedSinr);
769  }
770 }
771 
772 void
774 {
775  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
776 
777  RefreshUlCqiMaps ();
778 
779  std::map <uint16_t,uint32_t>::iterator it;
780  int nflows = 0;
781 
782  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
783  {
784  // remove old entries of this UE-LC
785  if ((*it).second > 0)
786  {
787  nflows++;
788  }
789  }
790 
791  if (nflows == 0)
792  {
793  return ; // no flows to be scheduled
794  }
795 
796 
797  // Divide the resource equally among the active users
798  int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
799  if (rbPerFlow == 0)
800  {
801  rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
802  }
803  int rbAllocated = 0;
804 
806  std::vector <uint16_t> rbgAllocationMap;
807  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
808  if (m_nextRntiUl != 0)
809  {
810  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
811  {
812  if ((*it).first == m_nextRntiUl)
813  {
814  break;
815  }
816  }
817  if (it == m_ceBsrRxed.end ())
818  {
819  NS_LOG_ERROR (this << " no user found");
820  }
821  }
822  else
823  {
824  it = m_ceBsrRxed.begin ();
825  m_nextRntiUl = (*it).first;
826  }
827  do
828  {
829  if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
830  {
831  // limit to physical resources last resource assignment
832  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
833  }
834 
835  UlDciListElement_s uldci;
836  uldci.m_rnti = (*it).first;
837  uldci.m_rbStart = rbAllocated;
838  uldci.m_rbLen = rbPerFlow;
839  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
840  int cqi = 0;
841  if (itCqi == m_ueCqi.end ())
842  {
843  // no cqi info about this UE
844  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
845  }
846  else
847  {
848  // take the lowest CQI value (worst RB)
849  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
850  if (minSinr == NO_SINR)
851  {
852  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
853  }
854  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
855  {
856  double sinr = (*itCqi).second.at (i);
857  if (sinr == NO_SINR)
858  {
859  sinr = EstimateUlSinr ((*it).first, i);
860  }
861  if ((*itCqi).second.at (i) < minSinr)
862  {
863  minSinr = (*itCqi).second.at (i);
864  }
865  }
866 
867  // translate SINR -> cqi: WILD ACK: same as DL
868  double s = log2 ( 1 + (
869  std::pow (10, minSinr / 10 ) /
870  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
872  if (cqi == 0)
873  {
874  it++;
875  if (it == m_ceBsrRxed.end ())
876  {
877  // restart from the first
878  it = m_ceBsrRxed.begin ();
879  }
880  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
881  }
882  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
883  }
884 
885  rbAllocated += rbPerFlow;
886  // store info on allocation for managing ul-cqi interpretation
887  for (int i = 0; i < rbPerFlow; i++)
888  {
889  rbgAllocationMap.push_back ((*it).first);
890  }
891  uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
892  NS_LOG_DEBUG (this << " UE " << (*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);
893  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
894  uldci.m_ndi = 1;
895  uldci.m_cceIndex = 0;
896  uldci.m_aggrLevel = 1;
897  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
898  uldci.m_hopping = false;
899  uldci.m_n2Dmrs = 0;
900  uldci.m_tpc = 0; // no power control
901  uldci.m_cqiRequest = false; // only period CQI at this stage
902  uldci.m_ulIndex = 0; // TDD parameter
903  uldci.m_dai = 1; // TDD parameter
904  uldci.m_freqHopping = 0;
905  uldci.m_pdcchPowerOffset = 0; // not used
906  ret.m_dciList.push_back (uldci);
907 
908  // update TTI UE stats
909  itStats = m_flowStatsUl.find ((*it).first);
910  if (itStats != m_flowStatsUl.end ())
911  {
912  (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
913  }
914  else
915  {
916  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
917  }
918 
919 
920  it++;
921  if (it == m_ceBsrRxed.end ())
922  {
923  // restart from the first
924  it = m_ceBsrRxed.begin ();
925  }
926  if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
927  {
928  // Stop allocation: no more PRBs
929  m_nextRntiUl = (*it).first;
930  break;
931  }
932  }
933  while ((*it).first != m_nextRntiUl);
934 
935 
936  // Update global UE stats
937  // update UEs stats
938  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
939  {
940  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
941  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
942  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
943  (*itStats).second.lastTtiBytesTransmitted = 0;
944  }
945  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
947  return;
948 }
949 
950 void
952 {
953  NS_FATAL_ERROR ("unimplemented");
954  return;
955 }
956 
957 void
959 {
960  NS_FATAL_ERROR ("unimplemented");
961  return;
962 }
963 
964 void
966 {
967  NS_LOG_FUNCTION (this);
968 
969  std::map <uint16_t,uint32_t>::iterator it;
970 
971  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
972  {
973  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
974  {
975  // buffer status report
976  // note that we only consider LCG 0, the other three LCGs are neglected
977  // this is consistent with the assumption in LteUeMac that the first LCG gathers all LCs
978  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
979  it = m_ceBsrRxed.find (rnti);
980  if (it == m_ceBsrRxed.end ())
981  {
982  // create the new entry
983  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
984  int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
985  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
986  }
987  else
988  {
989  // update the buffer size value
990  (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
991  }
992  }
993  }
994 
995  return;
996 }
997 
998 void
1000 {
1001  NS_LOG_FUNCTION (this);
1002  // retrieve the allocation for this subframe
1003  switch (m_ulCqiFilter)
1004  {
1006  {
1007  // filter all the CQIs that are not SRS based
1008  if (params.m_ulCqi.m_type!=UlCqi_s::SRS)
1009  {
1010  return;
1011  }
1012  }
1013  break;
1015  {
1016  // filter all the CQIs that are not SRS based
1017  if (params.m_ulCqi.m_type!=UlCqi_s::PUSCH)
1018  {
1019  return;
1020  }
1021  }
1023  break;
1024 
1025  default:
1026  NS_FATAL_ERROR ("Unknown UL CQI type");
1027  }
1028 
1029  switch (params.m_ulCqi.m_type)
1030  {
1031  case UlCqi_s::PUSCH:
1032  {
1033  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
1034  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1035  itMap = m_allocationMaps.find (params.m_sfnSf);
1036  if (itMap == m_allocationMaps.end ())
1037  {
1038  NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
1039  return;
1040  }
1041  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
1042  {
1043  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1044  // NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
1045  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
1046  itCqi = m_ueCqi.find ((*itMap).second.at (i));
1047  if (itCqi == m_ueCqi.end ())
1048  {
1049  // create a new entry
1050  std::vector <double> newCqi;
1051  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1052  {
1053  if (i == j)
1054  {
1055  newCqi.push_back (sinr);
1056  }
1057  else
1058  {
1059  // initialize with NO_SINR value.
1060  newCqi.push_back (NO_SINR);
1061  }
1062 
1063  }
1064  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
1065  // generate correspondent timer
1066  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
1067  }
1068  else
1069  {
1070  // update the value
1071  (*itCqi).second.at (i) = sinr;
1072  // update correspondent timer
1073  std::map <uint16_t, uint32_t>::iterator itTimers;
1074  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1075  (*itTimers).second = m_cqiTimersThreshold;
1076 
1077  }
1078 
1079  }
1080  // remove obsolete info on allocation
1081  m_allocationMaps.erase (itMap);
1082  }
1083  break;
1084  case UlCqi_s::SRS:
1085  {
1086  // get the RNTI from vendor specific parameters
1087  uint16_t rnti = 0;
1088  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1089  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1090  {
1091  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1092  {
1093  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1094  rnti = vsp->GetRnti ();
1095  }
1096  }
1097  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1098  itCqi = m_ueCqi.find (rnti);
1099  if (itCqi == m_ueCqi.end ())
1100  {
1101  // create a new entry
1102  std::vector <double> newCqi;
1103  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1104  {
1105  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1106  newCqi.push_back (sinr);
1107  NS_LOG_DEBUG (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1108 
1109  }
1110  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1111  // generate correspondent timer
1112  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1113  }
1114  else
1115  {
1116  // update the values
1117  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1118  {
1119  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1120  (*itCqi).second.at (j) = sinr;
1121  NS_LOG_DEBUG (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1122  }
1123  // update correspondent timer
1124  std::map <uint16_t, uint32_t>::iterator itTimers;
1125  itTimers = m_ueCqiTimers.find (rnti);
1126  (*itTimers).second = m_cqiTimersThreshold;
1127 
1128  }
1129 
1130 
1131  }
1132  break;
1133  case UlCqi_s::PUCCH_1:
1134  case UlCqi_s::PUCCH_2:
1135  case UlCqi_s::PRACH:
1136  {
1137  NS_FATAL_ERROR ("FdBetFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1138  }
1139  break;
1140  default:
1141  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1142  }
1143  return;
1144 }
1145 
1146 void
1148 {
1149  // refresh DL CQI P01 Map
1150  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1151  while (itP10!=m_p10CqiTimers.end ())
1152  {
1153 // NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1154  if ((*itP10).second == 0)
1155  {
1156  // delete correspondent entries
1157  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1158  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1159  NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
1160  m_p10CqiRxed.erase (itMap);
1161  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1162  itP10++;
1163  m_p10CqiTimers.erase (temp);
1164  }
1165  else
1166  {
1167  (*itP10).second--;
1168  itP10++;
1169  }
1170  }
1171 
1172  // refresh DL CQI A30 Map
1173  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1174  while (itA30!=m_a30CqiTimers.end ())
1175  {
1176 // NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1177  if ((*itA30).second == 0)
1178  {
1179  // delete correspondent entries
1180  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1181  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1182  NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
1183  m_a30CqiRxed.erase (itMap);
1184  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1185  itA30++;
1186  m_a30CqiTimers.erase (temp);
1187  }
1188  else
1189  {
1190  (*itA30).second--;
1191  itA30++;
1192  }
1193  }
1194 
1195  return;
1196 }
1197 
1198 
1199 void
1201 {
1202  // refresh UL CQI Map
1203  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1204  while (itUl!=m_ueCqiTimers.end ())
1205  {
1206 // NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1207  if ((*itUl).second == 0)
1208  {
1209  // delete correspondent entries
1210  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1211  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1212  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1213  (*itMap).second.clear ();
1214  m_ueCqi.erase (itMap);
1215  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1216  itUl++;
1217  m_ueCqiTimers.erase (temp);
1218  }
1219  else
1220  {
1221  (*itUl).second--;
1222  itUl++;
1223  }
1224  }
1225 
1226  return;
1227 }
1228 
1229 void
1230 FdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1231 {
1232  size = size - 2; // remove the minimum RLC overhead
1233  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1234  LteFlowId_t flow (rnti, lcid);
1235  it = m_rlcBufferReq.find (flow);
1236  if (it!=m_rlcBufferReq.end ())
1237  {
1238  // Update queues: RLC tx order Status, ReTx, Tx
1239  // Update status queue
1240  if ((*it).second.m_rlcStatusPduSize <= size)
1241  {
1242  size -= (*it).second.m_rlcStatusPduSize;
1243  (*it).second.m_rlcStatusPduSize = 0;
1244  }
1245  else
1246  {
1247  (*it).second.m_rlcStatusPduSize -= size;
1248  return;
1249  }
1250  // update retransmission queue
1251  if ((*it).second.m_rlcRetransmissionQueueSize <= size)
1252  {
1253  size -= (*it).second.m_rlcRetransmissionQueueSize;
1254  (*it).second.m_rlcRetransmissionQueueSize = 0;
1255  }
1256  else
1257  {
1258  (*it).second.m_rlcRetransmissionQueueSize -= size;
1259  return;
1260  }
1261  // update transmission queue
1262  if ((*it).second.m_rlcTransmissionQueueSize <= size)
1263  {
1264  size -= (*it).second.m_rlcTransmissionQueueSize;
1265  (*it).second.m_rlcTransmissionQueueSize = 0;
1266  }
1267  else
1268  {
1269  (*it).second.m_rlcTransmissionQueueSize -= size;
1270  return;
1271  }
1272  }
1273  else
1274  {
1275  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
1276  }
1277 }
1278 
1279 void
1280 FdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
1281 {
1282 
1283  size = size - 2; // remove the minimum RLC overhead
1284  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
1285  if (it!=m_ceBsrRxed.end ())
1286  {
1287  if ((*it).second >= size)
1288  {
1289  (*it).second -= size;
1290  }
1291  else
1292  {
1293  (*it).second = 0;
1294  }
1295  }
1296  else
1297  {
1298  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
1299  }
1300 
1301 }
1302 
1303 void
1305 {
1306  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
1308  params.m_rnti = rnti;
1309  params.m_transmissionMode = txMode;
1311 }
1312 
1313 
1314 }