A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-spectrum-value-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 CTTC
3 * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
4 * Copyright (c) 2017 Orange Labs
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Authors: Nicola Baldo <nbaldo@cttc.es>
20 * Giuseppe Piro <g.piro@poliba.it>
21 * Rediet <getachew.redieteab@orange.com>
22 */
23
25
26#include "ns3/assert.h"
27#include "ns3/fatal-error.h"
28#include "ns3/log.h"
29
30#include <cmath>
31#include <map>
32#include <sstream>
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("WifiSpectrumValueHelper");
38
39///< Wifi Spectrum Model structure
41{
42 uint32_t m_centerFrequency; ///< center frequency (in MHz)
43 uint16_t m_channelWidth; ///< channel width (in MHz)
44 uint32_t m_carrierSpacing; ///< carrier spacing (in Hz)
45 uint16_t m_guardBandwidth; ///< guard band width (in MHz)
46};
47
48/**
49 * Less than operator
50 * \param a the first wifi spectrum to compare
51 * \param b the second wifi spectrum to compare
52 * \returns true if the first spectrum is less than the second spectrum
53 */
54bool
56{
57 return (
61 (a.m_carrierSpacing < b.m_carrierSpacing)) // to cover coexistence of 11ax with legacy case
65 b.m_guardBandwidth))); // to cover 2.4 GHz case, where DSSS coexists with OFDM
66}
67
68static std::map<WifiSpectrumModelId, Ptr<SpectrumModel>>
69 g_wifiSpectrumModelMap; ///< static initializer for the class
70
73 uint16_t channelWidth,
74 uint32_t carrierSpacing,
75 uint16_t guardBandwidth)
76{
77 NS_LOG_FUNCTION(centerFrequency << channelWidth << carrierSpacing << guardBandwidth);
79 WifiSpectrumModelId key{centerFrequency, channelWidth, carrierSpacing, guardBandwidth};
80 auto it = g_wifiSpectrumModelMap.find(key);
81 if (it != g_wifiSpectrumModelMap.end())
82 {
83 ret = it->second;
84 }
85 else
86 {
87 Bands bands;
88 double centerFrequencyHz = centerFrequency * 1e6;
89 double bandwidth = (channelWidth + (2.0 * guardBandwidth)) * 1e6;
90 // For OFDM, the center subcarrier is null (at center frequency)
91 auto numBands = static_cast<uint32_t>((bandwidth / carrierSpacing) + 0.5);
92 NS_ASSERT(numBands > 0);
93 if (numBands % 2 == 0)
94 {
95 // round up to the nearest odd number of subbands so that bands
96 // are symmetric around center frequency
97 numBands += 1;
98 }
99 NS_ASSERT_MSG(numBands % 2 == 1, "Number of bands should be odd");
100 NS_LOG_DEBUG("Num bands " << numBands << " band bandwidth " << carrierSpacing);
101 // lay down numBands/2 bands symmetrically around center frequency
102 // and place an additional band at center frequency
103 double startingFrequencyHz =
104 centerFrequencyHz - (numBands / 2 * carrierSpacing) - carrierSpacing / 2;
105 for (size_t i = 0; i < numBands; i++)
106 {
107 BandInfo info;
108 double f = startingFrequencyHz + (i * carrierSpacing);
109 info.fl = f;
110 f += carrierSpacing / 2;
111 info.fc = f;
112 f += carrierSpacing / 2;
113 info.fh = f;
114 NS_LOG_DEBUG("creating band " << i << " (" << info.fl << ":" << info.fc << ":"
115 << info.fh << ")");
116 bands.push_back(info);
117 }
118 ret = Create<SpectrumModel>(std::move(bands));
120 }
121 NS_LOG_LOGIC("returning SpectrumModel::GetUid () == " << ret->GetUid());
122 return ret;
123}
124
125// Power allocated to 71 center subbands out of 135 total subbands in the band
128 double txPowerW,
129 uint16_t guardBandwidth)
130{
131 NS_LOG_FUNCTION(centerFrequency << txPowerW << +guardBandwidth);
132 uint16_t channelWidth = 22; // DSSS channels are 22 MHz wide
133 uint32_t carrierSpacing = 312500;
134 Ptr<SpectrumValue> c = Create<SpectrumValue>(
135 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
136 auto vit = c->ValuesBegin();
137 auto bit = c->ConstBandsBegin();
138 auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
139 auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
140 NS_ASSERT(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1));
141 // Evenly spread power across 22 MHz
142 double txPowerPerBand = txPowerW / nAllocatedBands;
143 for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++, bit++)
144 {
145 if ((i >= (nGuardBands / 2)) && (i <= ((nGuardBands / 2) + nAllocatedBands - 1)))
146 {
147 *vit = txPowerPerBand / (bit->fh - bit->fl);
148 }
149 }
150 return c;
151}
152
155 uint16_t channelWidth,
156 double txPowerW,
157 uint16_t guardBandwidth,
158 double minInnerBandDbr,
159 double minOuterBandDbr,
160 double lowestPointDbr)
161{
162 NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
163 << minOuterBandDbr << lowestPointDbr);
164 uint32_t carrierSpacing = 0;
165 uint32_t innerSlopeWidth = 0;
166 switch (channelWidth)
167 {
168 case 20:
169 carrierSpacing = 312500;
170 innerSlopeWidth = static_cast<uint32_t>((2e6 / carrierSpacing) + 0.5); // [-11;-9] & [9;11]
171 break;
172 case 10:
173 carrierSpacing = 156250;
174 innerSlopeWidth =
175 static_cast<uint32_t>((1e6 / carrierSpacing) + 0.5); // [-5.5;-4.5] & [4.5;5.5]
176 break;
177 case 5:
178 carrierSpacing = 78125;
179 innerSlopeWidth =
180 static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-2.75;-2.5] & [2.5;2.75]
181 break;
182 default:
183 NS_FATAL_ERROR("Channel width " << channelWidth << " should be correctly set.");
184 return nullptr;
185 }
186
187 Ptr<SpectrumValue> c = Create<SpectrumValue>(
188 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
189 auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
190 auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
191 NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
192 "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
193 // 52 subcarriers (48 data + 4 pilot)
194 // skip guard band and 6 subbands, then place power in 26 subbands, then
195 // skip the center subband, then place power in 26 subbands, then skip
196 // the final 6 subbands and the guard band.
197 double txPowerPerBandW = txPowerW / 52;
198 NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
199 uint32_t start1 = (nGuardBands / 2) + 6;
200 uint32_t stop1 = start1 + 26 - 1;
201 uint32_t start2 = stop1 + 2;
202 uint32_t stop2 = start2 + 26 - 1;
203
204 // Build transmit spectrum mask
205 std::vector<WifiSpectrumBandIndices> subBands{
206 std::make_pair(start1, stop1),
207 std::make_pair(start2, stop2),
208 };
209 WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
211 subBands,
212 maskBand,
213 txPowerPerBandW,
214 nGuardBands,
215 innerSlopeWidth,
216 minInnerBandDbr,
217 minOuterBandDbr,
218 lowestPointDbr);
219 NormalizeSpectrumMask(c, txPowerW);
220 NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
221 return c;
222}
223
226 uint32_t centerFrequency,
227 uint16_t channelWidth,
228 double txPowerW,
229 uint16_t guardBandwidth,
230 double minInnerBandDbr,
231 double minOuterBandDbr,
232 double lowestPointDbr,
233 const std::vector<bool>& puncturedSubchannels)
234{
235 NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
236 << minOuterBandDbr << lowestPointDbr);
237 uint32_t carrierSpacing = 312500;
238 Ptr<SpectrumValue> c = Create<SpectrumValue>(
239 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
240 auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
241 auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
242 NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
243 "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
244 std::size_t num20MhzBands = channelWidth / 20;
245 std::size_t numAllocatedSubcarriersPer20MHz = 52;
246 NS_ASSERT(puncturedSubchannels.empty() || (puncturedSubchannels.size() == num20MhzBands));
247 double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
248 NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
249
250 std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
251 std::size_t numUnallocatedSubcarriersPer20MHz =
252 numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
253 std::vector<WifiSpectrumBandIndices>
254 subBands; // list of data/pilot-containing subBands (sent at 0dBr)
255 subBands.resize(num20MhzBands *
256 2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
257 uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
258 uint32_t stop;
259 uint8_t index = 0;
260 for (auto it = subBands.begin(); it != subBands.end();)
261 {
262 if (!puncturedSubchannels.empty() && puncturedSubchannels.at(index++))
263 {
264 // if subchannel is punctured, skip it and go the next one
265 NS_LOG_DEBUG("20 MHz subchannel " << +index << " is punctured");
266 it += 2;
267 continue;
268 }
269 stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
270 *it = std::make_pair(start, stop);
271 ++it;
272 start = stop + 2; // skip center subcarrier
273 stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
274 *it = std::make_pair(start, stop);
275 ++it;
276 start = stop + numUnallocatedSubcarriersPer20MHz;
277 }
278
279 // Prepare spectrum mask specific variables
280 auto innerSlopeWidth = static_cast<uint32_t>(
281 (2e6 / carrierSpacing) +
282 0.5); // size in number of subcarriers of the 0dBr<->20dBr slope (2MHz for HT/VHT)
283 WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
284
285 // Build transmit spectrum mask
287 subBands,
288 maskBand,
289 txPowerPerBandW,
290 nGuardBands,
291 innerSlopeWidth,
292 minInnerBandDbr,
293 minOuterBandDbr,
294 lowestPointDbr);
295 NormalizeSpectrumMask(c, txPowerW);
296 NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
297 return c;
298}
299
302 uint16_t channelWidth,
303 double txPowerW,
304 uint16_t guardBandwidth,
305 double minInnerBandDbr,
306 double minOuterBandDbr,
307 double lowestPointDbr)
308{
309 NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
310 << minOuterBandDbr << lowestPointDbr);
311 uint32_t carrierSpacing = 312500;
312 Ptr<SpectrumValue> c = Create<SpectrumValue>(
313 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
314 auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
315 auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
316 NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
317 "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
318 std::size_t num20MhzBands = channelWidth / 20;
319 std::size_t numAllocatedSubcarriersPer20MHz = 56;
320 double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
321 NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
322
323 std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
324 std::size_t numUnallocatedSubcarriersPer20MHz =
325 numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
326 std::vector<WifiSpectrumBandIndices>
327 subBands; // list of data/pilot-containing subBands (sent at 0dBr)
328 subBands.resize(num20MhzBands *
329 2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
330 uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
331 uint32_t stop;
332 for (auto it = subBands.begin(); it != subBands.end();)
333 {
334 stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
335 *it = std::make_pair(start, stop);
336 ++it;
337 start = stop + 2; // skip center subcarrier
338 stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
339 *it = std::make_pair(start, stop);
340 ++it;
341 start = stop + numUnallocatedSubcarriersPer20MHz;
342 }
343
344 // Prepare spectrum mask specific variables
345 auto innerSlopeWidth = static_cast<uint32_t>(
346 (2e6 / carrierSpacing) +
347 0.5); // size in number of subcarriers of the inner band (2MHz for HT/VHT)
348 WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
349
350 // Build transmit spectrum mask
352 subBands,
353 maskBand,
354 txPowerPerBandW,
355 nGuardBands,
356 innerSlopeWidth,
357 minInnerBandDbr,
358 minOuterBandDbr,
359 lowestPointDbr);
360 NormalizeSpectrumMask(c, txPowerW);
361 NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
362 return c;
363}
364
367 uint32_t centerFrequency,
368 uint16_t channelWidth,
369 double txPowerW,
370 uint16_t guardBandwidth,
371 double minInnerBandDbr,
372 double minOuterBandDbr,
373 double lowestPointDbr,
374 const std::vector<bool>& puncturedSubchannels)
375{
376 NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
377 << minOuterBandDbr << lowestPointDbr);
378 uint32_t carrierSpacing = 78125;
379 Ptr<SpectrumValue> c = Create<SpectrumValue>(
380 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
381 auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
382 auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
383 NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
384 "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
385 double txPowerPerBandW = 0.0;
386 uint32_t start1;
387 uint32_t stop1;
388 uint32_t start2;
389 uint32_t stop2;
390 uint32_t start3;
391 uint32_t stop3;
392 uint32_t start4;
393 uint32_t stop4;
394 // Prepare spectrum mask specific variables
395 auto innerSlopeWidth = static_cast<uint32_t>(
396 (1e6 / carrierSpacing) + 0.5); // size in number of subcarriers of the inner band
397 std::vector<WifiSpectrumBandIndices>
398 subBands; // list of data/pilot-containing subBands (sent at 0dBr)
399 WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
400 switch (channelWidth)
401 {
402 case 20:
403 // 242 subcarriers (234 data + 8 pilot)
404 txPowerPerBandW = txPowerW / 242;
405 innerSlopeWidth =
406 static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-10.25;-9.75] & [9.75;10.25]
407 // skip the guard band and 6 subbands, then place power in 121 subbands, then
408 // skip 3 DC, then place power in 121 subbands, then skip
409 // the final 5 subbands and the guard band.
410 start1 = (nGuardBands / 2) + 6;
411 stop1 = start1 + 121 - 1;
412 start2 = stop1 + 4;
413 stop2 = start2 + 121 - 1;
414 subBands.emplace_back(start1, stop1);
415 subBands.emplace_back(start2, stop2);
416 break;
417 case 40:
418 // 484 subcarriers (468 data + 16 pilot)
419 txPowerPerBandW = txPowerW / 484;
420 // skip the guard band and 12 subbands, then place power in 242 subbands, then
421 // skip 5 DC, then place power in 242 subbands, then skip
422 // the final 11 subbands and the guard band.
423 start1 = (nGuardBands / 2) + 12;
424 stop1 = start1 + 242 - 1;
425 start2 = stop1 + 6;
426 stop2 = start2 + 242 - 1;
427 subBands.emplace_back(start1, stop1);
428 subBands.emplace_back(start2, stop2);
429 break;
430 case 80:
431 // 996 subcarriers (980 data + 16 pilot)
432 txPowerPerBandW = txPowerW / 996;
433 // skip the guard band and 12 subbands, then place power in 498 subbands, then
434 // skip 5 DC, then place power in 498 subbands, then skip
435 // the final 11 subbands and the guard band.
436 start1 = (nGuardBands / 2) + 12;
437 stop1 = start1 + 498 - 1;
438 start2 = stop1 + 6;
439 stop2 = start2 + 498 - 1;
440 subBands.emplace_back(start1, stop1);
441 subBands.emplace_back(start2, stop2);
442 break;
443 case 160:
444 // 2 x 996 subcarriers (2 x 80 MHZ bands)
445 txPowerPerBandW = txPowerW / (2 * 996);
446 start1 = (nGuardBands / 2) + 12;
447 stop1 = start1 + 498 - 1;
448 start2 = stop1 + 6;
449 stop2 = start2 + 498 - 1;
450 start3 = stop2 + (2 * 12);
451 stop3 = start3 + 498 - 1;
452 start4 = stop3 + 6;
453 stop4 = start4 + 498 - 1;
454 subBands.emplace_back(start1, stop1);
455 subBands.emplace_back(start2, stop2);
456 subBands.emplace_back(start3, stop3);
457 subBands.emplace_back(start4, stop4);
458 break;
459 default:
460 NS_FATAL_ERROR("ChannelWidth " << channelWidth << " unsupported");
461 break;
462 }
463
464 // Create punctured bands
465 auto puncturedSlopeWidth =
466 static_cast<uint32_t>((500e3 / carrierSpacing) +
467 0.5); // size in number of subcarriers of the punctured slope band
468 std::vector<WifiSpectrumBandIndices> puncturedBands;
469 std::size_t subcarriersPerSuband = (20 * 1e6 / carrierSpacing);
470 uint32_t start = (nGuardBands / 2);
471 uint32_t stop = start + subcarriersPerSuband - 1;
472 for (auto puncturedSubchannel : puncturedSubchannels)
473 {
474 if (puncturedSubchannel)
475 {
476 puncturedBands.emplace_back(start, stop);
477 }
478 start = stop + 1;
479 stop = start + subcarriersPerSuband - 1;
480 }
481
482 // Build transmit spectrum mask
484 subBands,
485 maskBand,
486 txPowerPerBandW,
487 nGuardBands,
488 innerSlopeWidth,
489 minInnerBandDbr,
490 minOuterBandDbr,
491 lowestPointDbr,
492 puncturedBands,
493 puncturedSlopeWidth);
494 NormalizeSpectrumMask(c, txPowerW);
495 NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
496 return c;
497}
498
501 uint16_t channelWidth,
502 double txPowerW,
503 uint16_t guardBandwidth,
504 const WifiSpectrumBandIndices& ru)
505{
506 NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << ru.first
507 << ru.second);
508 uint32_t carrierSpacing = 78125;
509 Ptr<SpectrumValue> c = Create<SpectrumValue>(
510 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
511
512 // Build spectrum mask
513 auto vit = c->ValuesBegin();
514 auto bit = c->ConstBandsBegin();
515 double txPowerPerBandW = (txPowerW / (ru.second - ru.first + 1)); // FIXME: null subcarriers
516 uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
517 for (size_t i = 0; i < numBands; i++, vit++, bit++)
518 {
519 if (i < ru.first || i > ru.second) // outside the spectrum mask
520 {
521 *vit = 0.0;
522 }
523 else
524 {
525 *vit = (txPowerPerBandW / (bit->fh - bit->fl));
526 }
527 }
528
529 return c;
530}
531
534 uint16_t channelWidth,
535 uint32_t carrierSpacing,
536 double noiseFigure,
537 uint16_t guardBandwidth)
538{
539 Ptr<SpectrumModel> model =
540 GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth);
541 return CreateNoisePowerSpectralDensity(noiseFigure, model);
542}
543
546 Ptr<SpectrumModel> spectrumModel)
547{
548 NS_LOG_FUNCTION(noiseFigureDb << spectrumModel);
549
550 // see "LTE - From theory to practice"
551 // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure
552 const double kT_dBm_Hz = -174.0; // dBm/Hz
553 double kT_W_Hz = DbmToW(kT_dBm_Hz);
554 double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0);
555 double noisePowerSpectralDensity = kT_W_Hz * noiseFigureLinear;
556
557 Ptr<SpectrumValue> noisePsd = Create<SpectrumValue>(spectrumModel);
558 (*noisePsd) = noisePowerSpectralDensity;
559 NS_LOG_INFO("NoisePowerSpectralDensity has integrated power of " << Integral(*noisePsd));
560 return noisePsd;
561}
562
563void
566 const std::vector<WifiSpectrumBandIndices>& allocatedSubBands,
567 const WifiSpectrumBandIndices& maskBand,
568 double txPowerPerBandW,
569 uint32_t nGuardBands,
570 uint32_t innerSlopeWidth,
571 double minInnerBandDbr,
572 double minOuterBandDbr,
573 double lowestPointDbr,
574 const std::vector<WifiSpectrumBandIndices>& puncturedBands,
575 uint32_t puncturedSlopeWidth)
576{
577 NS_LOG_FUNCTION(c << allocatedSubBands.front().first << allocatedSubBands.back().second
578 << maskBand.first << maskBand.second << txPowerPerBandW << nGuardBands
579 << innerSlopeWidth << minInnerBandDbr << minOuterBandDbr << lowestPointDbr
580 << puncturedSlopeWidth);
581 uint32_t numSubBands = allocatedSubBands.size();
582 uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
583 uint32_t numMaskBands = maskBand.second - maskBand.first + 1;
584 NS_ASSERT(numSubBands && numBands && numMaskBands);
585 NS_LOG_LOGIC("Power per band " << txPowerPerBandW << "W");
586
587 // Different power levels
588 double txPowerRefDbm = (10.0 * std::log10(txPowerPerBandW * 1000.0));
589 double txPowerInnerBandMinDbm = txPowerRefDbm + minInnerBandDbr;
590 double txPowerMiddleBandMinDbm = txPowerRefDbm + minOuterBandDbr;
591 double txPowerOuterBandMinDbm =
592 txPowerRefDbm + lowestPointDbr; // TODO also take into account dBm/MHz constraints
593
594 // Different widths (in number of bands)
595 uint32_t outerSlopeWidth =
596 nGuardBands / 4; // nGuardBands is the total left+right guard band. The left/right outer
597 // part is half of the left/right guard band.
598 uint32_t middleSlopeWidth = outerSlopeWidth - (innerSlopeWidth / 2);
599 WifiSpectrumBandIndices outerBandLeft(
600 maskBand.first, // to handle cases where allocated channel is
601 // under WifiPhy configured channel width.
602 maskBand.first + outerSlopeWidth - 1);
603 WifiSpectrumBandIndices middleBandLeft(outerBandLeft.second + 1,
604 outerBandLeft.second + middleSlopeWidth);
605 WifiSpectrumBandIndices innerBandLeft(
606 allocatedSubBands.front().first - innerSlopeWidth,
607 allocatedSubBands.front().first -
608 1); // better to place slope based on allocated subcarriers
609 WifiSpectrumBandIndices flatJunctionLeft(
610 middleBandLeft.second + 1,
611 innerBandLeft.first - 1); // in order to handle shift due to guard subcarriers
612 WifiSpectrumBandIndices outerBandRight(
613 maskBand.second - outerSlopeWidth + 1,
614 maskBand.second); // start from outer edge to be able to compute flat junction width
615 WifiSpectrumBandIndices middleBandRight(outerBandRight.first - middleSlopeWidth,
616 outerBandRight.first - 1);
617 WifiSpectrumBandIndices innerBandRight(allocatedSubBands.back().second + 1,
618 allocatedSubBands.back().second + innerSlopeWidth);
619 WifiSpectrumBandIndices flatJunctionRight(innerBandRight.second + 1, middleBandRight.first - 1);
620 std::ostringstream ss;
621 ss << "outerBandLeft=[" << outerBandLeft.first << ";" << outerBandLeft.second << "] "
622 << "middleBandLeft=[" << middleBandLeft.first << ";" << middleBandLeft.second << "] "
623 << "flatJunctionLeft=[" << flatJunctionLeft.first << ";" << flatJunctionLeft.second << "] "
624 << "innerBandLeft=[" << innerBandLeft.first << ";" << innerBandLeft.second << "] "
625 << "subBands=[" << allocatedSubBands.front().first << ";" << allocatedSubBands.back().second
626 << "] ";
627 if (!puncturedBands.empty())
628 {
629 ss << "puncturedBands=[" << puncturedBands.front().first << ";"
630 << puncturedBands.back().second << "] ";
631 }
632 ss << "innerBandRight=[" << innerBandRight.first << ";" << innerBandRight.second << "] "
633 << "flatJunctionRight=[" << flatJunctionRight.first << ";" << flatJunctionRight.second
634 << "] "
635 << "middleBandRight=[" << middleBandRight.first << ";" << middleBandRight.second << "] "
636 << "outerBandRight=[" << outerBandRight.first << ";" << outerBandRight.second << "] ";
637 NS_LOG_DEBUG(ss.str());
638 NS_ASSERT(numMaskBands ==
639 ((allocatedSubBands.back().second - allocatedSubBands.front().first +
640 1) // equivalent to allocatedBand (includes notches and DC)
641 + 2 * (innerSlopeWidth + middleSlopeWidth + outerSlopeWidth) +
642 (flatJunctionLeft.second - flatJunctionLeft.first + 1) // flat junctions
643 + (flatJunctionRight.second - flatJunctionRight.first + 1)));
644
645 // Different slopes
646 double innerSlope = (-1 * minInnerBandDbr) / innerSlopeWidth;
647 double middleSlope = (-1 * (minOuterBandDbr - minInnerBandDbr)) / middleSlopeWidth;
648 double outerSlope = (txPowerMiddleBandMinDbm - txPowerOuterBandMinDbm) / outerSlopeWidth;
649 double puncturedSlope = (-1 * minInnerBandDbr) / puncturedSlopeWidth;
650
651 // Build spectrum mask
652 auto vit = c->ValuesBegin();
653 auto bit = c->ConstBandsBegin();
654 double txPowerW = 0.0;
655 double previousTxPowerW = 0.0;
656 for (size_t i = 0; i < numBands; i++, vit++, bit++)
657 {
658 if (i < maskBand.first || i > maskBand.second) // outside the spectrum mask
659 {
660 txPowerW = 0.0;
661 }
662 else if (i <= outerBandLeft.second &&
663 i >= outerBandLeft.first) // better to put greater first (less computation)
664 {
665 txPowerW = DbmToW(txPowerOuterBandMinDbm + ((i - outerBandLeft.first) * outerSlope));
666 }
667 else if (i <= middleBandLeft.second && i >= middleBandLeft.first)
668 {
669 txPowerW = DbmToW(txPowerMiddleBandMinDbm + ((i - middleBandLeft.first) * middleSlope));
670 }
671 else if (i <= flatJunctionLeft.second && i >= flatJunctionLeft.first)
672 {
673 txPowerW = DbmToW(txPowerInnerBandMinDbm);
674 }
675 else if (i <= innerBandLeft.second && i >= innerBandLeft.first)
676 {
677 txPowerW =
678 (!puncturedBands.empty() &&
679 (puncturedBands.front().first <= allocatedSubBands.front().first))
680 ? DbmToW(txPowerInnerBandMinDbm)
681 : // first 20 MHz band is punctured
682 DbmToW(txPowerInnerBandMinDbm + ((i - innerBandLeft.first) * innerSlope));
683 }
684 else if (i <= allocatedSubBands.back().second &&
685 i >= allocatedSubBands.front().first) // roughly in allocated band
686 {
687 bool insideSubBand = false;
688 for (uint32_t j = 0; !insideSubBand && j < numSubBands;
689 j++) // continue until inside a sub-band
690 {
691 insideSubBand =
692 (i <= allocatedSubBands[j].second) && (i >= allocatedSubBands[j].first);
693 }
694 if (insideSubBand)
695 {
696 bool insidePuncturedSubBand = false;
697 uint32_t j = 0;
698 for (; !insidePuncturedSubBand && j < puncturedBands.size();
699 j++) // continue until inside a punctured sub-band
700 {
701 insidePuncturedSubBand =
702 (i <= puncturedBands[j].second) && (i >= puncturedBands[j].first);
703 }
704 if (insidePuncturedSubBand)
705 {
706 uint32_t startPuncturedSlope =
707 (puncturedBands[puncturedBands.size() - 1].second -
708 puncturedSlopeWidth); // only consecutive subchannels can be punctured
709 if (i >= startPuncturedSlope)
710 {
711 txPowerW = DbmToW(txPowerInnerBandMinDbm +
712 ((i - startPuncturedSlope) * puncturedSlope));
713 }
714 else
715 {
716 txPowerW = std::max(DbmToW(txPowerInnerBandMinDbm),
717 DbmToW(txPowerRefDbm - ((i - puncturedBands[0].first) *
718 puncturedSlope)));
719 }
720 }
721 else
722 {
723 txPowerW = txPowerPerBandW;
724 }
725 }
726 else
727 {
728 txPowerW = DbmToW(txPowerInnerBandMinDbm);
729 }
730 }
731 else if (i <= innerBandRight.second && i >= innerBandRight.first)
732 {
733 // take min to handle the case where last 20 MHz band is punctured
734 txPowerW = std::min(
735 previousTxPowerW,
736 DbmToW(txPowerRefDbm - ((i - innerBandRight.first + 1) *
737 innerSlope))); // +1 so as to be symmetric with left slope
738 }
739 else if (i <= flatJunctionRight.second && i >= flatJunctionRight.first)
740 {
741 txPowerW = DbmToW(txPowerInnerBandMinDbm);
742 }
743 else if (i <= middleBandRight.second && i >= middleBandRight.first)
744 {
745 txPowerW = DbmToW(txPowerInnerBandMinDbm -
746 ((i - middleBandRight.first + 1) *
747 middleSlope)); // +1 so as to be symmetric with left slope
748 }
749 else if (i <= outerBandRight.second && i >= outerBandRight.first)
750 {
751 txPowerW = DbmToW(txPowerMiddleBandMinDbm -
752 ((i - outerBandRight.first + 1) *
753 outerSlope)); // +1 so as to be symmetric with left slope
754 }
755 else
756 {
757 NS_FATAL_ERROR("Should have handled all cases");
758 }
759 double txPowerDbr = 10 * std::log10(txPowerW / txPowerPerBandW);
760 NS_LOG_LOGIC(uint32_t(i) << " -> " << txPowerDbr);
761 *vit = txPowerW / (bit->fh - bit->fl);
762 previousTxPowerW = txPowerW;
763 }
764 NS_LOG_INFO("Added signal power to subbands " << allocatedSubBands.front().first << "-"
765 << allocatedSubBands.back().second);
766}
767
768void
770{
771 NS_LOG_FUNCTION(c << txPowerW);
772 // Normalize power so that total signal power equals transmit power
773 double currentTxPowerW = Integral(*c);
774 double normalizationRatio = currentTxPowerW / txPowerW;
775 NS_LOG_LOGIC("Current power: " << currentTxPowerW << "W vs expected power: " << txPowerW << "W"
776 << " -> ratio (C/E) = " << normalizationRatio);
777 auto vit = c->ValuesBegin();
778 for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++)
779 {
780 *vit = (*vit) / normalizationRatio;
781 }
782}
783
784double
786{
787 return std::pow(10.0, 0.1 * (dBm - 30.0));
788}
789
790double
792{
793 double powerWattPerHertz = 0.0;
794 auto valueIt = psd->ConstValuesBegin() + band.first;
795 auto end = psd->ConstValuesBegin() + band.second;
796 auto bandIt = psd->ConstBandsBegin() + band.first;
797 while (valueIt <= end)
798 {
799 powerWattPerHertz += *valueIt;
800 ++valueIt;
801 }
802 return powerWattPerHertz * (bandIt->fh - bandIt->fl);
803}
804
805bool
806operator<(const FrequencyRange& left, const FrequencyRange& right)
807{
808 return left.minFrequency < right.minFrequency;
809}
810
811bool
812operator==(const FrequencyRange& left, const FrequencyRange& right)
813{
814 return (left.minFrequency == right.minFrequency) && (left.maxFrequency == right.maxFrequency);
815}
816
817bool
818operator!=(const FrequencyRange& left, const FrequencyRange& right)
819{
820 return !(left == right);
821}
822
823std::ostream&
824operator<<(std::ostream& os, const FrequencyRange& freqRange)
825{
826 os << "[" << freqRange.minFrequency << " MHz - " << freqRange.maxFrequency << " MHz]";
827 return os;
828}
829
830} // namespace ns3
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static Ptr< SpectrumValue > CreateNoisePowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, uint32_t carrierSpacing, double noiseFigure, uint16_t guardBandwidth)
Create a power spectral density corresponding to the noise.
static Ptr< SpectrumValue > CreateDuplicated20MhzTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40, const std::vector< bool > &puncturedSubchannels=std::vector< bool >{})
Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20 MHz subcha...
static void CreateSpectrumMaskForOfdm(Ptr< SpectrumValue > c, const std::vector< WifiSpectrumBandIndices > &allocatedSubBands, const WifiSpectrumBandIndices &maskBand, double txPowerPerBandW, uint32_t nGuardBands, uint32_t innerSlopeWidth, double minInnerBandDbr, double minOuterbandDbr, double lowestPointDbr, const std::vector< WifiSpectrumBandIndices > &puncturedSubBands=std::vector< WifiSpectrumBandIndices >{}, uint32_t puncturedSlopeWidth=0)
Create a transmit power spectral density corresponding to OFDM transmit spectrum mask requirements fo...
static Ptr< SpectrumValue > CreateHtOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40)
Create a transmit power spectral density corresponding to OFDM High Throughput (HT) (802....
static Ptr< SpectrumValue > CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40)
Create a transmit power spectral density corresponding to OFDM (802.11a/g).
static Ptr< SpectrumModel > GetSpectrumModel(uint32_t centerFrequency, uint16_t channelWidth, uint32_t carrierSpacing, uint16_t guardBandwidth)
Return a SpectrumModel instance corresponding to the center frequency and channel width.
static Ptr< SpectrumValue > CreateDsssTxPowerSpectralDensity(uint32_t centerFrequency, double txPowerW, uint16_t guardBandwidth)
Create a transmit power spectral density corresponding to DSSS.
static double GetBandPowerW(Ptr< SpectrumValue > psd, const WifiSpectrumBandIndices &band)
Calculate the power of the specified band composed of uniformly-sized sub-bands.
static double DbmToW(double dbm)
Convert from dBm to Watts.
static void NormalizeSpectrumMask(Ptr< SpectrumValue > c, double txPowerW)
Normalize the transmit spectrum mask generated by CreateSpectrumMaskForOfdm so that the total transmi...
static Ptr< SpectrumValue > CreateHeMuOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, const WifiSpectrumBandIndices &ru)
Create a transmit power spectral density corresponding to the OFDMA part of HE TB PPDUs for a given R...
static Ptr< SpectrumValue > CreateHeOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40, const std::vector< bool > &puncturedSubchannels=std::vector< bool >{})
Create a transmit power spectral density corresponding to OFDM High Efficiency (HE) (802....
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool operator!=(Callback< R, Args... > a, Callback< R, Args... > b)
Inequality test.
Definition: callback.h:680
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:157
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
double Integral(const SpectrumValue &arg)
std::vector< BandInfo > Bands
Container of BandInfo.
std::pair< uint32_t, uint32_t > WifiSpectrumBandIndices
typedef for a pair of start and stop sub-band indices
bool operator<(const EventId &a, const EventId &b)
Definition: event-id.h:170
static std::map< WifiSpectrumModelId, Ptr< SpectrumModel > > g_wifiSpectrumModelMap
static initializer for the class
The building block of a SpectrumModel.
double fc
center frequency
double fl
lower limit of subband
double fh
upper limit of subband
Struct defining a frequency range between minFrequency (MHz) and maxFrequency (MHz).
uint16_t maxFrequency
the maximum frequency in MHz
uint16_t minFrequency
the minimum frequency in MHz
Wifi Spectrum Model structure.
uint32_t m_centerFrequency
center frequency (in MHz)
uint16_t m_guardBandwidth
guard band width (in MHz)
uint16_t m_channelWidth
channel width (in MHz)
uint32_t m_carrierSpacing
carrier spacing (in Hz)