This example program can be used to experiment with spatial
// reuse mechanisms of 802.11ax.
//
// The geometry is as follows:
//
// STA1 STA1
// | |
// d1 | |d2
// | d3 |
// AP1 -----------AP2
//
// STA1 and AP1 are in one BSS (with color set to 1), while STA2 and AP2 are in
// another BSS (with color set to 2). The distances are configurable (d1 through d3).
//
// STA1 is continously transmitting data to AP1, while STA2 is continuously sending data to AP2.
// Each STA has configurable traffic loads (inter packet interval and packet size).
// It is also possible to configure TX power per node as well as their CCA-ED tresholds.
// OBSS_PD spatial reuse feature can be enabled (default) or disabled, and the OBSS_PD
// threshold can be set as well (default: -72 dBm).
// A simple Friis path loss model is used and a constant PHY rate is considered.
//
// In general, the program can be configured at run-time by passing command-line arguments.
// The following command will display all of the available run-time help options:
// ./ns3 run "wifi-spatial-reuse --help"
//
// According to the Wi-Fi models of ns-3.36 release, throughput with
// OBSS PD enabled (--enableObssPd=True) was roughly 6.5 Mbps, and with
// it disabled (--enableObssPd=False) was roughly 3.5 Mbps.
//
// This difference between those results is because OBSS_PD spatial
// reuse enables to ignore transmissions from another BSS when the
// received power is below the configured threshold, and therefore
// either defer during ongoing transmission or transmit at the same
// time.
//
// Note that, by default, this script configures a network using a
// channel bandwidth of 20 MHz. Changing this value alone (through
// the --channelWidth argument) without properly adjusting other
// parameters will void the effect of spatial reuse: since energy is
// measured over the 20 MHz primary channel regardless of the channel
// width, doubling the transmission bandwidth creates a 3 dB drop in
// the measured energy level (i.e., a halving of the measured
// energy). Because of this, when using the channelWidth argument
// users should also adjust the CCA-ED Thresholds (via --ccaEdTrSta1,
// --ccaEdTrSta2, --ccaEdTrAp1, and --ccaEdTrAp2), the Minimum RSSI
// for preamble detection (via --minimumRssi), and the OBSS PD
// Threshold (via --obssPdThreshold) appropriately. For instance,
// this can be accomplished for a channel width of 40 MHz by lowering
// all these values by 3 dB compared to their defaults.
//
// In addition, consider that adapting the adjustments shown above
// for an 80 MHz bandwidth (using a 6 dB threshold adjustment instead
// of 3 dB) will not produce any changes when enableObssPd is enabled
// or disabled. The cause for this is the insufficient amount of
// traffic that is generated by default in the example: increasing
// the bandwidth shortens the frame durations, and lowers the
// collision probability. Collisions between BSSs are a necessary
// condition to see the improvements brought by spatial reuse, and
// thus increasing the amount of generated traffic by setting the
// interval argument to a lower value is necessary to see the
// benefits of spatial reuse in this scenario. This can, for
// instance, be accomplished by setting --interval=0.0001.
//
#include "ns3/abort.h"
#include "ns3/command-line.h"
#include "ns3/config.h"
#include "ns3/string.h"
#include "ns3/double.h"
#include "ns3/spectrum-wifi-helper.h"
#include "ns3/ssid.h"
#include "ns3/mobility-helper.h"
#include "ns3/application-container.h"
#include "ns3/multi-model-spectrum-channel.h"
#include "ns3/wifi-net-device.h"
#include "ns3/ap-wifi-mac.h"
#include "ns3/he-configuration.h"
#include "ns3/packet-socket-helper.h"
#include "ns3/packet-socket-client.h"
#include "ns3/packet-socket-server.h"
using namespace ns3;
std::vector<uint32_t> bytesReceived (4);
uint32_t
ContextToNodeId (std::string context)
{
std::string sub = context.substr (10);
uint32_t pos = sub.find ("/Device");
return atoi (sub.substr (0, pos).c_str ());
}
void
SocketRx (std::string context, Ptr<const Packet> p, const Address &addr)
{
uint32_t nodeId = ContextToNodeId (context);
bytesReceived[nodeId] += p->GetSize ();
}
int
main (int argc, char *argv[])
{
double duration = 10.0; // seconds
double d1 = 30.0; // meters
double d2 = 30.0; // meters
double d3 = 30.0; // meters
double d4 = 30.0; // meters
double d5 = 150.0; // meters
double powSta1 = 10.0; // dBm
double powSta2 = 10.0; // dBm
double powSta3 = 10.0; // dBm
double powSta4 = 10.0; // dBm
double powAp1 = 21.0; // dBm
double powAp2 = 21.0; // dBm
double ccaEdTrSta1 = -62; // dBm
double ccaEdTrSta2 = -62; // dBm
double ccaEdTrSta3 = -62; // dBm
double ccaEdTrSta4 = -62; // dBm
double ccaEdTrAp1 = -62; // dBm
double ccaEdTrAp2 = -62; // dBm
double minimumRssi = -82; // dBm
int channelBandwidth = 20; // MHz
uint32_t payloadSize = 1500; // bytes
uint32_t mcs = 0; // MCS value
double interval = 0.001; // seconds
bool enableObssPd = true;
double obssPdThreshold = -72.0; // dBm
CommandLine cmd (__FILE__);
cmd.AddValue ("duration", "Duration of simulation (s)", duration);
cmd.AddValue ("interval", "Inter packet interval (s)", interval);
cmd.AddValue ("enableObssPd", "Enable/disable OBSS_PD", enableObssPd);
cmd.AddValue ("d1", "Distance between STA1 and AP1 (m)", d1);
cmd.AddValue ("d2", "Distance between STA2 and AP2 (m)", d2);
cmd.AddValue ("d3", "Distance between STA3 and AP1 (m)", d3);
cmd.AddValue ("d4", "Distance between STA4 and AP2 (m)", d4);
cmd.AddValue ("d5", "Distance between AP1 and AP2 (m)", d5);
cmd.AddValue ("powSta1", "Power of STA1 (dBm)", powSta1);
cmd.AddValue ("powSta2", "Power of STA2 (dBm)", powSta2);
cmd.AddValue ("powSta3", "Power of STA3 (dBm)", powSta3);
cmd.AddValue ("powSta4", "Power of STA4 (dBm)", powSta4);
cmd.AddValue ("powAp1", "Power of AP1 (dBm)", powAp1);
cmd.AddValue ("powAp2", "Power of AP2 (dBm)", powAp2);
cmd.AddValue ("ccaEdTrSta1", "CCA-ED Threshold of STA1 (dBm)", ccaEdTrSta1);
cmd.AddValue ("ccaEdTrSta2", "CCA-ED Threshold of STA2 (dBm)", ccaEdTrSta2);
cmd.AddValue ("ccaEdTrSta3", "CCA-ED Threshold of STA3 (dBm)", ccaEdTrSta3);
cmd.AddValue ("ccaEdTrSta4", "CCA-ED Threshold of STA4 (dBm)", ccaEdTrSta4);
cmd.AddValue ("ccaEdTrAp1", "CCA-ED Threshold of AP1 (dBm)", ccaEdTrAp1);
cmd.AddValue ("ccaEdTrAp2", "CCA-ED Threshold of AP2 (dBm)", ccaEdTrAp2);
cmd.AddValue ("minimumRssi", "Minimum RSSI for the ThresholdPreambleDetectionModel", minimumRssi);
cmd.AddValue ("channelBandwidth", "Bandwidth of the channel in MHz [20, 40, or 80]", channelBandwidth);
cmd.AddValue ("obssPdThreshold", "Threshold for the OBSS PD Algorithm", obssPdThreshold);
cmd.AddValue ("mcs", "The constant MCS value to transmit HE PPDUs", mcs);
cmd.Parse (argc, argv);
NodeContainer wifiStaNodes;
wifiStaNodes.Create (4);
NodeContainer wifiApNodes;
wifiApNodes.Create (2);
SpectrumWifiPhyHelper spectrumPhy;
Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel> ();
Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel> ();
spectrumChannel->AddPropagationLossModel (lossModel);
Ptr<ConstantSpeedPropagationDelayModel> delayModel = CreateObject<ConstantSpeedPropagationDelayModel> ();
spectrumChannel->SetPropagationDelayModel (delayModel);
spectrumPhy.SetChannel (spectrumChannel);
spectrumPhy.SetErrorRateModel ("ns3::YansErrorRateModel");
switch (channelBandwidth)
{
case 20:
spectrumPhy.Set ("ChannelSettings", StringValue ("{36, 20, BAND_5GHZ, 0}"));
break;
case 40:
spectrumPhy.Set ("ChannelSettings", StringValue ("{62, 40, BAND_5GHZ, 0}"));
break;
case 80:
spectrumPhy.Set ("ChannelSettings", StringValue ("{171, 80, BAND_5GHZ, 0}"));
break;
default:
NS_ABORT_MSG ("Unrecognized channel bandwidth: " << channelBandwidth);
break;
}
spectrumPhy.SetPreambleDetectionModel ("ns3::ThresholdPreambleDetectionModel",
"MinimumRssi", DoubleValue (minimumRssi));
WifiHelper wifi;
wifi.SetStandard (WIFI_STANDARD_80211ax);
if (enableObssPd)
{
wifi.SetObssPdAlgorithm ("ns3::ConstantObssPdAlgorithm",
"ObssPdLevel", DoubleValue (obssPdThreshold));
}
WifiMacHelper mac;
std::ostringstream oss;
oss << "HeMcs" << mcs;
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
"DataMode", StringValue (oss.str ()),
"ControlMode", StringValue (oss.str ()));
// wifi.SetRemoteStationManager ("ns3::MistrelHtWifiManager");
spectrumPhy.Set ("TxPowerStart", DoubleValue (powSta1));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powSta1));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrSta1));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
Ssid ssidA = Ssid ("A");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssidA));
NetDeviceContainer staDeviceA = wifi.Install (spectrumPhy, mac, wifiStaNodes.Get (0));
spectrumPhy.Set ("TxPowerStart", DoubleValue (powAp1));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powAp1));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrAp1));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssidA));
NetDeviceContainer apDeviceA = wifi.Install (spectrumPhy, mac, wifiApNodes.Get (0));
Ptr<WifiNetDevice> apDevice = apDeviceA.Get (0)->GetObject<WifiNetDevice> ();
Ptr<ApWifiMac> apWifiMac = apDevice->GetMac ()->GetObject<ApWifiMac> ();
if (enableObssPd)
{
apDevice->GetHeConfiguration ()->SetAttribute ("BssColor", UintegerValue (1));
}
spectrumPhy.Set ("TxPowerStart", DoubleValue (powSta3));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powSta3));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrSta3));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
Ssid ssidC = Ssid ("C");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssidC));
NetDeviceContainer staDeviceC = wifi.Install (spectrumPhy, mac, wifiStaNodes.Get (0));
spectrumPhy.Set ("TxPowerStart", DoubleValue (powAp1));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powAp1));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrAp1));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssidC));
NetDeviceContainer apDeviceC = wifi.Install (spectrumPhy, mac, wifiApNodes.Get (0));
Ptr<WifiNetDevice> ap3Device = apDeviceC.Get (0)->GetObject<WifiNetDevice> ();
apWifiMac = ap3Device->GetMac ()->GetObject<ApWifiMac> ();
if (enableObssPd)
{
ap3Device->GetHeConfiguration ()->SetAttribute ("BssColor", UintegerValue (1));
}
spectrumPhy.Set ("TxPowerStart", DoubleValue (powSta2));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powSta2));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrSta2));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
Ssid ssidB = Ssid ("B");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssidB));
NetDeviceContainer staDeviceB = wifi.Install (spectrumPhy, mac, wifiStaNodes.Get (1));
spectrumPhy.Set ("TxPowerStart", DoubleValue (powAp2));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powAp2));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrAp2));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssidB));
NetDeviceContainer apDeviceB = wifi.Install (spectrumPhy, mac, wifiApNodes.Get (1));
Ptr<WifiNetDevice> ap2Device = apDeviceB.Get (0)->GetObject<WifiNetDevice> ();
apWifiMac = ap2Device->GetMac ()->GetObject<ApWifiMac> ();
if (enableObssPd)
{
ap2Device->GetHeConfiguration ()->SetAttribute ("BssColor", UintegerValue (2));
}
spectrumPhy.Set ("TxPowerStart", DoubleValue (powSta4));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powSta4));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrSta4));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
Ssid ssidD = Ssid ("D");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssidD));
NetDeviceContainer staDeviceD = wifi.Install (spectrumPhy, mac, wifiStaNodes.Get (1));
spectrumPhy.Set ("TxPowerStart", DoubleValue (powAp2));
spectrumPhy.Set ("TxPowerEnd", DoubleValue (powAp2));
spectrumPhy.Set ("CcaEdThreshold", DoubleValue (ccaEdTrAp2));
spectrumPhy.Set ("RxSensitivity", DoubleValue (-92.0));
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssidD));
NetDeviceContainer apDeviceD = wifi.Install (spectrumPhy, mac, wifiApNodes.Get (1));
Ptr<WifiNetDevice> ap4Device = apDeviceD.Get (0)->GetObject<WifiNetDevice> ();
apWifiMac = ap4Device->GetMac ()->GetObject<ApWifiMac> ();
if (enableObssPd)
{
ap4Device->GetHeConfiguration ()->SetAttribute ("BssColor", UintegerValue (2));
}
MobilityHelper mobility;
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // AP1
positionAlloc->Add (Vector (d5, 0.0, 0.0)); // AP2
positionAlloc->Add (Vector (0.0, d1, 0.0)); // STA1
positionAlloc->Add (Vector (d5, d2, 0.0)); // STA2
positionAlloc->Add (Vector (d2, d1, 0.0)); // STA3
positionAlloc->Add (Vector (d5, -d2, 0.0)); // STA4
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.SetPositionAllocator (positionAlloc);
mobility.Install (wifiApNodes);
mobility.Install (wifiStaNodes);
PacketSocketHelper packetSocket;
packetSocket.Install (wifiApNodes);
packetSocket.Install (wifiStaNodes);
ApplicationContainer apps;
TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
//BSS 1
{
PacketSocketAddress socketAddr;
socketAddr.SetSingleDevice (staDeviceA.Get (0)->GetIfIndex ());
socketAddr.SetPhysicalAddress (apDeviceA.Get (0)->GetAddress ());
// socketAddr.SetSingleDevice (staDeviceC.Get (0)->GetIfIndex ());
//socketAddr.SetPhysicalAddress (apDeviceC.Get (0)->GetAddress ());
socketAddr.SetProtocol (1);
Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient> ();
client->SetRemote (socketAddr);
wifiStaNodes.Get (0)->AddApplication (client);
//wifiStaNodes.Get (3)->AddApplication (client);
client->SetAttribute ("PacketSize", UintegerValue (payloadSize));
client->SetAttribute ("MaxPackets", UintegerValue (0));
client->SetAttribute ("Interval", TimeValue (Seconds (interval)));
Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
server->SetLocal (socketAddr);
wifiApNodes.Get (0)->AddApplication (server);
}
// BSS 2
{
PacketSocketAddress socketAddr;
socketAddr.SetSingleDevice (staDeviceB.Get (0)->GetIfIndex ());
socketAddr.SetPhysicalAddress (apDeviceB.Get (0)->GetAddress ());
// socketAddr.SetSingleDevice (staDeviceD.Get (0)->GetIfIndex ());
//socketAddr.SetPhysicalAddress (apDeviceD.Get (0)->GetAddress ());
socketAddr.SetProtocol (1);
Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient> ();
client->SetRemote (socketAddr);
wifiStaNodes.Get (1)->AddApplication (client);
//wifiStaNodes.Get (4)->AddApplication (client);
client->SetAttribute ("PacketSize", UintegerValue (payloadSize));
client->SetAttribute ("MaxPackets", UintegerValue (0));
client->SetAttribute ("Interval", TimeValue (Seconds (interval)));
Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
server->SetLocal (socketAddr);
wifiApNodes.Get (1)->AddApplication (server);
}
//BSS 1
{
PacketSocketAddress socketAddr;
// socketAddr.SetSingleDevice (staDeviceA.Get (0)->GetIfIndex ());
// socketAddr.SetPhysicalAddress (apDeviceA.Get (0)->GetAddress ());
socketAddr.SetSingleDevice (staDeviceC.Get (0)->GetIfIndex ());
socketAddr.SetPhysicalAddress (apDeviceC.Get (0)->GetAddress ());
socketAddr.SetProtocol (1);
Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient> ();
client->SetRemote (socketAddr);
// wifiStaNodes.Get (0)->AddApplication (client);
wifiStaNodes.Get (3)->AddApplication (client);
client->SetAttribute ("PacketSize", UintegerValue (payloadSize));
client->SetAttribute ("MaxPackets", UintegerValue (0));
client->SetAttribute ("Interval", TimeValue (Seconds (interval)));
Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
server->SetLocal (socketAddr);
wifiApNodes.Get (0)->AddApplication (server);
}
// BSS 2
{
PacketSocketAddress socketAddr;
//socketAddr.SetSingleDevice (staDeviceB.Get (0)->GetIfIndex ());
//socketAddr.SetPhysicalAddress (apDeviceB.Get (0)->GetAddress ());
socketAddr.SetSingleDevice (staDeviceD.Get (0)->GetIfIndex ());
socketAddr.SetPhysicalAddress (apDeviceD.Get (0)->GetAddress ());
socketAddr.SetProtocol (1);
Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient> ();
client->SetRemote (socketAddr);
//wifiStaNodes.Get (1)->AddApplication (client);
wifiStaNodes.Get (4)->AddApplication (client);
client->SetAttribute ("PacketSize", UintegerValue (payloadSize));
client->SetAttribute ("MaxPackets", UintegerValue (0));
client->SetAttribute ("Interval", TimeValue (Seconds (interval)));
Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
server->SetLocal (socketAddr);
wifiApNodes.Get (1)->AddApplication (server);
}
Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx", MakeCallback (&SocketRx));
Simulator::Stop (Seconds (duration));
Simulator::Run ();
Simulator::Destroy ();
for (uint32_t i = 0; i < 2; i++)
{
double throughput = static_cast<double> (bytesReceived[2 + i]) * 8 / 1000 / 1000 / duration;
std::cout << "Throughput for BSS " << i + 1 << ": " << throughput << " Mbit/s" << std::endl;
}
return 0;
}