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