A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
tdbet-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/tdbet-ff-mac-scheduler.h>
29 #include <ns3/lte-vendor-specific-parameters.h>
30 
31 NS_LOG_COMPONENT_DEFINE ("TdBetFfMacScheduler");
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 (TdBetFfMacScheduler);
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::TdBetFfMacScheduler")
243  .AddConstructor<TdBetFfMacScheduler> ()
244  .AddAttribute ("CqiTimerThreshold",
245  "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
246  UintegerValue (1000),
247  MakeUintegerAccessor (&TdBetFfMacScheduler::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, tdbetsFlowPerf_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  tdbetsFlowPerf_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, tdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
325  tdbetsFlowPerf_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, tdbetsFlowPerf_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 < TdBetType0AllocationRbg[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  // evaluate the relative channel quality indicator for each UE per each RBG
438  // (since we are using allocation type 0 the small unit of allocation is RBG)
439  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
440 
441  RefreshDlCqiMaps ();
442 
444  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
445  std::map <uint16_t, std::vector <uint16_t> > allocationMap;
446  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
447  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itMax = m_flowStatsDl.end ();
448  double metricMax = 0.0;
449  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
450  {
451  double metric = 1 / (*it).second.lastAveragedThroughput;
452 
453  if (metric > metricMax)
454  {
455  metricMax = metric;
456  itMax = it;
457  }
458  } // end for m_flowStatsDl
459 
460  if (itMax == m_flowStatsDl.end ())
461  {
462  // no UE available for downlink
463  return;
464  }
465  else
466  {
467  // assign all RBGs to this UE
468  std::vector <uint16_t> tempMap;
469  for (int i = 0; i < rbgNum; i++)
470  {
471  tempMap.push_back (i);
472  }
473  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
474  }
475 
476  // reset TTI stats of users
477  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
478  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
479  {
480  (*itStats).second.lastTtiBytesTransmitted = 0;
481  }
482 
483  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
484  // creating the correspondent DCIs
486  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
487  while (itMap != allocationMap.end ())
488  {
489  // create new BuildDataListElement_s for this LC
491  newEl.m_rnti = (*itMap).first;
492  // create the DlDciListElement_s
493  DlDciListElement_s newDci;
494  std::vector <struct RlcPduListElement_s> newRlcPduLe;
495  newDci.m_rnti = (*itMap).first;
496 
497  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
498  std::map <uint16_t,uint8_t>::iterator itCqi;
499  itCqi = m_p10CqiRxed.find ((*itMap).first);
500  std::map <uint16_t,uint8_t>::iterator itTxMode;
501  itTxMode = m_uesTxMode.find ((*itMap).first);
502  if (itTxMode == m_uesTxMode.end ())
503  {
504  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
505  }
506  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
507  uint32_t bytesTxed = 0;
508  for (uint8_t i = 0; i < nLayer; i++)
509  {
510  if (itCqi == m_p10CqiRxed.end ())
511  {
512  newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
513  }
514  else
515  {
516  newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
517  }
518  }
519 
520  for (uint8_t i = 0; i < nLayer; i++)
521  {
522  int tbSize = (m_amc->GetTbSizeFromMcs (newDci.m_mcs.at (0), rbgNum * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
523  newDci.m_tbsSize.push_back (tbSize);
524  bytesTxed += tbSize;
525  }
526 
527  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
528  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
529  uint32_t rbgMask = 0;
530  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
531  {
532  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
533  }
534  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
535 
536  // create the rlc PDUs -> equally divide resources among actives LCs
537  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
538  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
539  {
540  if (((*itBufReq).first.m_rnti == (*itMap).first) &&
541  (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
542  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
543  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
544  {
545  for (uint8_t j = 0; j < nLayer; j++)
546  {
547  RlcPduListElement_s newRlcEl;
548  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
549  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
550  newRlcPduLe.push_back (newRlcEl);
551  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
552  }
553  }
554  if ((*itBufReq).first.m_rnti > (*itMap).first)
555  {
556  break;
557  }
558  }
559  newDci.m_ndi.push_back (1); // TBD (new data indicator)
560  newDci.m_rv.push_back (0); // TBD (redundancy version)
561 
562  newEl.m_dci = newDci;
563  // ...more parameters -> ingored in this version
564 
565  newEl.m_rlcPduList.push_back (newRlcPduLe);
566  ret.m_buildDataList.push_back (newEl);
567 
568  // update UE stats
569  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
570  it = m_flowStatsDl.find ((*itMap).first);
571  if (it != m_flowStatsDl.end ())
572  {
573  (*it).second.lastTtiBytesTransmitted = bytesTxed;
574  }
575  else
576  {
577  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
578  }
579 
580  itMap++;
581  } // end while allocation
582  ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
583 
584 
585  // update UEs stats
586  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
587  {
588  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
589  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
590  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
591  (*itStats).second.lastTtiBytesTransmitted = 0;
592  }
593 
595 
596 
597  return;
598 }
599 
600 void
602 {
603  NS_FATAL_ERROR ("unimplemented");
604  return;
605 }
606 
607 void
609 {
610  NS_LOG_FUNCTION (this);
611 
612  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
613  {
614  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
615  {
616  // wideband CQI reporting
617  std::map <uint16_t,uint8_t>::iterator it;
618  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
619  it = m_p10CqiRxed.find (rnti);
620  if (it == m_p10CqiRxed.end ())
621  {
622  // create the new entry
623  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)
624  // generate correspondent timer
625  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
626  }
627  else
628  {
629  // update the CQI value and refresh correspondent timer
630  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
631  // update correspondent timer
632  std::map <uint16_t,uint32_t>::iterator itTimers;
633  itTimers = m_p10CqiTimers.find (rnti);
634  (*itTimers).second = m_cqiTimersThreshold;
635  }
636  }
637  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
638  {
639  // subband CQI reporting high layer configured
640  std::map <uint16_t,SbMeasResult_s>::iterator it;
641  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
642  it = m_a30CqiRxed.find (rnti);
643  if (it == m_a30CqiRxed.end ())
644  {
645  // create the new entry
646  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
647  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
648  }
649  else
650  {
651  // update the CQI value and refresh correspondent timer
652  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
653  std::map <uint16_t,uint32_t>::iterator itTimers;
654  itTimers = m_a30CqiTimers.find (rnti);
655  (*itTimers).second = m_cqiTimersThreshold;
656  }
657  }
658  else
659  {
660  NS_LOG_ERROR (this << " CQI type unknown");
661  }
662  }
663 
664  return;
665 }
666 
667 
668 double
669 TdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
670 {
671  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
672  if (itCqi == m_ueCqi.end ())
673  {
674  // no cqi info about this UE
675  return (NO_SINR);
676 
677  }
678  else
679  {
680  // take the average SINR value among the available
681  double sinrSum = 0;
682  int sinrNum = 0;
683  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
684  {
685  double sinr = (*itCqi).second.at (i);
686  if (sinr != NO_SINR)
687  {
688  sinrSum += sinr;
689  sinrNum++;
690  }
691  }
692  double estimatedSinr = sinrSum / (double)sinrNum;
693  // store the value
694  (*itCqi).second.at (rb) = estimatedSinr;
695  return (estimatedSinr);
696  }
697 }
698 
699 void
701 {
702  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
703 
704  RefreshUlCqiMaps ();
705 
706  std::map <uint16_t,uint32_t>::iterator it;
707  int nflows = 0;
708 
709  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
710  {
711  // remove old entries of this UE-LC
712  if ((*it).second > 0)
713  {
714  nflows++;
715  }
716  }
717 
718  if (nflows == 0)
719  {
720  return ; // no flows to be scheduled
721  }
722 
723 
724  // Divide the resource equally among the active users
725  int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
726  if (rbPerFlow == 0)
727  {
728  rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
729  }
730  int rbAllocated = 0;
731 
733  std::vector <uint16_t> rbgAllocationMap;
734  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
735  if (m_nextRntiUl != 0)
736  {
737  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
738  {
739  if ((*it).first == m_nextRntiUl)
740  {
741  break;
742  }
743  }
744  if (it == m_ceBsrRxed.end ())
745  {
746  NS_LOG_ERROR (this << " no user found");
747  }
748  }
749  else
750  {
751  it = m_ceBsrRxed.begin ();
752  m_nextRntiUl = (*it).first;
753  }
754  do
755  {
756  if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
757  {
758  // limit to physical resources last resource assignment
759  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
760  }
761 
762  UlDciListElement_s uldci;
763  uldci.m_rnti = (*it).first;
764  uldci.m_rbStart = rbAllocated;
765  uldci.m_rbLen = rbPerFlow;
766  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
767  int cqi = 0;
768  if (itCqi == m_ueCqi.end ())
769  {
770  // no cqi info about this UE
771  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
772  }
773  else
774  {
775  // take the lowest CQI value (worst RB)
776  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
777  if (minSinr == NO_SINR)
778  {
779  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
780  }
781  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
782  {
783  double sinr = (*itCqi).second.at (i);
784  if (sinr == NO_SINR)
785  {
786  sinr = EstimateUlSinr ((*it).first, i);
787  }
788  if ((*itCqi).second.at (i) < minSinr)
789  {
790  minSinr = (*itCqi).second.at (i);
791  }
792  }
793 
794  // translate SINR -> cqi: WILD ACK: same as DL
795  double s = log2 ( 1 + (
796  std::pow (10, minSinr / 10 ) /
797  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
799  if (cqi == 0)
800  {
801  it++;
802  if (it == m_ceBsrRxed.end ())
803  {
804  // restart from the first
805  it = m_ceBsrRxed.begin ();
806  }
807  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
808  }
809  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
810 
811  }
812 
813  rbAllocated += rbPerFlow;
814  // store info on allocation for managing ul-cqi interpretation
815  for (int i = 0; i < rbPerFlow; i++)
816  {
817  rbgAllocationMap.push_back ((*it).first);
818  }
819  uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
820  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);
821  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
822  uldci.m_ndi = 1;
823  uldci.m_cceIndex = 0;
824  uldci.m_aggrLevel = 1;
825  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
826  uldci.m_hopping = false;
827  uldci.m_n2Dmrs = 0;
828  uldci.m_tpc = 0; // no power control
829  uldci.m_cqiRequest = false; // only period CQI at this stage
830  uldci.m_ulIndex = 0; // TDD parameter
831  uldci.m_dai = 1; // TDD parameter
832  uldci.m_freqHopping = 0;
833  uldci.m_pdcchPowerOffset = 0; // not used
834  ret.m_dciList.push_back (uldci);
835 
836  // update TTI UE stats
837  itStats = m_flowStatsUl.find ((*it).first);
838  if (itStats != m_flowStatsUl.end ())
839  {
840  (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
841  }
842  else
843  {
844  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
845  }
846 
847 
848  it++;
849  if (it == m_ceBsrRxed.end ())
850  {
851  // restart from the first
852  it = m_ceBsrRxed.begin ();
853  }
854  if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
855  {
856  // Stop allocation: no more PRBs
857  m_nextRntiUl = (*it).first;
858  break;
859  }
860  }
861  while ((*it).first != m_nextRntiUl);
862 
863 
864  // Update global UE stats
865  // update UEs stats
866  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
867  {
868  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
869  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
870  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
871  (*itStats).second.lastTtiBytesTransmitted = 0;
872  }
873  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
875  return;
876 }
877 
878 void
880 {
881  NS_FATAL_ERROR ("unimplemented");
882  return;
883 }
884 
885 void
887 {
888  NS_FATAL_ERROR ("unimplemented");
889  return;
890 }
891 
892 void
894 {
895  NS_LOG_FUNCTION (this);
896 
897  std::map <uint16_t,uint32_t>::iterator it;
898 
899  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
900  {
901  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
902  {
903  // buffer status report
904  // note that we only consider LCG 0, the other three LCGs are neglected
905  // this is consistent with the assumption in LteUeMac that the first LCG gathers all LCs
906  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
907  it = m_ceBsrRxed.find (rnti);
908  if (it == m_ceBsrRxed.end ())
909  {
910  // create the new entry
911  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
912  int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
913  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
914  }
915  else
916  {
917  // update the buffer size value
918  (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
919  }
920  }
921  }
922 
923  return;
924 }
925 
926 void
928 {
929  NS_LOG_FUNCTION (this);
930  // retrieve the allocation for this subframe
931  switch (m_ulCqiFilter)
932  {
934  {
935  // filter all the CQIs that are not SRS based
936  if (params.m_ulCqi.m_type!=UlCqi_s::SRS)
937  {
938  return;
939  }
940  }
941  break;
943  {
944  // filter all the CQIs that are not SRS based
945  if (params.m_ulCqi.m_type!=UlCqi_s::PUSCH)
946  {
947  return;
948  }
949  }
951  break;
952 
953  default:
954  NS_FATAL_ERROR ("Unknown UL CQI type");
955  }
956 
957  switch (params.m_ulCqi.m_type)
958  {
959  case UlCqi_s::PUSCH:
960  {
961  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
962  std::map <uint16_t, std::vector <double> >::iterator itCqi;
963  itMap = m_allocationMaps.find (params.m_sfnSf);
964  if (itMap == m_allocationMaps.end ())
965  {
966  NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
967  return;
968  }
969  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
970  {
971  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
972  // NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
973  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
974  itCqi = m_ueCqi.find ((*itMap).second.at (i));
975  if (itCqi == m_ueCqi.end ())
976  {
977  // create a new entry
978  std::vector <double> newCqi;
979  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
980  {
981  if (i == j)
982  {
983  newCqi.push_back (sinr);
984  }
985  else
986  {
987  // initialize with NO_SINR value.
988  newCqi.push_back (NO_SINR);
989  }
990 
991  }
992  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
993  // generate correspondent timer
994  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
995  }
996  else
997  {
998  // update the value
999  (*itCqi).second.at (i) = sinr;
1000  // update correspondent timer
1001  std::map <uint16_t, uint32_t>::iterator itTimers;
1002  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1003  (*itTimers).second = m_cqiTimersThreshold;
1004 
1005  }
1006 
1007  }
1008  // remove obsolete info on allocation
1009  m_allocationMaps.erase (itMap);
1010  }
1011  break;
1012  case UlCqi_s::SRS:
1013  {
1014  // get the RNTI from vendor specific parameters
1015  uint16_t rnti = 0;
1016  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1017  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1018  {
1019  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1020  {
1021  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1022  rnti = vsp->GetRnti ();
1023  }
1024  }
1025  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1026  itCqi = m_ueCqi.find (rnti);
1027  if (itCqi == m_ueCqi.end ())
1028  {
1029  // create a new entry
1030  std::vector <double> newCqi;
1031  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1032  {
1033  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1034  newCqi.push_back (sinr);
1035  NS_LOG_DEBUG (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1036 
1037  }
1038  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1039  // generate correspondent timer
1040  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1041  }
1042  else
1043  {
1044  // update the values
1045  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1046  {
1047  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1048  (*itCqi).second.at (j) = sinr;
1049  NS_LOG_DEBUG (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1050  }
1051  // update correspondent timer
1052  std::map <uint16_t, uint32_t>::iterator itTimers;
1053  itTimers = m_ueCqiTimers.find (rnti);
1054  (*itTimers).second = m_cqiTimersThreshold;
1055 
1056  }
1057 
1058 
1059  }
1060  break;
1061  case UlCqi_s::PUCCH_1:
1062  case UlCqi_s::PUCCH_2:
1063  case UlCqi_s::PRACH:
1064  {
1065  NS_FATAL_ERROR ("TdBetFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1066  }
1067  break;
1068  default:
1069  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1070  }
1071  return;
1072 }
1073 
1074 void
1076 {
1077  // refresh DL CQI P01 Map
1078  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1079  while (itP10!=m_p10CqiTimers.end ())
1080  {
1081 // NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1082  if ((*itP10).second == 0)
1083  {
1084  // delete correspondent entries
1085  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1086  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1087  NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
1088  m_p10CqiRxed.erase (itMap);
1089  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1090  itP10++;
1091  m_p10CqiTimers.erase (temp);
1092  }
1093  else
1094  {
1095  (*itP10).second--;
1096  itP10++;
1097  }
1098  }
1099 
1100  // refresh DL CQI A30 Map
1101  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1102  while (itA30!=m_a30CqiTimers.end ())
1103  {
1104 // NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1105  if ((*itA30).second == 0)
1106  {
1107  // delete correspondent entries
1108  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1109  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1110  NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
1111  m_a30CqiRxed.erase (itMap);
1112  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1113  itA30++;
1114  m_a30CqiTimers.erase (temp);
1115  }
1116  else
1117  {
1118  (*itA30).second--;
1119  itA30++;
1120  }
1121  }
1122 
1123  return;
1124 }
1125 
1126 
1127 void
1129 {
1130  // refresh UL CQI Map
1131  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1132  while (itUl!=m_ueCqiTimers.end ())
1133  {
1134 // NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1135  if ((*itUl).second == 0)
1136  {
1137  // delete correspondent entries
1138  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1139  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1140  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1141  (*itMap).second.clear ();
1142  m_ueCqi.erase (itMap);
1143  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1144  itUl++;
1145  m_ueCqiTimers.erase (temp);
1146  }
1147  else
1148  {
1149  (*itUl).second--;
1150  itUl++;
1151  }
1152  }
1153 
1154  return;
1155 }
1156 
1157 void
1158 TdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1159 {
1160  size = size - 2; // remove the minimum RLC overhead
1161  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1162  LteFlowId_t flow (rnti, lcid);
1163  it = m_rlcBufferReq.find (flow);
1164  if (it!=m_rlcBufferReq.end ())
1165  {
1166  // Update queues: RLC tx order Status, ReTx, Tx
1167  // Update status queue
1168  if ((*it).second.m_rlcStatusPduSize <= size)
1169  {
1170  size -= (*it).second.m_rlcStatusPduSize;
1171  (*it).second.m_rlcStatusPduSize = 0;
1172  }
1173  else
1174  {
1175  (*it).second.m_rlcStatusPduSize -= size;
1176  return;
1177  }
1178  // update retransmission queue
1179  if ((*it).second.m_rlcRetransmissionQueueSize <= size)
1180  {
1181  size -= (*it).second.m_rlcRetransmissionQueueSize;
1182  (*it).second.m_rlcRetransmissionQueueSize = 0;
1183  }
1184  else
1185  {
1186  (*it).second.m_rlcRetransmissionQueueSize -= size;
1187  return;
1188  }
1189  // update transmission queue
1190  if ((*it).second.m_rlcTransmissionQueueSize <= size)
1191  {
1192  size -= (*it).second.m_rlcTransmissionQueueSize;
1193  (*it).second.m_rlcTransmissionQueueSize = 0;
1194  }
1195  else
1196  {
1197  (*it).second.m_rlcTransmissionQueueSize -= size;
1198  return;
1199  }
1200  }
1201  else
1202  {
1203  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
1204  }
1205 }
1206 
1207 void
1208 TdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
1209 {
1210 
1211  size = size - 2; // remove the minimum RLC overhead
1212  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
1213  if (it!=m_ceBsrRxed.end ())
1214  {
1215  if ((*it).second >= size)
1216  {
1217  (*it).second -= size;
1218  }
1219  else
1220  {
1221  (*it).second = 0;
1222  }
1223  }
1224  else
1225  {
1226  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
1227  }
1228 
1229 }
1230 
1231 void
1233 {
1234  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
1236  params.m_rnti = rnti;
1237  params.m_transmissionMode = txMode;
1239 }
1240 
1241 
1242 }