1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 Piotr Gawlowicz
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Piotr Gawlowicz <gawlowicz.p@gmail.com>
19  *
20  */
21 
22 #include <ns3/simulator.h>
23 #include <ns3/log.h>
24 #include <ns3/callback.h>
25 #include <ns3/config.h>
26 #include <ns3/string.h>
27 #include <ns3/double.h>
28 #include <ns3/enum.h>
29 #include <ns3/boolean.h>
30 #include <ns3/pointer.h>
31 #include "ns3/ff-mac-scheduler.h"
32 #include "ns3/mobility-helper.h"
33 #include "ns3/lte-helper.h"
34 
35 #include "lte-ffr-simple.h"
36 #include "ns3/lte-rrc-sap.h"
37 #include <ns3/lte-ue-net-device.h>
38 #include <ns3/lte-ue-mac.h>
39 
40 #include "lte-test-cqi-generation.h"
41 
42 using namespace ns3;
43 
44 NS_LOG_COMPONENT_DEFINE ("LteCqiGenerationTest");
45 
46 void
LteTestDlSchedulingCallback(LteCqiGenerationTestCase * testcase,std::string path,DlSchedulingCallbackInfo dlInfo)47 LteTestDlSchedulingCallback (LteCqiGenerationTestCase *testcase, std::string path, DlSchedulingCallbackInfo dlInfo)
48 {
49   testcase->DlScheduling (dlInfo);
50 }
51 
52 void
LteTestUlSchedulingCallback(LteCqiGenerationTestCase * testcase,std::string path,uint32_t frameNo,uint32_t subframeNo,uint16_t rnti,uint8_t mcs,uint16_t sizeTb,uint8_t ccId)53 LteTestUlSchedulingCallback (LteCqiGenerationTestCase *testcase, std::string path,
54                              uint32_t frameNo, uint32_t subframeNo, uint16_t rnti,
55                              uint8_t mcs, uint16_t sizeTb, uint8_t ccId)
56 {
57   testcase->UlScheduling (frameNo, subframeNo, rnti, mcs, sizeTb);
58 }
59 
60 void
LteTestDlSchedulingCallback2(LteCqiGenerationDlPowerControlTestCase * testcase,std::string path,DlSchedulingCallbackInfo dlInfo)61 LteTestDlSchedulingCallback2 (LteCqiGenerationDlPowerControlTestCase *testcase, std::string path,
62 		                      DlSchedulingCallbackInfo dlInfo)
63 {
64   testcase->DlScheduling (dlInfo);
65 }
66 
67 void
LteTestUlSchedulingCallback2(LteCqiGenerationDlPowerControlTestCase * testcase,std::string path,uint32_t frameNo,uint32_t subframeNo,uint16_t rnti,uint8_t mcs,uint16_t sizeTb,uint8_t componentCarrierId)68 LteTestUlSchedulingCallback2 (LteCqiGenerationDlPowerControlTestCase *testcase, std::string path,
69                               uint32_t frameNo, uint32_t subframeNo, uint16_t rnti,
70                               uint8_t mcs, uint16_t sizeTb, uint8_t componentCarrierId)
71 {
72   testcase->UlScheduling (frameNo, subframeNo, rnti, mcs, sizeTb);
73 }
74 
75 
76 /**
77  * TestSuite
78  */
79 
LteCqiGenerationTestSuite()80 LteCqiGenerationTestSuite::LteCqiGenerationTestSuite ()
81   : TestSuite ("lte-cqi-generation", SYSTEM)
82 {
83 //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
84 //  LogComponentEnable ("LteCqiGenerationTest", logLevel);
85   NS_LOG_INFO ("Creating LteCqiGenerationTestSuite");
86 
87   AddTestCase (new LteCqiGenerationTestCase ("UsePdcchForCqiGeneration", false, 4, 2), TestCase::QUICK);
88   AddTestCase (new LteCqiGenerationTestCase ("UsePdschForCqiGeneration", true, 28, 2), TestCase::QUICK);
89 
90   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
91                                                            LteRrcSap::PdschConfigDedicated::dB0, LteRrcSap::PdschConfigDedicated::dB0, 4, 2), TestCase::QUICK);
92   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
93                                                            LteRrcSap::PdschConfigDedicated::dB0, LteRrcSap::PdschConfigDedicated::dB_3, 8, 2), TestCase::QUICK);
94   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
95                                                            LteRrcSap::PdschConfigDedicated::dB0, LteRrcSap::PdschConfigDedicated::dB_6, 10, 2), TestCase::QUICK);
96   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
97                                                            LteRrcSap::PdschConfigDedicated::dB1, LteRrcSap::PdschConfigDedicated::dB_6, 12, 2), TestCase::QUICK);
98   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
99                                                            LteRrcSap::PdschConfigDedicated::dB2, LteRrcSap::PdschConfigDedicated::dB_6, 14, 2), TestCase::QUICK);
100   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
101                                                            LteRrcSap::PdschConfigDedicated::dB3, LteRrcSap::PdschConfigDedicated::dB_6, 14, 2), TestCase::QUICK);
102   AddTestCase (new LteCqiGenerationDlPowerControlTestCase ("CqiGenerationWithDlPowerControl",
103                                                            LteRrcSap::PdschConfigDedicated::dB3, LteRrcSap::PdschConfigDedicated::dB0, 8, 2), TestCase::QUICK);
104 }
105 
106 static LteCqiGenerationTestSuite lteCqiGenerationTestSuite;
107 
108 
LteCqiGenerationTestCase(std::string name,bool usePdcchForCqiGeneration,uint16_t dlMcs,uint16_t ulMcs)109 LteCqiGenerationTestCase::LteCqiGenerationTestCase (std::string name, bool usePdcchForCqiGeneration,
110                                                     uint16_t dlMcs, uint16_t ulMcs)
111   : TestCase ("Downlink Power Control: " + name),
112     m_dlMcs (dlMcs),
113     m_ulMcs (ulMcs)
114 {
115   m_usePdschForCqiGeneration = usePdcchForCqiGeneration;
116   NS_LOG_INFO ("Creating LteCqiGenerationTestCase");
117 }
118 
~LteCqiGenerationTestCase()119 LteCqiGenerationTestCase::~LteCqiGenerationTestCase ()
120 {
121 }
122 
123 void
DlScheduling(DlSchedulingCallbackInfo dlInfo)124 LteCqiGenerationTestCase::DlScheduling (DlSchedulingCallbackInfo dlInfo)
125 {
126   // need to allow for RRC connection establishment + CQI feedback reception
127   if (Simulator::Now () > MilliSeconds (35))
128     {
129 //	  NS_LOG_UNCOND("DL MSC: " << (uint32_t)mcsTb1 << " expected DL MCS: " << (uint32_t)m_dlMcs);
130       NS_TEST_ASSERT_MSG_EQ ((uint32_t)dlInfo.mcsTb1, (uint32_t)m_dlMcs, "Wrong DL MCS ");
131     }
132 }
133 
134 void
UlScheduling(uint32_t frameNo,uint32_t subframeNo,uint16_t rnti,uint8_t mcs,uint16_t sizeTb)135 LteCqiGenerationTestCase::UlScheduling (uint32_t frameNo, uint32_t subframeNo, uint16_t rnti,
136                                         uint8_t mcs, uint16_t sizeTb)
137 {
138   // need to allow for RRC connection establishment + SRS transmission
139   if (Simulator::Now () > MilliSeconds (50))
140     {
141 //	  NS_LOG_UNCOND("UL MSC: " << (uint32_t)mcs << " expected UL MCS: " << (uint32_t)m_ulMcs);
142       NS_TEST_ASSERT_MSG_EQ ((uint32_t)mcs, (uint32_t)m_ulMcs, "Wrong UL MCS");
143     }
144 }
145 
146 void
DoRun(void)147 LteCqiGenerationTestCase::DoRun (void)
148 {
149   NS_LOG_DEBUG ("LteCqiGenerationTestCase");
150 
151   Config::Reset ();
152   Config::SetDefault ("ns3::LteHelper::UseIdealRrc", BooleanValue (true));
153   Config::SetDefault ("ns3::LteHelper::UsePdschForCqiGeneration", BooleanValue (m_usePdschForCqiGeneration));
154 
155   Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (true));
156   Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));
157 
158   Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
159 
160   // Create Nodes: eNodeB and UE
161   NodeContainer enbNodes;
162   NodeContainer ueNodes1;
163   NodeContainer ueNodes2;
164   enbNodes.Create (2);
165   ueNodes1.Create (1);
166   ueNodes2.Create (1);
167   NodeContainer allNodes = NodeContainer ( enbNodes, ueNodes1, ueNodes2);
168 
169   /*
170    * The topology is the following:
171    *
172    *  eNB1                        UE1 UE2                        eNB2
173    *    |                            |                            |
174    *    x -------------------------- x -------------------------- x
175    *                  500 m                       500 m
176    *
177    */
178 
179   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
180   positionAlloc->Add (Vector (0.0, 0.0, 0.0));   // eNB1
181   positionAlloc->Add (Vector (1000, 0.0, 0.0)); // eNB2
182   positionAlloc->Add (Vector (500.0, 0.0, 0.0));  // UE1
183   positionAlloc->Add (Vector (500, 0.0, 0.0));  // UE2
184   MobilityHelper mobility;
185   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
186   mobility.SetPositionAllocator (positionAlloc);
187   mobility.Install (allNodes);
188 
189   // Create Devices and install them in the Nodes (eNB and UE)
190   NetDeviceContainer enbDevs;
191   NetDeviceContainer ueDevs1;
192   NetDeviceContainer ueDevs2;
193   lteHelper->SetSchedulerType ("ns3::PfFfMacScheduler");
194   lteHelper->SetSchedulerAttribute ("UlCqiFilter", EnumValue (FfMacScheduler::PUSCH_UL_CQI));
195 
196   lteHelper->SetFfrAlgorithmType ("ns3::LteFrHardAlgorithm");
197 
198   lteHelper->SetFfrAlgorithmAttribute ("DlSubBandOffset", UintegerValue (0));
199   lteHelper->SetFfrAlgorithmAttribute ("DlSubBandwidth", UintegerValue (12));
200   lteHelper->SetFfrAlgorithmAttribute ("UlSubBandOffset", UintegerValue (0));
201   lteHelper->SetFfrAlgorithmAttribute ("UlSubBandwidth", UintegerValue (25));
202   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (0)));
203 
204   lteHelper->SetFfrAlgorithmAttribute ("DlSubBandOffset", UintegerValue (12));
205   lteHelper->SetFfrAlgorithmAttribute ("DlSubBandwidth", UintegerValue (12));
206   lteHelper->SetFfrAlgorithmAttribute ("UlSubBandOffset", UintegerValue (0));
207   lteHelper->SetFfrAlgorithmAttribute ("UlSubBandwidth", UintegerValue (25));
208   enbDevs.Add (lteHelper->InstallEnbDevice (enbNodes.Get (1)));
209 
210   ueDevs1 = lteHelper->InstallUeDevice (ueNodes1);
211   ueDevs2 = lteHelper->InstallUeDevice (ueNodes2);
212 
213   // Attach a UE to a eNB
214   lteHelper->Attach (ueDevs1, enbDevs.Get (0));
215   lteHelper->Attach (ueDevs2, enbDevs.Get (1));
216 
217   // Activate an EPS bearer
218   enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
219   EpsBearer bearer (q);
220   lteHelper->ActivateDataRadioBearer (ueDevs1, bearer);
221   lteHelper->ActivateDataRadioBearer (ueDevs2, bearer);
222 
223   Config::Connect ("/NodeList/0/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/DlScheduling",
224                    MakeBoundCallback (&LteTestDlSchedulingCallback, this));
225 
226   Config::Connect ("/NodeList/0/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/UlScheduling",
227                    MakeBoundCallback (&LteTestUlSchedulingCallback, this));
228 
229   Config::Connect ("/NodeList/1/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/DlScheduling",
230                    MakeBoundCallback (&LteTestDlSchedulingCallback, this));
231 
232   Config::Connect ("/NodeList/1/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/UlScheduling",
233                    MakeBoundCallback (&LteTestUlSchedulingCallback, this));
234 
235   Simulator::Stop (Seconds (1.100));
236   Simulator::Run ();
237 
238   Simulator::Destroy ();
239 }
240 
LteCqiGenerationDlPowerControlTestCase(std::string name,uint8_t cell0Pa,uint8_t cell1Pa,uint16_t dlMcs,uint16_t ulMcs)241 LteCqiGenerationDlPowerControlTestCase::LteCqiGenerationDlPowerControlTestCase (std::string name,
242                                                                                 uint8_t cell0Pa, uint8_t cell1Pa, uint16_t dlMcs, uint16_t ulMcs)
243   : TestCase ("Downlink Power Control: " + name),
244     m_cell0Pa (cell0Pa),
245     m_cell1Pa (cell1Pa),
246     m_dlMcs (dlMcs),
247     m_ulMcs (ulMcs)
248 {
249   NS_LOG_INFO ("Creating LteCqiGenerationTestCase");
250 }
251 
~LteCqiGenerationDlPowerControlTestCase()252 LteCqiGenerationDlPowerControlTestCase::~LteCqiGenerationDlPowerControlTestCase ()
253 {
254 }
255 
256 void
DlScheduling(DlSchedulingCallbackInfo dlInfo)257 LteCqiGenerationDlPowerControlTestCase::DlScheduling (DlSchedulingCallbackInfo dlInfo)
258 {
259   // need to allow for RRC connection establishment + CQI feedback reception
260   if (Simulator::Now () > MilliSeconds (500))
261     {
262 //	  NS_LOG_UNCOND("DL MSC: " << (uint32_t)mcsTb1 << " expected DL MCS: " << (uint32_t)m_dlMcs);
263       NS_TEST_ASSERT_MSG_EQ ((uint32_t)dlInfo.mcsTb1, (uint32_t)m_dlMcs, "Wrong DL MCS ");
264     }
265 }
266 
267 void
UlScheduling(uint32_t frameNo,uint32_t subframeNo,uint16_t rnti,uint8_t mcs,uint16_t sizeTb)268 LteCqiGenerationDlPowerControlTestCase::UlScheduling (uint32_t frameNo, uint32_t subframeNo, uint16_t rnti,
269                                                       uint8_t mcs, uint16_t sizeTb)
270 {
271   // need to allow for RRC connection establishment + SRS transmission
272   if (Simulator::Now () > MilliSeconds (500))
273     {
274 //	  NS_LOG_UNCOND("UL MSC: " << (uint32_t)mcs << " expected UL MCS: " << (uint32_t)m_ulMcs);
275       NS_TEST_ASSERT_MSG_EQ ((uint32_t)mcs, (uint32_t)m_ulMcs, "Wrong UL MCS");
276     }
277 }
278 
279 void
DoRun(void)280 LteCqiGenerationDlPowerControlTestCase::DoRun (void)
281 {
282   NS_LOG_DEBUG ("LteCqiGenerationTestCase");
283 
284   Config::Reset ();
285   Config::SetDefault ("ns3::LteHelper::UseIdealRrc", BooleanValue (true));
286   Config::SetDefault ("ns3::LteHelper::UsePdschForCqiGeneration", BooleanValue (true));
287 
288   Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (true));
289   Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));
290 
291   Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
292   lteHelper->SetFfrAlgorithmType ("ns3::LteFfrSimple");
293 
294   // Create Nodes: eNodeB and UE
295   NodeContainer enbNodes;
296   NodeContainer ueNodes1;
297   NodeContainer ueNodes2;
298   enbNodes.Create (2);
299   ueNodes1.Create (1);
300   ueNodes2.Create (2);
301   NodeContainer allNodes = NodeContainer ( enbNodes, ueNodes1, ueNodes2);
302 
303   /*
304    * The topology is the following:
305    *
306    *  eNB1                        UE1 UE2                        eNB2 UE3
307    *    |                            |                            |    |
308    *    x -------------------------- x -------------------------- x----x
309    *                  500 m                       500 m             50m
310    *
311    * see https://www.nsnam.org/bugzilla/show_bug.cgi?id=2048#c4 for why we need UE3
312    */
313 
314   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
315   positionAlloc->Add (Vector (0.0, 0.0, 0.0));   // eNB1
316   positionAlloc->Add (Vector (1000, 0.0, 0.0)); // eNB2
317   positionAlloc->Add (Vector (500.0, 0.0, 0.0));  // UE1
318   positionAlloc->Add (Vector (500, 0.0, 0.0));  // UE2
319   positionAlloc->Add (Vector (1050, 0.0, 0.0));  // UE3
320   MobilityHelper mobility;
321   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
322   mobility.SetPositionAllocator (positionAlloc);
323   mobility.Install (allNodes);
324 
325   // Create Devices and install them in the Nodes (eNB and UE)
326   NetDeviceContainer enbDevs;
327   NetDeviceContainer ueDevs1;
328   NetDeviceContainer ueDevs2;
329   lteHelper->SetSchedulerType ("ns3::PfFfMacScheduler");
330   //In this scenario, eNB2 with 2 UEs will assign 12 RBs to UE2.
331   //On the other hand eNB1 will assign 25 RBs to UE1. As per the new uplink power
332   //spectral density computation, UE with less RBs to Tx will have more power
333   //per RB. Therefore UE2 will harm UE1 more, thus, both the UEs will have
334   //different Uplink CQI, which will cause the test to fail.
335   //In this case, we can use SRS based CQIs, since, they are not dependent on
336   //the transmission bandwidth.
337   lteHelper->SetSchedulerAttribute ("UlCqiFilter", EnumValue (FfMacScheduler::SRS_UL_CQI));
338   enbDevs = lteHelper->InstallEnbDevice (enbNodes);
339   ueDevs1 = lteHelper->InstallUeDevice (ueNodes1);
340   ueDevs2 = lteHelper->InstallUeDevice (ueNodes2);
341   //We need to fix the stream to have control over
342   //random preamble generation by the UEs.
343   Ptr<LteUeNetDevice> lteUeDev;
344   Ptr<LteUeMac> lteUeMac;
345   lteUeDev = DynamicCast<LteUeNetDevice> (ueDevs1.Get(0));
346   lteUeMac = lteUeDev->GetMac();
347   lteUeMac->AssignStreams(1);
348   lteUeDev = DynamicCast<LteUeNetDevice> (ueDevs2.Get(0));
349   lteUeMac = lteUeDev->GetMac();
350   lteUeMac->AssignStreams(1);
351   lteUeDev = DynamicCast<LteUeNetDevice> (ueDevs2.Get(1));
352   lteUeMac = lteUeDev->GetMac();
353   lteUeMac->AssignStreams(2);
354 
355   // Attach a UE to a eNB
356   lteHelper->Attach (ueDevs1, enbDevs.Get (0));
357   lteHelper->Attach (ueDevs2, enbDevs.Get (1));
358 
359   // Activate an EPS bearer
360   enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE;
361   EpsBearer bearer (q);
362   lteHelper->ActivateDataRadioBearer (ueDevs1, bearer);
363   lteHelper->ActivateDataRadioBearer (ueDevs2, bearer);
364 
365   PointerValue tmp;
366   enbDevs.Get (0)->GetAttribute ("LteFfrAlgorithm", tmp);
367   Ptr<LteFfrSimple> simpleFfrAlgorithmEnb0 = DynamicCast<LteFfrSimple>(tmp.GetObject ());
368   simpleFfrAlgorithmEnb0->ChangePdschConfigDedicated (true);
369 
370   LteRrcSap::PdschConfigDedicated pdschConfigDedicatedEnb0;
371   pdschConfigDedicatedEnb0.pa = m_cell0Pa;
372   simpleFfrAlgorithmEnb0->SetPdschConfigDedicated (pdschConfigDedicatedEnb0);
373 
374   enbDevs.Get (1)->GetAttribute ("LteFfrAlgorithm", tmp);
375   Ptr<LteFfrSimple> simpleFfrAlgorithmEnb1 = DynamicCast<LteFfrSimple>(tmp.GetObject ());
376   simpleFfrAlgorithmEnb1->ChangePdschConfigDedicated (true);
377 
378   LteRrcSap::PdschConfigDedicated pdschConfigDedicatedEnb1;
379   pdschConfigDedicatedEnb1.pa = m_cell1Pa;
380   simpleFfrAlgorithmEnb1->SetPdschConfigDedicated (pdschConfigDedicatedEnb1);
381 
382 
383   Config::Connect ("/NodeList/0/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/DlScheduling",
384                    MakeBoundCallback (&LteTestDlSchedulingCallback2, this));
385 
386   Config::Connect ("/NodeList/0/DeviceList/0/ComponentCarrierMap/*/LteEnbMac/UlScheduling",
387                    MakeBoundCallback (&LteTestUlSchedulingCallback2, this));
388 
389   Simulator::Stop (Seconds (1.100));
390   Simulator::Run ();
391 
392   Simulator::Destroy ();
393 }
394 
395