A Discrete-Event Network Simulator
API
wifi-spatial-reuse.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 University of Washington
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
18  */
19 
20 //
21 // This example program can be used to experiment with spatial
22 // reuse mechanisms of 802.11ax.
23 //
24 // The geometry is as follows:
25 //
26 // STA1 STA2
27 // | |
28 // d1 | |d2
29 // | d3 |
30 // AP1 -----------AP2
31 //
32 // STA1 and AP1 are in one BSS (with color set to 1), while STA2 and AP2 are in
33 // another BSS (with color set to 2). The distances are configurable (d1 through d3).
34 //
35 // STA1 is continuously transmitting data to AP1, while STA2 is continuously sending data to AP2.
36 // Each STA has configurable traffic loads (inter packet interval and packet size).
37 // It is also possible to configure TX power per node as well as their CCA-ED thresholds.
38 // OBSS_PD spatial reuse feature can be enabled (default) or disabled, and the OBSS_PD
39 // threshold can be set as well (default: -72 dBm).
40 // A simple Friis path loss model is used and a constant PHY rate is considered.
41 //
42 // In general, the program can be configured at run-time by passing command-line arguments.
43 // The following command will display all of the available run-time help options:
44 // ./ns3 run "wifi-spatial-reuse --help"
45 //
46 // According to the Wi-Fi models of ns-3.36 release, throughput with
47 // OBSS PD enabled (--enableObssPd=True) was roughly 6.5 Mbps, and with
48 // it disabled (--enableObssPd=False) was roughly 3.5 Mbps.
49 //
50 // This difference between those results is because OBSS_PD spatial
51 // reuse enables to ignore transmissions from another BSS when the
52 // received power is below the configured threshold, and therefore
53 // either defer during ongoing transmission or transmit at the same
54 // time.
55 //
56 // Note that, by default, this script configures a network using a
57 // channel width of 20 MHz. Changing this value alone (through
58 // the --channelWidth argument) without properly adjusting other
59 // parameters will void the effect of spatial reuse: since energy is
60 // measured over the 20 MHz primary channel regardless of the channel
61 // width, doubling the transmission bandwidth creates a 3 dB drop in
62 // the measured energy level (i.e., a halving of the measured
63 // energy). Because of this, when using the channelWidth argument
64 // users should also adjust the CCA-ED Thresholds (via --ccaEdTrSta1,
65 // --ccaEdTrSta2, --ccaEdTrAp1, and --ccaEdTrAp2), the Minimum RSSI
66 // for preamble detection (via --minimumRssi), and the OBSS PD
67 // Threshold (via --obssPdThreshold) appropriately. For instance,
68 // this can be accomplished for a channel width of 40 MHz by lowering
69 // all these values by 3 dB compared to their defaults.
70 //
71 // In addition, consider that adapting the adjustments shown above
72 // for an 80 MHz channel width (using a 6 dB threshold adjustment instead
73 // of 3 dB) will not produce any changes when enableObssPd is enabled
74 // or disabled. The cause for this is the insufficient amount of
75 // traffic that is generated by default in the example: increasing
76 // the channel width shortens the frame durations, and lowers the
77 // collision probability. Collisions between BSSs are a necessary
78 // condition to see the improvements brought by spatial reuse, and
79 // thus increasing the amount of generated traffic by setting the
80 // interval argument to a lower value is necessary to see the
81 // benefits of spatial reuse in this scenario. This can, for
82 // instance, be accomplished by setting --interval=0.0001.
83 //
84 // Spatial reuse reset events are traced in two text files:
85 // - wifi-spatial-reuse-resets-bss-1.txt (for STA 1)
86 // - wifi-spatial-reuse-resets-bss-2.txt (for STA 2)
87 
88 #include "ns3/abort.h"
89 #include "ns3/ap-wifi-mac.h"
90 #include "ns3/application-container.h"
91 #include "ns3/command-line.h"
92 #include "ns3/config.h"
93 #include "ns3/double.h"
94 #include "ns3/he-configuration.h"
95 #include "ns3/he-phy.h"
96 #include "ns3/mobility-helper.h"
97 #include "ns3/multi-model-spectrum-channel.h"
98 #include "ns3/obss-pd-algorithm.h"
99 #include "ns3/packet-socket-client.h"
100 #include "ns3/packet-socket-helper.h"
101 #include "ns3/packet-socket-server.h"
102 #include "ns3/spectrum-wifi-helper.h"
103 #include "ns3/ssid.h"
104 #include "ns3/string.h"
105 #include "ns3/wifi-net-device.h"
106 
107 using namespace ns3;
108 
109 std::vector<uint32_t> bytesReceived(4);
110 std::ofstream g_resetFile1;
111 std::ofstream g_resetFile2;
112 
113 uint32_t
114 ContextToNodeId(std::string context)
115 {
116  std::string sub = context.substr(10);
117  uint32_t pos = sub.find("/Device");
118  return std::stoi(sub.substr(0, pos));
119 }
120 
121 void
122 SocketRx(std::string context, Ptr<const Packet> p, const Address& addr)
123 {
124  uint32_t nodeId = ContextToNodeId(context);
125  bytesReceived[nodeId] += p->GetSize();
126 }
127 
128 void
129 ResetTrace(std::string context,
130  uint8_t bssColor,
131  double rssiDbm,
132  bool powerRestricted,
133  double txPowerMaxDbmSiso,
134  double txPowerMaxDbmMimo)
135 {
136  if (context == "1")
137  {
138  g_resetFile1 << Simulator::Now().GetSeconds() << " bssColor: " << +bssColor
139  << " rssiDbm: " << rssiDbm << " powerRestricted: " << powerRestricted
140  << " txPowerMaxDbmSiso: " << txPowerMaxDbmSiso
141  << " txPowerMaxDbmMimo: " << txPowerMaxDbmMimo << std::endl;
142  }
143  else if (context == "2")
144  {
145  g_resetFile2 << Simulator::Now().GetSeconds() << " bssColor: " << +bssColor
146  << " rssiDbm: " << rssiDbm << " powerRestricted: " << powerRestricted
147  << " txPowerMaxDbmSiso: " << txPowerMaxDbmSiso
148  << " txPowerMaxDbmMimo: " << txPowerMaxDbmMimo << std::endl;
149  }
150  else
151  {
152  NS_FATAL_ERROR("Unknown context " << context);
153  }
154 }
155 
156 int
157 main(int argc, char* argv[])
158 {
159  double duration = 10.0; // seconds
160  double d1 = 30.0; // meters
161  double d2 = 30.0; // meters
162  double d3 = 150.0; // meters
163  double powSta1 = 10.0; // dBm
164  double powSta2 = 10.0; // dBm
165  double powAp1 = 21.0; // dBm
166  double powAp2 = 21.0; // dBm
167  double ccaEdTrSta1 = -62; // dBm
168  double ccaEdTrSta2 = -62; // dBm
169  double ccaEdTrAp1 = -62; // dBm
170  double ccaEdTrAp2 = -62; // dBm
171  double minimumRssi = -82; // dBm
172  int channelWidth = 20; // MHz
173  uint32_t payloadSize = 1500; // bytes
174  uint32_t mcs = 0; // MCS value
175  double interval = 0.001; // seconds
176  bool enableObssPd = true;
177  double obssPdThreshold = -72.0; // dBm
178 
179  CommandLine cmd(__FILE__);
180  cmd.AddValue("duration", "Duration of simulation (s)", duration);
181  cmd.AddValue("interval", "Inter packet interval (s)", interval);
182  cmd.AddValue("enableObssPd", "Enable/disable OBSS_PD", enableObssPd);
183  cmd.AddValue("d1", "Distance between STA1 and AP1 (m)", d1);
184  cmd.AddValue("d2", "Distance between STA2 and AP2 (m)", d2);
185  cmd.AddValue("d3", "Distance between AP1 and AP2 (m)", d3);
186  cmd.AddValue("powSta1", "Power of STA1 (dBm)", powSta1);
187  cmd.AddValue("powSta2", "Power of STA2 (dBm)", powSta2);
188  cmd.AddValue("powAp1", "Power of AP1 (dBm)", powAp1);
189  cmd.AddValue("powAp2", "Power of AP2 (dBm)", powAp2);
190  cmd.AddValue("ccaEdTrSta1", "CCA-ED Threshold of STA1 (dBm)", ccaEdTrSta1);
191  cmd.AddValue("ccaEdTrSta2", "CCA-ED Threshold of STA2 (dBm)", ccaEdTrSta2);
192  cmd.AddValue("ccaEdTrAp1", "CCA-ED Threshold of AP1 (dBm)", ccaEdTrAp1);
193  cmd.AddValue("ccaEdTrAp2", "CCA-ED Threshold of AP2 (dBm)", ccaEdTrAp2);
194  cmd.AddValue("minimumRssi",
195  "Minimum RSSI for the ThresholdPreambleDetectionModel",
196  minimumRssi);
197  cmd.AddValue("channelWidth", "Bandwidth of the channel in MHz [20, 40, or 80]", channelWidth);
198  cmd.AddValue("obssPdThreshold", "Threshold for the OBSS PD Algorithm", obssPdThreshold);
199  cmd.AddValue("mcs", "The constant MCS value to transmit HE PPDUs", mcs);
200  cmd.Parse(argc, argv);
201 
202  g_resetFile1.open("wifi-spatial-reuse-resets-bss-1.txt", std::ofstream::out);
203  g_resetFile2.open("wifi-spatial-reuse-resets-bss-2.txt", std::ofstream::out);
204 
206  wifiStaNodes.Create(2);
207 
208  NodeContainer wifiApNodes;
209  wifiApNodes.Create(2);
210 
211  SpectrumWifiPhyHelper spectrumPhy;
212  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
213  Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
214  spectrumChannel->AddPropagationLossModel(lossModel);
216  CreateObject<ConstantSpeedPropagationDelayModel>();
217  spectrumChannel->SetPropagationDelayModel(delayModel);
218 
219  spectrumPhy.SetChannel(spectrumChannel);
220  spectrumPhy.SetErrorRateModel("ns3::YansErrorRateModel");
221  switch (channelWidth)
222  {
223  case 20:
224  spectrumPhy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
225  break;
226  case 40:
227  spectrumPhy.Set("ChannelSettings", StringValue("{62, 40, BAND_5GHZ, 0}"));
228  break;
229  case 80:
230  spectrumPhy.Set("ChannelSettings", StringValue("{171, 80, BAND_5GHZ, 0}"));
231  break;
232  default:
233  NS_ABORT_MSG("Unrecognized channel width: " << channelWidth);
234  break;
235  }
236  spectrumPhy.SetPreambleDetectionModel("ns3::ThresholdPreambleDetectionModel",
237  "MinimumRssi",
238  DoubleValue(minimumRssi));
239 
241  wifi.SetStandard(WIFI_STANDARD_80211ax);
242  if (enableObssPd)
243  {
244  wifi.SetObssPdAlgorithm("ns3::ConstantObssPdAlgorithm",
245  "ObssPdLevel",
246  DoubleValue(obssPdThreshold));
247  }
248 
250  std::ostringstream oss;
251  oss << "HeMcs" << mcs;
252  wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
253  "DataMode",
254  StringValue(oss.str()),
255  "ControlMode",
256  StringValue(oss.str()));
257 
258  spectrumPhy.Set("TxPowerStart", DoubleValue(powSta1));
259  spectrumPhy.Set("TxPowerEnd", DoubleValue(powSta1));
260  spectrumPhy.Set("CcaEdThreshold", DoubleValue(ccaEdTrSta1));
261  spectrumPhy.Set("RxSensitivity", DoubleValue(-92.0));
262 
263  Ssid ssidA = Ssid("A");
264  mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssidA));
265  NetDeviceContainer staDeviceA = wifi.Install(spectrumPhy, mac, wifiStaNodes.Get(0));
266 
267  spectrumPhy.Set("TxPowerStart", DoubleValue(powAp1));
268  spectrumPhy.Set("TxPowerEnd", DoubleValue(powAp1));
269  spectrumPhy.Set("CcaEdThreshold", DoubleValue(ccaEdTrAp1));
270  spectrumPhy.Set("RxSensitivity", DoubleValue(-92.0));
271 
272  mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssidA));
273  NetDeviceContainer apDeviceA = wifi.Install(spectrumPhy, mac, wifiApNodes.Get(0));
274 
275  Ptr<WifiNetDevice> apDevice = apDeviceA.Get(0)->GetObject<WifiNetDevice>();
276  Ptr<ApWifiMac> apWifiMac = apDevice->GetMac()->GetObject<ApWifiMac>();
277  if (enableObssPd)
278  {
279  apDevice->GetHeConfiguration()->SetAttribute("BssColor", UintegerValue(1));
280  }
281 
282  spectrumPhy.Set("TxPowerStart", DoubleValue(powSta2));
283  spectrumPhy.Set("TxPowerEnd", DoubleValue(powSta2));
284  spectrumPhy.Set("CcaEdThreshold", DoubleValue(ccaEdTrSta2));
285  spectrumPhy.Set("RxSensitivity", DoubleValue(-92.0));
286 
287  Ssid ssidB = Ssid("B");
288  mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssidB));
289  NetDeviceContainer staDeviceB = wifi.Install(spectrumPhy, mac, wifiStaNodes.Get(1));
290 
291  spectrumPhy.Set("TxPowerStart", DoubleValue(powAp2));
292  spectrumPhy.Set("TxPowerEnd", DoubleValue(powAp2));
293  spectrumPhy.Set("CcaEdThreshold", DoubleValue(ccaEdTrAp2));
294  spectrumPhy.Set("RxSensitivity", DoubleValue(-92.0));
295 
296  mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssidB));
297  NetDeviceContainer apDeviceB = wifi.Install(spectrumPhy, mac, wifiApNodes.Get(1));
298 
299  Ptr<WifiNetDevice> ap2Device = apDeviceB.Get(0)->GetObject<WifiNetDevice>();
300  apWifiMac = ap2Device->GetMac()->GetObject<ApWifiMac>();
301  if (enableObssPd)
302  {
303  ap2Device->GetHeConfiguration()->SetAttribute("BssColor", UintegerValue(2));
304  }
305 
307  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
308  positionAlloc->Add(Vector(0.0, 0.0, 0.0)); // AP1
309  positionAlloc->Add(Vector(d3, 0.0, 0.0)); // AP2
310  positionAlloc->Add(Vector(0.0, d1, 0.0)); // STA1
311  positionAlloc->Add(Vector(d3, d2, 0.0)); // STA2
312  mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
313  mobility.SetPositionAllocator(positionAlloc);
314  mobility.Install(wifiApNodes);
315  mobility.Install(wifiStaNodes);
316 
317  PacketSocketHelper packetSocket;
318  packetSocket.Install(wifiApNodes);
319  packetSocket.Install(wifiStaNodes);
321 
322  // BSS 1
323  {
324  PacketSocketAddress socketAddr;
325  socketAddr.SetSingleDevice(staDeviceA.Get(0)->GetIfIndex());
326  socketAddr.SetPhysicalAddress(apDeviceA.Get(0)->GetAddress());
327  socketAddr.SetProtocol(1);
328  Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
329  client->SetRemote(socketAddr);
330  wifiStaNodes.Get(0)->AddApplication(client);
331  client->SetAttribute("PacketSize", UintegerValue(payloadSize));
332  client->SetAttribute("MaxPackets", UintegerValue(0));
333  client->SetAttribute("Interval", TimeValue(Seconds(interval)));
334  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
335  server->SetLocal(socketAddr);
336  wifiApNodes.Get(0)->AddApplication(server);
337  }
338 
339  // BSS 2
340  {
341  PacketSocketAddress socketAddr;
342  socketAddr.SetSingleDevice(staDeviceB.Get(0)->GetIfIndex());
343  socketAddr.SetPhysicalAddress(apDeviceB.Get(0)->GetAddress());
344  socketAddr.SetProtocol(1);
345  Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
346  client->SetRemote(socketAddr);
347  wifiStaNodes.Get(1)->AddApplication(client);
348  client->SetAttribute("PacketSize", UintegerValue(payloadSize));
349  client->SetAttribute("MaxPackets", UintegerValue(0));
350  client->SetAttribute("Interval", TimeValue(Seconds(interval)));
351  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
352  server->SetLocal(socketAddr);
353  wifiApNodes.Get(1)->AddApplication(server);
354  }
355 
356  Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx",
358 
359  // Obtain pointers to the ObssPdAlgorithm objects and hook trace sinks
360  // to the Reset trace source on each STA. Note that this trace connection
361  // cannot be done through the Config path system, so pointers are used.
362  auto deviceA = staDeviceA.Get(0)->GetObject<WifiNetDevice>();
363  auto hePhyA = DynamicCast<HePhy>(deviceA->GetPhy()->GetPhyEntity(WIFI_MOD_CLASS_HE));
364  // Pass in the context string "1" to allow the trace to distinguish objects
365  hePhyA->GetObssPdAlgorithm()->TraceConnect("Reset", "1", MakeCallback(&ResetTrace));
366  auto deviceB = staDeviceB.Get(0)->GetObject<WifiNetDevice>();
367  auto hePhyB = DynamicCast<HePhy>(deviceB->GetPhy()->GetPhyEntity(WIFI_MOD_CLASS_HE));
368  // Pass in the context string "2" to allow the trace to distinguish objects
369  hePhyB->GetObssPdAlgorithm()->TraceConnect("Reset", "2", MakeCallback(&ResetTrace));
370 
371  Simulator::Stop(Seconds(duration));
372  Simulator::Run();
373 
375 
376  for (uint32_t i = 0; i < 2; i++)
377  {
378  double throughput = static_cast<double>(bytesReceived[2 + i]) * 8 / 1000 / 1000 / duration;
379  std::cout << "Throughput for BSS " << i + 1 << ": " << throughput << " Mbit/s" << std::endl;
380  }
381 
382  g_resetFile1.close();
383  g_resetFile2.close();
384 
385  return 0;
386 }
a polymophic address class
Definition: address.h:101
Wi-Fi AP state machine.
Definition: ap-wifi-mac.h:65
holds a vector of ns3::Application pointers.
Parse command-line arguments.
Definition: command-line.h:232
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition: node.cc:169
bool TraceConnect(std::string name, std::string context, const CallbackBase &cb)
Connect a TraceSource to a Callback with a context.
Definition: object-base.cc:329
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Make it easy to create and manage PHY objects for the spectrum model.
void SetChannel(const Ptr< SpectrumChannel > channel)
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
Hold variables of type string.
Definition: string.h:56
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
Hold an unsigned integer type.
Definition: uinteger.h:45
helps to create WifiNetDevice objects
Definition: wifi-helper.h:324
create MAC layers for a ns3::WifiNetDevice.
Hold together all Wifi-related objects.
Ptr< WifiMac > GetMac() const
Ptr< HeConfiguration > GetHeConfiguration() const
void Set(std::string name, const AttributeValue &v)
Definition: wifi-helper.cc:163
void SetErrorRateModel(std::string type, Args &&... args)
Helper function used to set the error rate model.
Definition: wifi-helper.h:550
void SetPreambleDetectionModel(std::string type, Args &&... args)
Helper function used to set the preamble detection model.
Definition: wifi-helper.h:586
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:974
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
@ WIFI_STANDARD_80211ax
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
cmd
Definition: second.py:40
mac
Definition: third.py:92
wifi
Definition: third.py:95
mobility
Definition: third.py:105
wifiStaNodes
Definition: third.py:84
std::ofstream throughput
uint32_t ContextToNodeId(std::string context)
std::ofstream g_resetFile2
void ResetTrace(std::string context, uint8_t bssColor, double rssiDbm, bool powerRestricted, double txPowerMaxDbmSiso, double txPowerMaxDbmMimo)
std::vector< uint32_t > bytesReceived(4)
std::ofstream g_resetFile1
void SocketRx(std::string context, Ptr< const Packet > p, const Address &addr)