A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
107using namespace ns3;
108
109std::vector<uint32_t> bytesReceived(4);
110std::ofstream g_resetFile1;
111std::ofstream g_resetFile2;
112
114ContextToNodeId(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
121void
122SocketRx(std::string context, Ptr<const Packet> p, const Address& addr)
123{
124 uint32_t nodeId = ContextToNodeId(context);
125 bytesReceived[nodeId] += p->GetSize();
126}
127
128void
129ResetTrace(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
156int
157main(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));
373
375
376 for (uint32_t i = 0; i < 2; i++)
377 {
378 const auto throughput = bytesReceived[2 + i] * 8.0 / 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:164
bool TraceConnect(std::string name, std::string context, const CallbackBase &cb)
Connect a TraceSource to a Callback with a context.
Definition: object-base.cc:337
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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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
AttributeValue implementation for Ssid.
Definition: ssid.h:96
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
AttributeValue implementation for Time.
Definition: nstime.h:1406
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.
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:551
void SetPreambleDetectionModel(std::string type, Args &&... args)
Helper function used to set the preamble detection model.
Definition: wifi-helper.h:587
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:978
#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:1319
@ 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:706
ns cmd
Definition: second.py:40
ns wifi
Definition: third.py:95
ns mac
Definition: third.py:92
ns mobility
Definition: third.py:105
ns wifiStaNodes
Definition: third.py:84
uint32_t bytesReceived
Counter of the received bytes.
Definition: object-names.cc:36
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::ofstream g_resetFile1
void SocketRx(std::string context, Ptr< const Packet > p, const Address &addr)