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