A Discrete-Event Network Simulator
API
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 
34 namespace ns3
35 {
36 
37 NS_LOG_COMPONENT_DEFINE("WifiSpectrumValueHelper");
38 
41 {
42  uint32_t m_centerFrequency;
43  uint16_t m_channelWidth;
44  uint32_t m_carrierSpacing;
45  uint16_t m_guardBandwidth;
46 };
47 
54 bool
56 {
57  return (
61  (a.m_carrierSpacing < b.m_carrierSpacing)) // to cover coexistence of 11ax with legacy case
62  || ((a.m_centerFrequency == b.m_centerFrequency) &&
64  (a.m_guardBandwidth <
65  b.m_guardBandwidth))); // to cover 2.4 GHz case, where DSSS coexists with OFDM
66 }
67 
68 static std::map<WifiSpectrumModelId, Ptr<SpectrumModel>>
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));
119  g_wifiSpectrumModelMap.insert(std::pair<WifiSpectrumModelId, Ptr<SpectrumModel>>(key, ret));
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 
563 void
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 
768 void
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 
784 double
786 {
787  return std::pow(10.0, 0.1 * (dBm - 30.0));
788 }
789 
790 double
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 
805 bool
806 operator<(const FrequencyRange& left, const FrequencyRange& right)
807 {
808  return left.minFrequency < right.minFrequency;
809 }
810 
811 bool
812 operator==(const FrequencyRange& left, const FrequencyRange& right)
813 {
814  return (left.minFrequency == right.minFrequency) && (left.maxFrequency == right.maxFrequency);
815 }
816 
817 bool
818 operator!=(const FrequencyRange& left, const FrequencyRange& right)
819 {
820  return !(left == right);
821 }
822 
823 std::ostream&
824 operator<<(std::ostream& os, const FrequencyRange& freqRange)
825 {
826  os << "[" << freqRange.minFrequency << " MHz - " << freqRange.maxFrequency << " MHz]";
827  return os;
828 }
829 
830 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
double f(double x, void *params)
Definition: 80211b.c:70
#define max(a, b)
Definition: 80211b.c:42
size_t GetNumBands() const
SpectrumModelUid_t GetUid() const
Values::const_iterator ConstValuesBegin() const
Values::iterator ValuesBegin()
Bands::const_iterator ConstBandsBegin() const
Ptr< const SpectrumModel > GetSpectrumModel() const
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:678
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:157
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
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
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)