--- a/src/lte/doc/source/lte-design.rst Mon Jun 25 11:52:17 2012 -0700
+++ b/src/lte/doc/source/lte-design.rst Sun Jul 01 21:06:56 2012 -0300
@@ -652,6 +652,84 @@
\right)}{\tau}
+Maximum Throughphut (MT) Scheduler
+----------------------------------
+
+The Maximum Throughput (MT) scheduler [FCapo2012]_ aims to maximize the overall throughput of eNB.
+It allocates each RB to the user that can achieve the maximum achievable rate in the current TTI.
+Currently, MT scheduler in LENA has two versions: frequency domain (FDMT) and time domain (TDMT).
+In FDMT, every TTI, MAC scheduler allocates RBGs to the UE who has highest achievable rate calculated
+by subband cqi. In TDMT, every TTI, MAC scheduler selects one UE which has highest achievable rate
+calculated by wideband cqi. Then MAC scheduler allocates all RBGs to this UE in current TTI.
+The caculation of achievable rate in FDMT and TDMT is as same as the one in PF.
+Let :math:`i,j` denote generic users; let :math:`t` be the
+subframe index, and :math:`k` be the resource block index; let :math:`M_{i,k}(t)` be MCS
+usable by user :math:`i` on resource block :math:`k` according to what reported by the AMC
+model (see `Adaptive Modulation and Coding`_); finally, let :math:`S(M, B)` be the TB
+size in bits as defined in [TS36.213]_ for the case where a number :math:`B` of
+resource blocks is used. The achievable rate :math:`R_{i}(k,t)` in bit/s for user :math:`i`
+on resource block :math:`k` at subframe :math:`t` is defined as
+
+.. math::
+
+ R_{i}(k,t) = \frac{S\left( M_{i,k}(t), 1\right)}{\tau}
+
+where :math:`\tau` is the TTI duration.
+At the start of each subframe :math:`t`, each RB is assigned to a certain user.
+In detail, the index :math:`\widehat{i}_{k}(t)` to which RB :math:`k` is assigned at time
+:math:`t` is determined as
+
+.. math::
+
+ \widehat{i}_{k}(t) = \underset{j=1,...,N}{\operatorname{argmax}}
+ \left( { R_{j}(k,t) } \right)
+
+When there are several UEs having the same achievable rate, current implementation always select
+the first UE created in script. Although MT can maximize cell throughput, it cannot provide
+faireness to UEs in poor chennel condition.
+
+
+Throughphut to Average (TTA) Scheduler
+--------------------------------------
+
+The Throughput to Average (TTA) scheduler [FCapo2012]_ can be considered as an intermidiate between MT and PF.
+The metric used in TTA is caculated as follows:
+
+.. math::
+
+ \widehat{i}_{k}(t) = \underset{j=1,...,N}{\operatorname{argmax}}
+ \left( \frac{ R_{j}(k,t) }{ R_{j}(t) } \right)
+
+Here,:math:`R_{i}(k,t)` in bit/s represents the achievable rate for user :math:`i`
+on resource block :math:`k` at subframe :math:`t`. The
+caculation method already is shown in MT and PF. Meanwhile, :math:`R_{i}(t)` in bit/s stands
+for the achievable rate for :math:`i` at subframe :math:`t`. The difference between those two
+achievable rates is how to get MCS. For :math:`R_{i}(k,t)`, MCS is caculatd by subband cqi while
+:math:`R_{i}(t)` is caculated by wideband cqi. TTA scheduler can only be implemented in frequency domain (FD) because
+the achievable rate of paritular RBG is only related to FD scheduling.
+
+Blind Average Throughput Scheduler
+----------------------------------
+
+The Blind Average Throughput scheduler [FCapo2012]_ aims to provide equal throughput to all UEs under eNB. The metric
+used in TTA is caculated as follows:
+
+.. math::
+
+ \widehat{i}_{k}(t) = \underset{j=1,...,N}{\operatorname{argmax}}
+ \left( \frac{ 1 }{ T_\mathrm{j}(t) } \right)
+
+where :math:`T_{j}(t)` is the past througput performance perceived by the user :math:`j` and can be caculated by the
+same method in PF scheduler. In the time domain blind average throughput (TD-BET), the scheduler selects the UE
+with largest priority metirc and allocates all RBGs to this UE. On the other hand, in the frequency domain blind
+average throughput (FD-BET), every TTI, the scheduler first selects one UE with lowest pastAverageThroughput (largest
+prioriy metric). Then scheduler assigns one RBG to this UE, it calculates expected throughput of this UE and uses it
+to compare with past average throughput :math:`T_{j}(t)` of other UEs. The scheduler continues
+to allocate RBG to this UE until its expected throughput is not the smallest one among past average throughput
+math:`T_{j}(t)` of all UE. Then the scheduler will use the same way to allocate RBG for a new UE which has the
+lowest past average throughput :math:`T_{j}(t)` until all RBGs are allocated to UEs. The principle behind this is
+that, in every TTI, the scheduler tries the best to achieve the equal throughput among all UEs.
+
Transport Blocks
----------------
--- a/src/lte/doc/source/lte-references.rst Mon Jun 25 11:52:17 2012 -0700
+++ b/src/lte/doc/source/lte-references.rst Sun Jul 01 21:06:56 2012 -0300
@@ -72,4 +72,7 @@
.. [Ikuno2010] J.C. Ikuno, M. Wrulich, M. Rupp, "System Level Simulation of LTE Networks," Vehicular Technology Conference (VTC 2010-Spring), 2010 IEEE 71st , vol., no., pp.1-5, 16-19 May 2010
+.. [GPiro2011] G. Piro, L. A. Grieco, G. Boggia, R. Fortuna, and P. Camarda, "Two-level downlink scheduling for real-time multimedia services in LTE networks", IEEE Trans. Multimedia, vol.13, no.5, pp.1052-1065, Oct.,2011
+.. [FCapo2012] F.Capozzi, G.Piro L.A.Grieco, G.Boggia, P.Camarda, "Downlink Packet Scheduling in LTE Cellular Networks: Key Design Issues and a Survey", IEEE Comm. Surveys and Tutorials, to appear
+
--- a/src/lte/doc/source/lte-testing.rst Mon Jun 25 11:52:17 2012 -0700
+++ b/src/lte/doc/source/lte-testing.rst Sun Jul 01 21:06:56 2012 -0300
@@ -347,6 +347,93 @@
where the UEs have MCS index :math:`28, 24, 16, 12, 6`
+Maximum Throughput scheduler performance
+----------------------------------------
+
+Test suites ``lte-fdmt-ff-mac-scheduler`` and ``lte-tdmt-ff-mac-scheduler``
+create different test cases with a single eNB and several UEs, all having the same
+Radio Bearer specification, using the Frequency Domain Maximum Throughput (FDMT)
+scheduler and Time Domain Maximum Throughput (TDMT) scheduler repectively,
+In other words, UEs are all placed at the
+same distance from the eNB, and hence all placed in order to have the
+same SINR. Different test cases are implemented by using a different
+SINR value and a different number of UEs. The test consists on
+checking that the obtained throughput performance matches with the
+known reference throughput up to a given tolerance.The expected
+behavior of both FDMT and TDMT scheduler when all UEs have the same SNR is that
+scheduler allocates all RBGs to the first UE defined in script. This is because
+current FDMT and TDMT implementation always select the first UE to serve when there are
+multiple UEs having the same SNR value. We calculate the reference
+throughput value for first UE by the throughput achievable of a sinlge UE
+at the given SNR, while reference throughput value for other UEs by zero.
+Let :math:`\tau` be the TTI duration, :math:`B` the transmission
+bandwidth configuration in number of RBs, :math:`M` the modulation and
+coding scheme in use at the given SINR and :math:`S(M, B)` be the
+transport block size as defined in [TS36.213]_. The reference
+throughput :math:`T` in bit/s achieved by each UE is calculated as
+
+.. math::
+
+ T = \frac{S(M,B)}{\tau}
+
+The curves labeled "MT" in Figure XX represent the test values
+calculated for the FDMT and TDMT scheduler test case that we just described.
+
+
+Throughput to Average scheduler performance
+-------------------------------------------
+
+Test suites ``lte-tta-ff-mac-scheduler``
+create different test cases with a single eNB and several UEs, all having the same
+Radio Bearer specification using TTA scheduler. Network topology and configurations in
+TTA test case are as same as the test for MT scheduler. More complex test case need to be
+developed to show the fairness feature of TTA scheduler.
+
+
+Blind Average Throughput scheduler performance
+----------------------------------------------
+
+Test suites ``lte-tdbet-ff-mac-scheduler`` and ``lte-fdbet-ff-mac-scheduler`` create different
+test cases with a single eNB and several UEs, all having the same Radio Bearer specification.
+
+In the first test case of ``lte-tdbet-ff-mac-scheduler`` and ``lte-fdbet-ff-mac-scheduler``,
+the UEs are all placed at the same distance from the eNB, and hence all placed in order to
+have the same SINR. Different test cases are implemented by using a different SINR value and
+a different number of UEs. The test consists on checking that the obtained throughput performance
+matches with the known reference throughput up to a given tolerance. In long term, the expected
+behavior of both TD-BET and FD-BET when all UEs have the same SNR is that each UE should get an
+equal throughput. However, the exact throughput value of TD-BET and FD-BET in this test case is not
+the same.
+
+When all UEs have the same SNR, TD-BET can be seen as a specific case of PF where achievable rate equals
+to 1. Therefore, the throughput get by TD-BET is equal to that of PF. On the other hand, FD-BET performs
+very similar to the round robin (RR) scheduler in case of that all UEs have the same SNR and the number of UE(RBG)
+is an integer multiple of the number of RBG(UE). In this case, FD-BET always allocate the same number of RBGs
+to each UE. For example, if eNB has 12 RBGs and there are 6 UEs, then each UE will get 2 RBGs in each TTI.
+Or if eNB has 12 RBGs and there are 24 UEs, then each UE will get 2 RBGs per two TTIs. When the number of
+UE (RBG) is not an integer multiple of the number of RBG (UE), FD-BET will not follow the RR behavior because
+it will assigned different number of RBGs to some UEs, while the throughput of each UE is still the same.
+
+The second category of tests aims at verifying the fairness of the both TD-BET and FD-BET schedulers in a more realistic
+simulation scenario where the UEs have a different SINR (constant for the whole simulation). In this case,
+both scheduler should give the same amount of throughput to each user.
+
+Specifically, for TD-BET, let :math:`F_i` be the fraction of time allocated to user i in total simulation time,
+:math:`R^{fb}_i` be the the full bandwidth achievable rate for user i and :math: `T_i` be the achieved throughput of
+user i. Then we have:
+
+.. math::
+
+ T_i = F_i R^{fb}_i
+
+In TD-BET, the sum of :math:`F_i` for all user equals one. In long term, all UE has the same :math:`T_i` so that we replace
+:math: `T_i` by :math: `T`. Then we have:
+
+.. math::
+
+ T = \frac{1}{ \sum_{i=1}~N \frac{1}{R^{fb}_i} }
+
+
Building Propagation Loss Model
-------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/fdbet-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,1208 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifdef __FreeBSD__
+#define log2(x) (log(x) / M_LN2)
+#endif /* __FreeBSD__ */
+
+#include <ns3/log.h>
+#include <ns3/pointer.h>
+
+#include <ns3/simulator.h>
+#include <ns3/lte-amc.h>
+#include <ns3/fdbet-ff-mac-scheduler.h>
+
+NS_LOG_COMPONENT_DEFINE ("FdBetFfMacScheduler");
+
+namespace ns3 {
+
+int FdBetType0AllocationRbg[4] = {
+ 10, // RGB size 1
+ 26, // RGB size 2
+ 63, // RGB size 3
+ 110 // RGB size 4
+}; // see table 7.1.6.1-1 of 36.213
+
+
+NS_OBJECT_ENSURE_REGISTERED (FdBetFfMacScheduler);
+
+
+
+class FdBetSchedulerMemberCschedSapProvider : public FfMacCschedSapProvider
+{
+public:
+ FdBetSchedulerMemberCschedSapProvider (FdBetFfMacScheduler* scheduler);
+
+ // inherited from FfMacCschedSapProvider
+ virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
+ virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
+ virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
+ virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
+ virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
+
+private:
+ FdBetSchedulerMemberCschedSapProvider ();
+ FdBetFfMacScheduler* m_scheduler;
+};
+
+FdBetSchedulerMemberCschedSapProvider::FdBetSchedulerMemberCschedSapProvider ()
+{
+}
+
+FdBetSchedulerMemberCschedSapProvider::FdBetSchedulerMemberCschedSapProvider (FdBetFfMacScheduler* scheduler) : m_scheduler (scheduler)
+{
+}
+
+
+void
+FdBetSchedulerMemberCschedSapProvider::CschedCellConfigReq (const struct CschedCellConfigReqParameters& params)
+{
+ m_scheduler->DoCschedCellConfigReq (params);
+}
+
+void
+FdBetSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
+{
+ m_scheduler->DoCschedUeConfigReq (params);
+}
+
+
+void
+FdBetSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
+{
+ m_scheduler->DoCschedLcConfigReq (params);
+}
+
+void
+FdBetSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedLcReleaseReq (params);
+}
+
+void
+FdBetSchedulerMemberCschedSapProvider::CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedUeReleaseReq (params);
+}
+
+
+
+
+class FdBetSchedulerMemberSchedSapProvider : public FfMacSchedSapProvider
+{
+public:
+ FdBetSchedulerMemberSchedSapProvider (FdBetFfMacScheduler* scheduler);
+
+ // inherited from FfMacSchedSapProvider
+ virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
+ virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
+ virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
+ virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
+ virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
+ virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
+ virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
+ virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
+ virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
+ virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
+ virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
+
+
+private:
+ FdBetSchedulerMemberSchedSapProvider ();
+ FdBetFfMacScheduler* m_scheduler;
+};
+
+
+
+FdBetSchedulerMemberSchedSapProvider::FdBetSchedulerMemberSchedSapProvider ()
+{
+}
+
+
+FdBetSchedulerMemberSchedSapProvider::FdBetSchedulerMemberSchedSapProvider (FdBetFfMacScheduler* scheduler)
+ : m_scheduler (scheduler)
+{
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlRlcBufferReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlPagingBufferReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlMacBufferReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedDlTriggerReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlRachInfoReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlCqiInfoReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedUlTriggerReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
+{
+ m_scheduler->DoSchedUlNoiseInterferenceReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlSrInfoReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlMacCtrlInfoReq (params);
+}
+
+void
+FdBetSchedulerMemberSchedSapProvider::SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlCqiInfoReq (params);
+}
+
+
+
+
+
+FdBetFfMacScheduler::FdBetFfMacScheduler ()
+ : m_cschedSapUser (0),
+ m_schedSapUser (0),
+ m_timeWindow (99.0),
+ m_nextRntiUl (0)
+{
+ m_amc = CreateObject <LteAmc> ();
+ m_cschedSapProvider = new FdBetSchedulerMemberCschedSapProvider (this);
+ m_schedSapProvider = new FdBetSchedulerMemberSchedSapProvider (this);
+}
+
+FdBetFfMacScheduler::~FdBetFfMacScheduler ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+FdBetFfMacScheduler::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_cschedSapProvider;
+ delete m_schedSapProvider;
+}
+
+TypeId
+FdBetFfMacScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::FdBetFfMacScheduler")
+ .SetParent<FfMacScheduler> ()
+ .AddConstructor<FdBetFfMacScheduler> ()
+ .AddAttribute ("CqiTimerThreshold",
+ "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
+ UintegerValue (1000),
+ MakeUintegerAccessor (&FdBetFfMacScheduler::m_cqiTimersThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+
+void
+FdBetFfMacScheduler::SetFfMacCschedSapUser (FfMacCschedSapUser* s)
+{
+ m_cschedSapUser = s;
+}
+
+void
+FdBetFfMacScheduler::SetFfMacSchedSapUser (FfMacSchedSapUser* s)
+{
+ m_schedSapUser = s;
+}
+
+FfMacCschedSapProvider*
+FdBetFfMacScheduler::GetFfMacCschedSapProvider ()
+{
+ return m_cschedSapProvider;
+}
+
+FfMacSchedSapProvider*
+FdBetFfMacScheduler::GetFfMacSchedSapProvider ()
+{
+ return m_schedSapProvider;
+}
+
+void
+FdBetFfMacScheduler::DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // Read the subset of parameters used
+ m_cschedCellConfig = params;
+ FfMacCschedSapUser::CschedUeConfigCnfParameters cnf;
+ cnf.m_result = SUCCESS;
+ m_cschedSapUser->CschedUeConfigCnf (cnf);
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
+ std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
+ if (it==m_uesTxMode.end ())
+ {
+ m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+ }
+ else
+ {
+ (*it).second = params.m_transmissionMode;
+ }
+ return;
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
+
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator it;
+ for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
+ {
+ it = m_flowStatsDl.find (params.m_rnti);
+
+ if (it == m_flowStatsDl.end ())
+ {
+ fdbetsFlowPerf_t flowStatsDl;
+ flowStatsDl.flowStart = Simulator::Now ();
+ flowStatsDl.totalBytesTransmitted = 0;
+ flowStatsDl.lastTtiBytesTrasmitted = 0;
+ flowStatsDl.lastAveragedThroughput = 1;
+ m_flowStatsDl.insert (std::pair<uint16_t, fdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
+ fdbetsFlowPerf_t flowStatsUl;
+ flowStatsUl.flowStart = Simulator::Now ();
+ flowStatsUl.totalBytesTransmitted = 0;
+ flowStatsUl.lastTtiBytesTrasmitted = 0;
+ flowStatsUl.lastAveragedThroughput = 1;
+ m_flowStatsUl.insert (std::pair<uint16_t, fdbetsFlowPerf_t> (params.m_rnti, flowStatsUl));
+ }
+ else
+ {
+ NS_LOG_ERROR ("RNTI already exists");
+ }
+ }
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+
+void
+FdBetFfMacScheduler::DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
+ // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
+
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+
+ LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
+
+ it = m_rlcBufferReq.find (flow);
+
+ if (it == m_rlcBufferReq.end ())
+ {
+ m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
+ }
+ else
+ {
+ (*it).second = params;
+ }
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+int
+FdBetFfMacScheduler::GetRbgSize (int dlbandwidth)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (dlbandwidth < FdBetType0AllocationRbg[i])
+ {
+ return (i + 1);
+ }
+ }
+
+ return (-1);
+}
+
+
+int
+FdBetFfMacScheduler::LcActivePerFlow (uint16_t rnti)
+{
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ int lcActive = 0;
+ for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
+ {
+ if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
+ || ((*it).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*it).second.m_rlcStatusPduSize > 0) ))
+ {
+ lcActive++;
+ }
+ if ((*it).first.m_rnti > rnti)
+ {
+ break;
+ }
+ }
+ return (lcActive);
+
+}
+
+
+void
+FdBetFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+ // API generated by RLC for triggering the scheduling of a DL subframe
+
+
+ // evaluate the relative channel quality indicator for each UE per each RBG
+ // (since we are using allocation type 0 the small unit of allocation is RBG)
+ // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
+
+ RefreshDlCqiMaps ();
+
+ int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+ int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+ std::map <uint16_t, std::vector <uint16_t> > allocationMap;
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator itFlow;
+ std::map <uint16_t, double> estAveThr; // store exptected average throughput for UE
+ std::map <uint16_t, double>::iterator itMax = estAveThr.end();
+ std::map <uint16_t, double>::iterator it;
+ std::map <uint16_t, int> rbgPerRntiLog; // record the number of RBG assigned to UE
+ double metricMax = 0.0;
+
+ for (itFlow = m_flowStatsDl.begin (); itFlow != m_flowStatsDl.end (); itFlow++)
+ {
+ estAveThr.insert(std::pair <uint16_t, double> ((*itFlow).first, (*itFlow).second.lastAveragedThroughput));
+ }
+
+ // Find UE with largest priority metric
+ for (it = estAveThr.begin(); it != estAveThr.end(); it++)
+ {
+ double metric = 1 / (*it).second;
+ if (metric > metricMax)
+ {
+ metricMax = metric;
+ itMax = it;
+ }
+ rbgPerRntiLog.insert(std::pair<uint16_t, int> ((*it).first, 1));
+ }
+
+ // The scheduler tries the best to achieve the equal throughput among all UEs
+ int i = 0;
+ do {
+ // allocate one RBG to current UE
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::vector <uint16_t> tempMap;
+ itMap = allocationMap.find ((*itMax).first);
+ if (itMap == allocationMap.end ())
+ {
+ tempMap.push_back (i);
+ allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
+ }
+ else
+ {
+ (*itMap).second.push_back (i);
+ }
+
+ // caculate expected throughput for current UE
+ std::map <uint16_t,uint8_t>::iterator itCqi;
+ itCqi = m_p10CqiRxed.find ((*itMax).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMax).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMax).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> mcs;
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ if (itCqi == m_p10CqiRxed.end ())
+ {
+ mcs.push_back (0); // no info on this user -> lowest MCS
+ }
+ else
+ {
+ mcs.push_back(m_amc->GetMcsFromCqi ((*itCqi).second));
+ }
+ }
+
+ std::map <uint16_t,int>::iterator itRbgPerRntiLog;
+ itRbgPerRntiLog = rbgPerRntiLog.find((*itMax).first);
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator itPastAveThr;
+ itPastAveThr = m_flowStatsDl.find((*itMax).first);
+ uint32_t bytesTxed = 0;
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ 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)
+ bytesTxed += tbSize;
+ }
+ double expectedAveThr = ((1.0 - (1.0 / m_timeWindow)) * (*itPastAveThr).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)(bytesTxed / 0.001));
+ //NS_LOG_DEBUG (Simulator::Now()<< " UE " << (*itMax).first << " espectedAveThr "<< expectedAveThr << " RBG " << (*itRbgPerRntiLog).second << " mcs " << (uint16_t)mcs.at(0) << " tbsize "<< bytesTxed << " layer "<<nLayer);
+
+ int rbgPerRnti = (*itRbgPerRntiLog).second;
+ rbgPerRnti++;
+ rbgPerRntiLog[(*itMax).first] = rbgPerRnti;
+ estAveThr[(*itMax).first] = expectedAveThr;
+
+ // find new UE with largest priority metric
+ metricMax = 0.0;
+ for (it = estAveThr.begin (); it != estAveThr.end (); it++)
+ {
+ double metric = 1 / (*it).second;
+ if (metric > metricMax)
+ {
+ itMax = it;
+ metricMax = metric;
+ }
+ } // end for estAveThr
+
+ i++;
+
+ } while ( i < rbgNum );// end for RBGs
+
+ // reset TTI stats of users
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
+ for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
+ {
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+
+ // generate the transmission opportunities by grouping the RBGs of the same RNTI and
+ // creating the correspondent DCIs
+ FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
+ while (itMap != allocationMap.end ())
+ {
+ // create new BuildDataListElement_s for this LC
+ BuildDataListElement_s newEl;
+ newEl.m_rnti = (*itMap).first;
+ // create the DlDciListElement_s
+ DlDciListElement_s newDci;
+ std::vector <struct RlcPduListElement_s> newRlcPduLe;
+ newDci.m_rnti = (*itMap).first;
+
+ uint16_t lcActives = LcActivePerFlow ((*itMap).first);
+// NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
+ uint16_t rbgPerRnti = (*itMap).second.size ();
+ std::map <uint16_t,uint8_t>::iterator itCqi;
+ itCqi = m_p10CqiRxed.find ((*itMap).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMap).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ uint32_t bytesTxed = 0;
+ for (uint8_t i = 0; i < nLayer; i++)
+ {
+ if (itCqi == m_p10CqiRxed.end ())
+ {
+ newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
+ }
+ else
+ {
+ newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
+ }
+ }
+
+ for (uint8_t i = 0; i < nLayer; i++)
+ {
+ 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)
+ //NS_LOG_DEBUG ( Simulator::Now() << this << "Allocate user " << newEl.m_rnti << " tbSize "<< tbSize << " PRBs " << rbgPerRnti*rbgSize << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " layers " << nLayer);
+ NS_LOG_DEBUG ( "UE " << newEl.m_rnti << " tbSize "<< tbSize << " PRBs " << rbgPerRnti*rbgSize << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " layers " << nLayer);
+
+ newDci.m_tbsSize.push_back (tbSize);
+ bytesTxed += tbSize;
+ }
+
+ newDci.m_resAlloc = 0; // only allocation type 0 at this stage
+ newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
+ uint32_t rbgMask = 0;
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
+// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+ }
+ newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
+
+ // create the rlc PDUs -> equally divide resources among actives LCs
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
+ for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
+ {
+ if (((*itBufReq).first.m_rnti == (*itMap).first) &&
+ (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ RlcPduListElement_s newRlcEl;
+ newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
+ newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
+ //NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
+ newRlcPduLe.push_back (newRlcEl);
+ UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
+ }
+ }
+ if ((*itBufReq).first.m_rnti > (*itMap).first)
+ {
+ break;
+ }
+ }
+ newDci.m_ndi.push_back (1); // TBD (new data indicator)
+ newDci.m_rv.push_back (0); // TBD (redundancy version)
+
+ newEl.m_dci = newDci;
+ // ...more parameters -> ingored in this version
+
+ newEl.m_rlcPduList.push_back (newRlcPduLe);
+ ret.m_buildDataList.push_back (newEl);
+
+ // update UE stats
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator it;
+ it = m_flowStatsDl.find ((*itMap).first);
+ if (it != m_flowStatsDl.end ())
+ {
+ (*it).second.lastTtiBytesTrasmitted = bytesTxed;
+// NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
+
+
+ }
+ else
+ {
+ NS_LOG_DEBUG (this << " No Stats for this allocated UE");
+ }
+
+ itMap++;
+ } // end while allocation
+ ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
+
+
+ // update UEs stats
+ for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
+ {
+ (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
+ // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
+ (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
+// NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
+// NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+
+ m_schedSapUser->SchedDlConfigInd (ret);
+
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
+ {
+ if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
+ {
+ // wideband CQI reporting
+ std::map <uint16_t,uint8_t>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_p10CqiRxed.find (rnti);
+ if (it == m_p10CqiRxed.end ())
+ {
+ // create the new entry
+ 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)
+ // generate correspondent timer
+ m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
+ // update correspondent timer
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_p10CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " CQI type unknown");
+ }
+ }
+
+ return;
+}
+
+
+double
+FdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
+{
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ return (NO_SINR);
+
+ }
+ else
+ {
+ // take the average SINR value among the available
+ double sinrSum = 0;
+ int sinrNum = 0;
+ for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
+ {
+ double sinr = (*itCqi).second.at (i);
+ if (sinr != NO_SINR)
+ {
+ sinrSum += sinr;
+ sinrNum++;
+ }
+ }
+ double estimatedSinr = sinrSum / (double)sinrNum;
+ // store the value
+ (*itCqi).second.at (rb) = estimatedSinr;
+ return (estimatedSinr);
+ }
+}
+
+void
+FdBetFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+
+ RefreshUlCqiMaps ();
+
+ std::map <uint16_t,uint32_t>::iterator it;
+ int nflows = 0;
+
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ // remove old entries of this UE-LC
+ if ((*it).second > 0)
+ {
+ nflows++;
+ }
+ }
+
+ if (nflows == 0)
+ {
+ return ; // no flows to be scheduled
+ }
+
+
+ // Divide the resource equally among the active users
+ int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+ if (rbPerFlow == 0)
+ {
+ rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
+ }
+ int rbAllocated = 0;
+
+ FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+ std::vector <uint16_t> rbgAllocationMap;
+ std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
+ if (m_nextRntiUl != 0)
+ {
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ if ((*it).first == m_nextRntiUl)
+ {
+ break;
+ }
+ }
+ if (it == m_ceBsrRxed.end ())
+ {
+ NS_LOG_ERROR (this << " no user found");
+ }
+ }
+ else
+ {
+ it = m_ceBsrRxed.begin ();
+ m_nextRntiUl = (*it).first;
+ }
+ do
+ {
+ if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
+ {
+ // limit to physical resources last resource assignment
+ rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
+ }
+
+ UlDciListElement_s uldci;
+ uldci.m_rnti = (*it).first;
+ uldci.m_rbStart = rbAllocated;
+ uldci.m_rbLen = rbPerFlow;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
+ int cqi = 0;
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
+// NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
+ }
+ else
+ {
+ // take the lowest CQI value (worst RB)
+ double minSinr = (*itCqi).second.at (uldci.m_rbStart);
+ if (minSinr == NO_SINR)
+ {
+ minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
+ }
+ for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
+ {
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
+ double sinr = (*itCqi).second.at (i);
+ if (sinr == NO_SINR)
+ {
+ sinr = EstimateUlSinr ((*it).first, i);
+ }
+ if ((*itCqi).second.at (i) < minSinr)
+ {
+ minSinr = (*itCqi).second.at (i);
+ }
+ }
+
+ // translate SINR -> cqi: WILD ACK: same as DL
+ double s = log2 ( 1 + (
+ pow (10, minSinr / 10 ) /
+ ( (-log (5.0 * 0.00005 )) / 1.5) ));
+ cqi = m_amc->GetCqiFromSpectralEfficiency (s);
+ if (cqi == 0)
+ {
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ }
+ uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
+
+ }
+
+ rbAllocated += rbPerFlow;
+ // store info on allocation for managing ul-cqi interpretation
+ for (int i = 0; i < rbPerFlow; i++)
+ {
+ rbgAllocationMap.push_back ((*it).first);
+ }
+ uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
+// 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);
+ UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
+ uldci.m_ndi = 1;
+ uldci.m_cceIndex = 0;
+ uldci.m_aggrLevel = 1;
+ uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
+ uldci.m_hopping = false;
+ uldci.m_n2Dmrs = 0;
+ uldci.m_tpc = 0; // no power control
+ uldci.m_cqiRequest = false; // only period CQI at this stage
+ uldci.m_ulIndex = 0; // TDD parameter
+ uldci.m_dai = 1; // TDD parameter
+ uldci.m_freqHopping = 0;
+ uldci.m_pdcchPowerOffset = 0; // not used
+ ret.m_dciList.push_back (uldci);
+
+ // update TTI UE stats
+ itStats = m_flowStatsUl.find ((*it).first);
+ if (itStats != m_flowStatsUl.end ())
+ {
+ (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
+// NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
+
+
+ }
+ else
+ {
+ NS_LOG_DEBUG (this << " No Stats for this allocated UE");
+ }
+
+
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
+ {
+ // Stop allocation: no more PRBs
+ m_nextRntiUl = (*it).first;
+ break;
+ }
+ }
+ while ((*it).first != m_nextRntiUl);
+
+
+ // Update global UE stats
+ // update UEs stats
+ for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
+ {
+ (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
+ // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
+ (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
+ // NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
+ // NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+ m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+ m_schedSapUser->SchedUlConfigInd (ret);
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ std::map <uint16_t,uint32_t>::iterator it;
+
+ for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
+ {
+ if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
+ {
+ // buffer status report
+ uint16_t rnti = params.m_macCeList.at (i).m_rnti;
+ it = m_ceBsrRxed.find (rnti);
+ if (it == m_ceBsrRxed.end ())
+ {
+ // create the new entry
+ uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
+ int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
+ m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer)); // only 1 buffer status is working now
+ }
+ else
+ {
+ // update the CQI value
+ (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
+ }
+ }
+ }
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+// NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
+ // retrieve the allocation for this subframe
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi;
+ itMap = m_allocationMaps.find (params.m_sfnSf);
+ if (itMap == m_allocationMaps.end ())
+ {
+ //NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
+ return;
+ }
+ for (uint32_t i = 0; i < (*itMap).second.size (); i++)
+ {
+ // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
+// NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
+ double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
+ //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
+ itCqi = m_ueCqi.find ((*itMap).second.at (i));
+ if (itCqi == m_ueCqi.end ())
+ {
+ // create a new entry
+ std::vector <double> newCqi;
+ for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
+ {
+ if (i == j)
+ {
+ newCqi.push_back (sinr);
+ }
+ else
+ {
+ // initialize with NO_SINR value.
+ newCqi.push_back (NO_SINR);
+ }
+
+ }
+ m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
+ // generate correspondent timer
+ m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the value
+ (*itCqi).second.at (i) = sinr;
+ // update correspondent timer
+ std::map <uint16_t, uint32_t>::iterator itTimers;
+ itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
+ (*itTimers).second = m_cqiTimersThreshold;
+
+ }
+
+ }
+ // remove obsolete info on allocation
+ m_allocationMaps.erase (itMap);
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::RefreshDlCqiMaps(void)
+{
+ // refresh DL CQI P01 Map
+ std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
+ while (itP10!=m_p10CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itP10).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
+ NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
+ NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
+ m_p10CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itP10;
+ itP10++;
+ m_p10CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itP10).second--;
+ itP10++;
+ }
+ }
+
+ return;
+}
+
+
+void
+FdBetFfMacScheduler::RefreshUlCqiMaps(void)
+{
+ // refresh UL CQI Map
+ std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
+ while (itUl!=m_ueCqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itUl).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
+ NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
+ NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
+ (*itMap).second.clear ();
+ m_ueCqi.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itUl;
+ itUl++;
+ m_ueCqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itUl).second--;
+ itUl++;
+ }
+ }
+
+ return;
+}
+
+void
+FdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
+{
+ std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ LteFlowId_t flow (rnti, lcid);
+ it = m_rlcBufferReq.find (flow);
+ if (it!=m_rlcBufferReq.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
+ // Update queues: RLC tx order Status, ReTx, Tx
+ // Update status queue
+ if ((*it).second.m_rlcStatusPduSize <= size)
+ {
+ size -= (*it).second.m_rlcStatusPduSize;
+ (*it).second.m_rlcStatusPduSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcStatusPduSize -= size;
+ return;
+ }
+ // update retransmission queue
+ if ((*it).second.m_rlcRetransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcRetransmissionQueueSize;
+ (*it).second.m_rlcRetransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcRetransmissionQueueSize -= size;
+ return;
+ }
+ // update transmission queue
+ if ((*it).second.m_rlcTransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcTransmissionQueueSize;
+ (*it).second.m_rlcTransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcTransmissionQueueSize -= size;
+ return;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
+ }
+}
+
+void
+FdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
+{
+
+
+ std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
+ if (it!=m_ceBsrRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
+ if ((*it).second >= size)
+ {
+ (*it).second -= size;
+ }
+ else
+ {
+ (*it).second = 0;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
+ }
+
+}
+
+void
+FdBetFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
+ FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+ params.m_rnti = rnti;
+ params.m_transmissionMode = txMode;
+ m_cschedSapUser->CschedUeConfigUpdateInd (params);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/fdbet-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,217 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmai.com>
+ */
+
+#ifndef FDBET_FF_MAC_SCHEDULER_H
+#define FDBET_FF_MAC_SCHEDULER_H
+
+#include <ns3/lte-common.h>
+#include <ns3/ff-mac-csched-sap.h>
+#include <ns3/ff-mac-sched-sap.h>
+#include <ns3/ff-mac-scheduler.h>
+#include <vector>
+#include <map>
+#include <ns3/nstime.h>
+#include <ns3/lte-amc.h>
+
+
+// value for SINR outside the range defined by FF-API, used to indicate that there
+// is no CQI for this element
+#define NO_SINR -5000
+
+namespace ns3 {
+
+
+struct fdbetsFlowPerf_t
+{
+ Time flowStart;
+ unsigned long totalBytesTransmitted;
+ unsigned int lastTtiBytesTrasmitted;
+ double lastAveragedThroughput;
+};
+
+
+/**
+ * \ingroup ff-api
+ * \defgroup FF-API FdBetFfMacScheduler
+ */
+/**
+ * \ingroup FdBetFfMacScheduler
+ * \brief Implements the SCHED SAP and CSCHED SAP for a Proportional Fair scheduler
+ *
+ * This class implements the interface defined by the FfMacScheduler abstract class
+ */
+
+class FdBetFfMacScheduler : public FfMacScheduler
+{
+public:
+ /**
+ * \brief Constructor
+ *
+ * Creates the MAC Scheduler interface implementation
+ */
+ FdBetFfMacScheduler ();
+
+ /**
+ * Destructor
+ */
+ virtual ~FdBetFfMacScheduler ();
+
+ // inherited from Object
+ virtual void DoDispose (void);
+ static TypeId GetTypeId (void);
+
+ // inherited from FfMacScheduler
+ virtual void SetFfMacCschedSapUser (FfMacCschedSapUser* s);
+ virtual void SetFfMacSchedSapUser (FfMacSchedSapUser* s);
+ virtual FfMacCschedSapProvider* GetFfMacCschedSapProvider ();
+ virtual FfMacSchedSapProvider* GetFfMacSchedSapProvider ();
+
+ friend class FdBetSchedulerMemberCschedSapProvider;
+ friend class FdBetSchedulerMemberSchedSapProvider;
+
+ void TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode);
+
+private:
+ //
+ // Implementation of the CSCHED API primitives
+ // (See 4.1 for description of the primitives)
+ //
+
+ void DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params);
+
+ void DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params);
+
+ void DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params);
+
+ void DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params);
+
+ void DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params);
+
+ //
+ // Implementation of the SCHED API primitives
+ // (See 4.2 for description of the primitives)
+ //
+
+ void DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params);
+
+ void DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params);
+
+ void DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params);
+
+ void DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params);
+
+ void DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params);
+
+ void DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params);
+
+ void DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params);
+
+ void DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params);
+
+ void DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
+
+ void DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params);
+
+ void DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
+
+
+ int GetRbgSize (int dlbandwidth);
+
+ int LcActivePerFlow (uint16_t rnti);
+
+ double EstimateUlSinr (uint16_t rnti, uint16_t rb);
+
+ void RefreshDlCqiMaps(void);
+ void RefreshUlCqiMaps(void);
+
+ void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
+ void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+ Ptr<LteAmc> m_amc;
+
+ /*
+ * Vectors of UE's LC info
+ */
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> m_rlcBufferReq;
+
+
+ /*
+ * Map of UE statistics (per RNTI basis) in downlink
+ */
+ std::map <uint16_t, fdbetsFlowPerf_t> m_flowStatsDl;
+
+ /*
+ * Map of UE statistics (per RNTI basis)
+ */
+ std::map <uint16_t, fdbetsFlowPerf_t> m_flowStatsUl;
+
+
+ /*
+ * Map of UE's DL CQI P01 received
+ */
+ std::map <uint16_t,uint8_t> m_p10CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI P01 received
+ */
+ std::map <uint16_t,uint32_t> m_p10CqiTimers;
+
+ /*
+ * Map of previous allocated UE per RBG
+ * (used to retrieve info from UL-CQI)
+ */
+ std::map <uint16_t, std::vector <uint16_t> > m_allocationMaps;
+
+ /*
+ * Map of UEs' UL-CQI per RBG
+ */
+ std::map <uint16_t, std::vector <double> > m_ueCqi;
+ /*
+ * Map of UEs' timers on UL-CQI per RBG
+ */
+ std::map <uint16_t, uint32_t> m_ueCqiTimers;
+
+ /*
+ * Map of UE's buffer status reports received
+ */
+ std::map <uint16_t,uint32_t> m_ceBsrRxed;
+
+ // MAC SAPs
+ FfMacCschedSapUser* m_cschedSapUser;
+ FfMacSchedSapUser* m_schedSapUser;
+ FfMacCschedSapProvider* m_cschedSapProvider;
+ FfMacSchedSapProvider* m_schedSapProvider;
+
+
+ // Internal parameters
+ FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig;
+
+
+ double m_timeWindow;
+
+ uint16_t m_nextRntiUl; // RNTI of the next user to be served next scheduling in UL
+
+ uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
+
+ std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+};
+
+} // namespace ns3
+
+#endif /* FDBET_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/fdmt-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,1201 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <ns3/log.h>
+#include <ns3/pointer.h>
+
+#include <ns3/simulator.h>
+#include <ns3/lte-amc.h>
+#include "fdmt-ff-mac-scheduler.h"
+
+NS_LOG_COMPONENT_DEFINE ("FdMtFfMacScheduler");
+
+namespace ns3 {
+
+int FdMtType0AllocationRbg[4] = {
+ 10, // RGB size 1
+ 26, // RGB size 2
+ 63, // RGB size 3
+ 110 // RGB size 4
+}; // see table 7.1.6.1-1 of 36.213
+
+
+NS_OBJECT_ENSURE_REGISTERED (FdMtFfMacScheduler);
+
+
+
+class FdMtSchedulerMemberCschedSapProvider : public FfMacCschedSapProvider
+{
+public:
+ FdMtSchedulerMemberCschedSapProvider (FdMtFfMacScheduler* scheduler);
+
+ // inherited from FfMacCschedSapProvider
+ virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
+ virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
+ virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
+ virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
+ virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
+
+private:
+ FdMtSchedulerMemberCschedSapProvider ();
+ FdMtFfMacScheduler* m_scheduler;
+};
+
+FdMtSchedulerMemberCschedSapProvider::FdMtSchedulerMemberCschedSapProvider ()
+{
+}
+
+FdMtSchedulerMemberCschedSapProvider::FdMtSchedulerMemberCschedSapProvider (FdMtFfMacScheduler* scheduler) : m_scheduler (scheduler)
+{
+}
+
+
+void
+FdMtSchedulerMemberCschedSapProvider::CschedCellConfigReq (const struct CschedCellConfigReqParameters& params)
+{
+ m_scheduler->DoCschedCellConfigReq (params);
+}
+
+void
+FdMtSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
+{
+ m_scheduler->DoCschedUeConfigReq (params);
+}
+
+
+void
+FdMtSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
+{
+ m_scheduler->DoCschedLcConfigReq (params);
+}
+
+void
+FdMtSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedLcReleaseReq (params);
+}
+
+void
+FdMtSchedulerMemberCschedSapProvider::CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedUeReleaseReq (params);
+}
+
+
+
+
+class FdMtSchedulerMemberSchedSapProvider : public FfMacSchedSapProvider
+{
+public:
+ FdMtSchedulerMemberSchedSapProvider (FdMtFfMacScheduler* scheduler);
+
+ // inherited from FfMacSchedSapProvider
+ virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
+ virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
+ virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
+ virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
+ virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
+ virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
+ virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
+ virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
+ virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
+ virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
+ virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
+
+
+private:
+ FdMtSchedulerMemberSchedSapProvider ();
+ FdMtFfMacScheduler* m_scheduler;
+};
+
+
+
+FdMtSchedulerMemberSchedSapProvider::FdMtSchedulerMemberSchedSapProvider ()
+{
+}
+
+
+FdMtSchedulerMemberSchedSapProvider::FdMtSchedulerMemberSchedSapProvider (FdMtFfMacScheduler* scheduler)
+ : m_scheduler (scheduler)
+{
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlRlcBufferReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlPagingBufferReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlMacBufferReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedDlTriggerReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlRachInfoReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlCqiInfoReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedUlTriggerReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
+{
+ m_scheduler->DoSchedUlNoiseInterferenceReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlSrInfoReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlMacCtrlInfoReq (params);
+}
+
+void
+FdMtSchedulerMemberSchedSapProvider::SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlCqiInfoReq (params);
+}
+
+
+
+
+
+FdMtFfMacScheduler::FdMtFfMacScheduler ()
+ : m_cschedSapUser (0),
+ m_schedSapUser (0),
+ m_nextRntiUl (0)
+{
+ m_amc = CreateObject <LteAmc> ();
+ m_cschedSapProvider = new FdMtSchedulerMemberCschedSapProvider (this);
+ m_schedSapProvider = new FdMtSchedulerMemberSchedSapProvider (this);
+}
+
+FdMtFfMacScheduler::~FdMtFfMacScheduler ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+FdMtFfMacScheduler::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_cschedSapProvider;
+ delete m_schedSapProvider;
+}
+
+TypeId
+FdMtFfMacScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::FdMtFfMacScheduler")
+ .SetParent<FfMacScheduler> ()
+ .AddConstructor<FdMtFfMacScheduler> ()
+ .AddAttribute ("CqiTimerThreshold",
+ "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
+ UintegerValue (1000),
+ MakeUintegerAccessor (&FdMtFfMacScheduler::m_cqiTimersThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+
+void
+FdMtFfMacScheduler::SetFfMacCschedSapUser (FfMacCschedSapUser* s)
+{
+ m_cschedSapUser = s;
+}
+
+void
+FdMtFfMacScheduler::SetFfMacSchedSapUser (FfMacSchedSapUser* s)
+{
+ m_schedSapUser = s;
+}
+
+FfMacCschedSapProvider*
+FdMtFfMacScheduler::GetFfMacCschedSapProvider ()
+{
+ return m_cschedSapProvider;
+}
+
+FfMacSchedSapProvider*
+FdMtFfMacScheduler::GetFfMacSchedSapProvider ()
+{
+ return m_schedSapProvider;
+}
+
+void
+FdMtFfMacScheduler::DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // Read the subset of parameters used
+ m_cschedCellConfig = params;
+ FfMacCschedSapUser::CschedUeConfigCnfParameters cnf;
+ cnf.m_result = SUCCESS;
+ m_cschedSapUser->CschedUeConfigCnf (cnf);
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
+ std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
+ if (it==m_uesTxMode.end ())
+ {
+ m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+ }
+ else
+ {
+ (*it).second = params.m_transmissionMode;
+ }
+ return;
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
+
+ std::set<uint16_t>::iterator it;
+
+ for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
+ {
+ it = m_flowStatsDl.find (params.m_rnti);
+
+ if (it == m_flowStatsDl.end ())
+ {
+ m_flowStatsDl.insert (params.m_rnti);
+ m_flowStatsUl.insert (params.m_rnti);
+ }
+ else
+ {
+ NS_LOG_ERROR ("RNTI already exists");
+ }
+
+ }
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+
+void
+FdMtFfMacScheduler::DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
+ // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
+
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+
+ LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
+
+ it = m_rlcBufferReq.find (flow);
+
+ if (it == m_rlcBufferReq.end ())
+ {
+ m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
+ }
+ else
+ {
+ (*it).second = params;
+ }
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+int
+FdMtFfMacScheduler::GetRbgSize (int dlbandwidth)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (dlbandwidth < FdMtType0AllocationRbg[i])
+ {
+ return (i + 1);
+ }
+ }
+
+ return (-1);
+}
+
+
+int
+FdMtFfMacScheduler::LcActivePerFlow (uint16_t rnti)
+{
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ int lcActive = 0;
+ for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
+ {
+ if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
+ || ((*it).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*it).second.m_rlcStatusPduSize > 0) ))
+ {
+ lcActive++;
+ }
+ if ((*it).first.m_rnti > rnti)
+ {
+ break;
+ }
+ }
+ return (lcActive);
+
+}
+
+
+void
+FdMtFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+ // API generated by RLC for triggering the scheduling of a DL subframe
+
+
+ // evaluate the relative channel quality indicator for each UE per each RBG
+ // (since we are using allocation type 0 the small unit of allocation is RBG)
+ // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
+
+ RefreshDlCqiMaps ();
+
+ int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+ int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+ std::map <uint16_t, std::vector <uint16_t> > allocationMap;
+ for (int i = 0; i < rbgNum; i++)
+ {
+// NS_LOG_DEBUG (this << " ALLOCATION for RBG " << i << " of " << rbgNum);
+ std::set <uint16_t>::iterator it;
+ std::set <uint16_t>::iterator itMax = m_flowStatsDl.end ();
+ double metricMax = 0.0;
+ for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
+ {
+ std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
+ itCqi = m_a30CqiRxed.find ((*it));
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*it));
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it));
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> sbCqi;
+ if (itCqi == m_a30CqiRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " No DL-CQI for this UE " << (*it));
+ for (uint8_t k = 0; k < nLayer; k++)
+ {
+ sbCqi.push_back (1); // start with lowest value
+ }
+ }
+ else
+ {
+ sbCqi = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
+// NS_LOG_INFO (this << " CQI " << (uint32_t)cqi);
+ }
+ uint8_t cqi1 = sbCqi.at(0);
+ uint8_t cqi2 = 1;
+ if (sbCqi.size () > 1)
+ {
+ cqi2 = sbCqi.at(1);
+ }
+
+ if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ {
+// NS_LOG_DEBUG (this << " LC active " << LcActivePerFlow (*it));
+ if (LcActivePerFlow (*it) > 0)
+ {
+ // this UE has data to transmit
+ double achievableRate = 0.0;
+ for (uint8_t k = 0; k < nLayer; k++)
+ {
+ uint8_t mcs = 0;
+ if (sbCqi.size () > k)
+ {
+ mcs = m_amc->GetMcsFromCqi (sbCqi.at (k));
+ }
+ else
+ {
+ // no info on this subband -> worst MCS
+ mcs = 0;
+ }
+ achievableRate += ((m_amc->GetTbSizeFromMcs (mcs, rbgSize) / 8) / 0.001); // = TB size / TTI
+ }
+ // always select first UE when there are multiple UEs have same SINR
+ double metric = achievableRate;
+// NS_LOG_DEBUG (this << " RNTI " << (*it) << " MCS " << (uint32_t)mcs << " achievableRate " << achievableRate << " RCQI " << rcqi);
+
+ if (metric > metricMax)
+ {
+ metricMax = metric;
+ itMax = it;
+ }
+ }
+ } // end if cqi
+ } // end for m_flowStatsDl
+
+ if (itMax == m_flowStatsDl.end ())
+ {
+ // no UE available for this RB
+ NS_LOG_DEBUG (this << " no UE found");
+ }
+ else
+ {
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ itMap = allocationMap.find ((*itMax));
+ if (itMap == allocationMap.end ())
+ {
+ // insert new element
+ std::vector <uint16_t> tempMap;
+ tempMap.push_back (i);
+ allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax), tempMap));
+ }
+ else
+ {
+ (*itMap).second.push_back (i);
+ }
+// NS_LOG_DEBUG (this << " UE assigned " << (*itMax).first);
+ }
+ } // end for RBGs
+
+ // generate the transmission opportunities by grouping the RBGs of the same RNTI and
+ // creating the correspondent DCIs
+ FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
+ while (itMap != allocationMap.end ())
+ {
+ // create new BuildDataListElement_s for this LC
+ BuildDataListElement_s newEl;
+ newEl.m_rnti = (*itMap).first;
+ // create the DlDciListElement_s
+ DlDciListElement_s newDci;
+ std::vector <struct RlcPduListElement_s> newRlcPduLe;
+ newDci.m_rnti = (*itMap).first;
+
+ uint16_t lcActives = LcActivePerFlow ((*itMap).first);
+// NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
+ uint16_t RgbPerRnti = (*itMap).second.size ();
+ std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
+ itCqi = m_a30CqiRxed.find ((*itMap).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMap).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> worstCqi (2, 15);
+ if (itCqi != m_a30CqiRxed.end ())
+ {
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ if ((*itCqi).second.m_higherLayerSelected.size () > (*itMap).second.at (k))
+ {
+// NS_LOG_DEBUG (this << " RBG " << (*itMap).second.at (k) << " CQI " << (uint16_t)((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (0)) );
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ if ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.size ()> j)
+ {
+ if (((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j)) < worstCqi.at (j))
+ {
+ worstCqi.at (j) = ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j));
+ }
+ }
+ else
+ {
+ // no CQI for this layer of this suband -> worst one
+ worstCqi.at (j) = 1;
+ }
+ }
+ }
+ else
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
+ }
+ }
+ }
+ }
+ else
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
+ }
+ }
+// NS_LOG_DEBUG (this << " CQI " << (uint16_t)worstCqi);
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ newDci.m_mcs.push_back (m_amc->GetMcsFromCqi (worstCqi.at (j)));
+ int tbSize = (m_amc->GetTbSizeFromMcs (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)
+ newDci.m_tbsSize.push_back (tbSize);
+ NS_LOG_DEBUG (this << " MCS " << m_amc->GetMcsFromCqi (worstCqi.at (j)));
+ }
+
+ newDci.m_resAlloc = 0; // only allocation type 0 at this stage
+ newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
+ uint32_t rbgMask = 0;
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
+// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+ }
+ newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
+
+ // create the rlc PDUs -> equally divide resources among actives LCs
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
+ for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
+ {
+ if (((*itBufReq).first.m_rnti == (*itMap).first) &&
+ (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ RlcPduListElement_s newRlcEl;
+ newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
+ newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
+ NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
+ newRlcPduLe.push_back (newRlcEl);
+ UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
+ }
+ }
+ if ((*itBufReq).first.m_rnti > (*itMap).first)
+ {
+ break;
+ }
+ }
+ newDci.m_ndi.push_back (1); // TBD (new data indicator)
+ newDci.m_rv.push_back (0); // TBD (redundancy version)
+
+ newEl.m_dci = newDci;
+ // ...more parameters -> ingored in this version
+
+ newEl.m_rlcPduList.push_back (newRlcPduLe);
+ ret.m_buildDataList.push_back (newEl);
+
+ itMap++;
+ } // end while allocation
+ ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
+
+ m_schedSapUser->SchedDlConfigInd (ret);
+
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
+ {
+ if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
+ {
+ // wideband CQI reporting
+ std::map <uint16_t,uint8_t>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_p10CqiRxed.find (rnti);
+ if (it == m_p10CqiRxed.end ())
+ {
+ // create the new entry
+ 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)
+ // generate correspondent timer
+ m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
+ // update correspondent timer
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_p10CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
+ {
+ // subband CQI reporting high layer configured
+ std::map <uint16_t,SbMeasResult_s>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_a30CqiRxed.find (rnti);
+ if (it == m_a30CqiRxed.end ())
+ {
+ // create the new entry
+ m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
+ m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_a30CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " CQI type unknown");
+ }
+ }
+
+ return;
+}
+
+
+double
+FdMtFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
+{
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ return (NO_SINR);
+
+ }
+ else
+ {
+ // take the average SINR value among the available
+ double sinrSum = 0;
+ int sinrNum = 0;
+ for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
+ {
+ double sinr = (*itCqi).second.at (i);
+ if (sinr != NO_SINR)
+ {
+ sinrSum += sinr;
+ sinrNum++;
+ }
+ }
+ double estimatedSinr = sinrSum / (double)sinrNum;
+ // store the value
+ (*itCqi).second.at (rb) = estimatedSinr;
+ return (estimatedSinr);
+ }
+}
+
+void
+FdMtFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+
+ RefreshUlCqiMaps ();
+
+ std::map <uint16_t,uint32_t>::iterator it;
+ int nflows = 0;
+
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ // remove old entries of this UE-LC
+ if ((*it).second > 0)
+ {
+ nflows++;
+ }
+ }
+
+ if (nflows == 0)
+ {
+ return ; // no flows to be scheduled
+ }
+
+
+ // Divide the resource equally among the active users
+ int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+ if (rbPerFlow == 0)
+ {
+ rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
+ }
+ int rbAllocated = 0;
+
+ FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+ std::vector <uint16_t> rbgAllocationMap;
+
+ if (m_nextRntiUl != 0)
+ {
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ if ((*it).first == m_nextRntiUl)
+ {
+ break;
+ }
+ }
+ if (it == m_ceBsrRxed.end ())
+ {
+ NS_LOG_ERROR (this << " no user found");
+ }
+ }
+ else
+ {
+ it = m_ceBsrRxed.begin ();
+ m_nextRntiUl = (*it).first;
+ }
+ do
+ {
+ if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
+ {
+ // limit to physical resources last resource assignment
+ rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
+ }
+
+ UlDciListElement_s uldci;
+ uldci.m_rnti = (*it).first;
+ uldci.m_rbStart = rbAllocated;
+ uldci.m_rbLen = rbPerFlow;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
+ int cqi = 0;
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
+// NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
+ }
+ else
+ {
+ // take the lowest CQI value (worst RB)
+ double minSinr = (*itCqi).second.at (uldci.m_rbStart);
+ if (minSinr == NO_SINR)
+ {
+ minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
+ }
+ for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
+ {
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
+ double sinr = (*itCqi).second.at (i);
+ if (sinr == NO_SINR)
+ {
+ sinr = EstimateUlSinr ((*it).first, i);
+ }
+ if ((*itCqi).second.at (i) < minSinr)
+ {
+ minSinr = (*itCqi).second.at (i);
+ }
+ }
+
+ // translate SINR -> cqi: WILD ACK: same as DL
+ double s = log2 ( 1 + (
+ pow (10, minSinr / 10 ) /
+ ( (-log (5.0 * 0.00005 )) / 1.5) ));
+ cqi = m_amc->GetCqiFromSpectralEfficiency (s);
+ if (cqi == 0)
+ {
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ }
+ uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
+
+ }
+
+ rbAllocated += rbPerFlow;
+ // store info on allocation for managing ul-cqi interpretation
+ for (int i = 0; i < rbPerFlow; i++)
+ {
+ rbgAllocationMap.push_back ((*it).first);
+ }
+ uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
+// 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);
+ UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
+ uldci.m_ndi = 1;
+ uldci.m_cceIndex = 0;
+ uldci.m_aggrLevel = 1;
+ uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
+ uldci.m_hopping = false;
+ uldci.m_n2Dmrs = 0;
+ uldci.m_tpc = 0; // no power control
+ uldci.m_cqiRequest = false; // only period CQI at this stage
+ uldci.m_ulIndex = 0; // TDD parameter
+ uldci.m_dai = 1; // TDD parameter
+ uldci.m_freqHopping = 0;
+ uldci.m_pdcchPowerOffset = 0; // not used
+ ret.m_dciList.push_back (uldci);
+
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
+ {
+ // Stop allocation: no more PRBs
+ m_nextRntiUl = (*it).first;
+ break;
+ }
+ }
+ while ((*it).first != m_nextRntiUl);
+
+ m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+ m_schedSapUser->SchedUlConfigInd (ret);
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ std::map <uint16_t,uint32_t>::iterator it;
+
+ for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
+ {
+ if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
+ {
+ // buffer status report
+ uint16_t rnti = params.m_macCeList.at (i).m_rnti;
+ it = m_ceBsrRxed.find (rnti);
+ if (it == m_ceBsrRxed.end ())
+ {
+ // create the new entry
+ uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
+ int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
+ m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer)); // only 1 buffer status is working now
+ }
+ else
+ {
+ // update the CQI value
+ (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
+ }
+ }
+ }
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+// NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
+ // retrieve the allocation for this subframe
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi;
+ itMap = m_allocationMaps.find (params.m_sfnSf);
+ if (itMap == m_allocationMaps.end ())
+ {
+ NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
+ return;
+ }
+ for (uint32_t i = 0; i < (*itMap).second.size (); i++)
+ {
+ // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
+// NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
+ double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
+ //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
+ itCqi = m_ueCqi.find ((*itMap).second.at (i));
+ if (itCqi == m_ueCqi.end ())
+ {
+ // create a new entry
+ std::vector <double> newCqi;
+ for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
+ {
+ if (i == j)
+ {
+ newCqi.push_back (sinr);
+ }
+ else
+ {
+ // initialize with NO_SINR value.
+ newCqi.push_back (NO_SINR);
+ }
+
+ }
+ m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
+ // generate correspondent timer
+ m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the value
+ (*itCqi).second.at (i) = sinr;
+ // update correspondent timer
+ std::map <uint16_t, uint32_t>::iterator itTimers;
+ itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
+ (*itTimers).second = m_cqiTimersThreshold;
+
+ }
+
+ }
+ // remove obsolete info on allocation
+ m_allocationMaps.erase (itMap);
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::RefreshDlCqiMaps(void)
+{
+ // refresh DL CQI P01 Map
+ std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
+ while (itP10!=m_p10CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itP10).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
+ NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
+ NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
+ m_p10CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itP10;
+ itP10++;
+ m_p10CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itP10).second--;
+ itP10++;
+ }
+ }
+
+ // refresh DL CQI A30 Map
+ std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
+ while (itA30!=m_a30CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itA30).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
+ NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
+ NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
+ m_a30CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itA30;
+ itA30++;
+ m_a30CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itA30).second--;
+ itA30++;
+ }
+ }
+
+ return;
+}
+
+
+void
+FdMtFfMacScheduler::RefreshUlCqiMaps(void)
+{
+ // refresh UL CQI Map
+ std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
+ while (itUl!=m_ueCqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itUl).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
+ NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
+ NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
+ (*itMap).second.clear ();
+ m_ueCqi.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itUl;
+ itUl++;
+ m_ueCqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itUl).second--;
+ itUl++;
+ }
+ }
+
+ return;
+}
+
+void
+FdMtFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
+{
+ std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ LteFlowId_t flow (rnti, lcid);
+ it = m_rlcBufferReq.find (flow);
+ if (it!=m_rlcBufferReq.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
+ // Update queues: RLC tx order Status, ReTx, Tx
+ // Update status queue
+ if ((*it).second.m_rlcStatusPduSize <= size)
+ {
+ size -= (*it).second.m_rlcStatusPduSize;
+ (*it).second.m_rlcStatusPduSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcStatusPduSize -= size;
+ return;
+ }
+ // update retransmission queue
+ if ((*it).second.m_rlcRetransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcRetransmissionQueueSize;
+ (*it).second.m_rlcRetransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcRetransmissionQueueSize -= size;
+ return;
+ }
+ // update transmission queue
+ if ((*it).second.m_rlcTransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcTransmissionQueueSize;
+ (*it).second.m_rlcTransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcTransmissionQueueSize -= size;
+ return;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
+ }
+}
+
+void
+FdMtFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
+{
+
+ std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
+ if (it!=m_ceBsrRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
+ if ((*it).second >= size)
+ {
+ (*it).second -= size;
+ }
+ else
+ {
+ (*it).second = 0;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
+ }
+
+}
+
+void
+FdMtFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
+ FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+ params.m_rnti = rnti;
+ params.m_transmissionMode = txMode;
+ m_cschedSapUser->CschedUeConfigUpdateInd (params);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/fdmt-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,215 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef FDMT_FF_MAC_SCHEDULER_H
+#define FDMT_FF_MAC_SCHEDULER_H
+
+#include <ns3/lte-common.h>
+#include <ns3/ff-mac-csched-sap.h>
+#include <ns3/ff-mac-sched-sap.h>
+#include <ns3/ff-mac-scheduler.h>
+#include <vector>
+#include <map>
+#include <set>
+#include <ns3/nstime.h>
+#include <ns3/lte-amc.h>
+
+
+// value for SINR outside the range defined by FF-API, used to indicate that there
+// is no CQI for this element
+#define NO_SINR -5000
+
+namespace ns3 {
+
+
+/**
+ * \ingroup ff-api
+ * \defgroup FF-API FdMtFfMacScheduler
+ */
+/**
+ * \ingroup FdMtFfMacScheduler
+ * \brief Implements the SCHED SAP and CSCHED SAP for a Frequency Domain Maximum Throughput scheduler
+ *
+ * This class implements the interface defined by the FfMacScheduler abstract class
+ */
+
+class FdMtFfMacScheduler : public FfMacScheduler
+{
+public:
+ /**
+ * \brief Constructor
+ *
+ * Creates the MAC Scheduler interface implementation
+ */
+ FdMtFfMacScheduler ();
+
+ /**
+ * Destructor
+ */
+ virtual ~FdMtFfMacScheduler ();
+
+ // inherited from Object
+ virtual void DoDispose (void);
+ static TypeId GetTypeId (void);
+
+ // inherited from FfMacScheduler
+ virtual void SetFfMacCschedSapUser (FfMacCschedSapUser* s);
+ virtual void SetFfMacSchedSapUser (FfMacSchedSapUser* s);
+ virtual FfMacCschedSapProvider* GetFfMacCschedSapProvider ();
+ virtual FfMacSchedSapProvider* GetFfMacSchedSapProvider ();
+
+ friend class FdMtSchedulerMemberCschedSapProvider;
+ friend class FdMtSchedulerMemberSchedSapProvider;
+
+ void TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode);
+
+private:
+ //
+ // Implementation of the CSCHED API primitives
+ // (See 4.1 for description of the primitives)
+ //
+
+ void DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params);
+
+ void DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params);
+
+ void DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params);
+
+ void DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params);
+
+ void DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params);
+
+ //
+ // Implementation of the SCHED API primitives
+ // (See 4.2 for description of the primitives)
+ //
+
+ void DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params);
+
+ void DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params);
+
+ void DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params);
+
+ void DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params);
+
+ void DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params);
+
+ void DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params);
+
+ void DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params);
+
+ void DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params);
+
+ void DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
+
+ void DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params);
+
+ void DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
+
+
+ int GetRbgSize (int dlbandwidth);
+
+ int LcActivePerFlow (uint16_t rnti);
+
+ double EstimateUlSinr (uint16_t rnti, uint16_t rb);
+
+ void RefreshDlCqiMaps(void);
+ void RefreshUlCqiMaps(void);
+
+ void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
+ void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+ Ptr<LteAmc> m_amc;
+
+ /*
+ * Vectors of UE's LC info
+ */
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> m_rlcBufferReq;
+
+
+ /*
+ * Set of UE's RNTI in downlink
+ */
+ std::set <uint16_t> m_flowStatsDl;
+
+ /*
+ * Set of UE's RNTI in uplink
+ */
+ std::set <uint16_t> m_flowStatsUl;
+
+
+ /*
+ * Map of UE's DL CQI P01 received
+ */
+ std::map <uint16_t,uint8_t> m_p10CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI P01 received
+ */
+ std::map <uint16_t,uint32_t> m_p10CqiTimers;
+
+ /*
+ * Map of UE's DL CQI A30 received
+ */
+ std::map <uint16_t,SbMeasResult_s> m_a30CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI A30 received
+ */
+ std::map <uint16_t,uint32_t> m_a30CqiTimers;
+
+ /*
+ * Map of previous allocated UE per RBG
+ * (used to retrieve info from UL-CQI)
+ */
+ std::map <uint16_t, std::vector <uint16_t> > m_allocationMaps;
+
+ /*
+ * Map of UEs' UL-CQI per RBG
+ */
+ std::map <uint16_t, std::vector <double> > m_ueCqi;
+ /*
+ * Map of UEs' timers on UL-CQI per RBG
+ */
+ std::map <uint16_t, uint32_t> m_ueCqiTimers;
+
+ /*
+ * Map of UE's buffer status reports received
+ */
+ std::map <uint16_t,uint32_t> m_ceBsrRxed;
+
+ // MAC SAPs
+ FfMacCschedSapUser* m_cschedSapUser;
+ FfMacSchedSapUser* m_schedSapUser;
+ FfMacCschedSapProvider* m_cschedSapProvider;
+ FfMacSchedSapProvider* m_schedSapProvider;
+
+
+ // Internal parameters
+ FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig;
+
+ uint16_t m_nextRntiUl; // RNTI of the next user to be served next scheduling in UL
+
+ uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
+
+ std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+};
+
+} // namespace ns3
+
+#endif /* FDMT_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tdbet-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,1141 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifdef __FreeBSD__
+#define log2(x) (log(x) / M_LN2)
+#endif /* __FreeBSD__ */
+
+#include <ns3/log.h>
+#include <ns3/pointer.h>
+
+#include <ns3/simulator.h>
+#include <ns3/lte-amc.h>
+#include <ns3/tdbet-ff-mac-scheduler.h>
+
+NS_LOG_COMPONENT_DEFINE ("TdBetFfMacScheduler");
+
+namespace ns3 {
+
+int TdBetType0AllocationRbg[4] = {
+ 10, // RGB size 1
+ 26, // RGB size 2
+ 63, // RGB size 3
+ 110 // RGB size 4
+}; // see table 7.1.6.1-1 of 36.213
+
+
+NS_OBJECT_ENSURE_REGISTERED (TdBetFfMacScheduler);
+
+
+
+class TdBetSchedulerMemberCschedSapProvider : public FfMacCschedSapProvider
+{
+public:
+ TdBetSchedulerMemberCschedSapProvider (TdBetFfMacScheduler* scheduler);
+
+ // inherited from FfMacCschedSapProvider
+ virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
+ virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
+ virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
+ virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
+ virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
+
+private:
+ TdBetSchedulerMemberCschedSapProvider ();
+ TdBetFfMacScheduler* m_scheduler;
+};
+
+TdBetSchedulerMemberCschedSapProvider::TdBetSchedulerMemberCschedSapProvider ()
+{
+}
+
+TdBetSchedulerMemberCschedSapProvider::TdBetSchedulerMemberCschedSapProvider (TdBetFfMacScheduler* scheduler) : m_scheduler (scheduler)
+{
+}
+
+
+void
+TdBetSchedulerMemberCschedSapProvider::CschedCellConfigReq (const struct CschedCellConfigReqParameters& params)
+{
+ m_scheduler->DoCschedCellConfigReq (params);
+}
+
+void
+TdBetSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
+{
+ m_scheduler->DoCschedUeConfigReq (params);
+}
+
+
+void
+TdBetSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
+{
+ m_scheduler->DoCschedLcConfigReq (params);
+}
+
+void
+TdBetSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedLcReleaseReq (params);
+}
+
+void
+TdBetSchedulerMemberCschedSapProvider::CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedUeReleaseReq (params);
+}
+
+
+
+
+class TdBetSchedulerMemberSchedSapProvider : public FfMacSchedSapProvider
+{
+public:
+ TdBetSchedulerMemberSchedSapProvider (TdBetFfMacScheduler* scheduler);
+
+ // inherited from FfMacSchedSapProvider
+ virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
+ virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
+ virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
+ virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
+ virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
+ virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
+ virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
+ virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
+ virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
+ virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
+ virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
+
+
+private:
+ TdBetSchedulerMemberSchedSapProvider ();
+ TdBetFfMacScheduler* m_scheduler;
+};
+
+
+
+TdBetSchedulerMemberSchedSapProvider::TdBetSchedulerMemberSchedSapProvider ()
+{
+}
+
+
+TdBetSchedulerMemberSchedSapProvider::TdBetSchedulerMemberSchedSapProvider (TdBetFfMacScheduler* scheduler)
+ : m_scheduler (scheduler)
+{
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlRlcBufferReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlPagingBufferReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlMacBufferReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedDlTriggerReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlRachInfoReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlCqiInfoReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedUlTriggerReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
+{
+ m_scheduler->DoSchedUlNoiseInterferenceReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlSrInfoReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlMacCtrlInfoReq (params);
+}
+
+void
+TdBetSchedulerMemberSchedSapProvider::SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlCqiInfoReq (params);
+}
+
+
+
+
+
+TdBetFfMacScheduler::TdBetFfMacScheduler ()
+ : m_cschedSapUser (0),
+ m_schedSapUser (0),
+ m_timeWindow (99.0),
+ m_nextRntiUl (0)
+{
+ m_amc = CreateObject <LteAmc> ();
+ m_cschedSapProvider = new TdBetSchedulerMemberCschedSapProvider (this);
+ m_schedSapProvider = new TdBetSchedulerMemberSchedSapProvider (this);
+}
+
+TdBetFfMacScheduler::~TdBetFfMacScheduler ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+TdBetFfMacScheduler::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_cschedSapProvider;
+ delete m_schedSapProvider;
+}
+
+TypeId
+TdBetFfMacScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TdBetFfMacScheduler")
+ .SetParent<FfMacScheduler> ()
+ .AddConstructor<TdBetFfMacScheduler> ()
+ .AddAttribute ("CqiTimerThreshold",
+ "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
+ UintegerValue (1000),
+ MakeUintegerAccessor (&TdBetFfMacScheduler::m_cqiTimersThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+
+void
+TdBetFfMacScheduler::SetFfMacCschedSapUser (FfMacCschedSapUser* s)
+{
+ m_cschedSapUser = s;
+}
+
+void
+TdBetFfMacScheduler::SetFfMacSchedSapUser (FfMacSchedSapUser* s)
+{
+ m_schedSapUser = s;
+}
+
+FfMacCschedSapProvider*
+TdBetFfMacScheduler::GetFfMacCschedSapProvider ()
+{
+ return m_cschedSapProvider;
+}
+
+FfMacSchedSapProvider*
+TdBetFfMacScheduler::GetFfMacSchedSapProvider ()
+{
+ return m_schedSapProvider;
+}
+
+void
+TdBetFfMacScheduler::DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // Read the subset of parameters used
+ m_cschedCellConfig = params;
+ FfMacCschedSapUser::CschedUeConfigCnfParameters cnf;
+ cnf.m_result = SUCCESS;
+ m_cschedSapUser->CschedUeConfigCnf (cnf);
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
+ std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
+ if (it==m_uesTxMode.end ())
+ {
+ m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+ }
+ else
+ {
+ (*it).second = params.m_transmissionMode;
+ }
+ return;
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
+
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
+ for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
+ {
+ it = m_flowStatsDl.find (params.m_rnti);
+
+ if (it == m_flowStatsDl.end ())
+ {
+ tdbetsFlowPerf_t flowStatsDl;
+ flowStatsDl.flowStart = Simulator::Now ();
+ flowStatsDl.totalBytesTransmitted = 0;
+ flowStatsDl.lastTtiBytesTrasmitted = 0;
+ flowStatsDl.lastAveragedThroughput = 1;
+ m_flowStatsDl.insert (std::pair<uint16_t, tdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
+ tdbetsFlowPerf_t flowStatsUl;
+ flowStatsUl.flowStart = Simulator::Now ();
+ flowStatsUl.totalBytesTransmitted = 0;
+ flowStatsUl.lastTtiBytesTrasmitted = 0;
+ flowStatsUl.lastAveragedThroughput = 1;
+ m_flowStatsUl.insert (std::pair<uint16_t, tdbetsFlowPerf_t> (params.m_rnti, flowStatsUl));
+ }
+ else
+ {
+ NS_LOG_ERROR ("RNTI already exists");
+ }
+ }
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+
+void
+TdBetFfMacScheduler::DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
+ // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
+
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+
+ LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
+
+ it = m_rlcBufferReq.find (flow);
+
+ if (it == m_rlcBufferReq.end ())
+ {
+ m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
+ }
+ else
+ {
+ (*it).second = params;
+ }
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+int
+TdBetFfMacScheduler::GetRbgSize (int dlbandwidth)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (dlbandwidth < TdBetType0AllocationRbg[i])
+ {
+ return (i + 1);
+ }
+ }
+
+ return (-1);
+}
+
+
+int
+TdBetFfMacScheduler::LcActivePerFlow (uint16_t rnti)
+{
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ int lcActive = 0;
+ for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
+ {
+ if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
+ || ((*it).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*it).second.m_rlcStatusPduSize > 0) ))
+ {
+ lcActive++;
+ }
+ if ((*it).first.m_rnti > rnti)
+ {
+ break;
+ }
+ }
+ return (lcActive);
+
+}
+
+
+void
+TdBetFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+ // API generated by RLC for triggering the scheduling of a DL subframe
+
+
+ // evaluate the relative channel quality indicator for each UE per each RBG
+ // (since we are using allocation type 0 the small unit of allocation is RBG)
+ // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
+
+ RefreshDlCqiMaps ();
+
+ int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+ int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+ NS_LOG_DEBUG (this << " DlBandwidth " << rbgNum * rbgSize << " rbgSize " <<rbgSize);
+ std::map <uint16_t, std::vector <uint16_t> > allocationMap;
+ //NS_LOG_DEBUG (this << " ALLOCATION for RBG " << i << " of " << rbgNum);
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator itMax = m_flowStatsDl.end ();
+ double metricMax = 0.0;
+ for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
+ {
+ double metric = 1 / (*it).second.lastAveragedThroughput;
+
+ if (metric > metricMax)
+ {
+ metricMax = metric;
+ itMax = it;
+ }
+ } // end for m_flowStatsDl
+
+
+ if (itMax == m_flowStatsDl.end ())
+ {
+ // no UE available for downlink
+ return;
+ }
+ else
+ {
+ // assign all RBGs to this UE
+ std::vector <uint16_t> tempMap;
+ for (int i = 0; i < rbgNum; i++)
+ {
+ tempMap.push_back (i);
+ }
+ allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
+ //NS_LOG_DEBUG (this << " UE assigned " << (*itMax).first);
+ }
+
+ // reset TTI stats of users
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
+ for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
+ {
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+
+ // generate the transmission opportunities by grouping the RBGs of the same RNTI and
+ // creating the correspondent DCIs
+ FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
+ while (itMap != allocationMap.end ())
+ {
+ // create new BuildDataListElement_s for this LC
+ BuildDataListElement_s newEl;
+ newEl.m_rnti = (*itMap).first;
+ // create the DlDciListElement_s
+ DlDciListElement_s newDci;
+ std::vector <struct RlcPduListElement_s> newRlcPduLe;
+ newDci.m_rnti = (*itMap).first;
+
+ uint16_t lcActives = LcActivePerFlow ((*itMap).first);
+// NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
+ std::map <uint16_t,uint8_t>::iterator itCqi;
+ itCqi = m_p10CqiRxed.find ((*itMap).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMap).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ uint32_t bytesTxed = 0;
+ for (uint8_t i = 0; i < nLayer; i++)
+ {
+ if (itCqi == m_p10CqiRxed.end ())
+ {
+ newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
+ }
+ else
+ {
+ newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
+ }
+ }
+
+ for (uint8_t i = 0; i < nLayer; i++)
+ {
+ 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)
+ NS_LOG_DEBUG ( Simulator::Now() << this << "Allocate user " << newEl.m_rnti << " tbSize "<< tbSize << " PRBs " << 0 << " ... " << rbgNum * rbgSize - 1 << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " layers " << nLayer);
+ newDci.m_tbsSize.push_back (tbSize);
+ bytesTxed += tbSize;
+ }
+
+ newDci.m_resAlloc = 0; // only allocation type 0 at this stage
+ newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
+ uint32_t rbgMask = 0;
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
+// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+ }
+ newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
+
+ // create the rlc PDUs -> equally divide resources among actives LCs
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
+ for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
+ {
+ if (((*itBufReq).first.m_rnti == (*itMap).first) &&
+ (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ RlcPduListElement_s newRlcEl;
+ newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
+ newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
+ //NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
+ newRlcPduLe.push_back (newRlcEl);
+ UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
+ }
+ }
+ if ((*itBufReq).first.m_rnti > (*itMap).first)
+ {
+ break;
+ }
+ }
+ newDci.m_ndi.push_back (1); // TBD (new data indicator)
+ newDci.m_rv.push_back (0); // TBD (redundancy version)
+
+ newEl.m_dci = newDci;
+ // ...more parameters -> ingored in this version
+
+ newEl.m_rlcPduList.push_back (newRlcPduLe);
+ ret.m_buildDataList.push_back (newEl);
+
+ // update UE stats
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
+ it = m_flowStatsDl.find ((*itMap).first);
+ if (it != m_flowStatsDl.end ())
+ {
+ (*it).second.lastTtiBytesTrasmitted = bytesTxed;
+// NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
+
+
+ }
+ else
+ {
+ NS_LOG_DEBUG (this << " No Stats for this allocated UE");
+ }
+
+ itMap++;
+ } // end while allocation
+ ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
+
+
+ // update UEs stats
+ for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
+ {
+ (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
+ // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
+ (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
+// NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
+// NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+
+ m_schedSapUser->SchedDlConfigInd (ret);
+
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
+ {
+ if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
+ {
+ // wideband CQI reporting
+ std::map <uint16_t,uint8_t>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_p10CqiRxed.find (rnti);
+ if (it == m_p10CqiRxed.end ())
+ {
+ // create the new entry
+ 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)
+ // generate correspondent timer
+ m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
+ // update correspondent timer
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_p10CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " CQI type unknown");
+ }
+ }
+
+ return;
+}
+
+
+double
+TdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
+{
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ return (NO_SINR);
+
+ }
+ else
+ {
+ // take the average SINR value among the available
+ double sinrSum = 0;
+ int sinrNum = 0;
+ for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
+ {
+ double sinr = (*itCqi).second.at (i);
+ if (sinr != NO_SINR)
+ {
+ sinrSum += sinr;
+ sinrNum++;
+ }
+ }
+ double estimatedSinr = sinrSum / (double)sinrNum;
+ // store the value
+ (*itCqi).second.at (rb) = estimatedSinr;
+ return (estimatedSinr);
+ }
+}
+
+void
+TdBetFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+
+ RefreshUlCqiMaps ();
+
+ std::map <uint16_t,uint32_t>::iterator it;
+ int nflows = 0;
+
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ // remove old entries of this UE-LC
+ if ((*it).second > 0)
+ {
+ nflows++;
+ }
+ }
+
+ if (nflows == 0)
+ {
+ return ; // no flows to be scheduled
+ }
+
+
+ // Divide the resource equally among the active users
+ int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+ if (rbPerFlow == 0)
+ {
+ rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
+ }
+ int rbAllocated = 0;
+
+ FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+ std::vector <uint16_t> rbgAllocationMap;
+ std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
+ if (m_nextRntiUl != 0)
+ {
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ if ((*it).first == m_nextRntiUl)
+ {
+ break;
+ }
+ }
+ if (it == m_ceBsrRxed.end ())
+ {
+ NS_LOG_ERROR (this << " no user found");
+ }
+ }
+ else
+ {
+ it = m_ceBsrRxed.begin ();
+ m_nextRntiUl = (*it).first;
+ }
+ do
+ {
+ if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
+ {
+ // limit to physical resources last resource assignment
+ rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
+ }
+
+ UlDciListElement_s uldci;
+ uldci.m_rnti = (*it).first;
+ uldci.m_rbStart = rbAllocated;
+ uldci.m_rbLen = rbPerFlow;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
+ int cqi = 0;
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
+// NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
+ }
+ else
+ {
+ // take the lowest CQI value (worst RB)
+ double minSinr = (*itCqi).second.at (uldci.m_rbStart);
+ if (minSinr == NO_SINR)
+ {
+ minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
+ }
+ for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
+ {
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
+ double sinr = (*itCqi).second.at (i);
+ if (sinr == NO_SINR)
+ {
+ sinr = EstimateUlSinr ((*it).first, i);
+ }
+ if ((*itCqi).second.at (i) < minSinr)
+ {
+ minSinr = (*itCqi).second.at (i);
+ }
+ }
+
+ // translate SINR -> cqi: WILD ACK: same as DL
+ double s = log2 ( 1 + (
+ pow (10, minSinr / 10 ) /
+ ( (-log (5.0 * 0.00005 )) / 1.5) ));
+ cqi = m_amc->GetCqiFromSpectralEfficiency (s);
+ if (cqi == 0)
+ {
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ }
+ uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
+
+ }
+
+ rbAllocated += rbPerFlow;
+ // store info on allocation for managing ul-cqi interpretation
+ for (int i = 0; i < rbPerFlow; i++)
+ {
+ rbgAllocationMap.push_back ((*it).first);
+ }
+ uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
+// 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);
+ UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
+ uldci.m_ndi = 1;
+ uldci.m_cceIndex = 0;
+ uldci.m_aggrLevel = 1;
+ uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
+ uldci.m_hopping = false;
+ uldci.m_n2Dmrs = 0;
+ uldci.m_tpc = 0; // no power control
+ uldci.m_cqiRequest = false; // only period CQI at this stage
+ uldci.m_ulIndex = 0; // TDD parameter
+ uldci.m_dai = 1; // TDD parameter
+ uldci.m_freqHopping = 0;
+ uldci.m_pdcchPowerOffset = 0; // not used
+ ret.m_dciList.push_back (uldci);
+
+ // update TTI UE stats
+ itStats = m_flowStatsUl.find ((*it).first);
+ if (itStats != m_flowStatsUl.end ())
+ {
+ (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
+// NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
+
+
+ }
+ else
+ {
+ NS_LOG_DEBUG (this << " No Stats for this allocated UE");
+ }
+
+
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
+ {
+ // Stop allocation: no more PRBs
+ m_nextRntiUl = (*it).first;
+ break;
+ }
+ }
+ while ((*it).first != m_nextRntiUl);
+
+
+ // Update global UE stats
+ // update UEs stats
+ for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
+ {
+ (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
+ // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
+ (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
+ // NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
+ // NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
+ (*itStats).second.lastTtiBytesTrasmitted = 0;
+ }
+ m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+ m_schedSapUser->SchedUlConfigInd (ret);
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ std::map <uint16_t,uint32_t>::iterator it;
+
+ for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
+ {
+ if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
+ {
+ // buffer status report
+ uint16_t rnti = params.m_macCeList.at (i).m_rnti;
+ it = m_ceBsrRxed.find (rnti);
+ if (it == m_ceBsrRxed.end ())
+ {
+ // create the new entry
+ uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
+ int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
+ m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer)); // only 1 buffer status is working now
+ }
+ else
+ {
+ // update the CQI value
+ (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
+ }
+ }
+ }
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+// NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
+ // retrieve the allocation for this subframe
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi;
+ itMap = m_allocationMaps.find (params.m_sfnSf);
+ if (itMap == m_allocationMaps.end ())
+ {
+ //NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
+ return;
+ }
+ for (uint32_t i = 0; i < (*itMap).second.size (); i++)
+ {
+ // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
+// NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
+ double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
+ //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
+ itCqi = m_ueCqi.find ((*itMap).second.at (i));
+ if (itCqi == m_ueCqi.end ())
+ {
+ // create a new entry
+ std::vector <double> newCqi;
+ for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
+ {
+ if (i == j)
+ {
+ newCqi.push_back (sinr);
+ }
+ else
+ {
+ // initialize with NO_SINR value.
+ newCqi.push_back (NO_SINR);
+ }
+
+ }
+ m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
+ // generate correspondent timer
+ m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the value
+ (*itCqi).second.at (i) = sinr;
+ // update correspondent timer
+ std::map <uint16_t, uint32_t>::iterator itTimers;
+ itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
+ (*itTimers).second = m_cqiTimersThreshold;
+
+ }
+
+ }
+ // remove obsolete info on allocation
+ m_allocationMaps.erase (itMap);
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::RefreshDlCqiMaps(void)
+{
+ // refresh DL CQI P01 Map
+ std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
+ while (itP10!=m_p10CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itP10).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
+ NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
+ NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
+ m_p10CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itP10;
+ itP10++;
+ m_p10CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itP10).second--;
+ itP10++;
+ }
+ }
+
+ return;
+}
+
+
+void
+TdBetFfMacScheduler::RefreshUlCqiMaps(void)
+{
+ // refresh UL CQI Map
+ std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
+ while (itUl!=m_ueCqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itUl).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
+ NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
+ NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
+ (*itMap).second.clear ();
+ m_ueCqi.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itUl;
+ itUl++;
+ m_ueCqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itUl).second--;
+ itUl++;
+ }
+ }
+
+ return;
+}
+
+void
+TdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
+{
+ std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ LteFlowId_t flow (rnti, lcid);
+ it = m_rlcBufferReq.find (flow);
+ if (it!=m_rlcBufferReq.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
+ // Update queues: RLC tx order Status, ReTx, Tx
+ // Update status queue
+ if ((*it).second.m_rlcStatusPduSize <= size)
+ {
+ size -= (*it).second.m_rlcStatusPduSize;
+ (*it).second.m_rlcStatusPduSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcStatusPduSize -= size;
+ return;
+ }
+ // update retransmission queue
+ if ((*it).second.m_rlcRetransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcRetransmissionQueueSize;
+ (*it).second.m_rlcRetransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcRetransmissionQueueSize -= size;
+ return;
+ }
+ // update transmission queue
+ if ((*it).second.m_rlcTransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcTransmissionQueueSize;
+ (*it).second.m_rlcTransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcTransmissionQueueSize -= size;
+ return;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
+ }
+}
+
+void
+TdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
+{
+
+
+ std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
+ if (it!=m_ceBsrRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
+ if ((*it).second >= size)
+ {
+ (*it).second -= size;
+ }
+ else
+ {
+ (*it).second = 0;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
+ }
+
+}
+
+void
+TdBetFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
+ FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+ params.m_rnti = rnti;
+ params.m_transmissionMode = txMode;
+ m_cschedSapUser->CschedUeConfigUpdateInd (params);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tdbet-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,216 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ */
+
+#ifndef TDBET_FF_MAC_SCHEDULER_H
+#define TDBET_FF_MAC_SCHEDULER_H
+
+#include <ns3/lte-common.h>
+#include <ns3/ff-mac-csched-sap.h>
+#include <ns3/ff-mac-sched-sap.h>
+#include <ns3/ff-mac-scheduler.h>
+#include <vector>
+#include <map>
+#include <ns3/nstime.h>
+#include <ns3/lte-amc.h>
+
+
+// value for SINR outside the range defined by FF-API, used to indicate that there
+// is no CQI for this element
+#define NO_SINR -5000
+
+namespace ns3 {
+
+
+struct tdbetsFlowPerf_t
+{
+ Time flowStart;
+ unsigned long totalBytesTransmitted;
+ unsigned int lastTtiBytesTrasmitted;
+ double lastAveragedThroughput;
+};
+
+
+/**
+ * \ingroup ff-api
+ * \defgroup FF-API TdBetFfMacScheduler
+ */
+/**
+ * \ingroup TdBetFfMacScheduler
+ * \brief Implements the SCHED SAP and CSCHED SAP for a Proportional Fair scheduler
+ *
+ * This class implements the interface defined by the FfMacScheduler abstract class
+ */
+
+class TdBetFfMacScheduler : public FfMacScheduler
+{
+public:
+ /**
+ * \brief Constructor
+ *
+ * Creates the MAC Scheduler interface implementation
+ */
+ TdBetFfMacScheduler ();
+
+ /**
+ * Destructor
+ */
+ virtual ~TdBetFfMacScheduler ();
+
+ // inherited from Object
+ virtual void DoDispose (void);
+ static TypeId GetTypeId (void);
+
+ // inherited from FfMacScheduler
+ virtual void SetFfMacCschedSapUser (FfMacCschedSapUser* s);
+ virtual void SetFfMacSchedSapUser (FfMacSchedSapUser* s);
+ virtual FfMacCschedSapProvider* GetFfMacCschedSapProvider ();
+ virtual FfMacSchedSapProvider* GetFfMacSchedSapProvider ();
+
+ friend class TdBetSchedulerMemberCschedSapProvider;
+ friend class TdBetSchedulerMemberSchedSapProvider;
+
+ void TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode);
+
+private:
+ //
+ // Implementation of the CSCHED API primitives
+ // (See 4.1 for description of the primitives)
+ //
+
+ void DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params);
+
+ void DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params);
+
+ void DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params);
+
+ void DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params);
+
+ void DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params);
+
+ //
+ // Implementation of the SCHED API primitives
+ // (See 4.2 for description of the primitives)
+ //
+
+ void DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params);
+
+ void DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params);
+
+ void DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params);
+
+ void DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params);
+
+ void DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params);
+
+ void DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params);
+
+ void DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params);
+
+ void DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params);
+
+ void DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
+
+ void DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params);
+
+ void DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
+
+
+ int GetRbgSize (int dlbandwidth);
+
+ int LcActivePerFlow (uint16_t rnti);
+
+ double EstimateUlSinr (uint16_t rnti, uint16_t rb);
+
+ void RefreshDlCqiMaps(void);
+ void RefreshUlCqiMaps(void);
+
+ void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
+ void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+ Ptr<LteAmc> m_amc;
+
+ /*
+ * Vectors of UE's LC info
+ */
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> m_rlcBufferReq;
+
+
+ /*
+ * Map of UE statistics (per RNTI basis) in downlink
+ */
+ std::map <uint16_t, tdbetsFlowPerf_t> m_flowStatsDl;
+
+ /*
+ * Map of UE statistics (per RNTI basis)
+ */
+ std::map <uint16_t, tdbetsFlowPerf_t> m_flowStatsUl;
+
+
+ /*
+ * Map of UE's DL CQI P01 received
+ */
+ std::map <uint16_t,uint8_t> m_p10CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI P01 received
+ */
+ std::map <uint16_t,uint32_t> m_p10CqiTimers;
+
+ /*
+ * Map of previous allocated UE per RBG
+ * (used to retrieve info from UL-CQI)
+ */
+ std::map <uint16_t, std::vector <uint16_t> > m_allocationMaps;
+
+ /*
+ * Map of UEs' UL-CQI per RBG
+ */
+ std::map <uint16_t, std::vector <double> > m_ueCqi;
+ /*
+ * Map of UEs' timers on UL-CQI per RBG
+ */
+ std::map <uint16_t, uint32_t> m_ueCqiTimers;
+
+ /*
+ * Map of UE's buffer status reports received
+ */
+ std::map <uint16_t,uint32_t> m_ceBsrRxed;
+
+ // MAC SAPs
+ FfMacCschedSapUser* m_cschedSapUser;
+ FfMacSchedSapUser* m_schedSapUser;
+ FfMacCschedSapProvider* m_cschedSapProvider;
+ FfMacSchedSapProvider* m_schedSapProvider;
+
+
+ // Internal parameters
+ FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig;
+
+
+ double m_timeWindow;
+
+ uint16_t m_nextRntiUl; // RNTI of the next user to be served next scheduling in UL
+
+ uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
+
+ std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+};
+
+} // namespace ns3
+
+#endif /* TDBET_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tdmt-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,1143 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <ns3/log.h>
+#include <ns3/pointer.h>
+
+#include <ns3/simulator.h>
+#include <ns3/lte-amc.h>
+#include "tdmt-ff-mac-scheduler.h"
+
+NS_LOG_COMPONENT_DEFINE ("TdMtFfMacScheduler");
+
+namespace ns3 {
+
+int TdMtType0AllocationRbg[4] = {
+ 10, // RGB size 1
+ 26, // RGB size 2
+ 63, // RGB size 3
+ 110 // RGB size 4
+}; // see table 7.1.6.1-1 of 36.213
+
+
+NS_OBJECT_ENSURE_REGISTERED (TdMtFfMacScheduler);
+
+
+
+class TdMtSchedulerMemberCschedSapProvider : public FfMacCschedSapProvider
+{
+public:
+ TdMtSchedulerMemberCschedSapProvider (TdMtFfMacScheduler* scheduler);
+
+ // inherited from FfMacCschedSapProvider
+ virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
+ virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
+ virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
+ virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
+ virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
+
+private:
+ TdMtSchedulerMemberCschedSapProvider ();
+ TdMtFfMacScheduler* m_scheduler;
+};
+
+TdMtSchedulerMemberCschedSapProvider::TdMtSchedulerMemberCschedSapProvider ()
+{
+}
+
+TdMtSchedulerMemberCschedSapProvider::TdMtSchedulerMemberCschedSapProvider (TdMtFfMacScheduler* scheduler) : m_scheduler (scheduler)
+{
+}
+
+
+void
+TdMtSchedulerMemberCschedSapProvider::CschedCellConfigReq (const struct CschedCellConfigReqParameters& params)
+{
+ m_scheduler->DoCschedCellConfigReq (params);
+}
+
+void
+TdMtSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
+{
+ m_scheduler->DoCschedUeConfigReq (params);
+}
+
+
+void
+TdMtSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
+{
+ m_scheduler->DoCschedLcConfigReq (params);
+}
+
+void
+TdMtSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedLcReleaseReq (params);
+}
+
+void
+TdMtSchedulerMemberCschedSapProvider::CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedUeReleaseReq (params);
+}
+
+
+
+
+class TdMtSchedulerMemberSchedSapProvider : public FfMacSchedSapProvider
+{
+public:
+ TdMtSchedulerMemberSchedSapProvider (TdMtFfMacScheduler* scheduler);
+
+ // inherited from FfMacSchedSapProvider
+ virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
+ virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
+ virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
+ virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
+ virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
+ virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
+ virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
+ virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
+ virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
+ virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
+ virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
+
+
+private:
+ TdMtSchedulerMemberSchedSapProvider ();
+ TdMtFfMacScheduler* m_scheduler;
+};
+
+
+
+TdMtSchedulerMemberSchedSapProvider::TdMtSchedulerMemberSchedSapProvider ()
+{
+}
+
+
+TdMtSchedulerMemberSchedSapProvider::TdMtSchedulerMemberSchedSapProvider (TdMtFfMacScheduler* scheduler)
+ : m_scheduler (scheduler)
+{
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlRlcBufferReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlPagingBufferReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlMacBufferReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedDlTriggerReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlRachInfoReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlCqiInfoReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedUlTriggerReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
+{
+ m_scheduler->DoSchedUlNoiseInterferenceReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlSrInfoReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlMacCtrlInfoReq (params);
+}
+
+void
+TdMtSchedulerMemberSchedSapProvider::SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlCqiInfoReq (params);
+}
+
+
+
+
+
+TdMtFfMacScheduler::TdMtFfMacScheduler ()
+ : m_cschedSapUser (0),
+ m_schedSapUser (0),
+ m_nextRntiUl (0)
+{
+ m_amc = CreateObject <LteAmc> ();
+ m_cschedSapProvider = new TdMtSchedulerMemberCschedSapProvider (this);
+ m_schedSapProvider = new TdMtSchedulerMemberSchedSapProvider (this);
+}
+
+TdMtFfMacScheduler::~TdMtFfMacScheduler ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+TdMtFfMacScheduler::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_cschedSapProvider;
+ delete m_schedSapProvider;
+}
+
+TypeId
+TdMtFfMacScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TdMtFfMacScheduler")
+ .SetParent<FfMacScheduler> ()
+ .AddConstructor<TdMtFfMacScheduler> ()
+ .AddAttribute ("CqiTimerThreshold",
+ "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
+ UintegerValue (1000),
+ MakeUintegerAccessor (&TdMtFfMacScheduler::m_cqiTimersThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+
+void
+TdMtFfMacScheduler::SetFfMacCschedSapUser (FfMacCschedSapUser* s)
+{
+ m_cschedSapUser = s;
+}
+
+void
+TdMtFfMacScheduler::SetFfMacSchedSapUser (FfMacSchedSapUser* s)
+{
+ m_schedSapUser = s;
+}
+
+FfMacCschedSapProvider*
+TdMtFfMacScheduler::GetFfMacCschedSapProvider ()
+{
+ return m_cschedSapProvider;
+}
+
+FfMacSchedSapProvider*
+TdMtFfMacScheduler::GetFfMacSchedSapProvider ()
+{
+ return m_schedSapProvider;
+}
+
+void
+TdMtFfMacScheduler::DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // Read the subset of parameters used
+ m_cschedCellConfig = params;
+ FfMacCschedSapUser::CschedUeConfigCnfParameters cnf;
+ cnf.m_result = SUCCESS;
+ m_cschedSapUser->CschedUeConfigCnf (cnf);
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
+ std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
+ if (it==m_uesTxMode.end ())
+ {
+ m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+ }
+ else
+ {
+ (*it).second = params.m_transmissionMode;
+ }
+ return;
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
+
+ std::set<uint16_t>::iterator it;
+
+ for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
+ {
+ it = m_flowStatsDl.find (params.m_rnti);
+
+ if (it == m_flowStatsDl.end ())
+ {
+ m_flowStatsDl.insert (params.m_rnti);
+ m_flowStatsUl.insert (params.m_rnti);
+ }
+ else
+ {
+ NS_LOG_ERROR ("RNTI already exists");
+ }
+
+ }
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+
+void
+TdMtFfMacScheduler::DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
+ // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
+
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+
+ LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
+
+ it = m_rlcBufferReq.find (flow);
+
+ if (it == m_rlcBufferReq.end ())
+ {
+ m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
+ }
+ else
+ {
+ (*it).second = params;
+ }
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+int
+TdMtFfMacScheduler::GetRbgSize (int dlbandwidth)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (dlbandwidth < TdMtType0AllocationRbg[i])
+ {
+ return (i + 1);
+ }
+ }
+
+ return (-1);
+}
+
+
+int
+TdMtFfMacScheduler::LcActivePerFlow (uint16_t rnti)
+{
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ int lcActive = 0;
+ for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
+ {
+ if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
+ || ((*it).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*it).second.m_rlcStatusPduSize > 0) ))
+ {
+ lcActive++;
+ }
+ if ((*it).first.m_rnti > rnti)
+ {
+ break;
+ }
+ }
+ return (lcActive);
+
+}
+
+
+void
+TdMtFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+ // API generated by RLC for triggering the scheduling of a DL subframe
+
+
+ // evaluate the wideband channel quality indicator for each UE and allocate
+ // all RBGs to the UE with highest achievable rate
+ // (since we are using allocation type 0 the small unit of allocation is RBG)
+ // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
+
+ RefreshDlCqiMaps ();
+
+ int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+ int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+ std::map <uint16_t, std::vector <uint16_t> > allocationMap;
+ std::set <uint16_t>::iterator it;
+ std::set <uint16_t>::iterator itMax = m_flowStatsDl.end ();
+ double metricMax = 0.0;
+ for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
+ {
+ std::map <uint16_t,uint8_t>::iterator itCqi;
+ itCqi = m_p10CqiRxed.find ((*it));
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*it));
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it));
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ uint8_t wbCqi = 0;
+ if (itCqi == m_p10CqiRxed.end())
+ {
+ //NS_LOG_DEBUG (this << " No DL-CQI for this UE " << (*it));
+ wbCqi = 1; // start with lowest value
+ }
+ else
+ {
+ wbCqi = (*itCqi).second;
+ //NS_LOG_INFO (this << " CQI " << (uint32_t)wbCqi);
+ }
+
+ if (wbCqi > 0)
+ {
+ if (LcActivePerFlow (*it) > 0)
+ {
+ // this UE has data to transmit
+ double achievableRate = 0.0;
+ for (uint8_t k = 0; k < nLayer; k++)
+ {
+ uint8_t mcs = 0;
+ mcs = m_amc->GetMcsFromCqi (wbCqi);
+ achievableRate += ((m_amc->GetTbSizeFromMcs (mcs, rbgSize) / 8) / 0.001); // = TB size / TTI
+ }
+
+ double metric = achievableRate;
+ //NS_LOG_DEBUG (this << " RNTI " << (*it) << " MCS " << (uint32_t)mcs << " achievableRate " << achievableRate << " RCQI " << rcqi);
+
+ if (metric > metricMax)
+ {
+ metricMax = metric;
+ itMax = it;
+ }
+ }
+ } // end of wbCqi
+ } // end for m_flowStatsDl
+
+ if (itMax == m_flowStatsDl.end ())
+ {
+ // no UE available for downlink
+ return;
+ }
+ else
+ {
+ // assign all RBGs to this UE
+ std::vector <uint16_t> tempMap;
+ for (int i = 0; i < rbgNum; i++)
+ {
+ tempMap.push_back (i);
+ }
+ allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax), tempMap));
+ //NS_LOG_DEBUG (this << " UE assigned " << (*itMax));
+ }
+
+ // generate the transmission opportunities by allocating all RBGs to selected UE and
+ // creating the correspondent DCIs
+ FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
+ while (itMap != allocationMap.end ())
+ {
+ // create new BuildDataListElement_s for this LC
+ BuildDataListElement_s newEl;
+ newEl.m_rnti = (*itMap).first;
+ // create the DlDciListElement_s
+ DlDciListElement_s newDci;
+ std::vector <struct RlcPduListElement_s> newRlcPduLe;
+ newDci.m_rnti = (*itMap).first;
+
+ uint16_t lcActives = LcActivePerFlow ((*itMap).first);
+// NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
+ std::map <uint16_t,uint8_t>::iterator itCqi;
+ itCqi = m_p10CqiRxed.find((*itMap).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMap).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> worstCqi (2, 15);
+
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ if (itCqi == m_p10CqiRxed.end ())
+ {
+ newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
+ }
+ else
+ {
+ newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
+ }
+ // allocate all RBGs to this UE
+ int tbSize = (m_amc->GetTbSizeFromMcs (newDci.m_mcs.at (j), rbgNum * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
+
+ newDci.m_tbsSize.push_back (tbSize);
+ NS_LOG_DEBUG (this << " MCS " << m_amc->GetMcsFromCqi ((*itCqi).second));
+ }
+
+ newDci.m_resAlloc = 0; // only allocation type 0 at this stage
+ newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
+ uint32_t rbgMask = 0;
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
+// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+ }
+ newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
+
+ // create the rlc PDUs -> equally divide resources among actives LCs
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
+ for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
+ {
+ if (((*itBufReq).first.m_rnti == (*itMap).first) &&
+ (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ RlcPduListElement_s newRlcEl;
+ newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
+ newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
+ NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
+ newRlcPduLe.push_back (newRlcEl);
+ UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
+ }
+ }
+ if ((*itBufReq).first.m_rnti > (*itMap).first)
+ {
+ break;
+ }
+ }
+ newDci.m_ndi.push_back (1); // TBD (new data indicator)
+ newDci.m_rv.push_back (0); // TBD (redundancy version)
+
+ newEl.m_dci = newDci;
+ // ...more parameters -> ingored in this version
+
+ newEl.m_rlcPduList.push_back (newRlcPduLe);
+ ret.m_buildDataList.push_back (newEl);
+
+ itMap++;
+ } // end while allocation
+ ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
+
+ m_schedSapUser->SchedDlConfigInd (ret);
+
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
+ {
+ if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
+ {
+ // wideband CQI reporting
+ std::map <uint16_t,uint8_t>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_p10CqiRxed.find (rnti);
+ if (it == m_p10CqiRxed.end ())
+ {
+ // create the new entry
+ 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)
+ // generate correspondent timer
+ m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
+ // update correspondent timer
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_p10CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
+ {
+ // subband CQI reporting high layer configured
+ std::map <uint16_t,SbMeasResult_s>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_a30CqiRxed.find (rnti);
+ if (it == m_a30CqiRxed.end ())
+ {
+ // create the new entry
+ m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
+ m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_a30CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " CQI type unknown");
+ }
+ }
+
+ return;
+}
+
+
+double
+TdMtFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
+{
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ return (NO_SINR);
+
+ }
+ else
+ {
+ // take the average SINR value among the available
+ double sinrSum = 0;
+ int sinrNum = 0;
+ for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
+ {
+ double sinr = (*itCqi).second.at (i);
+ if (sinr != NO_SINR)
+ {
+ sinrSum += sinr;
+ sinrNum++;
+ }
+ }
+ double estimatedSinr = sinrSum / (double)sinrNum;
+ // store the value
+ (*itCqi).second.at (rb) = estimatedSinr;
+ return (estimatedSinr);
+ }
+}
+
+void
+TdMtFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+
+ RefreshUlCqiMaps ();
+
+ std::map <uint16_t,uint32_t>::iterator it;
+ int nflows = 0;
+
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ // remove old entries of this UE-LC
+ if ((*it).second > 0)
+ {
+ nflows++;
+ }
+ }
+
+ if (nflows == 0)
+ {
+ return ; // no flows to be scheduled
+ }
+
+
+ // Divide the resource equally among the active users
+ int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+ if (rbPerFlow == 0)
+ {
+ rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
+ }
+ int rbAllocated = 0;
+
+ FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+ std::vector <uint16_t> rbgAllocationMap;
+
+ if (m_nextRntiUl != 0)
+ {
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ if ((*it).first == m_nextRntiUl)
+ {
+ break;
+ }
+ }
+ if (it == m_ceBsrRxed.end ())
+ {
+ NS_LOG_ERROR (this << " no user found");
+ }
+ }
+ else
+ {
+ it = m_ceBsrRxed.begin ();
+ m_nextRntiUl = (*it).first;
+ }
+ do
+ {
+ if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
+ {
+ // limit to physical resources last resource assignment
+ rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
+ }
+
+ UlDciListElement_s uldci;
+ uldci.m_rnti = (*it).first;
+ uldci.m_rbStart = rbAllocated;
+ uldci.m_rbLen = rbPerFlow;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
+ int cqi = 0;
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
+// NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
+ }
+ else
+ {
+ // take the lowest CQI value (worst RB)
+ double minSinr = (*itCqi).second.at (uldci.m_rbStart);
+ if (minSinr == NO_SINR)
+ {
+ minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
+ }
+ for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
+ {
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
+ double sinr = (*itCqi).second.at (i);
+ if (sinr == NO_SINR)
+ {
+ sinr = EstimateUlSinr ((*it).first, i);
+ }
+ if ((*itCqi).second.at (i) < minSinr)
+ {
+ minSinr = (*itCqi).second.at (i);
+ }
+ }
+
+ // translate SINR -> cqi: WILD ACK: same as DL
+ double s = log2 ( 1 + (
+ pow (10, minSinr / 10 ) /
+ ( (-log (5.0 * 0.00005 )) / 1.5) ));
+ cqi = m_amc->GetCqiFromSpectralEfficiency (s);
+ if (cqi == 0)
+ {
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ }
+ uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
+
+ }
+
+ rbAllocated += rbPerFlow;
+ // store info on allocation for managing ul-cqi interpretation
+ for (int i = 0; i < rbPerFlow; i++)
+ {
+ rbgAllocationMap.push_back ((*it).first);
+ }
+ uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
+// 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);
+ UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
+ uldci.m_ndi = 1;
+ uldci.m_cceIndex = 0;
+ uldci.m_aggrLevel = 1;
+ uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
+ uldci.m_hopping = false;
+ uldci.m_n2Dmrs = 0;
+ uldci.m_tpc = 0; // no power control
+ uldci.m_cqiRequest = false; // only period CQI at this stage
+ uldci.m_ulIndex = 0; // TDD parameter
+ uldci.m_dai = 1; // TDD parameter
+ uldci.m_freqHopping = 0;
+ uldci.m_pdcchPowerOffset = 0; // not used
+ ret.m_dciList.push_back (uldci);
+
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
+ {
+ // Stop allocation: no more PRBs
+ m_nextRntiUl = (*it).first;
+ break;
+ }
+ }
+ while ((*it).first != m_nextRntiUl);
+
+ m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+ m_schedSapUser->SchedUlConfigInd (ret);
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ std::map <uint16_t,uint32_t>::iterator it;
+
+ for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
+ {
+ if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
+ {
+ // buffer status report
+ uint16_t rnti = params.m_macCeList.at (i).m_rnti;
+ it = m_ceBsrRxed.find (rnti);
+ if (it == m_ceBsrRxed.end ())
+ {
+ // create the new entry
+ uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
+ int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
+ m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer)); // only 1 buffer status is working now
+ }
+ else
+ {
+ // update the CQI value
+ (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
+ }
+ }
+ }
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+// NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
+ // retrieve the allocation for this subframe
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi;
+ itMap = m_allocationMaps.find (params.m_sfnSf);
+ if (itMap == m_allocationMaps.end ())
+ {
+ NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
+ return;
+ }
+ for (uint32_t i = 0; i < (*itMap).second.size (); i++)
+ {
+ // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
+// NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
+ double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
+ //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
+ itCqi = m_ueCqi.find ((*itMap).second.at (i));
+ if (itCqi == m_ueCqi.end ())
+ {
+ // create a new entry
+ std::vector <double> newCqi;
+ for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
+ {
+ if (i == j)
+ {
+ newCqi.push_back (sinr);
+ }
+ else
+ {
+ // initialize with NO_SINR value.
+ newCqi.push_back (NO_SINR);
+ }
+
+ }
+ m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
+ // generate correspondent timer
+ m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the value
+ (*itCqi).second.at (i) = sinr;
+ // update correspondent timer
+ std::map <uint16_t, uint32_t>::iterator itTimers;
+ itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
+ (*itTimers).second = m_cqiTimersThreshold;
+
+ }
+
+ }
+ // remove obsolete info on allocation
+ m_allocationMaps.erase (itMap);
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::RefreshDlCqiMaps(void)
+{
+ // refresh DL CQI P01 Map
+ std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
+ while (itP10!=m_p10CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itP10).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
+ NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
+ NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
+ m_p10CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itP10;
+ itP10++;
+ m_p10CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itP10).second--;
+ itP10++;
+ }
+ }
+
+ // refresh DL CQI A30 Map
+ std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
+ while (itA30!=m_a30CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itA30).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
+ NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
+ NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
+ m_a30CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itA30;
+ itA30++;
+ m_a30CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itA30).second--;
+ itA30++;
+ }
+ }
+
+ return;
+}
+
+
+void
+TdMtFfMacScheduler::RefreshUlCqiMaps(void)
+{
+ // refresh UL CQI Map
+ std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
+ while (itUl!=m_ueCqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itUl).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
+ NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
+ NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
+ (*itMap).second.clear ();
+ m_ueCqi.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itUl;
+ itUl++;
+ m_ueCqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itUl).second--;
+ itUl++;
+ }
+ }
+
+ return;
+}
+
+void
+TdMtFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
+{
+ std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ LteFlowId_t flow (rnti, lcid);
+ it = m_rlcBufferReq.find (flow);
+ if (it!=m_rlcBufferReq.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
+ // Update queues: RLC tx order Status, ReTx, Tx
+ // Update status queue
+ if ((*it).second.m_rlcStatusPduSize <= size)
+ {
+ size -= (*it).second.m_rlcStatusPduSize;
+ (*it).second.m_rlcStatusPduSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcStatusPduSize -= size;
+ return;
+ }
+ // update retransmission queue
+ if ((*it).second.m_rlcRetransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcRetransmissionQueueSize;
+ (*it).second.m_rlcRetransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcRetransmissionQueueSize -= size;
+ return;
+ }
+ // update transmission queue
+ if ((*it).second.m_rlcTransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcTransmissionQueueSize;
+ (*it).second.m_rlcTransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcTransmissionQueueSize -= size;
+ return;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
+ }
+}
+
+void
+TdMtFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
+{
+
+ std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
+ if (it!=m_ceBsrRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
+ if ((*it).second >= size)
+ {
+ (*it).second -= size;
+ }
+ else
+ {
+ (*it).second = 0;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
+ }
+
+}
+
+void
+TdMtFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
+ FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+ params.m_rnti = rnti;
+ params.m_transmissionMode = txMode;
+ m_cschedSapUser->CschedUeConfigUpdateInd (params);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tdmt-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,215 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef TDMT_FF_MAC_SCHEDULER_H
+#define TDMT_FF_MAC_SCHEDULER_H
+
+#include <ns3/lte-common.h>
+#include <ns3/ff-mac-csched-sap.h>
+#include <ns3/ff-mac-sched-sap.h>
+#include <ns3/ff-mac-scheduler.h>
+#include <vector>
+#include <map>
+#include <set>
+#include <ns3/nstime.h>
+#include <ns3/lte-amc.h>
+
+
+// value for SINR outside the range defined by FF-API, used to indicate that there
+// is no CQI for this element
+#define NO_SINR -5000
+
+namespace ns3 {
+
+
+/**
+ * \ingroup ff-api
+ * \defgroup FF-API TdMtFfMacScheduler
+ */
+/**
+ * \ingroup TdMtFfMacScheduler
+ * \brief Implements the SCHED SAP and CSCHED SAP for a Time Domain Maximum Throughput scheduler
+ *
+ * This class implements the interface defined by the FfMacScheduler abstract class
+ */
+
+class TdMtFfMacScheduler : public FfMacScheduler
+{
+public:
+ /**
+ * \brief Constructor
+ *
+ * Creates the MAC Scheduler interface implementation
+ */
+ TdMtFfMacScheduler ();
+
+ /**
+ * Destructor
+ */
+ virtual ~TdMtFfMacScheduler ();
+
+ // inherited from Object
+ virtual void DoDispose (void);
+ static TypeId GetTypeId (void);
+
+ // inherited from FfMacScheduler
+ virtual void SetFfMacCschedSapUser (FfMacCschedSapUser* s);
+ virtual void SetFfMacSchedSapUser (FfMacSchedSapUser* s);
+ virtual FfMacCschedSapProvider* GetFfMacCschedSapProvider ();
+ virtual FfMacSchedSapProvider* GetFfMacSchedSapProvider ();
+
+ friend class TdMtSchedulerMemberCschedSapProvider;
+ friend class TdMtSchedulerMemberSchedSapProvider;
+
+ void TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode);
+
+private:
+ //
+ // Implementation of the CSCHED API primitives
+ // (See 4.1 for description of the primitives)
+ //
+
+ void DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params);
+
+ void DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params);
+
+ void DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params);
+
+ void DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params);
+
+ void DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params);
+
+ //
+ // Implementation of the SCHED API primitives
+ // (See 4.2 for description of the primitives)
+ //
+
+ void DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params);
+
+ void DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params);
+
+ void DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params);
+
+ void DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params);
+
+ void DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params);
+
+ void DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params);
+
+ void DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params);
+
+ void DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params);
+
+ void DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
+
+ void DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params);
+
+ void DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
+
+
+ int GetRbgSize (int dlbandwidth);
+
+ int LcActivePerFlow (uint16_t rnti);
+
+ double EstimateUlSinr (uint16_t rnti, uint16_t rb);
+
+ void RefreshDlCqiMaps(void);
+ void RefreshUlCqiMaps(void);
+
+ void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
+ void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+ Ptr<LteAmc> m_amc;
+
+ /*
+ * Vectors of UE's LC info
+ */
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> m_rlcBufferReq;
+
+
+ /*
+ * Set of UE's RNTI in downlink
+ */
+ std::set <uint16_t> m_flowStatsDl;
+
+ /*
+ * Set of UE's RNTI in uplink
+ */
+ std::set <uint16_t> m_flowStatsUl;
+
+
+ /*
+ * Map of UE's DL CQI P01 received
+ */
+ std::map <uint16_t,uint8_t> m_p10CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI P01 received
+ */
+ std::map <uint16_t,uint32_t> m_p10CqiTimers;
+
+ /*
+ * Map of UE's DL CQI A30 received
+ */
+ std::map <uint16_t,SbMeasResult_s> m_a30CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI A30 received
+ */
+ std::map <uint16_t,uint32_t> m_a30CqiTimers;
+
+ /*
+ * Map of previous allocated UE per RBG
+ * (used to retrieve info from UL-CQI)
+ */
+ std::map <uint16_t, std::vector <uint16_t> > m_allocationMaps;
+
+ /*
+ * Map of UEs' UL-CQI per RBG
+ */
+ std::map <uint16_t, std::vector <double> > m_ueCqi;
+ /*
+ * Map of UEs' timers on UL-CQI per RBG
+ */
+ std::map <uint16_t, uint32_t> m_ueCqiTimers;
+
+ /*
+ * Map of UE's buffer status reports received
+ */
+ std::map <uint16_t,uint32_t> m_ceBsrRxed;
+
+ // MAC SAPs
+ FfMacCschedSapUser* m_cschedSapUser;
+ FfMacSchedSapUser* m_schedSapUser;
+ FfMacCschedSapProvider* m_cschedSapProvider;
+ FfMacSchedSapProvider* m_schedSapProvider;
+
+
+ // Internal parameters
+ FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig;
+
+ uint16_t m_nextRntiUl; // RNTI of the next user to be served next scheduling in UL
+
+ uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
+
+ std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+};
+
+} // namespace ns3
+
+#endif /* TDMT_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tta-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,1222 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <ns3/log.h>
+#include <ns3/pointer.h>
+
+#include <ns3/simulator.h>
+#include <ns3/lte-amc.h>
+#include "tta-ff-mac-scheduler.h"
+
+NS_LOG_COMPONENT_DEFINE ("TtaFfMacScheduler");
+
+namespace ns3 {
+
+int TtaType0AllocationRbg[4] = {
+ 10, // RGB size 1
+ 26, // RGB size 2
+ 63, // RGB size 3
+ 110 // RGB size 4
+}; // see table 7.1.6.1-1 of 36.213
+
+
+NS_OBJECT_ENSURE_REGISTERED (TtaFfMacScheduler);
+
+
+
+class TtaSchedulerMemberCschedSapProvider : public FfMacCschedSapProvider
+{
+public:
+ TtaSchedulerMemberCschedSapProvider (TtaFfMacScheduler* scheduler);
+
+ // inherited from FfMacCschedSapProvider
+ virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
+ virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
+ virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
+ virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
+ virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
+
+private:
+ TtaSchedulerMemberCschedSapProvider ();
+ TtaFfMacScheduler* m_scheduler;
+};
+
+TtaSchedulerMemberCschedSapProvider::TtaSchedulerMemberCschedSapProvider ()
+{
+}
+
+TtaSchedulerMemberCschedSapProvider::TtaSchedulerMemberCschedSapProvider (TtaFfMacScheduler* scheduler) : m_scheduler (scheduler)
+{
+}
+
+
+void
+TtaSchedulerMemberCschedSapProvider::CschedCellConfigReq (const struct CschedCellConfigReqParameters& params)
+{
+ m_scheduler->DoCschedCellConfigReq (params);
+}
+
+void
+TtaSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
+{
+ m_scheduler->DoCschedUeConfigReq (params);
+}
+
+
+void
+TtaSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
+{
+ m_scheduler->DoCschedLcConfigReq (params);
+}
+
+void
+TtaSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedLcReleaseReq (params);
+}
+
+void
+TtaSchedulerMemberCschedSapProvider::CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params)
+{
+ m_scheduler->DoCschedUeReleaseReq (params);
+}
+
+
+
+
+class TtaSchedulerMemberSchedSapProvider : public FfMacSchedSapProvider
+{
+public:
+ TtaSchedulerMemberSchedSapProvider (TtaFfMacScheduler* scheduler);
+
+ // inherited from FfMacSchedSapProvider
+ virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
+ virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
+ virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
+ virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
+ virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
+ virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
+ virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
+ virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
+ virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
+ virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
+ virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
+
+
+private:
+ TtaSchedulerMemberSchedSapProvider ();
+ TtaFfMacScheduler* m_scheduler;
+};
+
+
+
+TtaSchedulerMemberSchedSapProvider::TtaSchedulerMemberSchedSapProvider ()
+{
+}
+
+
+TtaSchedulerMemberSchedSapProvider::TtaSchedulerMemberSchedSapProvider (TtaFfMacScheduler* scheduler)
+ : m_scheduler (scheduler)
+{
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlRlcBufferReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlPagingBufferReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
+{
+ m_scheduler->DoSchedDlMacBufferReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedDlTriggerReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlRachInfoReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedDlCqiInfoReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
+{
+ m_scheduler->DoSchedUlTriggerReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
+{
+ m_scheduler->DoSchedUlNoiseInterferenceReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlSrInfoReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlMacCtrlInfoReq (params);
+}
+
+void
+TtaSchedulerMemberSchedSapProvider::SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params)
+{
+ m_scheduler->DoSchedUlCqiInfoReq (params);
+}
+
+
+
+
+
+TtaFfMacScheduler::TtaFfMacScheduler ()
+ : m_cschedSapUser (0),
+ m_schedSapUser (0),
+ m_nextRntiUl (0)
+{
+ m_amc = CreateObject <LteAmc> ();
+ m_cschedSapProvider = new TtaSchedulerMemberCschedSapProvider (this);
+ m_schedSapProvider = new TtaSchedulerMemberSchedSapProvider (this);
+}
+
+TtaFfMacScheduler::~TtaFfMacScheduler ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+TtaFfMacScheduler::DoDispose ()
+{
+ NS_LOG_FUNCTION (this);
+ delete m_cschedSapProvider;
+ delete m_schedSapProvider;
+}
+
+TypeId
+TtaFfMacScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TtaFfMacScheduler")
+ .SetParent<FfMacScheduler> ()
+ .AddConstructor<TtaFfMacScheduler> ()
+ .AddAttribute ("CqiTimerThreshold",
+ "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
+ UintegerValue (1000),
+ MakeUintegerAccessor (&TtaFfMacScheduler::m_cqiTimersThreshold),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+
+void
+TtaFfMacScheduler::SetFfMacCschedSapUser (FfMacCschedSapUser* s)
+{
+ m_cschedSapUser = s;
+}
+
+void
+TtaFfMacScheduler::SetFfMacSchedSapUser (FfMacSchedSapUser* s)
+{
+ m_schedSapUser = s;
+}
+
+FfMacCschedSapProvider*
+TtaFfMacScheduler::GetFfMacCschedSapProvider ()
+{
+ return m_cschedSapProvider;
+}
+
+FfMacSchedSapProvider*
+TtaFfMacScheduler::GetFfMacSchedSapProvider ()
+{
+ return m_schedSapProvider;
+}
+
+void
+TtaFfMacScheduler::DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // Read the subset of parameters used
+ m_cschedCellConfig = params;
+ FfMacCschedSapUser::CschedUeConfigCnfParameters cnf;
+ cnf.m_result = SUCCESS;
+ m_cschedSapUser->CschedUeConfigCnf (cnf);
+ return;
+}
+
+void
+TtaFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
+ std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
+ if (it==m_uesTxMode.end ())
+ {
+ m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+ }
+ else
+ {
+ (*it).second = params.m_transmissionMode;
+ }
+ return;
+ return;
+}
+
+void
+TtaFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
+
+ std::set<uint16_t>::iterator it;
+
+ for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
+ {
+ it = m_flowStatsDl.find (params.m_rnti);
+
+ if (it == m_flowStatsDl.end ())
+ {
+ m_flowStatsDl.insert (params.m_rnti);
+ m_flowStatsUl.insert (params.m_rnti);
+ }
+ else
+ {
+ NS_LOG_ERROR ("RNTI already exists");
+ }
+
+ }
+
+ return;
+}
+
+void
+TtaFfMacScheduler::DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TtaFfMacScheduler::DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+
+void
+TtaFfMacScheduler::DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
+ // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
+
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+
+ LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
+
+ it = m_rlcBufferReq.find (flow);
+
+ if (it == m_rlcBufferReq.end ())
+ {
+ m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
+ }
+ else
+ {
+ (*it).second = params;
+ }
+
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+int
+TtaFfMacScheduler::GetRbgSize (int dlbandwidth)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (dlbandwidth < TtaType0AllocationRbg[i])
+ {
+ return (i + 1);
+ }
+ }
+
+ return (-1);
+}
+
+
+int
+TtaFfMacScheduler::LcActivePerFlow (uint16_t rnti)
+{
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ int lcActive = 0;
+ for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
+ {
+ if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
+ || ((*it).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*it).second.m_rlcStatusPduSize > 0) ))
+ {
+ lcActive++;
+ }
+ if ((*it).first.m_rnti > rnti)
+ {
+ break;
+ }
+ }
+ return (lcActive);
+
+}
+
+
+void
+TtaFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+ // API generated by RLC for triggering the scheduling of a DL subframe
+
+
+ // evaluate the relative channel quality indicator for each UE per each RBG
+ // (since we are using allocation type 0 the small unit of allocation is RBG)
+ // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
+
+ RefreshDlCqiMaps ();
+
+ int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+ int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+ std::map <uint16_t, std::vector <uint16_t> > allocationMap;
+ for (int i = 0; i < rbgNum; i++)
+ {
+// NS_LOG_DEBUG (this << " ALLOCATION for RBG " << i << " of " << rbgNum);
+ std::set <uint16_t>::iterator it;
+ std::set <uint16_t>::iterator itMax = m_flowStatsDl.end ();
+ double metricMax = 0.0;
+ for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
+ {
+ std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
+ itCqi = m_a30CqiRxed.find ((*it));
+ std::map <uint16_t,uint8_t>::iterator itWbCqi;
+ itWbCqi = m_p10CqiRxed.find ((*it));
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*it));
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it));
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> sbCqi;
+ if (itCqi == m_a30CqiRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " No DL-CQI for this UE " << (*it));
+ for (uint8_t k = 0; k < nLayer; k++)
+ {
+ sbCqi.push_back (1); // start with lowest value
+ }
+ }
+ else
+ {
+ sbCqi = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
+// NS_LOG_INFO (this << " CQI " << (uint32_t)cqi);
+ }
+
+ uint8_t wbCqi = 0;
+ if (itWbCqi == m_p10CqiRxed.end())
+ {
+ //NS_LOG_DEBUG (this << " No DL-CQI for this UE " << (*it));
+ wbCqi = 1; // start with lowest value
+ }
+ else
+ {
+ wbCqi = (*itWbCqi).second;
+ //NS_LOG_INFO (this << " CQI " << (uint32_t)wbCqi);
+ }
+
+ uint8_t cqi1 = sbCqi.at(0);
+ uint8_t cqi2 = 1;
+ if (sbCqi.size () > 1)
+ {
+ cqi2 = sbCqi.at(1);
+ }
+
+ if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ {
+// NS_LOG_DEBUG (this << " LC active " << LcActivePerFlow (*it));
+ if (LcActivePerFlow (*it) > 0)
+ {
+ // this UE has data to transmit
+ uint8_t sbMcs = 0;
+ uint8_t wbMcs = 0;
+ double achievableWbRate = 0.0;
+ double achievableSbRate = 1.0;
+ for (uint8_t k = 0; k < nLayer; k++)
+ {
+ if (sbCqi.size () > k)
+ {
+ sbMcs = m_amc->GetMcsFromCqi (sbCqi.at (k));
+ }
+ else
+ {
+ // no info on this subband -> worst MCS
+ sbMcs = 0;
+ }
+ achievableSbRate += ((m_amc->GetTbSizeFromMcs (sbMcs, rbgSize) / 8) / 0.001); // = TB size / TTI
+
+ wbMcs = m_amc->GetMcsFromCqi (wbCqi);
+ achievableWbRate += ((m_amc->GetTbSizeFromMcs (wbMcs, rbgSize) / 8) / 0.001); // = TB size / TTI
+ }
+
+ // always select first UE when there are multiple UEs have same SINR
+ double metric = achievableSbRate / achievableWbRate;
+ //NS_LOG_DEBUG (Simulator::Now()<< " " << this << " RNTI " << (*it).first << " SBMCS " << (uint32_t)sbMcs <<" WBMCS " << (uint32_t)wbMcs <<" achievableSbRate " << achievableSbRate << " achievableWbRate " << achievableWbRate << " RCQI " << metric);
+
+ if (metric - metricMax > 1e-3)
+ {
+ metricMax = metric;
+ itMax = it;
+ }
+ }
+ } // end if cqi
+ } // end for m_flowStatsDl
+
+ if (itMax == m_flowStatsDl.end ())
+ {
+ // no UE available for this RB
+ NS_LOG_DEBUG (this << " no UE found");
+ }
+ else
+ {
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ itMap = allocationMap.find ((*itMax));
+ if (itMap == allocationMap.end ())
+ {
+ // insert new element
+ std::vector <uint16_t> tempMap;
+ tempMap.push_back (i);
+ allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax), tempMap));
+ }
+ else
+ {
+ (*itMap).second.push_back (i);
+ }
+// NS_LOG_DEBUG (this << " UE assigned " << (*itMax).first);
+ }
+ } // end for RBGs
+
+ // generate the transmission opportunities by grouping the RBGs of the same RNTI and
+ // creating the correspondent DCIs
+ FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
+ while (itMap != allocationMap.end ())
+ {
+ // create new BuildDataListElement_s for this LC
+ BuildDataListElement_s newEl;
+ newEl.m_rnti = (*itMap).first;
+ // create the DlDciListElement_s
+ DlDciListElement_s newDci;
+ std::vector <struct RlcPduListElement_s> newRlcPduLe;
+ newDci.m_rnti = (*itMap).first;
+
+ uint16_t lcActives = LcActivePerFlow ((*itMap).first);
+// NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
+ uint16_t RgbPerRnti = (*itMap).second.size ();
+ std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
+ itCqi = m_a30CqiRxed.find ((*itMap).first);
+ std::map <uint16_t,uint8_t>::iterator itTxMode;
+ itTxMode = m_uesTxMode.find ((*itMap).first);
+ if (itTxMode == m_uesTxMode.end())
+ {
+ NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
+ }
+ int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+ std::vector <uint8_t> worstCqi (2, 15);
+ if (itCqi != m_a30CqiRxed.end ())
+ {
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ if ((*itCqi).second.m_higherLayerSelected.size () > (*itMap).second.at (k))
+ {
+// NS_LOG_DEBUG (this << " RBG " << (*itMap).second.at (k) << " CQI " << (uint16_t)((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (0)) );
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ if ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.size ()> j)
+ {
+ if (((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j)) < worstCqi.at (j))
+ {
+ worstCqi.at (j) = ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j));
+ }
+ }
+ else
+ {
+ // no CQI for this layer of this suband -> worst one
+ worstCqi.at (j) = 1;
+ }
+ }
+ }
+ else
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
+ }
+ }
+ }
+ }
+ else
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
+ }
+ }
+// NS_LOG_DEBUG (this << " CQI " << (uint16_t)worstCqi);
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ newDci.m_mcs.push_back (m_amc->GetMcsFromCqi (worstCqi.at (j)));
+ int tbSize = (m_amc->GetTbSizeFromMcs (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)
+ newDci.m_tbsSize.push_back (tbSize);
+ NS_LOG_DEBUG (this << " MCS " << m_amc->GetMcsFromCqi (worstCqi.at (j)));
+ }
+
+ newDci.m_resAlloc = 0; // only allocation type 0 at this stage
+ newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
+ uint32_t rbgMask = 0;
+ for (uint16_t k = 0; k < (*itMap).second.size (); k++)
+ {
+ rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
+// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+ }
+ newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
+
+ // create the rlc PDUs -> equally divide resources among actives LCs
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
+ for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
+ {
+ if (((*itBufReq).first.m_rnti == (*itMap).first) &&
+ (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
+ || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
+ {
+ for (uint8_t j = 0; j < nLayer; j++)
+ {
+ RlcPduListElement_s newRlcEl;
+ newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
+ newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
+ NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
+ newRlcPduLe.push_back (newRlcEl);
+ UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
+ }
+ }
+ if ((*itBufReq).first.m_rnti > (*itMap).first)
+ {
+ break;
+ }
+ }
+ newDci.m_ndi.push_back (1); // TBD (new data indicator)
+ newDci.m_rv.push_back (0); // TBD (redundancy version)
+
+ newEl.m_dci = newDci;
+ // ...more parameters -> ingored in this version
+
+ newEl.m_rlcPduList.push_back (newRlcPduLe);
+ ret.m_buildDataList.push_back (newEl);
+
+ itMap++;
+ } // end while allocation
+ ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
+
+ m_schedSapUser->SchedDlConfigInd (ret);
+
+
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
+ {
+ if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
+ {
+ // wideband CQI reporting
+ std::map <uint16_t,uint8_t>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_p10CqiRxed.find (rnti);
+ if (it == m_p10CqiRxed.end ())
+ {
+ // create the new entry
+ 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)
+ // generate correspondent timer
+ m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
+ // update correspondent timer
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_p10CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
+ {
+ // subband CQI reporting high layer configured
+ std::map <uint16_t,SbMeasResult_s>::iterator it;
+ uint16_t rnti = params.m_cqiList.at (i).m_rnti;
+ it = m_a30CqiRxed.find (rnti);
+ if (it == m_a30CqiRxed.end ())
+ {
+ // create the new entry
+ m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
+ m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the CQI value and refresh correspondent timer
+ (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
+ std::map <uint16_t,uint32_t>::iterator itTimers;
+ itTimers = m_a30CqiTimers.find (rnti);
+ (*itTimers).second = m_cqiTimersThreshold;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " CQI type unknown");
+ }
+ }
+
+ return;
+}
+
+
+double
+TtaFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
+{
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ return (NO_SINR);
+
+ }
+ else
+ {
+ // take the average SINR value among the available
+ double sinrSum = 0;
+ int sinrNum = 0;
+ for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
+ {
+ double sinr = (*itCqi).second.at (i);
+ if (sinr != NO_SINR)
+ {
+ sinrSum += sinr;
+ sinrNum++;
+ }
+ }
+ double estimatedSinr = sinrSum / (double)sinrNum;
+ // store the value
+ (*itCqi).second.at (rb) = estimatedSinr;
+ return (estimatedSinr);
+ }
+}
+
+void
+TtaFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
+{
+ NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
+
+ RefreshUlCqiMaps ();
+
+ std::map <uint16_t,uint32_t>::iterator it;
+ int nflows = 0;
+
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ // remove old entries of this UE-LC
+ if ((*it).second > 0)
+ {
+ nflows++;
+ }
+ }
+
+ if (nflows == 0)
+ {
+ return ; // no flows to be scheduled
+ }
+
+
+ // Divide the resource equally among the active users
+ int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+ if (rbPerFlow == 0)
+ {
+ rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
+ }
+ int rbAllocated = 0;
+
+ FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+ std::vector <uint16_t> rbgAllocationMap;
+
+ if (m_nextRntiUl != 0)
+ {
+ for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
+ {
+ if ((*it).first == m_nextRntiUl)
+ {
+ break;
+ }
+ }
+ if (it == m_ceBsrRxed.end ())
+ {
+ NS_LOG_ERROR (this << " no user found");
+ }
+ }
+ else
+ {
+ it = m_ceBsrRxed.begin ();
+ m_nextRntiUl = (*it).first;
+ }
+ do
+ {
+ if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
+ {
+ // limit to physical resources last resource assignment
+ rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
+ }
+
+ UlDciListElement_s uldci;
+ uldci.m_rnti = (*it).first;
+ uldci.m_rbStart = rbAllocated;
+ uldci.m_rbLen = rbPerFlow;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
+ int cqi = 0;
+ if (itCqi == m_ueCqi.end ())
+ {
+ // no cqi info about this UE
+ uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
+// NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
+ }
+ else
+ {
+ // take the lowest CQI value (worst RB)
+ double minSinr = (*itCqi).second.at (uldci.m_rbStart);
+ if (minSinr == NO_SINR)
+ {
+ minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
+ }
+ for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
+ {
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
+ double sinr = (*itCqi).second.at (i);
+ if (sinr == NO_SINR)
+ {
+ sinr = EstimateUlSinr ((*it).first, i);
+ }
+ if ((*itCqi).second.at (i) < minSinr)
+ {
+ minSinr = (*itCqi).second.at (i);
+ }
+ }
+
+ // translate SINR -> cqi: WILD ACK: same as DL
+ double s = log2 ( 1 + (
+ pow (10, minSinr / 10 ) /
+ ( (-log (5.0 * 0.00005 )) / 1.5) ));
+ cqi = m_amc->GetCqiFromSpectralEfficiency (s);
+ if (cqi == 0)
+ {
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
+ }
+ uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
+// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
+
+ }
+
+ rbAllocated += rbPerFlow;
+ // store info on allocation for managing ul-cqi interpretation
+ for (int i = 0; i < rbPerFlow; i++)
+ {
+ rbgAllocationMap.push_back ((*it).first);
+ }
+ uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
+// 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);
+ UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
+ uldci.m_ndi = 1;
+ uldci.m_cceIndex = 0;
+ uldci.m_aggrLevel = 1;
+ uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
+ uldci.m_hopping = false;
+ uldci.m_n2Dmrs = 0;
+ uldci.m_tpc = 0; // no power control
+ uldci.m_cqiRequest = false; // only period CQI at this stage
+ uldci.m_ulIndex = 0; // TDD parameter
+ uldci.m_dai = 1; // TDD parameter
+ uldci.m_freqHopping = 0;
+ uldci.m_pdcchPowerOffset = 0; // not used
+ ret.m_dciList.push_back (uldci);
+
+ it++;
+ if (it == m_ceBsrRxed.end ())
+ {
+ // restart from the first
+ it = m_ceBsrRxed.begin ();
+ }
+ if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
+ {
+ // Stop allocation: no more PRBs
+ m_nextRntiUl = (*it).first;
+ break;
+ }
+ }
+ while ((*it).first != m_nextRntiUl);
+
+ m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+ m_schedSapUser->SchedUlConfigInd (ret);
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+ // TODO: Implementation of the API
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+
+ std::map <uint16_t,uint32_t>::iterator it;
+
+ for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
+ {
+ if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
+ {
+ // buffer status report
+ uint16_t rnti = params.m_macCeList.at (i).m_rnti;
+ it = m_ceBsrRxed.find (rnti);
+ if (it == m_ceBsrRxed.end ())
+ {
+ // create the new entry
+ uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
+ int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
+ m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer)); // only 1 buffer status is working now
+ }
+ else
+ {
+ // update the CQI value
+ (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
+ }
+ }
+ }
+
+ return;
+}
+
+void
+TtaFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
+{
+ NS_LOG_FUNCTION (this);
+// NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
+ // retrieve the allocation for this subframe
+ std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
+ std::map <uint16_t, std::vector <double> >::iterator itCqi;
+ itMap = m_allocationMaps.find (params.m_sfnSf);
+ if (itMap == m_allocationMaps.end ())
+ {
+ NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
+ return;
+ }
+ for (uint32_t i = 0; i < (*itMap).second.size (); i++)
+ {
+ // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
+// NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
+ double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
+ //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
+ itCqi = m_ueCqi.find ((*itMap).second.at (i));
+ if (itCqi == m_ueCqi.end ())
+ {
+ // create a new entry
+ std::vector <double> newCqi;
+ for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
+ {
+ if (i == j)
+ {
+ newCqi.push_back (sinr);
+ }
+ else
+ {
+ // initialize with NO_SINR value.
+ newCqi.push_back (NO_SINR);
+ }
+
+ }
+ m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
+ // generate correspondent timer
+ m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
+ }
+ else
+ {
+ // update the value
+ (*itCqi).second.at (i) = sinr;
+ // update correspondent timer
+ std::map <uint16_t, uint32_t>::iterator itTimers;
+ itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
+ (*itTimers).second = m_cqiTimersThreshold;
+
+ }
+
+ }
+ // remove obsolete info on allocation
+ m_allocationMaps.erase (itMap);
+
+ return;
+}
+
+void
+TtaFfMacScheduler::RefreshDlCqiMaps(void)
+{
+ // refresh DL CQI P01 Map
+ std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
+ while (itP10!=m_p10CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itP10).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
+ NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
+ NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
+ m_p10CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itP10;
+ itP10++;
+ m_p10CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itP10).second--;
+ itP10++;
+ }
+ }
+
+ // refresh DL CQI A30 Map
+ std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
+ while (itA30!=m_a30CqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itA30).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
+ NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
+ NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
+ m_a30CqiRxed.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itA30;
+ itA30++;
+ m_a30CqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itA30).second--;
+ itA30++;
+ }
+ }
+
+ return;
+}
+
+
+void
+TtaFfMacScheduler::RefreshUlCqiMaps(void)
+{
+ // refresh UL CQI Map
+ std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
+ while (itUl!=m_ueCqiTimers.end ())
+ {
+// NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
+ if ((*itUl).second == 0)
+ {
+ // delete correspondent entries
+ std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
+ NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
+ NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
+ (*itMap).second.clear ();
+ m_ueCqi.erase (itMap);
+ std::map <uint16_t,uint32_t>::iterator temp = itUl;
+ itUl++;
+ m_ueCqiTimers.erase (temp);
+ }
+ else
+ {
+ (*itUl).second--;
+ itUl++;
+ }
+ }
+
+ return;
+}
+
+void
+TtaFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
+{
+ std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
+ LteFlowId_t flow (rnti, lcid);
+ it = m_rlcBufferReq.find (flow);
+ if (it!=m_rlcBufferReq.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
+ // Update queues: RLC tx order Status, ReTx, Tx
+ // Update status queue
+ if ((*it).second.m_rlcStatusPduSize <= size)
+ {
+ size -= (*it).second.m_rlcStatusPduSize;
+ (*it).second.m_rlcStatusPduSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcStatusPduSize -= size;
+ return;
+ }
+ // update retransmission queue
+ if ((*it).second.m_rlcRetransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcRetransmissionQueueSize;
+ (*it).second.m_rlcRetransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcRetransmissionQueueSize -= size;
+ return;
+ }
+ // update transmission queue
+ if ((*it).second.m_rlcTransmissionQueueSize <= size)
+ {
+ size -= (*it).second.m_rlcTransmissionQueueSize;
+ (*it).second.m_rlcTransmissionQueueSize = 0;
+ }
+ else
+ {
+ (*it).second.m_rlcTransmissionQueueSize -= size;
+ return;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
+ }
+}
+
+void
+TtaFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
+{
+
+ std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
+ if (it!=m_ceBsrRxed.end ())
+ {
+// NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
+ if ((*it).second >= size)
+ {
+ (*it).second -= size;
+ }
+ else
+ {
+ (*it).second = 0;
+ }
+ }
+ else
+ {
+ NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
+ }
+
+}
+
+void
+TtaFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
+{
+ NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
+ FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+ params.m_rnti = rnti;
+ params.m_transmissionMode = txMode;
+ m_cschedSapUser->CschedUeConfigUpdateInd (params);
+}
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/tta-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,215 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef TTA_FF_MAC_SCHEDULER_H
+#define TTA_FF_MAC_SCHEDULER_H
+
+#include <ns3/lte-common.h>
+#include <ns3/ff-mac-csched-sap.h>
+#include <ns3/ff-mac-sched-sap.h>
+#include <ns3/ff-mac-scheduler.h>
+#include <vector>
+#include <map>
+#include <set>
+#include <ns3/nstime.h>
+#include <ns3/lte-amc.h>
+
+
+// value for SINR outside the range defined by FF-API, used to indicate that there
+// is no CQI for this element
+#define NO_SINR -5000
+
+namespace ns3 {
+
+
+/**
+ * \ingroup ff-api
+ * \defgroup FF-API TtaFfMacScheduler
+ */
+/**
+ * \ingroup TtaFfMacScheduler
+ * \brief Implements the SCHED SAP and CSCHED SAP for a Throughput to Average scheduler
+ *
+ * This class implements the interface defined by the FfMacScheduler abstract class
+ */
+
+class TtaFfMacScheduler : public FfMacScheduler
+{
+public:
+ /**
+ * \brief Constructor
+ *
+ * Creates the MAC Scheduler interface implementation
+ */
+ TtaFfMacScheduler ();
+
+ /**
+ * Destructor
+ */
+ virtual ~TtaFfMacScheduler ();
+
+ // inherited from Object
+ virtual void DoDispose (void);
+ static TypeId GetTypeId (void);
+
+ // inherited from FfMacScheduler
+ virtual void SetFfMacCschedSapUser (FfMacCschedSapUser* s);
+ virtual void SetFfMacSchedSapUser (FfMacSchedSapUser* s);
+ virtual FfMacCschedSapProvider* GetFfMacCschedSapProvider ();
+ virtual FfMacSchedSapProvider* GetFfMacSchedSapProvider ();
+
+ friend class TtaSchedulerMemberCschedSapProvider;
+ friend class TtaSchedulerMemberSchedSapProvider;
+
+ void TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode);
+
+private:
+ //
+ // Implementation of the CSCHED API primitives
+ // (See 4.1 for description of the primitives)
+ //
+
+ void DoCschedCellConfigReq (const struct FfMacCschedSapProvider::CschedCellConfigReqParameters& params);
+
+ void DoCschedUeConfigReq (const struct FfMacCschedSapProvider::CschedUeConfigReqParameters& params);
+
+ void DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params);
+
+ void DoCschedLcReleaseReq (const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters& params);
+
+ void DoCschedUeReleaseReq (const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters& params);
+
+ //
+ // Implementation of the SCHED API primitives
+ // (See 4.2 for description of the primitives)
+ //
+
+ void DoSchedDlRlcBufferReq (const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters& params);
+
+ void DoSchedDlPagingBufferReq (const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters& params);
+
+ void DoSchedDlMacBufferReq (const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters& params);
+
+ void DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params);
+
+ void DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params);
+
+ void DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params);
+
+ void DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params);
+
+ void DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params);
+
+ void DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
+
+ void DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params);
+
+ void DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
+
+
+ int GetRbgSize (int dlbandwidth);
+
+ int LcActivePerFlow (uint16_t rnti);
+
+ double EstimateUlSinr (uint16_t rnti, uint16_t rb);
+
+ void RefreshDlCqiMaps(void);
+ void RefreshUlCqiMaps(void);
+
+ void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
+ void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+ Ptr<LteAmc> m_amc;
+
+ /*
+ * Vectors of UE's LC info
+ */
+ std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> m_rlcBufferReq;
+
+
+ /*
+ * Set of UE's RNTI in downlink
+ */
+ std::set <uint16_t> m_flowStatsDl;
+
+ /*
+ * Set of UE's RNTI in uplink
+ */
+ std::set <uint16_t> m_flowStatsUl;
+
+
+ /*
+ * Map of UE's DL CQI P01 received
+ */
+ std::map <uint16_t,uint8_t> m_p10CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI P01 received
+ */
+ std::map <uint16_t,uint32_t> m_p10CqiTimers;
+
+ /*
+ * Map of UE's DL CQI A30 received
+ */
+ std::map <uint16_t,SbMeasResult_s> m_a30CqiRxed;
+ /*
+ * Map of UE's timers on DL CQI A30 received
+ */
+ std::map <uint16_t,uint32_t> m_a30CqiTimers;
+
+ /*
+ * Map of previous allocated UE per RBG
+ * (used to retrieve info from UL-CQI)
+ */
+ std::map <uint16_t, std::vector <uint16_t> > m_allocationMaps;
+
+ /*
+ * Map of UEs' UL-CQI per RBG
+ */
+ std::map <uint16_t, std::vector <double> > m_ueCqi;
+ /*
+ * Map of UEs' timers on UL-CQI per RBG
+ */
+ std::map <uint16_t, uint32_t> m_ueCqiTimers;
+
+ /*
+ * Map of UE's buffer status reports received
+ */
+ std::map <uint16_t,uint32_t> m_ceBsrRxed;
+
+ // MAC SAPs
+ FfMacCschedSapUser* m_cschedSapUser;
+ FfMacSchedSapUser* m_schedSapUser;
+ FfMacCschedSapProvider* m_cschedSapProvider;
+ FfMacSchedSapProvider* m_schedSapProvider;
+
+
+ // Internal parameters
+ FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig;
+
+ uint16_t m_nextRntiUl; // RNTI of the next user to be served next scheduling in UL
+
+ uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
+
+ std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+};
+
+} // namespace ns3
+
+#endif /* TTA_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,529 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <ns3/object.h>
+#include <ns3/spectrum-interference.h>
+#include <ns3/spectrum-error-model.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+#include <ns3/simulator.h>
+#include <ns3/packet.h>
+#include <ns3/ptr.h>
+#include "ns3/radio-bearer-stats-calculator.h"
+#include <ns3/constant-position-mobility-model.h>
+#include <ns3/eps-bearer.h>
+#include <ns3/node-container.h>
+#include <ns3/mobility-helper.h>
+#include <ns3/net-device-container.h>
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/lte-enb-net-device.h>
+#include <ns3/lte-ue-rrc.h>
+#include <ns3/lte-helper.h>
+#include "ns3/string.h"
+#include "ns3/double.h"
+#include <ns3/lte-enb-phy.h>
+#include <ns3/lte-ue-phy.h>
+#include <ns3/boolean.h>
+#include <ns3/enum.h>
+
+#include "lte-test-fdbet-ff-mac-scheduler.h"
+
+NS_LOG_COMPONENT_DEFINE ("LenaTestFdBetFfMacCheduler");
+
+namespace ns3 {
+
+LenaTestFdBetFfMacSchedulerSuite::LenaTestFdBetFfMacSchedulerSuite ()
+ : TestSuite ("lte-fdbet-ff-mac-scheduler", SYSTEM)
+{
+ NS_LOG_INFO ("creating LenaTestFdBetFfMacSchedulerSuite");
+
+ //Test Case 1: AMC works in FDBET
+
+ // DOWNLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 26 -> 2196 -> 2196000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ // UPLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 26 -> 2292 -> 2292000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (1,0,0,2196000,2292000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (3,0,0,749000,749000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (6,0,0,373000,373000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (12,0,0,185000,185000));
+
+ // DOWNLINK - DISTANCE 3000 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 20 -> 469 -> 469000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 20 -> 233 -> 233000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 20 -> 113 -> 113000 bytes/sec
+ // UPLINK - DISTANCE 3000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 18 -> 1239 -> 1239000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 18 -> 389 -> 389000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 18 -> 193 -> 193000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 18 -> 97 -> 97000 bytes/sec
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (1,0,3000,1383000,1239000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (3,0,3000,469000,389000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (6,0,3000,233500,193000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (12,0,3000,113000,97000));
+
+ // DOWNLINK - DISTANCE 6000 -> MCS 16 -> Itbs 15 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 15 -> 903 -> 903000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 15 -> 309 -> 309000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 15 -> 153 -> 153000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 15 -> 75 -> 75000 bytes/sec
+ // UPLINK - DISTANCE 6000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 11 -> 621 -> 621000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (1,0,6000,903000,621000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (3,0,6000,309000,201000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (6,0,6000,153000,97000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (12,0,6000,75000,47000));
+
+ // DOWNLINK - DISTANCE 9000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 11 -> 597 -> 597000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ // UPLINK - DISTANCE 9000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 8 -> 437 -> 437000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 8 -> 137 -> 137000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 8 -> 67 -> 67000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 8 -> 32 -> 32000 bytes/sec
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (1,0,9000,597000,437000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (3,0,9000,201000,137000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (6,0,9000,97000,67000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (12,0,9000,47000,32000));
+
+ // DOWNLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 6 -> 309 -> 309000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 101 -> 101000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 49 -> 49000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 22 -> 22000 bytes/sec
+ // UPLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 6 -> 233 -> 233000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 69 -> 69000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 32 -> 32000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 15 -> 15000 bytes/sec
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (1,0,15000,309000,233000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (3,0,15000,101000,69000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (6,0,15000,49000,32000));
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase1 (12,0,15000,22000,15000));
+
+ // Test Case 2: fairness check
+
+ std::vector<uint16_t> dist;
+ dist.push_back (0); // User 0 distance --> MCS 28
+ dist.push_back (3000); // User 1 distance --> MCS 24
+ dist.push_back (6000); // User 2 distance --> MCS 16
+ dist.push_back (9000); // User 3 distance --> MCS 12
+ std::vector<uint32_t> estAchievableRateDl;
+ estAchievableRateDl.push_back (2196000);
+ estAchievableRateDl.push_back (1383000);
+ estAchievableRateDl.push_back (903000);
+ estAchievableRateDl.push_back (597000);
+ std::vector<uint32_t> estThrFdBetUl;
+ estThrFdBetUl.push_back (549000); // User 0 estimated TTI throughput from FDBET
+ estThrFdBetUl.push_back (293000); // User 1 estimated TTI throughput from FDBET
+ estThrFdBetUl.push_back (149000); // User 2 estimated TTI throughput from FDBET
+ estThrFdBetUl.push_back (101000); // User 3 estimated TTI throughput from FDBET
+ AddTestCase (new LenaFdBetFfMacSchedulerTestCase2 (dist, estAchievableRateDl, estThrFdBetUl));
+
+
+}
+
+static LenaTestFdBetFfMacSchedulerSuite lenaTestFdBetFfMacSchedulerSuite;
+
+
+// --------------- T E S T - C A S E # 1 ------------------------------
+
+
+std::string
+LenaFdBetFfMacSchedulerTestCase1::BuildNameString (uint16_t nUser, uint16_t dist)
+{
+ std::ostringstream oss;
+ oss << nUser << " UEs, distance " << dist << " m";
+ return oss.str ();
+}
+
+LenaFdBetFfMacSchedulerTestCase1::LenaFdBetFfMacSchedulerTestCase1 (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl)
+ : TestCase (BuildNameString (nUser, dist)),
+ m_nUser (nUser),
+ m_nLc (nLc),
+ m_dist (dist),
+ m_thrRefDl (thrRefDl),
+ m_thrRefUl (thrRefUl)
+{
+}
+
+LenaFdBetFfMacSchedulerTestCase1::~LenaFdBetFfMacSchedulerTestCase1 ()
+{
+}
+
+void
+LenaFdBetFfMacSchedulerTestCase1::DoRun (void)
+{
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+ LogComponentDisableAll (LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbFdBetc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeFdBetc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+//
+// LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("FdBetFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestFdBetFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+// LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::FdBetFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist, 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+
+ double simulationTime = 1.0;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ /**
+ * Check that the downlink assignation is done in a "FD blind equal throughput" manner
+ */
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> dlDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_thrRefDl);
+ }
+ /**
+ * Check that the assignation is done in a "FD blind equal throughput" manner among users
+ * with equal SINRs: the bandwidth should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, m_thrRefDl, m_thrRefDl * tolerance, " Unfair Throughput!");
+ }
+
+ /**
+ * Check that the uplink assignation is done in a "FD blind equal throughput" manner
+ */
+ NS_LOG_INFO ("UL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << m_thrRefUl);
+ }
+ /**
+ * Check that the assignation is done in a "FD blind equal throughput" manner among users
+ * with equal SINRs: the bandwidht should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, m_thrRefUl, m_thrRefUl * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
+
+
+// --------------- T E S T - C A S E # 2 ------------------------------
+
+
+std::string
+LenaFdBetFfMacSchedulerTestCase2::BuildNameString (uint16_t nUser, std::vector<uint16_t> dist)
+{
+ std::ostringstream oss;
+ oss << "distances (m) = [ " ;
+ for (std::vector<uint16_t>::iterator it = dist.begin (); it != dist.end (); ++it)
+ {
+ oss << *it << " ";
+ }
+ oss << "]";
+ return oss.str ();
+}
+
+
+LenaFdBetFfMacSchedulerTestCase2::LenaFdBetFfMacSchedulerTestCase2 (std::vector<uint16_t> dist, std::vector<uint32_t> estAchievableRateDl, std::vector<uint32_t> estThrFdBetUl)
+ : TestCase (BuildNameString (dist.size (), dist)),
+ m_nUser (dist.size ()),
+ m_dist (dist),
+ m_achievableRateDl (estAchievableRateDl),
+ m_estThrFdBetUl (estThrFdBetUl)
+{
+}
+
+LenaFdBetFfMacSchedulerTestCase2::~LenaFdBetFfMacSchedulerTestCase2 ()
+{
+}
+
+void
+LenaFdBetFfMacSchedulerTestCase2::DoRun (void)
+{
+ // LogComponentEnable ("LteEnbFdBetc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeFdBetc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("FdBetFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestFdBetFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::FdBetFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist.at (i), 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+
+ double simulationTime = 1;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s)");
+ std::vector <uint64_t> dlDataRxed;
+ double totalData = 0;
+ double estTotalThr = 0;
+ double estUeThr = 0;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ totalData += (double)dlDataRxed.at (i);
+ estTotalThr += 1 / m_achievableRateDl.at(i);
+ //NS_LOG_INFO ("\tUser " << i << " dist " << m_dist.at (i) << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_nUser);
+ }
+
+ estTotalThr = m_nUser * (1 / estTotalThr);
+ estUeThr = estTotalThr / m_nUser;
+ /**
+ * Check that the assignation is done in a "FD blind equal throughput" manner among users
+ * with different SINRs: the bandwidth should be distributed equally in long term
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ double thrRatio = (double) 1 / m_nUser;
+ double estThrRatio = (double)dlDataRxed.at (i) / totalData;
+ NS_LOG_INFO ("\tUser " << i << " thrRatio " << thrRatio << " estThrRatio " << estThrRatio);
+ NS_TEST_ASSERT_MSG_EQ_TOL (estThrRatio, thrRatio, tolerance, " Unfair Throughput!");
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at(i) / simulationTime, estUeThr, estUeThr*tolerance, " Unfair Throughput!");
+
+ }
+
+ /**
+ * Check that the assignation in uplink is done in a round robin manner.
+ */
+
+ NS_LOG_INFO ("UL - Test with " << m_nUser);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " dist " << m_dist.at (i) << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << (double)m_estThrFdBetUl.at (i));
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, (double)m_estThrFdBetUl.at (i), (double)m_estThrFdBetUl.at (i) * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
+
+} // namespace ns3
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-fdbet-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef LENA_TEST_TDBET_FF_MAC_SCHEDULER_H
+#define LENA_TEST_TDBET_FF_MAC_SCHEDULER_H
+
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+
+
+namespace ns3 {
+
+
+/**
+* This system test program creates different test cases with a single eNB and
+* several UEs, all having the same Radio Bearer specification. In each test
+* case, the UEs see the same SINR from the eNB; different test cases are
+* implemented obtained by using different SINR values and different numbers of
+* UEs. The test consists on checking that the obtained throughput performance
+* is equal among users is consistent with the definition of proportional
+* fair scheduling
+*/
+class LenaFdBetFfMacSchedulerTestCase1 : public TestCase
+{
+public:
+ LenaFdBetFfMacSchedulerTestCase1 (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl);
+ virtual ~LenaFdBetFfMacSchedulerTestCase1 ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, uint16_t dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ uint16_t m_nLc;
+ uint16_t m_dist;
+ double m_thrRefDl;
+ double m_thrRefUl;
+};
+
+
+class LenaFdBetFfMacSchedulerTestCase2 : public TestCase
+{
+public:
+ LenaFdBetFfMacSchedulerTestCase2 (std::vector<uint16_t> dist, std::vector<uint32_t> m_achievableRateDl, std::vector<uint32_t> estThrFdBetUl);
+ virtual ~LenaFdBetFfMacSchedulerTestCase2 ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, std::vector<uint16_t> dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ std::vector<uint16_t> m_dist;
+ std::vector<uint32_t> m_achievableRateDl;
+ std::vector<uint32_t> m_estThrFdBetUl;
+};
+
+
+
+
+class LenaTestFdBetFfMacSchedulerSuite : public TestSuite
+{
+public:
+ LenaTestFdBetFfMacSchedulerSuite ();
+};
+
+
+
+
+} // namespace ns3
+
+
+#endif /* LENA_TEST_TDBET_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-fdmt-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <ns3/object.h>
+#include <ns3/spectrum-interference.h>
+#include <ns3/spectrum-error-model.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+#include <ns3/simulator.h>
+#include <ns3/packet.h>
+#include <ns3/ptr.h>
+#include "ns3/radio-bearer-stats-calculator.h"
+#include <ns3/constant-position-mobility-model.h>
+#include "ns3/lte-test-fdmt-ff-mac-scheduler.h"
+#include <ns3/eps-bearer.h>
+#include <ns3/node-container.h>
+#include <ns3/mobility-helper.h>
+#include <ns3/net-device-container.h>
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/lte-enb-net-device.h>
+#include <ns3/lte-ue-rrc.h>
+#include <ns3/lte-helper.h>
+#include "ns3/string.h"
+#include "ns3/double.h"
+#include <ns3/lte-enb-phy.h>
+#include <ns3/lte-ue-phy.h>
+#include <ns3/boolean.h>
+#include <ns3/enum.h>
+
+
+NS_LOG_COMPONENT_DEFINE ("LenaTestFdMtFfMacCheduler");
+
+using namespace ns3;
+
+LenaTestFdMtFfMacSchedulerSuite::LenaTestFdMtFfMacSchedulerSuite ()
+ : TestSuite ("lte-fdmt-ff-mac-scheduler", SYSTEM)
+{
+ NS_LOG_INFO ("creating LenaTestFdMtFfMacSchedulerSuite");
+
+ //Test Case : AMC works in FDMT
+
+ // DOWNLINK - DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 26 -> 2196 -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 2196000 among 3 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 2196000 among 6 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 2196000 among 12 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 2196000 among 15 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 26 -> 2292 -> 2292000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 26 -> 89 -> 89000 bytes/sec
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (1,0,0,2196000,2292000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (3,0,0,2196000,749000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (6,0,0,2196000,373000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (12,0,0,2196000,185000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (15,0,0,2196000,89000));
+
+ // DOWNLINK - DISTANCE 3000 -> MCS 24 -> Itbs 30 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 1383000 among 3 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 1383000 among 6 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 1383000 among 12 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 1383000 among 15 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 3000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 18 -> 1239 -> 1239000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 18 -> 389 -> 389000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 18 -> 193 -> 193000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 18 -> 97 -> 97000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 18 -> 47 -> 47000 bytes/sec
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (1,0,3000,1383000,1239000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (3,0,3000,1383000,389000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (6,0,3000,1383000,193000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (12,0,3000,1383000,97000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (15,0,3000,1383000,47000));
+
+ // DOWNLINK - DISTANCE 6000 -> MCS 16 -> Itbs 15 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 15 -> 903 -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 903000 among 3 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 903000 among 6 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 903000 among 12 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 903000 among 15 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 6000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 11 -> 621 -> 621000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 11 -> 22 -> 22000 bytes/sec
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (1,0,6000,903000,621000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (3,0,6000,903000,201000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (6,0,6000,903000,97000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (12,0,6000,903000,47000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (15,0,6000,903000,22000));
+
+ // DOWNLINK - DISTANCE 9000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 11 -> 597 -> 597000 bytes/sec
+ // 3 users -> 597000 among 3 users -> 199000 bytes/sec
+ // 6 users -> 597000 among 6 users -> 99500 bytes/sec
+ // 12 users -> 597000 among 12 users -> 49750 bytes/sec
+ // 15 users -> 597000 among 15 users -> 39800 bytes/sec
+ // UPLINK - DISTANCE 9000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 8 -> 437 -> 437000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 8 -> 137 -> 137000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 8 -> 67 -> 67000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 8 -> 32 -> 32000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 8 -> 15 -> 15000 bytes/sec
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (1,0,9000,597000,437000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (3,0,9000,597000,137000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (6,0,9000,597000,67000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (12,0,9000,597000,32000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (15,0,9000,597000,15000));
+
+ // DONWLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 6 -> 309 -> 309000 bytes/sec
+ // 3 users -> 309000 among 3 users -> 103000 bytes/sec
+ // 6 users -> 309000 among 6 users -> 51500 bytes/sec
+ // 12 users -> 309000 among 12 users -> 25750 bytes/sec
+ // 15 users -> 309000 among 15 users -> 20600 bytes/sec
+ // UPLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 6 -> 233 -> 233000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 69 -> 69000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 32 -> 32000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 15 -> 15000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 6 -> 7 -> 7000 bytes/sec
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (1,0,15000,309000,233000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (3,0,15000,309000,69000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (6,0,15000,309000,32000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (12,0,15000,309000,15000));
+ AddTestCase (new LenaFdMtFfMacSchedulerTestCase (15,0,15000,309000,7000));
+
+
+}
+
+static LenaTestFdMtFfMacSchedulerSuite lenaTestFdMtFfMacSchedulerSuite;
+
+
+// --------------- T E S T - C A S E ------------------------------
+
+
+std::string
+LenaFdMtFfMacSchedulerTestCase::BuildNameString (uint16_t nUser, uint16_t dist)
+{
+ std::ostringstream oss;
+ oss << nUser << " UEs, distance " << dist << " m";
+ return oss.str ();
+}
+
+LenaFdMtFfMacSchedulerTestCase::LenaFdMtFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl)
+ : TestCase (BuildNameString (nUser, dist)),
+ m_nUser (nUser),
+ m_nLc (nLc),
+ m_dist (dist),
+ m_thrRefDl (thrRefDl),
+ m_thrRefUl (thrRefUl)
+{
+}
+
+LenaFdMtFfMacSchedulerTestCase::~LenaFdMtFfMacSchedulerTestCase ()
+{
+}
+
+void
+LenaFdMtFfMacSchedulerTestCase::DoRun (void)
+{
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+ LogComponentDisableAll (LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+//
+// LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("FdMtFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestFdMtFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+// LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::FdMtFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist, 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+ lteHelper->EnableMacTraces ();
+
+
+ double simulationTime = 1.0;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ /**
+ * Check that the downlink assignation is done in a "maximum throughput" manner
+ */
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> dlDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_thrRefDl);
+ }
+ /**
+ * Check that the assignation is done in a "maximum throughput" manner among users
+ * with equal SINRs: all bandwidth should be allocated to the first UE in script
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ if (i == 0)
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, m_thrRefDl, m_thrRefDl * tolerance, " Invalid Throughput!");
+ else
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, 0, tolerance, " Invalid Throughput!");
+ }
+
+ /**
+ * Check that the uplink assignation is done in a "maximum throughput" manner
+ */
+ NS_LOG_INFO ("UL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << m_thrRefUl);
+ }
+ /**
+ * Check that the assignation is done in a "maximum throughput" manner among users
+ * with equal SINRs: the bandwidht should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ *
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, m_thrRefUl, m_thrRefUl * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-fdmt-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef LENA_TEST_FDMT_FF_MAC_SCHEDULER_H
+#define LENA_TEST_FDMT_FF_MAC_SCHEDULER_H
+
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+
+
+using namespace ns3;
+
+
+/**
+* This system test program creates different test cases with a single eNB and
+* several UEs, all having the same Radio Bearer specification. In each test
+* case, the UEs see the same SINR from the eNB; different test cases are
+* implemented obtained by using different SINR values and different numbers of
+* UEs. The test consists on checking that the obtained throughput performance
+* is consistent with the definition of maximum throughput
+* scheduling
+*/
+class LenaFdMtFfMacSchedulerTestCase : public TestCase
+{
+public:
+ LenaFdMtFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl);
+ virtual ~LenaFdMtFfMacSchedulerTestCase ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, uint16_t dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ uint16_t m_nLc;
+ uint16_t m_dist;
+ double m_thrRefDl;
+ double m_thrRefUl;
+};
+
+class LenaTestFdMtFfMacSchedulerSuite : public TestSuite
+{
+public:
+ LenaTestFdMtFfMacSchedulerSuite ();
+};
+
+
+
+
+#endif /* LENA_TEST_FDMT_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <ns3/object.h>
+#include <ns3/spectrum-interference.h>
+#include <ns3/spectrum-error-model.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+#include <ns3/simulator.h>
+#include <ns3/packet.h>
+#include <ns3/ptr.h>
+#include "ns3/radio-bearer-stats-calculator.h"
+#include <ns3/constant-position-mobility-model.h>
+#include <ns3/eps-bearer.h>
+#include <ns3/node-container.h>
+#include <ns3/mobility-helper.h>
+#include <ns3/net-device-container.h>
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/lte-enb-net-device.h>
+#include <ns3/lte-ue-rrc.h>
+#include <ns3/lte-helper.h>
+#include "ns3/string.h"
+#include "ns3/double.h"
+#include <ns3/lte-enb-phy.h>
+#include <ns3/lte-ue-phy.h>
+#include <ns3/boolean.h>
+#include <ns3/enum.h>
+
+#include "lte-test-tdbet-ff-mac-scheduler.h"
+
+NS_LOG_COMPONENT_DEFINE ("LenaTestTdBetFfMacCheduler");
+
+namespace ns3 {
+
+LenaTestTdBetFfMacSchedulerSuite::LenaTestTdBetFfMacSchedulerSuite ()
+ : TestSuite ("lte-tdbet-ff-mac-scheduler", SYSTEM)
+{
+ NS_LOG_INFO ("creating LenaTestTdBetFfMacSchedulerSuite");
+
+ //Test Case 1: AMC works in TDBET
+
+ // DOWNLINK - DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 26 -> 2196 -> 2196000 bytes/sec
+ // 3 users -> 2196000 among 3 users -> 732000 bytes/sec
+ // 6 users -> 2196000 among 6 users -> 366000 bytes/sec
+ // 12 users -> 2196000 among 12 users -> 183000 bytes/sec
+ // 15 users -> 2196000 among 15 users -> 146400 bytes/sec
+ // UPLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 26 -> 2292 -> 2292000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 26 -> 89 -> 89000 bytes/sec
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (1,0,0,2196000,2292000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (3,0,0,732000,749000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (6,0,0,366000,373000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (12,0,0,183000,185000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (15,0,0,146400,89000));
+
+ // DOWNLINK - DISTANCE 3000 -> MCS 24 -> Itbs 30 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec
+ // 3 users -> 1383000 among 3 users -> 461000 bytes/sec
+ // 6 users -> 1383000 among 6 users -> 230500 bytes/sec
+ // 12 users -> 1383000 among 12 users -> 115250 bytes/sec
+ // 15 users -> 1383000 among 15 users -> 92200 bytes/sec
+ // UPLINK - DISTANCE 3000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 18 -> 1239 -> 1239000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 18 -> 389 -> 389000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 18 -> 193 -> 193000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 18 -> 97 -> 97000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 18 -> 47 -> 47000 bytes/sec
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (1,0,3000,1383000,1239000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (3,0,3000,461000,389000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (6,0,3000,230500,193000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (12,0,3000,115250,97000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (15,0,3000,92200,47000));
+
+ // DOWNLINK - DISTANCE 6000 -> MCS 16 -> Itbs 15 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 15 -> 903 -> 903000 bytes/sec
+ // 3 users -> 903000 among 3 users -> 301000 bytes/sec
+ // 6 users -> 903000 among 6 users -> 150500 bytes/sec
+ // 12 users -> 903000 among 12 users -> 75250 bytes/sec
+ // 15 users -> 903000 among 15 users -> 60200 bytes/sec
+ // UPLINK - DISTANCE 6000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 11 -> 621 -> 621000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 11 -> 22 -> 22000 bytes/sec
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (1,0,6000,903000,621000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (3,0,6000,301000,201000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (6,0,6000,150500,97000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (12,0,6000,75250,47000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (15,0,6000,60200,22000));
+
+ // DOWNLINK - DISTANCE 9000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 11 -> 597 -> 597000 bytes/sec
+ // 3 users -> 597000 among 3 users -> 199000 bytes/sec
+ // 6 users -> 597000 among 6 users -> 99500 bytes/sec
+ // 12 users -> 597000 among 12 users -> 49750 bytes/sec
+ // 15 users -> 597000 among 15 users -> 39800 bytes/sec
+ // UPLINK - DISTANCE 9000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 8 -> 437 -> 437000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 8 -> 137 -> 137000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 8 -> 67 -> 67000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 8 -> 32 -> 32000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 8 -> 15 -> 15000 bytes/sec
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (1,0,9000,597000,437000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (3,0,9000,199000,137000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (6,0,9000,99500,67000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (12,0,9000,49750,32000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (15,0,9000,39800,15000));
+
+ // DONWLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 6 -> 309 -> 309000 bytes/sec
+ // 3 users -> 309000 among 3 users -> 103000 bytes/sec
+ // 6 users -> 309000 among 6 users -> 51500 bytes/sec
+ // 12 users -> 309000 among 12 users -> 25750 bytes/sec
+ // 15 users -> 309000 among 15 users -> 20600 bytes/sec
+ // UPLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 6 -> 233 -> 233000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 69 -> 69000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 32 -> 32000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 15 -> 15000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 6 -> 7 -> 7000 bytes/sec
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (1,0,15000,309000,233000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (3,0,15000,103000,69000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (6,0,15000,51500,32000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (12,0,15000,25750,15000));
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase1 (15,0,15000,20600,7000));
+
+ // Test Case 2: fairness check
+
+ std::vector<uint16_t> dist;
+ dist.push_back (0); // User 0 distance --> MCS 28
+ dist.push_back (3000); // User 1 distance --> MCS 24
+ dist.push_back (6000); // User 2 distance --> MCS 16
+ dist.push_back (9000); // User 3 distance --> MCS 12
+ dist.push_back (15000); // User 4 distance --> MCS 6
+ std::vector<uint32_t> estAchievableRateDl;
+ estAchievableRateDl.push_back (2196000);
+ estAchievableRateDl.push_back (1383000);
+ estAchievableRateDl.push_back (903000);
+ estAchievableRateDl.push_back (597000);
+ estAchievableRateDl.push_back (309000);
+ std::vector<uint32_t> estThrTdBetUl;
+ estThrTdBetUl.push_back (469000); // User 0 estimated TTI throughput from TDBET
+ estThrTdBetUl.push_back (249000); // User 1 estimated TTI throughput from TDBET
+ estThrTdBetUl.push_back (125000); // User 2 estimated TTI throughput from TDBET
+ estThrTdBetUl.push_back (85000); // User 3 estimated TTI throughput from TDBET
+ estThrTdBetUl.push_back (41000); // User 4 estimated TTI throughput from TDBET
+ AddTestCase (new LenaTdBetFfMacSchedulerTestCase2 (dist, estAchievableRateDl, estThrTdBetUl));
+
+
+}
+
+static LenaTestTdBetFfMacSchedulerSuite lenaTestTdBetFfMacSchedulerSuite;
+
+
+// --------------- T E S T - C A S E # 1 ------------------------------
+
+
+std::string
+LenaTdBetFfMacSchedulerTestCase1::BuildNameString (uint16_t nUser, uint16_t dist)
+{
+ std::ostringstream oss;
+ oss << nUser << " UEs, distance " << dist << " m";
+ return oss.str ();
+}
+
+LenaTdBetFfMacSchedulerTestCase1::LenaTdBetFfMacSchedulerTestCase1 (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl)
+ : TestCase (BuildNameString (nUser, dist)),
+ m_nUser (nUser),
+ m_nLc (nLc),
+ m_dist (dist),
+ m_thrRefDl (thrRefDl),
+ m_thrRefUl (thrRefUl)
+{
+}
+
+LenaTdBetFfMacSchedulerTestCase1::~LenaTdBetFfMacSchedulerTestCase1 ()
+{
+}
+
+void
+LenaTdBetFfMacSchedulerTestCase1::DoRun (void)
+{
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+ LogComponentDisableAll (LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+//
+// LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("TdBetFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestTdBetFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+// LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::TdBetFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist, 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+
+ double simulationTime = 1.0;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ /**
+ * Check that the downlink assignation is done in a "TD blind equal throughput" manner
+ */
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> dlDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_thrRefDl);
+ }
+ /**
+ * Check that the assignation is done in a "TD blind equal throughput" manner among users
+ * with equal SINRs: the bandwidth should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, m_thrRefDl, m_thrRefDl * tolerance, " Unfair Throughput!");
+ }
+
+ /**
+ * Check that the uplink assignation is done in a "TD blind equal throughput" manner
+ */
+ NS_LOG_INFO ("UL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << m_thrRefUl);
+ }
+ /**
+ * Check that the assignation is done in a "TD blind equal throughput" manner among users
+ * with equal SINRs: the bandwidht should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, m_thrRefUl, m_thrRefUl * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
+
+
+// --------------- T E S T - C A S E # 2 ------------------------------
+
+
+std::string
+LenaTdBetFfMacSchedulerTestCase2::BuildNameString (uint16_t nUser, std::vector<uint16_t> dist)
+{
+ std::ostringstream oss;
+ oss << "distances (m) = [ " ;
+ for (std::vector<uint16_t>::iterator it = dist.begin (); it != dist.end (); ++it)
+ {
+ oss << *it << " ";
+ }
+ oss << "]";
+ return oss.str ();
+}
+
+
+LenaTdBetFfMacSchedulerTestCase2::LenaTdBetFfMacSchedulerTestCase2 (std::vector<uint16_t> dist, std::vector<uint32_t> estAchievableRateDl, std::vector<uint32_t> estThrTdBetUl)
+ : TestCase (BuildNameString (dist.size (), dist)),
+ m_nUser (dist.size ()),
+ m_dist (dist),
+ m_achievableRateDl (estAchievableRateDl),
+ m_estThrTdBetUl (estThrTdBetUl)
+{
+}
+
+LenaTdBetFfMacSchedulerTestCase2::~LenaTdBetFfMacSchedulerTestCase2 ()
+{
+}
+
+void
+LenaTdBetFfMacSchedulerTestCase2::DoRun (void)
+{
+ // LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("TdBetFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestTdBetFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::TdBetFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist.at (i), 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+
+ double simulationTime = 1;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s)");
+ std::vector <uint64_t> dlDataRxed;
+ double totalData = 0;
+ double estTotalThr = 0;
+ double estUeThr = 0;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ totalData += (double)dlDataRxed.at (i);
+ estTotalThr += 1 / m_achievableRateDl.at(i);
+ //NS_LOG_INFO ("\tUser " << i << " dist " << m_dist.at (i) << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_nUser);
+ }
+
+ estTotalThr = m_nUser * (1 / estTotalThr);
+ estUeThr = estTotalThr / m_nUser;
+
+ /**
+ * Check that the assignation is done in a "TD blind equal throughput" manner among users
+ * with different SINRs: the bandwidth should be distributed equally in long term
+ */
+ for (int i = 0; i < m_nUser; i++)
+ {
+ double thrRatio = (double) 1 / m_nUser;
+ double estThrRatio = (double)dlDataRxed.at (i) / totalData;
+ NS_LOG_INFO ("\tUser " << i << " thrRatio " << thrRatio << " estThrRatio " << estThrRatio);
+ NS_TEST_ASSERT_MSG_EQ_TOL (estThrRatio, thrRatio, tolerance, " Unfair Throughput!");
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at(i) / simulationTime, estUeThr, estUeThr*tolerance, " Unfair Throughput!");
+ }
+
+ /**
+ * Check that the assignation in uplink is done in a round robin manner.
+ */
+
+ NS_LOG_INFO ("UL - Test with " << m_nUser);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " dist " << m_dist.at (i) << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << (double)m_estThrTdBetUl.at (i));
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, (double)m_estThrTdBetUl.at (i), (double)m_estThrTdBetUl.at (i) * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
+
+} // namespace ns3
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tdbet-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef LENA_TEST_TDBET_FF_MAC_SCHEDULER_H
+#define LENA_TEST_TDBET_FF_MAC_SCHEDULER_H
+
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+
+
+namespace ns3 {
+
+
+/**
+* This system test program creates different test cases with a single eNB and
+* several UEs, all having the same Radio Bearer specification. In each test
+* case, the UEs see the same SINR from the eNB; different test cases are
+* implemented obtained by using different SINR values and different numbers of
+* UEs. The test consists on checking that the obtained throughput performance
+* is equal among users is consistent with the definition of proportional
+* fair scheduling
+*/
+class LenaTdBetFfMacSchedulerTestCase1 : public TestCase
+{
+public:
+ LenaTdBetFfMacSchedulerTestCase1 (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl);
+ virtual ~LenaTdBetFfMacSchedulerTestCase1 ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, uint16_t dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ uint16_t m_nLc;
+ uint16_t m_dist;
+ double m_thrRefDl;
+ double m_thrRefUl;
+};
+
+
+class LenaTdBetFfMacSchedulerTestCase2 : public TestCase
+{
+public:
+ LenaTdBetFfMacSchedulerTestCase2 (std::vector<uint16_t> dist, std::vector<uint32_t> m_achievableRateDl, std::vector<uint32_t> estThrTdBetUl);
+ virtual ~LenaTdBetFfMacSchedulerTestCase2 ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, std::vector<uint16_t> dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ std::vector<uint16_t> m_dist;
+ std::vector<uint32_t> m_achievableRateDl;
+ std::vector<uint32_t> m_estThrTdBetUl;
+};
+
+
+
+
+class LenaTestTdBetFfMacSchedulerSuite : public TestSuite
+{
+public:
+ LenaTestTdBetFfMacSchedulerSuite ();
+};
+
+
+
+
+} // namespace ns3
+
+
+#endif /* LENA_TEST_TDBET_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tdmt-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <ns3/object.h>
+#include <ns3/spectrum-interference.h>
+#include <ns3/spectrum-error-model.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+#include <ns3/simulator.h>
+#include <ns3/packet.h>
+#include <ns3/ptr.h>
+#include "ns3/radio-bearer-stats-calculator.h"
+#include <ns3/constant-position-mobility-model.h>
+#include "ns3/lte-test-tdmt-ff-mac-scheduler.h"
+#include <ns3/eps-bearer.h>
+#include <ns3/node-container.h>
+#include <ns3/mobility-helper.h>
+#include <ns3/net-device-container.h>
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/lte-enb-net-device.h>
+#include <ns3/lte-ue-rrc.h>
+#include <ns3/lte-helper.h>
+#include "ns3/string.h"
+#include "ns3/double.h"
+#include <ns3/lte-enb-phy.h>
+#include <ns3/lte-ue-phy.h>
+#include <ns3/boolean.h>
+#include <ns3/enum.h>
+
+
+NS_LOG_COMPONENT_DEFINE ("LenaTestTdMtFfMacCheduler");
+
+using namespace ns3;
+
+LenaTestTdMtFfMacSchedulerSuite::LenaTestTdMtFfMacSchedulerSuite ()
+ : TestSuite ("lte-tdmt-ff-mac-scheduler", SYSTEM)
+{
+ NS_LOG_INFO ("creating LenaTestTdMtFfMacSchedulerSuite");
+
+ //Test Case : AMC works in TDMT
+
+ // DOWNLINK - DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 26 -> 2196 -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 2196000 among 3 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 2196000 among 6 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 2196000 among 12 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 2196000 among 15 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 26 -> 2292 -> 2292000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 26 -> 89 -> 89000 bytes/sec
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (1,0,0,2196000,2292000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (3,0,0,2196000,749000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (6,0,0,2196000,373000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (12,0,0,2196000,185000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (15,0,0,2196000,89000));
+
+ // DOWNLINK - DISTANCE 3000 -> MCS 24 -> Itbs 30 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 1383000 among 3 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 1383000 among 6 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 1383000 among 12 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 1383000 among 15 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 3000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 18 -> 1239 -> 1239000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 18 -> 389 -> 389000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 18 -> 193 -> 193000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 18 -> 97 -> 97000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 18 -> 47 -> 47000 bytes/sec
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (1,0,3000,1383000,1239000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (3,0,3000,1383000,389000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (6,0,3000,1383000,193000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (12,0,3000,1383000,97000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (15,0,3000,1383000,47000));
+
+ // DOWNLINK - DISTANCE 6000 -> MCS 16 -> Itbs 15 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 15 -> 903 -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 903000 among 3 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 903000 among 6 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 903000 among 12 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 903000 among 15 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 6000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 11 -> 621 -> 621000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 11 -> 22 -> 22000 bytes/sec
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (1,0,6000,903000,621000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (3,0,6000,903000,201000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (6,0,6000,903000,97000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (12,0,6000,903000,47000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (15,0,6000,903000,22000));
+
+ // DOWNLINK - DISTANCE 9000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 11 -> 597 -> 597000 bytes/sec
+ // 3 users -> 597000 among 3 users -> 199000 bytes/sec
+ // 6 users -> 597000 among 6 users -> 99500 bytes/sec
+ // 12 users -> 597000 among 12 users -> 49750 bytes/sec
+ // 15 users -> 597000 among 15 users -> 39800 bytes/sec
+ // UPLINK - DISTANCE 9000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 8 -> 437 -> 437000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 8 -> 137 -> 137000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 8 -> 67 -> 67000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 8 -> 32 -> 32000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 8 -> 15 -> 15000 bytes/sec
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (1,0,9000,597000,437000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (3,0,9000,597000,137000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (6,0,9000,597000,67000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (12,0,9000,597000,32000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (15,0,9000,597000,15000));
+
+ // DONWLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 6 -> 309 -> 309000 bytes/sec
+ // 3 users -> 309000 among 3 users -> 103000 bytes/sec
+ // 6 users -> 309000 among 6 users -> 51500 bytes/sec
+ // 12 users -> 309000 among 12 users -> 25750 bytes/sec
+ // 15 users -> 309000 among 15 users -> 20600 bytes/sec
+ // UPLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 6 -> 233 -> 233000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 69 -> 69000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 32 -> 32000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 15 -> 15000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 6 -> 7 -> 7000 bytes/sec
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (1,0,15000,309000,233000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (3,0,15000,309000,69000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (6,0,15000,309000,32000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (12,0,15000,309000,15000));
+ AddTestCase (new LenaTdMtFfMacSchedulerTestCase (15,0,15000,309000,7000));
+
+
+}
+
+static LenaTestTdMtFfMacSchedulerSuite lenaTestTdMtFfMacSchedulerSuite;
+
+
+// --------------- T E S T - C A S E ------------------------------
+
+
+std::string
+LenaTdMtFfMacSchedulerTestCase::BuildNameString (uint16_t nUser, uint16_t dist)
+{
+ std::ostringstream oss;
+ oss << nUser << " UEs, distance " << dist << " m";
+ return oss.str ();
+}
+
+LenaTdMtFfMacSchedulerTestCase::LenaTdMtFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl)
+ : TestCase (BuildNameString (nUser, dist)),
+ m_nUser (nUser),
+ m_nLc (nLc),
+ m_dist (dist),
+ m_thrRefDl (thrRefDl),
+ m_thrRefUl (thrRefUl)
+{
+}
+
+LenaTdMtFfMacSchedulerTestCase::~LenaTdMtFfMacSchedulerTestCase ()
+{
+}
+
+void
+LenaTdMtFfMacSchedulerTestCase::DoRun (void)
+{
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+ LogComponentDisableAll (LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+//
+// LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("TdMtFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestTdMtFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+// LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::TdMtFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist, 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+ lteHelper->EnableMacTraces ();
+
+
+ double simulationTime = 1.0;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ /**
+ * Check that the downlink assignation is done in a "maximum throughput" manner
+ */
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> dlDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_thrRefDl);
+ }
+ /**
+ * Check that the assignation is done in a "maximum throughput" manner among users
+ * with equal SINRs: all bandwidth should be allocated to the first UE in script
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ if (i == 0)
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, m_thrRefDl, m_thrRefDl * tolerance, " Invalid Throughput!");
+ else
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, 0, tolerance, " Invalid Throughput!");
+ }
+
+ /**
+ * Check that the uplink assignation is done in a "maximum throughput" manner
+ */
+ NS_LOG_INFO ("UL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << m_thrRefUl);
+ }
+ /**
+ * Check that the assignation is done in a "maximum throughput" manner among users
+ * with equal SINRs: the bandwidht should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ *
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, m_thrRefUl, m_thrRefUl * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tdmt-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef LENA_TEST_TDMT_FF_MAC_SCHEDULER_H
+#define LENA_TEST_TDMT_FF_MAC_SCHEDULER_H
+
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+
+
+using namespace ns3;
+
+
+/**
+* This system test program creates different test cases with a single eNB and
+* several UEs, all having the same Radio Bearer specification. In each test
+* case, the UEs see the same SINR from the eNB; different test cases are
+* implemented obtained by using different SINR values and different numbers of
+* UEs. The test consists on checking that the obtained throughput performance
+* is consistent with the definition of maximum throughput
+* scheduling
+*/
+class LenaTdMtFfMacSchedulerTestCase : public TestCase
+{
+public:
+ LenaTdMtFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl);
+ virtual ~LenaTdMtFfMacSchedulerTestCase ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, uint16_t dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ uint16_t m_nLc;
+ uint16_t m_dist;
+ double m_thrRefDl;
+ double m_thrRefUl;
+};
+
+class LenaTestTdMtFfMacSchedulerSuite : public TestSuite
+{
+public:
+ LenaTestTdMtFfMacSchedulerSuite ();
+};
+
+
+
+
+#endif /* LENA_TEST_TDMT_FF_MAC_SCHEDULER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tta-ff-mac-scheduler.cc Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <ns3/object.h>
+#include <ns3/spectrum-interference.h>
+#include <ns3/spectrum-error-model.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+#include <ns3/simulator.h>
+#include <ns3/packet.h>
+#include <ns3/ptr.h>
+#include "ns3/radio-bearer-stats-calculator.h"
+#include <ns3/constant-position-mobility-model.h>
+#include "ns3/lte-test-tta-ff-mac-scheduler.h"
+#include <ns3/eps-bearer.h>
+#include <ns3/node-container.h>
+#include <ns3/mobility-helper.h>
+#include <ns3/net-device-container.h>
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/lte-enb-net-device.h>
+#include <ns3/lte-ue-rrc.h>
+#include <ns3/lte-helper.h>
+#include "ns3/string.h"
+#include "ns3/double.h"
+#include <ns3/lte-enb-phy.h>
+#include <ns3/lte-ue-phy.h>
+#include <ns3/boolean.h>
+#include <ns3/enum.h>
+
+
+NS_LOG_COMPONENT_DEFINE ("LenaTestTtaFfMacCheduler");
+
+using namespace ns3;
+
+LenaTestTtaFfMacSchedulerSuite::LenaTestTtaFfMacSchedulerSuite ()
+ : TestSuite ("lte-tta-ff-mac-scheduler", SYSTEM)
+{
+ NS_LOG_INFO ("creating LenaTestTtaFfMacSchedulerSuite");
+
+ //Test Case : AMC works in TTA
+
+ // DOWNLINK - DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 26 -> 2196 -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 2196000 among 3 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 2196000 among 6 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 2196000 among 12 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 2196000 among 15 users -> 2196000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK- DISTANCE 0 -> MCS 28 -> Itbs 26 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 26 -> 2292 -> 2292000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 26 -> 749 -> 749000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 26 -> 89 -> 89000 bytes/sec
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (1,0,0,2196000,2292000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (3,0,0,2196000,749000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (6,0,0,2196000,373000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (12,0,0,2196000,185000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (15,0,0,2196000,89000));
+
+ // DOWNLINK - DISTANCE 3000 -> MCS 24 -> Itbs 30 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 1383000 among 3 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 1383000 among 6 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 1383000 among 12 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 1383000 among 15 users -> 1383000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 3000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 18 -> 1239 -> 1239000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 18 -> 389 -> 389000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 18 -> 193 -> 193000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 18 -> 97 -> 97000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 18 -> 47 -> 47000 bytes/sec
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (1,0,3000,1383000,1239000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (3,0,3000,1383000,389000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (6,0,3000,1383000,193000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (12,0,3000,1383000,97000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (15,0,3000,1383000,47000));
+
+ // DOWNLINK - DISTANCE 6000 -> MCS 16 -> Itbs 15 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 15 -> 903 -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 3 users -> 903000 among 3 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 6 users -> 903000 among 6 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 12 users -> 903000 among 12 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // 15 users -> 903000 among 15 users -> 903000 bytes/sec for first UE; 0 bytes/sec for other UEs
+ // UPLINK - DISTANCE 6000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 11 -> 621 -> 621000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 11 -> 201 -> 201000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 11 -> 47 -> 47000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 11 -> 22 -> 22000 bytes/sec
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (1,0,6000,903000,621000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (3,0,6000,903000,201000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (6,0,6000,903000,97000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (12,0,6000,903000,47000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (15,0,6000,903000,22000));
+
+ // DOWNLINK - DISTANCE 9000 -> MCS 12 -> Itbs 11 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 11 -> 597 -> 597000 bytes/sec
+ // 3 users -> 597000 among 3 users -> 199000 bytes/sec
+ // 6 users -> 597000 among 6 users -> 99500 bytes/sec
+ // 12 users -> 597000 among 12 users -> 49750 bytes/sec
+ // 15 users -> 597000 among 15 users -> 39800 bytes/sec
+ // UPLINK - DISTANCE 9000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 8 -> 437 -> 437000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 8 -> 137 -> 137000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 8 -> 67 -> 67000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 8 -> 32 -> 32000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 8 -> 15 -> 15000 bytes/sec
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (1,0,9000,597000,437000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (3,0,9000,597000,137000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (6,0,9000,597000,67000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (12,0,9000,597000,32000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (15,0,9000,597000,15000));
+
+ // DONWLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 24 PRB at Itbs 6 -> 309 -> 309000 bytes/sec
+ // 3 users -> 309000 among 3 users -> 103000 bytes/sec
+ // 6 users -> 309000 among 6 users -> 51500 bytes/sec
+ // 12 users -> 309000 among 12 users -> 25750 bytes/sec
+ // 15 users -> 309000 among 15 users -> 20600 bytes/sec
+ // UPLINK - DISTANCE 15000 -> MCS 6 -> Itbs 6 (from table 7.1.7.2.1-1 of 36.213)
+ // 1 user -> 25 PRB at Itbs 6 -> 233 -> 233000 bytes/sec
+ // 3 users -> 8 PRB at Itbs 6 -> 69 -> 69000 bytes/sec
+ // 6 users -> 4 PRB at Itbs 6 -> 32 -> 32000 bytes/sec
+ // 12 users -> 2 PRB at Itbs 6 -> 15 -> 15000 bytes/sec
+ // 15 users -> 1 PRB at Itbs 6 -> 7 -> 7000 bytes/sec
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (1,0,15000,309000,233000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (3,0,15000,309000,69000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (6,0,15000,309000,32000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (12,0,15000,309000,15000));
+ AddTestCase (new LenaTtaFfMacSchedulerTestCase (15,0,15000,309000,7000));
+
+
+}
+
+static LenaTestTtaFfMacSchedulerSuite lenaTestTtaFfMacSchedulerSuite;
+
+
+// --------------- T E S T - C A S E ------------------------------
+
+
+std::string
+LenaTtaFfMacSchedulerTestCase::BuildNameString (uint16_t nUser, uint16_t dist)
+{
+ std::ostringstream oss;
+ oss << nUser << " UEs, distance " << dist << " m";
+ return oss.str ();
+}
+
+LenaTtaFfMacSchedulerTestCase::LenaTtaFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl)
+ : TestCase (BuildNameString (nUser, dist)),
+ m_nUser (nUser),
+ m_nLc (nLc),
+ m_dist (dist),
+ m_thrRefDl (thrRefDl),
+ m_thrRefUl (thrRefUl)
+{
+}
+
+LenaTtaFfMacSchedulerTestCase::~LenaTtaFfMacSchedulerTestCase ()
+{
+}
+
+void
+LenaTtaFfMacSchedulerTestCase::DoRun (void)
+{
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+ LogComponentDisableAll (LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
+//
+// LogComponentEnable ("LtePhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
+// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
+
+ // LogComponentEnable ("LteSpectrumPhy", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteInterference", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteSinrChunkProcessor", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LtePropagationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("ShadowingLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PenetrationLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("MultipathLossModel", LOG_LEVEL_ALL);
+ // LogComponentEnable ("PathLossModel", LOG_LEVEL_ALL);
+ //
+ // LogComponentEnable ("LteNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteUeNetDevice", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
+
+// LogComponentEnable ("TtaFfMacScheduler", LOG_LEVEL_ALL);
+ LogComponentEnable ("LenaTestTtaFfMacCheduler", LOG_LEVEL_ALL);
+ // LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
+// LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+
+ /**
+ * Initialize Simulation Scenario: 1 eNB and m_nUser UEs
+ */
+
+ Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+
+ lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::FriisSpectrumPropagationLossModel"));
+
+ // Create Nodes: eNodeB and UE
+ NodeContainer enbNodes;
+ NodeContainer ueNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (m_nUser);
+
+ // Install Mobility Model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (enbNodes);
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.Install (ueNodes);
+
+ // Create Devices and install them in the Nodes (eNB and UE)
+ NetDeviceContainer enbDevs;
+ NetDeviceContainer ueDevs;
+ lteHelper->SetSchedulerType ("ns3::TtaFfMacScheduler");
+ enbDevs = lteHelper->InstallEnbDevice (enbNodes);
+ ueDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ // Attach a UE to a eNB
+ lteHelper->Attach (ueDevs, enbDevs.Get (0));
+
+ // Activate an EPS bearer
+ enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
+ EpsBearer bearer (q);
+ lteHelper->ActivateEpsBearer (ueDevs, bearer, EpcTft::Default ());
+
+ Ptr<LteEnbNetDevice> lteEnbDev = enbDevs.Get (0)->GetObject<LteEnbNetDevice> ();
+ Ptr<LteEnbPhy> enbPhy = lteEnbDev->GetPhy ();
+ enbPhy->SetAttribute ("TxPower", DoubleValue (30.0));
+ enbPhy->SetAttribute ("NoiseFigure", DoubleValue (5.0));
+
+ // Set UEs' position and power
+ for (int i = 0; i < m_nUser; i++)
+ {
+ Ptr<ConstantPositionMobilityModel> mm = ueNodes.Get (i)->GetObject<ConstantPositionMobilityModel> ();
+ mm->SetPosition (Vector (m_dist, 0.0, 0.0));
+ Ptr<LteUeNetDevice> lteUeDev = ueDevs.Get (i)->GetObject<LteUeNetDevice> ();
+ Ptr<LteUePhy> uePhy = lteUeDev->GetPhy ();
+ uePhy->SetAttribute ("TxPower", DoubleValue (23.0));
+ uePhy->SetAttribute ("NoiseFigure", DoubleValue (9.0));
+ }
+
+ lteHelper->EnableRlcTraces ();
+ lteHelper->EnableMacTraces ();
+
+
+ double simulationTime = 1.0;
+ double tolerance = 0.1;
+ Simulator::Stop (Seconds (simulationTime));
+
+ Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
+ rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (simulationTime)));
+
+ Simulator::Run ();
+
+ /**
+ * Check that the downlink assignation is done in a "throughput to average" manner
+ */
+ NS_LOG_INFO ("DL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> dlDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ dlDataRxed.push_back (rlcStats->GetDlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)dlDataRxed.at (i) << " thr " << (double)dlDataRxed.at (i) / simulationTime << " ref " << m_thrRefDl);
+ }
+ /**
+ * Check that the assignation is done in a "throughput to average" manner among users
+ * with equal SINRs: all bandwidth should be allocated to the first UE in script
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ if (i == 0)
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, m_thrRefDl, m_thrRefDl * tolerance, " Invalid Throughput!");
+ else
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)dlDataRxed.at (i) / simulationTime, 0, tolerance, " Invalid Throughput!");
+ }
+
+ /**
+ * Check that the uplink assignation is done in a "throughput to average" manner
+ */
+ NS_LOG_INFO ("UL - Test with " << m_nUser << " user(s) at distance " << m_dist);
+ std::vector <uint64_t> ulDataRxed;
+ for (int i = 0; i < m_nUser; i++)
+ {
+ // get the imsi
+ uint64_t imsi = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetImsi ();
+ // get the lcId
+ uint8_t lcId = ueDevs.Get (i)->GetObject<LteUeNetDevice> ()->GetRrc ()->GetLcIdVector ().at (0);
+ ulDataRxed.push_back (rlcStats->GetUlRxData (imsi, lcId));
+ NS_LOG_INFO ("\tUser " << i << " imsi " << imsi << " bytes rxed " << (double)ulDataRxed.at (i) << " thr " << (double)ulDataRxed.at (i) / simulationTime << " ref " << m_thrRefUl);
+ }
+ /**
+ * Check that the assignation is done in a "throughput to average" manner among users
+ * with equal SINRs: the bandwidht should be distributed according to the
+ * ratio of the estimated throughput per TTI of each user; therefore equally
+ * partitioning the whole bandwidth achievable from a single users in a TTI
+ *
+ */
+ for (int i = 0; i < 1; i++)
+ {
+ NS_TEST_ASSERT_MSG_EQ_TOL ((double)ulDataRxed.at (i) / simulationTime, m_thrRefUl, m_thrRefUl * tolerance, " Unfair Throughput!");
+ }
+ Simulator::Destroy ();
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/test/lte-test-tta-ff-mac-scheduler.h Sun Jul 01 21:06:56 2012 -0300
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Marco Miozzo <marco.miozzo@cttc.es>,
+ * Nicola Baldo <nbaldo@cttc.es>
+ * Dizhi Zhou <dizhi.zhou@gmail.com>
+ */
+
+#ifndef LENA_TEST_TTA_FF_MAC_SCHEDULER_H
+#define LENA_TEST_TTA_FF_MAC_SCHEDULER_H
+
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+
+
+using namespace ns3;
+
+
+/**
+* This system test program creates different test cases with a single eNB and
+* several UEs, all having the same Radio Bearer specification. In each test
+* case, the UEs see the same SINR from the eNB; different test cases are
+* implemented obtained by using different SINR values and different numbers of
+* UEs. The test consists on checking that the obtained throughput performance
+* is consistent with the definition of throughput to average scheduling
+*/
+class LenaTtaFfMacSchedulerTestCase : public TestCase
+{
+public:
+ LenaTtaFfMacSchedulerTestCase (uint16_t nUser, uint16_t nLc, uint16_t dist, double thrRefDl, double thrRefUl);
+ virtual ~LenaTtaFfMacSchedulerTestCase ();
+
+private:
+ static std::string BuildNameString (uint16_t nUser, uint16_t dist);
+ virtual void DoRun (void);
+ uint16_t m_nUser;
+ uint16_t m_nLc;
+ uint16_t m_dist;
+ double m_thrRefDl;
+ double m_thrRefUl;
+};
+
+class LenaTestTtaFfMacSchedulerSuite : public TestSuite
+{
+public:
+ LenaTestTtaFfMacSchedulerSuite ();
+};
+
+
+
+
+#endif /* LENA_TEST_TTA_FF_MAC_SCHEDULER_H */