5G-LENA nr-v3.1-14-g738b08bc
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
cc-bwp-helper.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "cc-bwp-helper.h"
6
7#include <ns3/log.h>
8#include <ns3/spectrum-channel.h>
9#include <ns3/three-gpp-propagation-loss-model.h>
10#include <ns3/three-gpp-spectrum-propagation-loss-model.h>
11
12#include <fstream>
13#include <memory>
14
15namespace ns3
16{
17
18NS_LOG_COMPONENT_DEFINE("CcBwpHelper");
19
20bool
22{
23 NS_LOG_FUNCTION(this);
24
25 bool ret = true;
26
27 NS_ASSERT(bwp->m_lowerFrequency >= m_lowerFrequency);
28 NS_ASSERT(bwp->m_higherFrequency <= m_higherFrequency);
29
30 m_bwp.emplace_back(std::move(bwp));
31
32 uint32_t i = 0;
33 while (i < m_bwp.size() - 1)
34 {
35 auto& bwp = m_bwp.at(i);
36 auto& nextBwp = m_bwp.at(i + 1);
37 if (bwp->m_higherFrequency > nextBwp->m_lowerFrequency)
38 {
39 NS_LOG_ERROR("BWP ID "
40 << +bwp->m_bwpId << " has higher freq = " << bwp->m_higherFrequency / 1e6
41 << "MHz while BWP ID " << +nextBwp->m_bwpId
42 << " has lower freq = " << nextBwp->m_lowerFrequency / 1e6 << " MHz.");
43 ret = false;
44 }
45 ++i;
46 }
47
48 for (auto& bwp : m_bwp)
49 {
50 NS_LOG_INFO("Create BWP with bwpId: "
51 << +bwp->m_bwpId << " lower: " << bwp->m_lowerFrequency / 1e6
52 << " with central freq: " << bwp->m_centralFrequency / 1e6
53 << " higher: " << bwp->m_higherFrequency / 1e6
54 << " BW: " << bwp->m_channelBandwidth / 1e6 << " MHz");
55 }
56
57 return ret;
58}
59
60bool
62{
63 NS_LOG_FUNCTION(this);
64 bool ret = true;
65
66 NS_ASSERT(cc->m_lowerFrequency >= m_lowerFrequency);
67 NS_ASSERT(cc->m_higherFrequency <= m_higherFrequency);
68
69 m_cc.emplace_back(std::move(cc));
70
71 uint32_t i = 0;
72 while (i < m_cc.size() - 1)
73 {
74 auto& cc = m_cc.at(i);
75 auto& nextCc = m_cc.at(i + 1);
76 if (cc->m_higherFrequency > nextCc->m_lowerFrequency)
77 {
78 NS_LOG_WARN("Cc at " << i << " has higher freq " << cc->m_higherFrequency / 1e6
79 << " while Cc at " << i + 1 << " has freq at "
80 << m_lowerFrequency / 1e6);
81 ret = false;
82 }
83 ++i;
84 }
85
86 for (auto& cc : m_cc)
87 {
88 NS_LOG_INFO("Create CC with ccId: "
89 << +cc->m_ccId << " lower: " << cc->m_lowerFrequency / 1e6
90 << " with central freq: " << cc->m_centralFrequency / 1e6
91 << " higher: " << cc->m_higherFrequency / 1e6
92 << " BW: " << cc->m_channelBandwidth / 1e6 << " MHz");
93 }
94
95 return ret;
96}
97
99OperationBandInfo::GetBwpAt(uint32_t ccId, uint32_t bwpId) const
100{
101 return m_cc.at(ccId)->m_bwp.at(bwpId);
102}
103
106{
107 std::vector<std::reference_wrapper<BandwidthPartInfoPtr>> ret;
108
109 for (const auto& cc : m_cc)
110 {
111 for (auto& bwp : cc->m_bwp)
112 {
113 ret.emplace_back(bwp);
114 }
115 }
116
117 return ret;
118}
119
120// cc is a unique_pointer... I'm allowing myself to use a reference, because
121// if I would use a pointer (like I was telling you to do) then we end up
122// with a pointer to a pointer, and we have to use (*cc)->m_centralFreq...
123// a bit useless here.
124void
125CcBwpCreator::InitializeCc(std::unique_ptr<ComponentCarrierInfo>& cc,
126 double ccBandwidth,
127 double lowerFreq,
128 uint8_t ccPosition,
129 uint8_t ccId) const
130{
131 NS_LOG_FUNCTION(this);
132 cc->m_centralFrequency = lowerFreq + ccPosition * ccBandwidth + ccBandwidth / 2;
133 cc->m_lowerFrequency = lowerFreq + ccPosition * ccBandwidth;
134 cc->m_higherFrequency = lowerFreq + (ccPosition + 1) * ccBandwidth - 1;
135 cc->m_channelBandwidth = ccBandwidth;
136 cc->m_ccId = ccId;
137 NS_LOG_INFO("Initialize the op band "
138 << +ccPosition << "st (or nd) CC of BW " << ccBandwidth / 1e6 << " MHz "
139 << " from " << lowerFreq / 1e6 << "MHz, resulting in: " << *cc);
140}
141
142void
143CcBwpCreator::InitializeBwp(std::unique_ptr<BandwidthPartInfo>& bwp,
144 double bwOfBwp,
145 double lowerFreq,
146 uint8_t bwpPosition,
147 uint8_t bwpId) const
148{
149 NS_LOG_FUNCTION(this);
150 bwp->m_centralFrequency = lowerFreq + bwpPosition * bwOfBwp + bwOfBwp / 2;
151 bwp->m_lowerFrequency = lowerFreq + bwpPosition * bwOfBwp;
152 bwp->m_higherFrequency = lowerFreq + (bwpPosition + 1) * bwOfBwp - 1;
153 bwp->m_channelBandwidth = bwOfBwp;
154 bwp->m_bwpId = bwpId;
155 NS_LOG_INFO("Initialize the " << +bwpPosition << "st (or nd) BWP of BW " << bwOfBwp / 1e6
156 << " MHz, from " << lowerFreq / 1e6
157 << "MHz, resulting in: " << *bwp);
158}
159
160std::unique_ptr<ComponentCarrierInfo>
161CcBwpCreator::CreateCc(double ccBandwidth,
162 double lowerFreq,
163 uint8_t ccPosition,
164 uint8_t ccId,
165 uint8_t bwpNumber,
167{
168 // Create a CC with a single BWP
169 std::unique_ptr<ComponentCarrierInfo> cc(new ComponentCarrierInfo());
170 InitializeCc(cc, ccBandwidth, lowerFreq, ccPosition, ccId);
171
172 double bwpBandwidth = ccBandwidth / bwpNumber;
173
174 for (uint8_t i = 0; i < bwpNumber; ++i)
175 {
176 std::unique_ptr<BandwidthPartInfo> bwp(new BandwidthPartInfo());
177 InitializeBwp(bwp, bwpBandwidth, cc->m_lowerFrequency, i, m_bandwidthPartCounter++);
178 bwp->m_scenario = scenario;
179 bool ret = cc->AddBwp(std::move(bwp));
180 NS_ASSERT(ret);
181 }
182
183 // bwp is not longer a valid pointer
184 return cc;
185}
186
187OperationBandInfo
189{
190 NS_LOG_FUNCTION(this);
191 NS_LOG_INFO("Creating an op band formed by " << +conf.m_numCc << " contiguous CC"
192 << " central freq "
193 << conf.m_centralFrequency / 1e6 << " MHz with BW "
194 << conf.m_channelBandwidth / 1e6 << " MHz");
195
197 band.m_bandId = m_operationBandCounter++;
200 band.m_lowerFrequency = band.m_centralFrequency - (conf.m_channelBandwidth / 2.0);
202
203 NS_LOG_INFO("Resulting OpBand: " << band);
204
205 uint32_t maxCcBandwidth = 198e6;
206
207 if (conf.m_centralFrequency > 6e9)
208 {
209 maxCcBandwidth = 396e6;
210 }
211
212 double ccBandwidth = std::min(static_cast<double>(maxCcBandwidth),
213 static_cast<double>(conf.m_channelBandwidth) / conf.m_numCc);
214
215 for (uint8_t ccPosition = 0; ccPosition < conf.m_numCc; ++ccPosition)
216 {
217 bool ret = band.AddCc(CreateCc(ccBandwidth,
218 band.m_lowerFrequency,
219 ccPosition,
220 m_componentCarrierCounter++,
221 conf.m_numBwp,
222 conf.m_scenario));
223 NS_ASSERT(ret);
224 }
225
226 NS_ASSERT(band.m_cc.size() == conf.m_numCc);
227 return band;
228}
229
232 const std::vector<SimpleOperationBandConf>& configuration)
233{
235 band.m_bandId = m_operationBandCounter++;
236
237 for (const auto& conf : configuration)
238 {
239 NS_ASSERT(conf.m_numBwp == 1);
240 band.AddCc(CreateCc(conf.m_channelBandwidth,
241 band.m_lowerFrequency,
242 0,
243 m_componentCarrierCounter++,
244 conf.m_numBwp,
245 conf.m_scenario));
246 }
247
248 return band;
249}
250
253 const std::vector<std::reference_wrapper<OperationBandInfo>>& operationBands)
254{
256
257 for (const auto& operationBand : operationBands)
258 {
259 auto v = operationBand.get().GetBwps();
260 ret.insert(ret.end(), std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
261 }
262
263 return ret;
264}
265
266void
267CcBwpCreator::PlotNrCaBwpConfiguration(const std::vector<OperationBandInfo*>& bands,
268 const std::string& filename)
269{
270 std::ofstream outFile;
271 outFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
272 if (!outFile.is_open())
273 {
274 NS_LOG_ERROR("Can't open file " << filename);
275 return;
276 }
277
278 // FIXME: I think I can do this with calling the gnuclass in ns3 by calling
279 // plot.AppendExtra (whatever gnu line string) (see gnuplot documentation
280 // in ns3
281
282 // Set the range for the x axis.
283 double minFreq = 100e9;
284 double maxFreq = 0;
285 for (const auto& band : bands)
286 {
287 if (band->m_lowerFrequency < minFreq)
288 {
289 minFreq = band->m_lowerFrequency;
290 }
291 if (band->m_higherFrequency > maxFreq)
292 {
293 maxFreq = band->m_higherFrequency;
294 }
295 }
296
297 outFile << "set term eps" << std::endl;
298 outFile << "set output \"" << filename << ".eps\"" << std::endl;
299 outFile << "set grid" << std::endl;
300
301 outFile << "set xrange [";
302 outFile << minFreq * 1e-6 - 1;
303 outFile << ":";
304 outFile << maxFreq * 1e-6 + 1;
305 outFile << "]";
306 outFile << std::endl;
307
308 outFile << "set yrange [1:100]" << std::endl;
309 outFile << "set xlabel \"f [MHz]\"" << std::endl;
310
311 uint16_t index = 1; //<! Index must be larger than zero for gnuplot
312 for (const auto& band : bands)
313 {
314 std::string label = "n";
315 uint16_t bandId = static_cast<uint16_t>(band->m_bandId);
316 label += std::to_string(bandId);
317 PlotFrequencyBand(outFile,
318 index,
319 band->m_lowerFrequency * 1e-6,
320 band->m_higherFrequency * 1e-6,
321 70,
322 90,
323 label);
324 index++;
325 for (auto& cc : band->m_cc)
326 {
327 uint16_t ccId = static_cast<uint16_t>(cc->m_ccId);
328 label = "CC" + std::to_string(ccId);
329 PlotFrequencyBand(outFile,
330 index,
331 cc->m_lowerFrequency * 1e-6,
332 cc->m_higherFrequency * 1e-6,
333 40,
334 60,
335 label);
336 index++;
337 for (auto& bwp : cc->m_bwp)
338 {
339 uint16_t bwpId = static_cast<uint16_t>(bwp->m_bwpId);
340 label = "BWP" + std::to_string(bwpId);
341 PlotFrequencyBand(outFile,
342 index,
343 bwp->m_lowerFrequency * 1e-6,
344 bwp->m_higherFrequency * 1e-6,
345 10,
346 30,
347 label);
348 index++;
349 }
350 }
351 }
352
353 outFile << "unset key" << std::endl;
354 outFile << "plot -x" << std::endl;
355}
356
357void
358CcBwpCreator::PlotLteCaConfiguration(const std::vector<OperationBandInfo*>& bands,
359 const std::string& filename)
360{
361 std::ofstream outFile;
362 outFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
363 if (!outFile.is_open())
364 {
365 NS_LOG_ERROR("Can't open file " << filename);
366 return;
367 }
368
369 // FIXME: I think I can do this with calling the gnuclass in ns3 and use
370 // plot.AppendExtra (whatever string);
371
372 double minFreq = 100e9;
373 double maxFreq = 0;
374 for (const auto& band : bands)
375 {
376 if (band->m_lowerFrequency < minFreq)
377 {
378 minFreq = band->m_lowerFrequency;
379 }
380 if (band->m_higherFrequency > maxFreq)
381 {
382 maxFreq = band->m_higherFrequency;
383 }
384 }
385
386 outFile << "set term eps" << std::endl;
387 outFile << "set output \"" << filename << ".eps\"" << std::endl;
388 outFile << "set grid" << std::endl;
389
390 outFile << "set xrange [";
391 outFile << minFreq * 1e-6 - 1;
392 outFile << ":";
393 outFile << maxFreq * 1e-6 + 1;
394 outFile << "]";
395 outFile << std::endl;
396
397 outFile << "set yrange [1:100]" << std::endl;
398 outFile << "set xlabel \"f [MHz]\"" << std::endl;
399
400 uint16_t index = 1; //<! Index must be larger than zero for gnuplot
401 for (const auto& band : bands)
402 {
403 std::string label = "n";
404 uint16_t bandId = static_cast<uint16_t>(band->m_bandId);
405 label += std::to_string(bandId);
406 PlotFrequencyBand(outFile,
407 index,
408 band->m_lowerFrequency * 1e-6,
409 band->m_higherFrequency * 1e-6,
410 70,
411 90,
412 label);
413 index++;
414 for (auto& cc : band->m_cc)
415 {
416 uint16_t ccId = static_cast<uint16_t>(cc->m_ccId);
417 label = "CC" + std::to_string(ccId);
418 PlotFrequencyBand(outFile,
419 index,
420 cc->m_lowerFrequency * 1e-6,
421 cc->m_higherFrequency * 1e-6,
422 40,
423 60,
424 label);
425 index++;
426 }
427 }
428
429 outFile << "unset key" << std::endl;
430 outFile << "plot -x" << std::endl;
431}
432
433void
434CcBwpCreator::PlotFrequencyBand(std::ofstream& outFile,
435 uint16_t index,
436 double xmin,
437 double xmax,
438 double ymin,
439 double ymax,
440 const std::string& label)
441{
442 outFile << "set object " << index << " rect from " << xmin << "," << ymin << " to " << xmax
443 << "," << ymax << " front fs empty " << std::endl;
444
445 outFile << "LABEL" << index << " = \"" << label << "\"" << std::endl;
446
447 outFile << "set label " << index << " at " << xmin << "," << (ymin + ymax) / 2 << " LABEL"
448 << index << std::endl;
449}
450
451BandwidthPartInfo::BandwidthPartInfo(uint8_t bwpId,
452 double centralFrequency,
453 double channelBandwidth,
454 enum Scenario scenario)
455 : m_bwpId(bwpId),
456 m_centralFrequency(centralFrequency),
457 m_channelBandwidth(channelBandwidth),
458 m_scenario(scenario)
459{
460 NS_ASSERT_MSG(centralFrequency > channelBandwidth / 2,
461 "Configuration error with channel bandwidth");
462 m_lowerFrequency = centralFrequency - channelBandwidth / 2;
463 m_higherFrequency = centralFrequency + channelBandwidth / 2;
464}
465
466std::string
468{
469 NS_LOG_FUNCTION(this);
470 static std::unordered_map<Scenario, std::string, std::hash<int>> lookupTable{
471 {RMa, "RMa"},
472 {RMa_LoS, "RMa"},
473 {RMa_nLoS, "RMa"},
474 {UMa, "UMa"},
475 {UMa_LoS, "UMa"},
476 {UMa_nLoS, "UMa"},
477 {UMi_StreetCanyon, "UMi-StreetCanyon"},
478 {UMi_StreetCanyon_LoS, "UMi-StreetCanyon"},
479 {UMi_StreetCanyon_nLoS, "UMi-StreetCanyon"},
480 {InH_OfficeOpen, "InH-OfficeOpen"},
481 {InH_OfficeOpen_LoS, "InH-OfficeOpen"},
482 {InH_OfficeOpen_nLoS, "InH-OfficeOpen"},
483 {InH_OfficeMixed, "InH-OfficeMixed"},
484 {InH_OfficeMixed_LoS, "InH-OfficeMixed"},
485 {InH_OfficeMixed_nLoS, "InH-OfficeMixed"},
486 {UMa_Buildings, "UMa"},
487 {UMi_Buildings, "UMi-StreetCanyon"},
488 {V2V_Highway, "V2V-Highway"},
489 {V2V_Urban, "V2V-Urban"},
490 {Custom, "Custom"},
491 };
492
493 return lookupTable[m_scenario];
494}
495
496std::ostream&
497operator<<(std::ostream& os, const ComponentCarrierInfo& item)
498{
499 os << "id: " << +item.m_ccId << " lower freq " << item.m_lowerFrequency / 1e6
500 << " MHz central freq " << item.m_centralFrequency / 1e6 << " MHz higher freq "
501 << item.m_higherFrequency / 1e6 << " MHz bw " << item.m_channelBandwidth / 1e6 << " MHz."
502 << std::endl;
503 for (const auto& bwp : item.m_bwp)
504 {
505 os << "\t\t" << *bwp << std::endl;
506 }
507 return os;
508}
509
510std::ostream&
511operator<<(std::ostream& os, const OperationBandInfo& item)
512{
513 os << "id: " << +item.m_bandId << " lower freq " << item.m_lowerFrequency / 1e6
514 << " MHz central freq " << item.m_centralFrequency / 1e6 << " MHz higher freq "
515 << item.m_higherFrequency / 1e6 << " MHz bw " << item.m_channelBandwidth / 1e6 << " MHz."
516 << std::endl;
517 for (const auto& cc : item.m_cc)
518 {
519 os << "\t" << *cc << std::endl;
520 }
521 return os;
522}
523
524std::ostream&
525operator<<(std::ostream& os, const BandwidthPartInfo& item)
526{
527 os << "id: " << +item.m_bwpId << " lower freq " << item.m_lowerFrequency / 1e6
528 << " MHz central freq " << item.m_centralFrequency / 1e6 << " MHz higher freq "
529 << item.m_higherFrequency / 1e6 << " MHz bw " << item.m_channelBandwidth / 1e6 << " MHz.";
530 return os;
531}
532
533} // namespace ns3
OperationBandInfo CreateOperationBandContiguousCc(const SimpleOperationBandConf &conf)
Create an operation band with the CC specified.
static BandwidthPartInfoPtrVector GetAllBwps(const std::vector< std::reference_wrapper< OperationBandInfo > > &operationBands)
Get all the BWP pointers from the specified vector of operation bands.
static void PlotLteCaConfiguration(const std::vector< OperationBandInfo * > &bands, const std::string &filename)
Plots the CA/BWP configuration using GNUPLOT. There must be a valid configuration.
static void PlotNrCaBwpConfiguration(const std::vector< OperationBandInfo * > &bands, const std::string &filename)
Plots the CA/BWP configuration using GNUPLOT. There must be a valid configuration.
OperationBandInfo CreateOperationBandNonContiguousCc(const std::vector< SimpleOperationBandConf > &configuration)
Creates an operation band with non-contiguous CC.
std::unique_ptr< BandwidthPartInfo > BandwidthPartInfoPtr
unique_ptr of BandwidthPartInfo
std::vector< std::reference_wrapper< BandwidthPartInfoPtr > > BandwidthPartInfoPtrVector
vector of unique_ptr of BandwidthPartInfo
std::unique_ptr< ComponentCarrierInfo > ComponentCarrierInfoPtr
unique_ptr of ComponentCarrierInfo
double m_lowerFrequency
BWP lower frequency.
std::string GetScenario() const
Retrieve a string version of the scenario.
double m_higherFrequency
BWP higher frequency.
Scenario
Different types for the propagation loss model of this bandwidth part.
@ UMi_Buildings
UMi_StreetCanyon with buildings.
@ Custom
User-defined custom scenario.
@ UMa_LoS
UMa where all the nodes will be in Line-of-Sight.
@ RMa_LoS
RMa where all the nodes will be in Line-of-Sight.
@ InH_OfficeOpen
InH_OfficeOpen.
@ InH_OfficeOpen_nLoS
indoor office where all the nodes will not be in Line-of-Sight
@ V2V_Highway
V2V_Highway.
@ RMa_nLoS
RMA where all the nodes will not be in Line-of-Sight.
@ InH_OfficeMixed_nLoS
indoor office where all the nodes will not be in Line-of-Sight
@ UMa_Buildings
UMa with buildings.
@ InH_OfficeOpen_LoS
indoor office where all the nodes will be in Line-of-Sight
@ UMa_nLoS
UMa where all the nodes will not be in Line-of-Sight.
@ UMi_StreetCanyon_LoS
UMi_StreetCanyon where all the nodes will be in Line-of-Sight.
@ InH_OfficeMixed
InH_OfficeMixed.
@ UMi_StreetCanyon
UMi_StreetCanyon.
@ InH_OfficeMixed_LoS
indoor office where all the nodes will be in Line-of-Sight
Minimum configuration requirements for a OperationBand.
uint8_t m_numCc
Number of CC in this OpBand.
uint8_t m_numBwp
Number of BWP per CC.
double m_channelBandwidth
Total Bandwidth of the operation band.
BandwidthPartInfo::Scenario m_scenario
Scenario.
Component carrier configuration element.
double m_higherFrequency
BWP higher frequency.
bool AddBwp(BandwidthPartInfoPtr &&bwp)
Adds a bandwidth part configuration to the carrier.
double m_lowerFrequency
BWP lower frequency.
std::vector< BandwidthPartInfoPtr > m_bwp
Space for BWP.
double m_channelBandwidth
BWP bandwidth.
double m_centralFrequency
BWP central frequency.
Operation band information structure.
double m_channelBandwidth
Operation band bandwidth.
BandwidthPartInfoPtr & GetBwpAt(uint32_t ccId, uint32_t bwpId) const
Get the BWP at the cc/bwp specified.
std::vector< ComponentCarrierInfoPtr > m_cc
Operation band component carriers.
BandwidthPartInfoPtrVector GetBwps() const
Get the list of all the BWPs to pass to NrHelper.
bool AddCc(ComponentCarrierInfoPtr &&cc)
Adds the component carrier definition given as an input reference to the current operation band confi...
double m_lowerFrequency
Operation band lower frequency.
double m_centralFrequency
Operation band central frequency.
double m_higherFrequency
Operation band higher frequency.
uint8_t m_bandId
Operation band id.