From 9f1b4331eb209106d0251d38da206e253587e8fc Mon Sep 17 00:00:00 2001 From: Sebastien Deronne Date: Sat, 27 Apr 2019 20:50:03 +0000 Subject: [PATCH] wifi: Add first 802.11ax OBSS_PD SR algorithm --- CHANGES.html | 7 +- RELEASE_NOTES | 3 +- examples/wireless/80211n-mimo.cc | 2 +- .../wireless/power-adaptation-distance.cc | 4 +- .../wireless/power-adaptation-interference.cc | 4 +- examples/wireless/wifi-pcf.cc | 2 +- examples/wireless/wifi-spatial-reuse.cc | 287 ++++++++++ examples/wireless/wscript | 3 + src/netanim/model/animation-interface.cc | 2 +- src/netanim/model/animation-interface.h | 3 +- src/wifi/doc/source/wifi-design.rst | 39 +- src/wifi/doc/source/wifi-user.rst | 10 +- src/wifi/helper/wifi-helper.cc | 33 ++ src/wifi/helper/wifi-helper.h | 33 ++ src/wifi/model/channel-access-manager.cc | 6 + src/wifi/model/channel-access-manager.h | 1 + src/wifi/model/constant-obss-pd-algorithm.cc | 108 ++++ src/wifi/model/constant-obss-pd-algorithm.h | 66 +++ src/wifi/model/he-configuration.h | 1 + src/wifi/model/obss-pd-algorithm.cc | 111 ++++ src/wifi/model/obss-pd-algorithm.h | 99 ++++ src/wifi/model/spectrum-wifi-phy.cc | 5 +- src/wifi/model/sta-wifi-mac.h | 13 +- src/wifi/model/wifi-phy-state-helper.cc | 1 + src/wifi/model/wifi-phy.cc | 105 +++- src/wifi/model/wifi-phy.h | 42 +- src/wifi/model/wifi-tx-vector.cc | 11 +- src/wifi/model/wifi-tx-vector.h | 3 +- src/wifi/model/yans-wifi-phy.cc | 2 +- src/wifi/test/inter-bss-test-suite.cc | 509 ++++++++++++++++++ src/wifi/test/wifi-test.cc | 45 +- src/wifi/wscript | 5 + 32 files changed, 1484 insertions(+), 81 deletions(-) create mode 100644 examples/wireless/wifi-spatial-reuse.cc create mode 100644 src/wifi/model/constant-obss-pd-algorithm.cc create mode 100644 src/wifi/model/constant-obss-pd-algorithm.h create mode 100644 src/wifi/model/obss-pd-algorithm.cc create mode 100644 src/wifi/model/obss-pd-algorithm.h create mode 100644 src/wifi/test/inter-bss-test-suite.cc diff --git a/CHANGES.html b/CHANGES.html index 877858e17..705b94d05 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -62,9 +62,10 @@ us a note on ns-developers mailing list.

  • New attributes QosTxop::AddBaResponseTimeout and QosTxop::FailedAddBaTimeout have been added to set the timeout to wait for an ADDBA response after the ACK to the ADDBA request is received and to set the timeout after a failed BA agreement, respectively.
  • A new attribute QosTxop::UseExpliciteBarAfterMissedBlockAck has been added to specify whether explicit Block Ack Request should be sent upon missed Block Ack Response.
  • Added a new trace source EndOfHePreamble in WifiPhy for tracing end of preamble (after training fields) for received 802.11ax packets.
  • -
  • Added a new helper method to SpectrumWifiPhyHelper and YansWifiPhyHelper to set the frame capture model
  • -
  • Added a new helper method to SpectrumWifiPhyHelper and YansWifiPhyHelper to set the preamble detection model
  • -
  • Added a method to ObjectFactory to check whether a TypeId has been configured on the factory
  • +
  • Added a new helper method to SpectrumWifiPhyHelper and YansWifiPhyHelper to set the frame capture model.
  • +
  • Added a new helper method to SpectrumWifiPhyHelper and YansWifiPhyHelper to set the preamble detection model.
  • +
  • Added a method to ObjectFactory to check whether a TypeId has been configured on the factory.
  • +
  • Added a new helper method to WifiHelper to set the 802.11ax OBSS PD spatial reuse algorithm.
  • Changes to existing API:

    diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 1e5fb1d74..fdbb4b3fa 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -23,7 +23,8 @@ requirements (Note: not all features available on all platforms): New user-visible features ------------------------- -- (wifi) Preamble detection can now be modelled +- (wifi) Preamble detection can now be modelled. +- (wifi) 802.11ax spatial reuse is now supported. Bugs fixed ---------- diff --git a/examples/wireless/80211n-mimo.cc b/examples/wireless/80211n-mimo.cc index 697d9a6b2..4807c786e 100644 --- a/examples/wireless/80211n-mimo.cc +++ b/examples/wireless/80211n-mimo.cc @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: Sébastien Deronne + * Author: Sébastien Deronne */ // This example is used to validate 802.11n MIMO. diff --git a/examples/wireless/power-adaptation-distance.cc b/examples/wireless/power-adaptation-distance.cc index ca059268b..daf2de32c 100644 --- a/examples/wireless/power-adaptation-distance.cc +++ b/examples/wireless/power-adaptation-distance.cc @@ -117,7 +117,7 @@ class NodeStatistics public: NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas); - void PhyCallback (std::string path, Ptr packet); + void PhyCallback (std::string path, Ptr packet, double powerW); void RxCallback (std::string path, Ptr packet, const Address &from); void PowerCallback (std::string path, double oldPower, double newPower, Mac48Address dest); void RateCallback (std::string path, DataRate oldRate, DataRate newRate, Mac48Address dest); @@ -203,7 +203,7 @@ NodeStatistics::GetCalcTxTime (DataRate rate) } void -NodeStatistics::PhyCallback (std::string path, Ptr packet) +NodeStatistics::PhyCallback (std::string path, Ptr packet, double powerW) { WifiMacHeader head; packet->PeekHeader (head); diff --git a/examples/wireless/power-adaptation-interference.cc b/examples/wireless/power-adaptation-interference.cc index 9510ac5ae..9725a82d2 100644 --- a/examples/wireless/power-adaptation-interference.cc +++ b/examples/wireless/power-adaptation-interference.cc @@ -90,7 +90,7 @@ public: void CheckStatistics (double time); - void PhyCallback (std::string path, Ptr packet); + void PhyCallback (std::string path, Ptr packet, double powerW); void RxCallback (std::string path, Ptr packet, const Address &from); void PowerCallback (std::string path, double oldPower, double newPower, Mac48Address dest); void RateCallback (std::string path, DataRate oldRate, DataRate newRate, Mac48Address dest); @@ -202,7 +202,7 @@ NodeStatistics::GetCalcTxTime (DataRate rate) } void -NodeStatistics::PhyCallback (std::string path, Ptr packet) +NodeStatistics::PhyCallback (std::string path, Ptr packet, double powerW) { WifiMacHeader head; packet->PeekHeader (head); diff --git a/examples/wireless/wifi-pcf.cc b/examples/wireless/wifi-pcf.cc index ad03ea172..433426c7a 100644 --- a/examples/wireless/wifi-pcf.cc +++ b/examples/wireless/wifi-pcf.cc @@ -72,7 +72,7 @@ uint64_t m_countCfEndAck; uint64_t m_countDataNull; uint64_t m_countData; -void TxCallback (std::string context, Ptr p) +void TxCallback (std::string context, Ptr p, double txPowerW) { WifiMacHeader hdr; p->PeekHeader (hdr); diff --git a/examples/wireless/wifi-spatial-reuse.cc b/examples/wireless/wifi-spatial-reuse.cc new file mode 100644 index 000000000..cc1a8050b --- /dev/null +++ b/examples/wireless/wifi-spatial-reuse.cc @@ -0,0 +1,287 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +// +// 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: +// ./waf --run "wifi-spatial-reuse --help" +// +// By default, the script shows the benefit of the OBSS_PD spatial reuse script: +// ./waf --run wifi-spatial-reuse +// Throughput for BSS 1: 6.6468 Mbit/s +// Throughput for BSS 2: 6.6672 Mbit/s +// +// If one disables the OBSS_PD feature, a lower throughput is obtained per BSS: +// ./waf --run "wifi-spatial-reuse --enableObssPd=0" +// Throughput for BSS 1: 5.8692 Mbit/s +// Throughput for BSS 2: 5.9364 Mbit/ +// +// This difference between those results is because OBSS_PD spatial +// 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. +// + +#include "ns3/command-line.h" +#include "ns3/config.h" +#include "ns3/string.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 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 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 = 150.0; // meters + double powSta1 = 10.0; // dBm + double powSta2 = 10.0; // dBm + double powAp1 = 21.0; // dBm + double powAp2 = 21.0; // dBm + double ccaEdTrSta1 = -62; // dBm + double ccaEdTrSta2 = -62; // dBm + double ccaEdTrAp1 = -62; // dBm + double ccaEdTrAp2 = -62; // dBm + 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; + 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 AP1 and AP2 (m)", d3); + cmd.AddValue ("powSta1", "Power of STA1 (dBm)", powSta1); + cmd.AddValue ("powSta2", "Power of STA2 (dBm)", powSta2); + 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 ("ccaEdTrAp1", "CCA-ED Threshold of AP1 (dBm)", ccaEdTrAp1); + cmd.AddValue ("ccaEdTrAp2", "CCA-ED Threshold of AP2 (dBm)", ccaEdTrAp2); + cmd.AddValue ("mcs", "The constant MCS value to transmit HE PPDUs", mcs); + cmd.Parse (argc, argv); + + NodeContainer wifiStaNodes; + wifiStaNodes.Create (2); + + NodeContainer wifiApNodes; + wifiApNodes.Create (2); + + SpectrumWifiPhyHelper spectrumPhy = SpectrumWifiPhyHelper::Default (); + Ptr spectrumChannel = CreateObject (); + Ptr lossModel = CreateObject (); + spectrumChannel->AddPropagationLossModel (lossModel); + Ptr delayModel = CreateObject (); + spectrumChannel->SetPropagationDelayModel (delayModel); + + spectrumPhy.SetChannel (spectrumChannel); + spectrumPhy.SetErrorRateModel ("ns3::YansErrorRateModel"); + spectrumPhy.Set ("Frequency", UintegerValue (5180)); // channel 36 at 20 MHz + spectrumPhy.SetPreambleDetectionModel ("ns3::ThresholdPreambleDetectionModel"); + //TODO: add parameter to configure CCA-PD + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211ax_5GHZ); + 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 ())); + + 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 apDevice = apDeviceA.Get (0)->GetObject (); + Ptr apWifiMac = apDevice->GetMac ()->GetObject (); + if (enableObssPd) + { + apDevice->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 ap2Device = apDeviceB.Get (0)->GetObject (); + apWifiMac = ap2Device->GetMac ()->GetObject (); + if (enableObssPd) + { + ap2Device->GetHeConfiguration ()->SetAttribute ("BssColor", UintegerValue (2)); + } + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // AP1 + positionAlloc->Add (Vector (d3, 0.0, 0.0)); // AP2 + positionAlloc->Add (Vector (0.0, d1, 0.0)); // STA1 + positionAlloc->Add (Vector (d3, d2, 0.0)); // STA2 + 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.SetProtocol (1); + Ptr client = CreateObject (); + client->SetRemote (socketAddr); + wifiStaNodes.Get (0)->AddApplication (client); + client->SetAttribute ("PacketSize", UintegerValue (payloadSize)); + client->SetAttribute ("MaxPackets", UintegerValue (0)); + client->SetAttribute ("Interval", TimeValue (Seconds (interval))); + Ptr server = CreateObject (); + 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.SetProtocol (1); + Ptr client = CreateObject (); + client->SetRemote (socketAddr); + wifiStaNodes.Get (1)->AddApplication (client); + client->SetAttribute ("PacketSize", UintegerValue (payloadSize)); + client->SetAttribute ("MaxPackets", UintegerValue (0)); + client->SetAttribute ("Interval", TimeValue (Seconds (interval))); + Ptr server = CreateObject (); + 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 (bytesReceived[2 + i]) * 8 / 1000 / 1000 / duration; + std::cout << "Throughput for BSS " << i + 1 << ": " << throughput << " Mbit/s" << std::endl; + } + + return 0; +} diff --git a/examples/wireless/wscript b/examples/wireless/wscript index 839c545f4..3396e9fb3 100644 --- a/examples/wireless/wscript +++ b/examples/wireless/wscript @@ -115,3 +115,6 @@ def build(bld): obj = bld.create_ns3_program('wifi-pcf', ['wifi', 'applications']) obj.source = 'wifi-pcf.cc' + + obj = bld.create_ns3_program('wifi-spatial-reuse', ['wifi', 'applications']) + obj.source = 'wifi-spatial-reuse.cc' diff --git a/src/netanim/model/animation-interface.cc b/src/netanim/model/animation-interface.cc index b7372fc39..cb30fd99c 100644 --- a/src/netanim/model/animation-interface.cc +++ b/src/netanim/model/animation-interface.cc @@ -867,7 +867,7 @@ AnimationInterface::UanPhyGenRxTrace (std::string context, Ptr p) } void -AnimationInterface::WifiPhyTxBeginTrace (std::string context, Ptr p) +AnimationInterface::WifiPhyTxBeginTrace (std::string context, Ptr p, double txPowerW) { NS_LOG_FUNCTION (this); return GenericWirelessTxTrace (context, p, AnimationInterface::WIFI); diff --git a/src/netanim/model/animation-interface.h b/src/netanim/model/animation-interface.h index 28794a58f..29f073a10 100644 --- a/src/netanim/model/animation-interface.h +++ b/src/netanim/model/animation-interface.h @@ -1047,8 +1047,9 @@ private: * wifi Phy transmit begin trace function * \param context the context * \param p the packet + * \param txPowerW the tx power */ - void WifiPhyTxBeginTrace (std::string context, Ptr p); + void WifiPhyTxBeginTrace (std::string context, Ptr p, double txPowerW); /** * wifi Phy receive begin trace function * diff --git a/src/wifi/doc/source/wifi-design.rst b/src/wifi/doc/source/wifi-design.rst index 2d3f46709..576ac42f8 100644 --- a/src/wifi/doc/source/wifi-design.rst +++ b/src/wifi/doc/source/wifi-design.rst @@ -20,7 +20,7 @@ on the IEEE 802.11 standard [ieee80211]_. We will go into more detail below but |ns3| provides models for these aspects of 802.11: * basic 802.11 DCF with **infrastructure** and **adhoc** modes -* **802.11a**, **802.11b**, **802.11g**, **802.11n** (both 2.4 and 5 GHz bands), **802.11ac** and **802.11ax** Draft 1.0 (both 2.4 and 5 GHz bands) physical layers +* **802.11a**, **802.11b**, **802.11g**, **802.11n** (both 2.4 and 5 GHz bands), **802.11ac** and **802.11ax** (both 2.4 and 5 GHz bands) physical layers * **MSDU aggregation** and **MPDU aggregation** extensions of 802.11n, and both can be combined together (two-level aggregation) * QoS-based EDCA and queueing extensions of **802.11e** * the ability to use different propagation loss models and propagation delay models, @@ -164,10 +164,7 @@ combines the effect of thermal noise and of interference from other Wi-Fi packets. Moreover, interference from other technologies is not modeled. The following details pertain to the physical layer and channel models: -* 802.11ax is still in draft phase, not all functionalities are implemented yet -* 802.11ax does not contain any of the high-density improvement * 802.11ax MU-OFDMA is not supported -* 802.11ax can only be used with Constant rate control algorithm * 802.11ax only supports SU PPDU format * 802.11ac/ax MU-MIMO is not supported, and no more than 4 antennas can be configured * 802.11n/ac/ax beamforming is not supported @@ -704,6 +701,40 @@ The goal of the lookaround rate is to force minstrel to try higher rate than the For a more detailed information about minstrel, see [linuxminstrel]_. +802.11ax OBSS PD spatial reuse +############################## + +802.11ax mode supports OBSS PD spatial reuse feature. +OBSS PD stands for Overlapping Basic Service Set Preamble-Detection. +OBSS PD is an 802.11ax specific feature that allows a STA, under specific conditions, +to ignore an inter-BSS PPDU. + +OBSS PD Algorithm +################# + +``ObssPdAlgorithm`` is the base class of OBSS PD algorithms. +It implements the common functionalities. First, it makes sure the necessary callbacks are setup. +Second, when a PHY reset is requested by the algorithm, it performs the computation to determine the TX power +restrictions and informs the PHY object. + +The PHY keeps tracks of incoming requests from the MAC to get access to the channel. +If a request is received and if PHY reset(s) indicating TX power limitations occured +before a packet was transmitted, the next packet to be transmitted will be sent with +a reduced power. Otherwise, no TX power restrictions will be applied. + +Constant OBSS PD Algorithm +########################## + +Constant OBSS PD algorithm is a simple OBSS PD algorithm implemmented in the ``ConstantObssPdAlgorithm`` class. + +Once a HE preamble and its header have been received by the PHY, ``ConstantObssPdAlgorithm:: +ReceiveHeSig`` is triggered. +The algorithm then checks whether this is an OBSS frame by comparing its own BSS color with the BSS color of the received preamble. +If this is an OBSS frame, it compare the received RSSI with its configured OBSS PD level value. The PHY then gets reset to IDLE +state in case the received RSSI is lower than that constant OBSS PD level value, and is informed about a TX power restrictions. + +Note: since our model is based on a single threshold, the PHY only supports one restricted power level. + Modifying Wifi model #################### diff --git a/src/wifi/doc/source/wifi-user.rst b/src/wifi/doc/source/wifi-user.rst index 6c0bd5de1..5ba2b9fd6 100644 --- a/src/wifi/doc/source/wifi-user.rst +++ b/src/wifi/doc/source/wifi-user.rst @@ -736,7 +736,15 @@ In order to change parameters that are overwritten by ``WifiHelper::SetStandard` Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BasicBlockAckTimeout", TimeValue (MicroSeconds (basicBlockAckTimeout))); Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/CompressedBlockAckTimeout", TimeValue (MicroSeconds (compressedBlockAckTimeout))); -There are many |ns3| attributes that can be set on the above helpers to +The WifiHelper is also used to configure OBSS PD spatial reuse for 802.11ax. +The following line configure a WifiHelper to support OBSS PD spatial reuse +using the ``ConstantObssPdAlgorithm`` with a threshold set to -72 dBm:: + + WifiHelper wifi; + wifi.SetObssPdAlgorithm ("ns3::ConstantObssPdAlgorithm", + "ObssPdLevel", DoubleValue (-72.0)); + +There are many other |ns3| attributes that can be set on the above helpers to deviate from the default behavior; the example scripts show how to do some of this reconfiguration. diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index 8de1142cf..1b293a2b8 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -37,6 +37,7 @@ #include "ns3/ht-configuration.h" #include "ns3/vht-configuration.h" #include "ns3/he-configuration.h" +#include "ns3/obss-pd-algorithm.h" #include "wifi-helper.h" namespace ns3 { @@ -672,6 +673,29 @@ WifiHelper::SetRemoteStationManager (std::string type, m_stationManager.Set (n7, v7); } +void +WifiHelper::SetObssPdAlgorithm (std::string type, + std::string n0, const AttributeValue &v0, + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7) +{ + m_obssPdAlgorithm = ObjectFactory (); + m_obssPdAlgorithm.SetTypeId (type); + m_obssPdAlgorithm.Set (n0, v0); + m_obssPdAlgorithm.Set (n1, v1); + m_obssPdAlgorithm.Set (n2, v2); + m_obssPdAlgorithm.Set (n3, v3); + m_obssPdAlgorithm.Set (n4, v4); + m_obssPdAlgorithm.Set (n5, v5); + m_obssPdAlgorithm.Set (n6, v6); + m_obssPdAlgorithm.Set (n7, v7); +} + void WifiHelper::SetStandard (WifiPhyStandard standard) { @@ -720,6 +744,13 @@ WifiHelper::Install (const WifiPhyHelper &phyHelper, device->SetPhy (phy); device->SetRemoteStationManager (manager); node->AddDevice (device); + if ((m_standard >= WIFI_PHY_STANDARD_80211ax_2_4GHZ) && (m_obssPdAlgorithm.IsTypeIdSet ())) + + { + Ptr obssPdAlgorithm = m_obssPdAlgorithm.Create (); + device->AggregateObject (obssPdAlgorithm); + obssPdAlgorithm->ConnectWifiNetDevice (device); + } devices.Add (device); NS_LOG_DEBUG ("node=" << node << ", mob=" << node->GetObject ()); // Aggregate a NetDeviceQueueInterface object if a RegularWifiMac is installed @@ -807,6 +838,7 @@ WifiHelper::EnableLogComponents (void) LogComponentEnable ("BlockAckCache", LOG_LEVEL_ALL); LogComponentEnable ("BlockAckManager", LOG_LEVEL_ALL); LogComponentEnable ("CaraWifiManager", LOG_LEVEL_ALL); + LogComponentEnable ("ConstantObssPdAlgorithm", LOG_LEVEL_ALL); LogComponentEnable ("ConstantRateWifiManager", LOG_LEVEL_ALL); LogComponentEnable ("Txop", LOG_LEVEL_ALL); LogComponentEnable ("ChannelAccessManager", LOG_LEVEL_ALL); @@ -823,6 +855,7 @@ WifiHelper::EnableLogComponents (void) LogComponentEnable ("MpduAggregator", LOG_LEVEL_ALL); LogComponentEnable ("MsduAggregator", LOG_LEVEL_ALL); LogComponentEnable ("NistErrorRateModel", LOG_LEVEL_ALL); + LogComponentEnable ("ObssPdAlgorithm", LOG_LEVEL_ALL); LogComponentEnable ("OnoeWifiManager", LOG_LEVEL_ALL); LogComponentEnable ("ParfWifiManager", LOG_LEVEL_ALL); LogComponentEnable ("RegularWifiMac", LOG_LEVEL_ALL); diff --git a/src/wifi/helper/wifi-helper.h b/src/wifi/helper/wifi-helper.h index 742e33d71..b849565e3 100644 --- a/src/wifi/helper/wifi-helper.h +++ b/src/wifi/helper/wifi-helper.h @@ -338,6 +338,38 @@ public: std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + /** + * \param type the type of ns3::ObssPdAlgorithm to create. + * \param n0 the name of the attribute to set + * \param v0 the value of the attribute to set + * \param n1 the name of the attribute to set + * \param v1 the value of the attribute to set + * \param n2 the name of the attribute to set + * \param v2 the value of the attribute to set + * \param n3 the name of the attribute to set + * \param v3 the value of the attribute to set + * \param n4 the name of the attribute to set + * \param v4 the value of the attribute to set + * \param n5 the name of the attribute to set + * \param v5 the value of the attribute to set + * \param n6 the name of the attribute to set + * \param v6 the value of the attribute to set + * \param n7 the name of the attribute to set + * \param v7 the value of the attribute to set + * + * All the attributes specified in this method should exist + * in the requested algorithm. + */ + void SetObssPdAlgorithm (std::string type, + std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + /// Callback invoked to determine the MAC queue selected for a given packet typedef std::function)> SelectQueueCallback; @@ -436,6 +468,7 @@ protected: ObjectFactory m_stationManager; ///< station manager WifiPhyStandard m_standard; ///< wifi standard SelectQueueCallback m_selectQueueCallback; ///< select queue callback + ObjectFactory m_obssPdAlgorithm; ///< OBSS PD algorithm }; } //namespace ns3 diff --git a/src/wifi/model/channel-access-manager.cc b/src/wifi/model/channel-access-manager.cc index deaf07beb..af9b4d2e0 100644 --- a/src/wifi/model/channel-access-manager.cc +++ b/src/wifi/model/channel-access-manager.cc @@ -139,6 +139,7 @@ ChannelAccessManager::DoDispose (void) i->Dispose (); i = 0; } + m_phy = 0; } void @@ -148,6 +149,7 @@ ChannelAccessManager::SetupPhyListener (Ptr phy) NS_ASSERT (m_phyListener == 0); m_phyListener = new PhyListener (this); phy->RegisterListener (m_phyListener); + m_phy = phy; } void @@ -259,6 +261,10 @@ void ChannelAccessManager::RequestAccess (Ptr state, bool isCfPeriod) { NS_LOG_FUNCTION (this << state); + if (m_phy) + { + m_phy->NotifyChannelAccessRequested (); + } //Deny access if in sleep mode or off if (m_sleeping || m_off) { diff --git a/src/wifi/model/channel-access-manager.h b/src/wifi/model/channel-access-manager.h index f309a5e44..23219d44c 100644 --- a/src/wifi/model/channel-access-manager.h +++ b/src/wifi/model/channel-access-manager.h @@ -319,6 +319,7 @@ private: Time m_slot; //!< the slot time Time m_sifs; //!< the SIFS time PhyListener* m_phyListener; //!< the phy listener + Ptr m_phy; //!< Ptr to the PHY }; } //namespace ns3 diff --git a/src/wifi/model/constant-obss-pd-algorithm.cc b/src/wifi/model/constant-obss-pd-algorithm.cc new file mode 100644 index 000000000..10e68458a --- /dev/null +++ b/src/wifi/model/constant-obss-pd-algorithm.cc @@ -0,0 +1,108 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/config.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "constant-obss-pd-algorithm.h" +#include "sta-wifi-mac.h" +#include "wifi-utils.h" +#include "wifi-phy.h" +#include "wifi-net-device.h" +#include "he-configuration.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ConstantObssPdAlgorithm"); +NS_OBJECT_ENSURE_REGISTERED (ConstantObssPdAlgorithm); + +ConstantObssPdAlgorithm::ConstantObssPdAlgorithm () + : ObssPdAlgorithm () +{ + NS_LOG_FUNCTION (this); +} + +TypeId +ConstantObssPdAlgorithm::GetTypeId (void) +{ + static ns3::TypeId tid = ns3::TypeId ("ns3::ConstantObssPdAlgorithm") + .SetParent () + .SetGroupName ("Wifi") + .AddConstructor () + ; + return tid; +} + +void +ConstantObssPdAlgorithm::ConnectWifiNetDevice (const Ptr device) +{ + Ptr phy = device->GetPhy (); + phy->TraceConnectWithoutContext ("EndOfHePreamble", MakeCallback (&ConstantObssPdAlgorithm::ReceiveHeSig, this)); + ObssPdAlgorithm::ConnectWifiNetDevice (device); +} + +void +ConstantObssPdAlgorithm::ReceiveHeSig (HePreambleParameters params) +{ + NS_LOG_FUNCTION (this << +params.bssColor << WToDbm (params.rssiW)); + + Ptr mac = m_device->GetMac ()->GetObject(); + if (mac && !mac->IsAssociated ()) + { + NS_LOG_DEBUG ("This is not an associated STA: skip OBSS PD algorithm"); + return; + } + + Ptr heConfiguration = m_device->GetHeConfiguration (); + NS_ASSERT (heConfiguration); + UintegerValue bssColorAttribute; + heConfiguration->GetAttribute ("BssColor", bssColorAttribute); + uint8_t bssColor = bssColorAttribute.Get (); + + if (bssColor == 0) + { + NS_LOG_DEBUG ("BSS color is 0"); + return; + } + if (params.bssColor == 0) + { + NS_LOG_DEBUG ("Received BSS color is 0"); + return; + } + //TODO: SRP_AND_NON-SRG_OBSS-PD_PROHIBITED=1 => OBSS_PD SR is not allowed + + bool isObss = (bssColor != params.bssColor); + if (isObss) + { + if (WToDbm (params.rssiW) < m_obssPdLevel) + { + NS_LOG_DEBUG ("Frame is OBSS and RSSI " << WToDbm(params.rssiW) << " is below OBSS-PD level of " << m_obssPdLevel << "; reset PHY to IDLE"); + ResetPhy (params); + } + else + { + NS_LOG_DEBUG ("Frame is OBSS and RSSI is above OBSS-PD level"); + } + } +} + +} //namespace ns3 diff --git a/src/wifi/model/constant-obss-pd-algorithm.h b/src/wifi/model/constant-obss-pd-algorithm.h new file mode 100644 index 000000000..dd4759d52 --- /dev/null +++ b/src/wifi/model/constant-obss-pd-algorithm.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#ifndef CONSTANT_OBSS_PD_ALGORITHM_H +#define CONSTANT_OBSS_PD_ALGORITHM_H + +#include "obss-pd-algorithm.h" + +namespace ns3 { + +/** + * \brief Constant OBSS PD algorithm + * \ingroup wifi + * + * This constant OBSS_PD algorithm is a simple OBSS_PD algorithm which evalutes if a receiving + * signal should be accepted or rejected based on a constant threshold. + * + * Once a HE preamble and its header have been received by the PHY, the ReceiveHeSig method is + * triggered. The algorithm then checks whether this is an OBSS frame by comparing its own BSS + * color with the BSS color of the received preamble. If this is an OBSS frame, it compares the + * received RSSI with its configured OBSS_PD level value. The PHY then gets reset to IDLE state + * in case the received RSSI is lower than that constant OBSS PD level value, and is informed + * about TX power restrictions that might be applied to the next tranmission. + */ +class ConstantObssPdAlgorithm : public ObssPdAlgorithm +{ +public: + ConstantObssPdAlgorithm (); + + static TypeId GetTypeId (void); + + /** + * Connect the WifiNetDevice and setup eventual callbacks. + * + * \param device the WifiNetDevice + */ + void ConnectWifiNetDevice (const Ptr device); + + /** + * \param params the HE SIG parameters + * + * Evaluate the receipt of HE SIG. + */ + void ReceiveHeSig (HePreambleParameters params); +}; + +} //namespace ns3 + +#endif /* CONSTANT_OBSS_PD_ALGORITHM_H */ diff --git a/src/wifi/model/he-configuration.h b/src/wifi/model/he-configuration.h index 0e5f6d3e2..64d930f3e 100644 --- a/src/wifi/model/he-configuration.h +++ b/src/wifi/model/he-configuration.h @@ -21,6 +21,7 @@ #define HE_CONFIGURATION_H #include "ns3/object.h" +#include "ns3/nstime.h" namespace ns3 { diff --git a/src/wifi/model/obss-pd-algorithm.cc b/src/wifi/model/obss-pd-algorithm.cc new file mode 100644 index 000000000..0661dba77 --- /dev/null +++ b/src/wifi/model/obss-pd-algorithm.cc @@ -0,0 +1,111 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#include "ns3/log.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "obss-pd-algorithm.h" +#include "wifi-net-device.h" +#include "wifi-phy.h" +#include "wifi-utils.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ObssPdAlgorithm"); +NS_OBJECT_ENSURE_REGISTERED (ObssPdAlgorithm); + +TypeId +ObssPdAlgorithm::GetTypeId (void) +{ + static ns3::TypeId tid = ns3::TypeId ("ns3::ObssPdAlgorithm") + .SetParent () + .SetGroupName ("Wifi") + .AddAttribute ("ObssPdLevel", + "The current OBSS PD level.", + DoubleValue (-82.0), + MakeDoubleAccessor (&ObssPdAlgorithm::m_obssPdLevel), + MakeDoubleChecker (-101, -62)) + .AddAttribute ("ObssPdLevelMin", + "Minimum value (dBm) of OBSS PD level.", + DoubleValue (-82.0), + MakeDoubleAccessor (&ObssPdAlgorithm::m_obssPdLevelMin), + MakeDoubleChecker (-101, -62)) + .AddAttribute ("ObssPdLevelMax", + "Maximum value (dBm) of OBSS PD level.", + DoubleValue (-62.0), + MakeDoubleAccessor (&ObssPdAlgorithm::m_obssPdLevelMax), + MakeDoubleChecker (-101, -62)) + .AddAttribute ("TxPowerRefSiso", + "The SISO reference TX power level (dBm).", + DoubleValue (21), + MakeDoubleAccessor (&ObssPdAlgorithm::m_txPowerRefSiso), + MakeDoubleChecker ()) + .AddAttribute ("TxPowerRefMimo", + "The MIMO reference TX power level (dBm).", + DoubleValue (25), + MakeDoubleAccessor (&ObssPdAlgorithm::m_txPowerRefMimo), + MakeDoubleChecker ()) + .AddTraceSource ("Reset", "Trace CCA Reset event", + MakeTraceSourceAccessor (&ObssPdAlgorithm::m_resetEvent), + "ns3::ObssPdAlgorithm::ResetTracedCallback") + ; + return tid; +} + +void +ObssPdAlgorithm::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_device = 0; +} + +void +ObssPdAlgorithm::ConnectWifiNetDevice (const Ptr device) +{ + NS_LOG_FUNCTION (this << device); + m_device = device; +} + +void +ObssPdAlgorithm::ResetPhy (HePreambleParameters params) +{ + double txPowerMaxSiso = 0; + double txPowerMaxMimo = 0; + bool powerRestricted = false; + // Fetch my BSS color + Ptr heConfiguration = m_device->GetHeConfiguration (); + NS_ASSERT (heConfiguration); + UintegerValue bssColorAttribute; + heConfiguration->GetAttribute ("BssColor", bssColorAttribute); + uint8_t bssColor = bssColorAttribute.Get (); + NS_LOG_DEBUG ("My BSS color " << (uint16_t) bssColor << " received frame " << (uint16_t) params.bssColor); + + Ptr phy = m_device->GetPhy (); + if ((m_obssPdLevel > m_obssPdLevelMin) && (m_obssPdLevel <= m_obssPdLevelMax)) + { + txPowerMaxSiso = m_txPowerRefSiso - (m_obssPdLevel - m_obssPdLevelMin); + txPowerMaxMimo = m_txPowerRefMimo - (m_obssPdLevel - m_obssPdLevelMin); + powerRestricted = true; + } + m_resetEvent (bssColor, WToDbm (params.rssiW), powerRestricted, txPowerMaxSiso, txPowerMaxMimo); + phy->ResetCca (powerRestricted, txPowerMaxSiso, txPowerMaxMimo); +} + +} //namespace ns3 diff --git a/src/wifi/model/obss-pd-algorithm.h b/src/wifi/model/obss-pd-algorithm.h new file mode 100644 index 000000000..acf3bec55 --- /dev/null +++ b/src/wifi/model/obss-pd-algorithm.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sébastien Deronne + */ + +#ifndef OBSS_PD_ALGORITHM_H +#define OBSS_PD_ALGORITHM_H + +#include "ns3/object.h" +#include "ns3/traced-callback.h" +#include "he-configuration.h" + +namespace ns3 { + +struct HePreambleParameters; + +class WifiNetDevice; + +/** + * \brief OBSS PD algorithm interface + * \ingroup wifi-he + * + * This object provides the interface for all OBSS_PD algorithms + * and is designed to be subclassed. + * + * OBSS_PD stands for Overlapping Basic Service Set Preamble-Detection. + * OBSS_PD is an 802.11ax feature that allows a STA, under specific + * conditions, to ignore an inter-BSS PPDU. + */ +class ObssPdAlgorithm : public Object +{ +public: + static TypeId GetTypeId (void); + + /** + * Connect the WifiNetDevice and setup eventual callbacks. + * + * \param device the WifiNetDevice + */ + virtual void ConnectWifiNetDevice (const Ptr device); + + /** + * Reset PHY to IDLE. + * \param params HePreambleParameters causing PHY reset + */ + void ResetPhy (HePreambleParameters params); + + /** + * \param params the HE SIG parameters + * + * Evaluate the receipt of HE SIG. + */ + virtual void ReceiveHeSig (HePreambleParameters params) = 0; + + /** + * TracedCallback signature for OBSS_PD reset events. + * + * \param [in] bssColor The BSS color of frame triggering the reset + * \param [in] rssiDbm The RSSI (dBm) of frame triggering the reset + * \param [in] powerRestricted Whether a TX power restriction is triggered + * \param [in] txPowerMaxDbmSiso The SISO TX power restricted level (dBm) + * \param [in] txPowerMaxDbmMimo The MIMO TX power restricted level (dBm) + */ + typedef void (* ResetTracedCallback)(uint8_t bssColor, double rssiDbm, bool powerRestricted, double txPowerMaxDbmSiso, double txPowerMaxDbmMimo); + +protected: + virtual void DoDispose (void); + + Ptr m_device; ///< Pointer to the WifiNetDevice + double m_obssPdLevel; ///< Current OBSS PD level + + +private: + double m_obssPdLevelMin; ///< Minimum OBSS PD level + double m_obssPdLevelMax; ///< Maximum OBSS PD level + double m_txPowerRefSiso; ///< SISO reference TX power level + double m_txPowerRefMimo; ///< MIMO reference TX power level + + TracedCallback m_resetEvent; +}; + +} //namespace ns3 + +#endif /* OBSS_PD_ALGORITHM_H */ diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index 5abc5897b..ee6993946 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -313,8 +313,9 @@ SpectrumWifiPhy::GetCenterFrequencyForChannelWidth (WifiTxVector txVector) const void SpectrumWifiPhy::StartTx (Ptr packet, WifiTxVector txVector, Time txDuration) { - NS_LOG_DEBUG ("Start transmission: signal power before antenna gain=" << GetPowerDbm (txVector.GetTxPowerLevel ()) << "dBm"); - double txPowerWatts = DbmToW (GetPowerDbm (txVector.GetTxPowerLevel ()) + GetTxGain ()); + double txPowerDbm = GetTxPowerForTransmission (txVector) + GetTxGain (); + NS_LOG_DEBUG ("Start transmission: signal power before antenna gain=" << txPowerDbm << "dBm"); + double txPowerWatts = DbmToW (txPowerDbm); Ptr txPowerSpectrum = GetTxPowerSpectralDensity (GetCenterFrequencyForChannelWidth (txVector), txVector.GetChannelWidth (), txPowerWatts, txVector.GetMode ().GetModulationClass ()); Ptr txParams = Create (); txParams->duration = txDuration; diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index 0a82e39d0..8a4230fe6 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -143,6 +143,13 @@ public: */ void SetWifiPhy (const Ptr phy); + /** + * Return whether we are associated with an AP. + * + * \return true if we are associated with an AP, false otherwise + */ + bool IsAssociated (void) const; + private: /** @@ -250,12 +257,6 @@ private: * gathered while scanning. */ void ScanningTimeout (void); - /** - * Return whether we are associated with an AP. - * - * \return true if we are associated with an AP, false otherwise - */ - bool IsAssociated (void) const; /** * Return whether we are waiting for an association response from an AP. * diff --git a/src/wifi/model/wifi-phy-state-helper.cc b/src/wifi/model/wifi-phy-state-helper.cc index c60a624e8..d33b35ee0 100644 --- a/src/wifi/model/wifi-phy-state-helper.cc +++ b/src/wifi/model/wifi-phy-state-helper.cc @@ -576,6 +576,7 @@ WifiPhyStateHelper::SwitchFromRxAbort (void) NS_ASSERT (IsStateRx ()); NS_ASSERT (m_rxing); m_endRx = Simulator::Now (); + NotifyRxEndError (); DoSwitchFromRx (); NS_ASSERT (!IsStateRx ()); } diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index 902672cd9..e904b448e 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -1100,7 +1100,7 @@ WifiPhy::Configure80211ax (void) { Configure80211n (); } - + m_deviceMcsSet.push_back (WifiPhy::GetHeMcs0 ()); m_deviceMcsSet.push_back (WifiPhy::GetHeMcs1 ()); m_deviceMcsSet.push_back (WifiPhy::GetHeMcs2 ()); @@ -1513,6 +1513,8 @@ WifiPhy::GetChannelNumber (void) const bool WifiPhy::DoChannelSwitch (uint8_t nch) { + m_powerRestricted = false; + m_channelAccessRequested = false; if (!IsInitialized ()) { //this is not channel switch, this is initialization @@ -1537,10 +1539,10 @@ WifiPhy::DoChannelSwitch (uint8_t nch) case WifiPhyState::CCA_BUSY: case WifiPhyState::IDLE: if (m_endPreambleDetectionEvent.IsRunning ()) - { - m_endPreambleDetectionEvent.Cancel (); - m_endRxEvent.Cancel (); - } + { + m_endPreambleDetectionEvent.Cancel (); + m_endRxEvent.Cancel (); + } goto switchChannel; break; case WifiPhyState::SLEEP: @@ -1571,6 +1573,8 @@ switchChannel: bool WifiPhy::DoFrequencySwitch (uint16_t frequency) { + m_powerRestricted = false; + m_channelAccessRequested = false; if (!IsInitialized ()) { //this is not channel switch, this is initialization @@ -1595,10 +1599,10 @@ WifiPhy::DoFrequencySwitch (uint16_t frequency) case WifiPhyState::CCA_BUSY: case WifiPhyState::IDLE: if (m_endPreambleDetectionEvent.IsRunning ()) - { - m_endPreambleDetectionEvent.Cancel (); - m_endRxEvent.Cancel (); - } + { + m_endPreambleDetectionEvent.Cancel (); + m_endRxEvent.Cancel (); + } goto switchFrequency; break; case WifiPhyState::SLEEP: @@ -1630,6 +1634,8 @@ void WifiPhy::SetSleepMode (void) { NS_LOG_FUNCTION (this); + m_powerRestricted = false; + m_channelAccessRequested = false; switch (m_state->GetState ()) { case WifiPhyState::TX: @@ -1662,6 +1668,8 @@ void WifiPhy::SetOffMode (void) { NS_LOG_FUNCTION (this); + m_powerRestricted = false; + m_channelAccessRequested = false; m_endPlcpRxEvent.Cancel (); m_endRxEvent.Cancel (); m_endPreambleDetectionEvent.Cancel (); @@ -2047,7 +2055,7 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txVector, uint16_t freq double Nes = 1; //todo: improve logic to reduce the number of if cases //todo: extend to NSS > 4 for VHT rates - if (payloadMode == GetHtMcs21() + if (payloadMode == GetHtMcs21 () || payloadMode == GetHtMcs22 () || payloadMode == GetHtMcs23 () || payloadMode == GetHtMcs28 () @@ -2241,8 +2249,8 @@ WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txVector, uint16_t freq else if (mpdutype == NORMAL_MPDU || mpdutype == SINGLE_MPDU) { //Not an A-MPDU or single MPDU (i.e. the current payload contains both service and padding) - // The number of OFDM symbols in the data field when BCC encoding - // is used is given in equation 19-32 of the IEEE 802.11-2016 standard. + //The number of OFDM symbols in the data field when BCC encoding + //is used is given in equation 19-32 of the IEEE 802.11-2016 standard. numSymbols = lrint (stbc * ceil ((16 + size * 8.0 + 6.0 * Nes) / (stbc * numDataBitsPerSymbol))); } else @@ -2329,19 +2337,19 @@ WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txVector, uint16_t fre } void -WifiPhy::NotifyTxBegin (Ptr packet) +WifiPhy::NotifyTxBegin (Ptr packet, double txPowerW) { if (IsAmpdu (packet)) { std::list> mpdus = MpduAggregator::PeekMpdus (packet); for (auto & mpdu : mpdus) { - m_phyTxBeginTrace (mpdu); + m_phyTxBeginTrace (mpdu, txPowerW); } } else { - m_phyTxBeginTrace (packet); + m_phyTxBeginTrace (packet, txPowerW); } } @@ -2538,7 +2546,16 @@ WifiPhy::SendPacket (Ptr packet, WifiTxVector txVector) m_interference.NotifyRxEnd (); } - NotifyTxBegin (packet); + if (m_powerRestricted) + { + NS_LOG_DEBUG ("Transmitting with power restriction"); + } + else + { + NS_LOG_DEBUG ("Transmitting without power restriction"); + } + + NotifyTxBegin (packet, DbmToW (GetTxPowerForTransmission (txVector) + GetTxGain ())); NotifyMonitorSniffTx (packet, GetFrequency (), txVector); m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel ()), txVector); @@ -2559,6 +2576,9 @@ WifiPhy::SendPacket (Ptr packet, WifiTxVector txVector) newPacket->AddPacketTag (tag); StartTx (newPacket, txVector, txDuration); + + m_channelAccessRequested = false; + m_powerRestricted = false; } void @@ -2908,19 +2928,17 @@ WifiPhy::GetReceptionStatus (Ptr mpdu, Ptr event, Time rela ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << mpdu->GetSize () << ", relativeStart = " << relativeMpduStart.GetNanoSeconds () << "ns, duration = " << mpduDuration.GetNanoSeconds () << "ns"); - // // There are two error checks: PER and receive error model check. // PER check models is typical for Wi-Fi and is based on signal modulation; // Receive error model is optional, if we have an error model and // it indicates that the packet is corrupt, drop the packet. - // SignalNoiseDbm signalNoise; signalNoise.signal = WToDbm (event->GetRxPowerW ()); signalNoise.noise = WToDbm (event->GetRxPowerW () / snrPer.snr); if (m_random->GetValue () > snrPer.per && !(m_postReceptionErrorModel && m_postReceptionErrorModel->IsCorrupt (mpdu->Copy ()))) { - NS_LOG_DEBUG ("Reception OK: " << mpdu->ToString ()); + NS_LOG_DEBUG ("Reception succeeded: " << mpdu->ToString ()); NotifyRxEnd (mpdu); return std::make_pair (true, signalNoise); } @@ -2932,6 +2950,22 @@ WifiPhy::GetReceptionStatus (Ptr mpdu, Ptr event, Time rela } } +void +WifiPhy::EndReceiveInterBss (void) +{ + NS_LOG_FUNCTION (this); + if (!m_channelAccessRequested) + { + m_powerRestricted = false; + } +} + +void +WifiPhy::NotifyChannelAccessRequested (void) +{ + NS_LOG_FUNCTION (this); + m_channelAccessRequested = true; +} // Clause 15 rates (DSSS) @@ -3966,6 +4000,39 @@ WifiPhy::AbortCurrentReception () m_plcpSuccess = false; } +void +WifiPhy::ResetCca (bool powerRestricted, double txPowerMaxSiso, double txPowerMaxMimo) +{ + NS_LOG_FUNCTION (this << powerRestricted << txPowerMaxSiso << txPowerMaxMimo); + m_powerRestricted = powerRestricted; + m_txPowerMaxSiso = txPowerMaxSiso; + m_txPowerMaxMimo = txPowerMaxMimo; + NS_ASSERT ((m_currentEvent->GetEndTime () - Simulator::Now ()).IsPositive ()); + Simulator::Schedule (m_currentEvent->GetEndTime () - Simulator::Now (), &WifiPhy::EndReceiveInterBss, this); + AbortCurrentReception (); +} + +double +WifiPhy::GetTxPowerForTransmission (WifiTxVector txVector) const +{ + NS_LOG_FUNCTION (this << m_powerRestricted); + if (!m_powerRestricted) + { + return GetPowerDbm (txVector.GetTxPowerLevel ()); + } + else + { + if (txVector.GetNss () > 1) + { + return std::min (m_txPowerMaxMimo, GetPowerDbm (txVector.GetTxPowerLevel ())); + } + else + { + return std::min (m_txPowerMaxSiso, GetPowerDbm (txVector.GetTxPowerLevel ())); + } + } +} + void WifiPhy::StartRx (Ptr event, double rxPowerW, Time rxDuration) { diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 4ffc27fbb..656878efd 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -82,7 +82,7 @@ public: WifiPhy (); virtual ~WifiPhy (); - + /** * Return the WifiPhyStateHelper of this PHY * @@ -160,6 +160,12 @@ public: */ void EndReceive (Ptr event, Time psduDuration); + /** + * For HE receptions only, check and possibly modify the transmit power restriction state at + * the end of PPDU reception. + */ + void EndReceiveInterBss (void); + /** * \param packet the packet to send * \param txVector the TXVECTOR that has tx parameters such as mode, the transmission mode to use to send @@ -1083,8 +1089,9 @@ public: * Implemented for encapsulation purposes. * * \param packet the packet being transmitted + * \param txPowerW the transmit power in Watts */ - void NotifyTxBegin (Ptr packet); + void NotifyTxBegin (Ptr packet, double txPowerW); /** * Public method used to fire a PhyTxEnd trace. * Implemented for encapsulation purposes. @@ -1523,6 +1530,30 @@ public: */ double GetPowerDbm (uint8_t power) const; + /** + * Reset PHY to IDLE, with some potential TX power restrictions for the next transmission. + * + * \param powerRestricted flag whether the transmit power is restricted for the next transmission + * \param txPowerMaxSiso the SISO transmit power retriction for the next transmission + * \param txPowerMaxMimo the MIMO transmit power retriction for the next transmission + */ + void ResetCca (bool powerRestricted, double txPowerMaxSiso = 0, double txPowerMaxMimo = 0); + /** + * Compute the transmit power (in dBm) for the next transmission. + * + * \param txVector the TXVECTOR + * \return the transmit power in dBm for the next transmission + */ + double GetTxPowerForTransmission (WifiTxVector txVector) const; + /** + * Notify the PHY that an access to the channel was requested. + * This is typically called by the channel access manager to + * to notify the PHY about an ongoing transmission. + * The PHY will use this information to determine whether + * it should use power restriction as imposed by OBSS_PD SR. + */ + void NotifyChannelAccessRequested (void); + protected: // Inherited @@ -1705,7 +1736,7 @@ private: * * \see class CallBackTraceSource */ - TracedCallback > m_phyTxBeginTrace; + TracedCallback, double > m_phyTxBeginTrace; /** * The trace source fired when a packet ends the transmission process on @@ -1837,6 +1868,11 @@ private: double m_txPowerEndDbm; //!< Maximum transmission power (dBm) uint8_t m_nTxPower; //!< Number of available transmission power levels + bool m_powerRestricted; //!< Flag whether transmit power is retricted by OBSS PD SR + double m_txPowerMaxSiso; //!< SISO maximum transmit power due to OBSS PD SR power restriction + double m_txPowerMaxMimo; //!< MIMO maximum transmit power due to OBSS PD SR power restriction + bool m_channelAccessRequested; + bool m_greenfield; //!< Flag if GreenField format is supported (deprecated) bool m_shortGuardInterval; //!< Flag if HT/VHT short guard interval is supported (deprecated) bool m_shortPreamble; //!< Flag if short PLCP preamble is supported diff --git a/src/wifi/model/wifi-tx-vector.cc b/src/wifi/model/wifi-tx-vector.cc index d5ef7501f..cbf229c12 100644 --- a/src/wifi/model/wifi-tx-vector.cc +++ b/src/wifi/model/wifi-tx-vector.cc @@ -33,8 +33,7 @@ WifiTxVector::WifiTxVector () m_aggregation (false), m_stbc (false), m_bssColor (0), - m_modeInitialized (false), - m_txPowerLevelInitialized (false) + m_modeInitialized (false) { } @@ -60,8 +59,7 @@ WifiTxVector::WifiTxVector (WifiMode mode, m_aggregation (aggregation), m_stbc (stbc), m_bssColor (bssColor), - m_modeInitialized (true), - m_txPowerLevelInitialized (true) + m_modeInitialized (true) { } @@ -78,10 +76,6 @@ WifiTxVector::GetMode (void) const uint8_t WifiTxVector::GetTxPowerLevel (void) const { - if (!m_txPowerLevelInitialized) - { - NS_FATAL_ERROR ("WifiTxVector txPowerLevel must be set before using"); - } return m_txPowerLevel; } @@ -144,7 +138,6 @@ void WifiTxVector::SetTxPowerLevel (uint8_t powerlevel) { m_txPowerLevel = powerlevel; - m_txPowerLevelInitialized = true; } void diff --git a/src/wifi/model/wifi-tx-vector.h b/src/wifi/model/wifi-tx-vector.h index 4edee3e6a..edc725386 100644 --- a/src/wifi/model/wifi-tx-vector.h +++ b/src/wifi/model/wifi-tx-vector.h @@ -210,7 +210,7 @@ public: * * \return true if the WifiTxVector parameters are allowed by the standard */ - bool IsValid (void) const; + bool IsValid (void) const; private: @@ -231,7 +231,6 @@ private: uint8_t m_bssColor; /**< BSS color */ bool m_modeInitialized; /**< Internal initialization flag */ - bool m_txPowerLevelInitialized; /**< Internal initialization flag */ }; /** diff --git a/src/wifi/model/yans-wifi-phy.cc b/src/wifi/model/yans-wifi-phy.cc index 29322eeea..329243a16 100644 --- a/src/wifi/model/yans-wifi-phy.cc +++ b/src/wifi/model/yans-wifi-phy.cc @@ -78,7 +78,7 @@ void YansWifiPhy::StartTx (Ptr packet, WifiTxVector txVector, Time txDuration) { NS_LOG_DEBUG ("Start transmission: signal power before antenna gain=" << GetPowerDbm (txVector.GetTxPowerLevel ()) << "dBm"); - m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel ()) + GetTxGain (), txDuration); + m_channel->Send (this, packet, GetTxPowerForTransmission (txVector) + GetTxGain (), txDuration); } } //namespace ns3 diff --git a/src/wifi/test/inter-bss-test-suite.cc b/src/wifi/test/inter-bss-test-suite.cc new file mode 100644 index 000000000..d27c41ecf --- /dev/null +++ b/src/wifi/test/inter-bss-test-suite.cc @@ -0,0 +1,509 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018 University of Washington + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Sébastien Deronne + * Scott Carpenter + */ + +#include "ns3/log.h" +#include "ns3/test.h" +#include "ns3/uinteger.h" +#include "ns3/double.h" +#include "ns3/string.h" +#include "ns3/pointer.h" +#include "ns3/config.h" +#include "ns3/ssid.h" +#include "ns3/mobility-helper.h" +#include "ns3/wifi-net-device.h" +#include "ns3/spectrum-wifi-helper.h" +#include "ns3/multi-model-spectrum-channel.h" +#include "ns3/constant-obss-pd-algorithm.h" +#include "ns3/he-configuration.h" +#include "ns3/wifi-utils.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("InterBssTestSuite"); + +uint32_t +ConvertContextToNodeId (std::string context) +{ + std::string sub = context.substr (10); + uint32_t pos = sub.find ("/Device"); + uint32_t nodeId = atoi (sub.substr (0, pos).c_str ()); + return nodeId; +} + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Wifi Test + * + * This test case tests the transmission of inter-BSS cases + * and verify behavior of 11ax OBSS_PD spatial reuse. + * + * The topology for this test case is made of two networks, each with one AP and one STA: + * + * STA1 --d1-- AP1 --d2-- AP2 --d3-- STA2 + * RX1 TX1 TX2 RX2 + * + * Main parameters: + * OBSS_PD level = -72dbm + * Received Power by TX1 from TX2 = [-62dbm, -82dbm] + * Received SINR by RX1 from TX1 > 3dB (enough to pass MCS0 reception) + * Received SINR by RX2 from TX2 > 3dB (enough to pass MCS0 reception) + * TX1/RX1 BSS Color = 1 + * TX2/RX2 transmission PPDU BSS Color = [2 0] + * PHY = 11ax, MCS 0, 80MHz + */ + +class TestInterBssConstantObssPdAlgo : public TestCase +{ +public: + TestInterBssConstantObssPdAlgo (); + + virtual void DoRun (void); + +private: + /** + * Send one packet function + * \param tx_dev the transmitting device + * \param rx_dev the receiving device + * \param payloadSize the payload size + */ + void SendOnePacket (Ptr tx_dev, Ptr rx_dev, uint32_t payloadSize); + + /** + * Allocate the node positions + * \param d1 distance d1 (in meters) + * \param d2 distance d2 (in meters) + * \param d3 distance d3 (in meters) + */ + Ptr AllocatePositions (double d1, double d2, double d3); + + void SetExpectedTxPower (double txPowerDbm); + + /** + * Setup the simulation + */ + void SetupSimulation (); + + /** + * Check the results + */ + void CheckResults (); + + /** + * Reset the results + */ + void ResetResults (); + + /** + * Run one function + */ + void RunOne (); + + /** + * Check if the Phy State for a device is an expected value + */ + void CheckPhyState (Ptr device, WifiPhyState expectedState); + + /** + * Notify Phy transmit begin + * \param context the context + * \param p the packet + * \param txPowerW the tx power + */ + void NotifyPhyTxBegin (std::string context, Ptr p, double txPowerW); + + /** + * Notify Phy receive endsn + * \param context the context + * \param p the packet + */ + void NotifyPhyRxEnd (std::string context, Ptr p); + + unsigned int m_numSta1PacketsSent; ///< number of sent packets from STA1 + unsigned int m_numSta2PacketsSent; ///< number of sent packets from STA2 + unsigned int m_numAp1PacketsSent; ///< number of sent packets from AP1 + unsigned int m_numAp2PacketsSent; ///< number of sent packets from AP2 + + unsigned int m_numSta1PacketsReceived; ///< number of received packets from STA1 + unsigned int m_numSta2PacketsReceived; ///< number of received packets from STA2 + unsigned int m_numAp1PacketsReceived; ///< number of received packets from AP1 + unsigned int m_numAp2PacketsReceived; ///< number of received packets from AP2 + + unsigned int m_payloadSize1; ///< size in bytes of packet payload in BSS 1 + unsigned int m_payloadSize2; ///< size in bytes of packet payload in BSS 2 + + NetDeviceContainer m_staDevices; + NetDeviceContainer m_apDevices; + + double m_txPowerDbm; + double m_obssPdLevelDbm; + double m_obssRxPowerDbm; + double m_expectedTxPowerDbm; + + uint8_t m_bssColor1; + uint8_t m_bssColor2; +}; + +TestInterBssConstantObssPdAlgo::TestInterBssConstantObssPdAlgo () + : TestCase ("InterBssConstantObssPd"), + m_numSta1PacketsSent (0), + m_numSta2PacketsSent (0), + m_numAp1PacketsSent (0), + m_numAp2PacketsSent (0), + m_numSta1PacketsReceived (0), + m_numSta2PacketsReceived (0), + m_numAp1PacketsReceived (0), + m_numAp2PacketsReceived (0), + m_payloadSize1 (1000), + m_payloadSize2 (1500), + m_txPowerDbm (15), + m_obssPdLevelDbm (-72), + m_obssRxPowerDbm (-82), + m_expectedTxPowerDbm (15), + m_bssColor1 (1), + m_bssColor2 (2) +{ +} + +Ptr +TestInterBssConstantObssPdAlgo::AllocatePositions (double d1, double d2, double d3) +{ + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (d1, 0.0, 0.0)); // AP1 + positionAlloc->Add (Vector (d1 + d2, 0.0, 0.0)); // AP2 + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // STA1 + positionAlloc->Add (Vector (d1 + d2 + d3, 0.0, 0.0)); // STA2 + + return positionAlloc; +} + +void +TestInterBssConstantObssPdAlgo::SetupSimulation () +{ + Ptr ap_device1 = DynamicCast (m_apDevices.Get (0)); + Ptr ap_device2 = DynamicCast (m_apDevices.Get (1)); + Ptr sta_device1 = DynamicCast (m_staDevices.Get (0)); + Ptr sta_device2 = DynamicCast (m_staDevices.Get (1)); + + bool expectPhyReset = (m_bssColor1 != 0) && (m_bssColor2 != 0) && (m_obssPdLevelDbm >= m_obssRxPowerDbm); + + // AP1 sends packet #1 after 0.25s. The purpose is to have addba handshake established. + Simulator::Schedule (Seconds (0.25), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device1, sta_device1, m_payloadSize1); + // STA1 sends packet #2 after 0.5s. The purpose is to have addba handshake established. + Simulator::Schedule (Seconds (0.5), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1); + + // AP2 sends packet #3 after 0.75s. The purpose is to have addba handshake established. + Simulator::Schedule (Seconds (0.75), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2); + // STA2 sends packet #4 after 1.0s. The purpose is to have addba handshake established. + Simulator::Schedule (Seconds (1), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device2, ap_device2, m_payloadSize2); + + // AP2 sends packet #5 0.5s later. + Simulator::Schedule (Seconds (1.5), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (1), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device2, WifiPhyState::TX); + // All other PHYs should have stay idle until 4us (preamble detection time). + Simulator::Schedule (Seconds (1.5) + MicroSeconds (2), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, WifiPhyState::IDLE); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (2), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::IDLE); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (2), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, WifiPhyState::IDLE); + // All PHYs should be reeiving the PHY header if preamble has been detected (always the case in this test). + Simulator::Schedule (Seconds (1.5) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, WifiPhyState::RX); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (10), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, WifiPhyState::RX); + // PHYs of AP1 and STA1 should be idle if it was reset by OBSS PD, otherwise they should be receiving + Simulator::Schedule (Seconds (1.5) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::IDLE : WifiPhyState::RX); + Simulator::Schedule (Seconds (1.5) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, expectPhyReset ? WifiPhyState::IDLE : WifiPhyState::RX); + // STA2 should be receiving + Simulator::Schedule (Seconds (1.5) + MicroSeconds (50), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX); + + // AP2 sends another packet #6 0.1s later. + Simulator::Schedule (Seconds (1.6), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2); + // STA1 sends a packet #7 100us later. Even though AP2 is still transmitting, STA1 can transmit simultaneously if it's PHY was reset by OBSS PD SR. + Simulator::Schedule (Seconds (1.6) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1); + if (expectPhyReset) + { + // In this case, we check the TX power is restricted + double expectedTxPower = std::min (m_txPowerDbm, 21 - (m_obssPdLevelDbm + 82)); + Simulator::Schedule (Seconds (1.6) + MicroSeconds (100), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, expectedTxPower); + } + // Check simultaneous transmissions + Simulator::Schedule (Seconds (1.6) + MicroSeconds (350), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device1, expectPhyReset ? WifiPhyState::TX : WifiPhyState::RX); + Simulator::Schedule (Seconds (1.6) + MicroSeconds (350), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device1, WifiPhyState::RX); + Simulator::Schedule (Seconds (1.6) + MicroSeconds (350), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, sta_device2, WifiPhyState::RX); + Simulator::Schedule (Seconds (1.6) + MicroSeconds (350), &TestInterBssConstantObssPdAlgo::CheckPhyState, this, ap_device2, WifiPhyState::TX); + + // AP2 sends another packet #8 0.1s later. + Simulator::Schedule (Seconds (1.7), &TestInterBssConstantObssPdAlgo::SetExpectedTxPower, this, m_txPowerDbm); + Simulator::Schedule (Seconds (1.7), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, ap_device2, sta_device2, m_payloadSize2); + // STA1 sends a packet #9 0.1S later. Power retriction should not be applied. + Simulator::Schedule (Seconds (1.8), &TestInterBssConstantObssPdAlgo::SendOnePacket, this, sta_device1, ap_device1, m_payloadSize1); + + Simulator::Stop (Seconds (1.9)); +} + +void +TestInterBssConstantObssPdAlgo::ResetResults () +{ + m_numSta1PacketsSent = 0; + m_numSta2PacketsSent = 0; + m_numAp1PacketsSent = 0; + m_numAp2PacketsSent = 0; + m_numSta1PacketsReceived = 0; + m_numSta2PacketsReceived = 0; + m_numAp1PacketsReceived = 0; + m_numAp2PacketsReceived = 0; + m_expectedTxPowerDbm = m_txPowerDbm; +} + +void +TestInterBssConstantObssPdAlgo::CheckResults () +{ + NS_TEST_ASSERT_MSG_EQ (m_numSta1PacketsSent, 3, "The number of packets sent by STA1 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numSta2PacketsSent, 1, "The number of packets sent by STA2 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numAp1PacketsSent, 1, "The number of packets sent by AP1 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numAp2PacketsSent, 4, "The number of packets sent by AP2 is not correct!"); + + NS_TEST_ASSERT_MSG_EQ (m_numSta1PacketsReceived, 1, "The number of packets received by STA1 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numSta2PacketsReceived, 4, "The number of packets received by STA2 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numAp1PacketsReceived, 3, "The number of packets received by AP1 is not correct!"); + NS_TEST_ASSERT_MSG_EQ (m_numAp2PacketsReceived, 1, "The number of packets received by AP2 is not correct!"); +} + +void +TestInterBssConstantObssPdAlgo::NotifyPhyTxBegin (std::string context, Ptr p, double txPowerW) +{ + uint32_t idx = ConvertContextToNodeId (context); + uint32_t pktSize = p->GetSize () - 38; + if ((idx == 0) && (pktSize == m_payloadSize1)) + { + m_numSta1PacketsSent++; + NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!"); + } + else if ((idx == 1) && (pktSize == m_payloadSize2)) + { + m_numSta2PacketsSent++; + NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!"); + } + else if ((idx == 2) && (pktSize == m_payloadSize1)) + { + m_numAp1PacketsSent++; + NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!"); + } + else if ((idx == 3) && (pktSize == m_payloadSize2)) + { + m_numAp2PacketsSent++; + NS_TEST_EXPECT_MSG_EQ (TestDoubleIsEqual (WToDbm (txPowerW), m_expectedTxPowerDbm, 1e-12), true, "Tx power is not correct!"); + } +} + +void +TestInterBssConstantObssPdAlgo::NotifyPhyRxEnd (std::string context, Ptr p) +{ + uint32_t idx = ConvertContextToNodeId (context); + uint32_t pktSize = p->GetSize () - 38; + if ((idx == 0) && (pktSize == m_payloadSize1)) + { + m_numSta1PacketsReceived++; + } + else if ((idx == 1) && (pktSize == m_payloadSize2)) + { + m_numSta2PacketsReceived++; + } + else if ((idx == 2) && (pktSize == m_payloadSize1)) + { + m_numAp1PacketsReceived++; + } + else if ((idx == 3) && (pktSize == m_payloadSize2)) + { + m_numAp2PacketsReceived++; + } +} + +void +TestInterBssConstantObssPdAlgo::SendOnePacket (Ptr tx_dev, Ptr rx_dev, uint32_t payloadSize) +{ + Ptr p = Create (payloadSize); + tx_dev->Send (p, rx_dev->GetAddress (), 1); +} + +void +TestInterBssConstantObssPdAlgo::SetExpectedTxPower (double txPowerDbm) +{ + m_expectedTxPowerDbm = txPowerDbm; +} + +void +TestInterBssConstantObssPdAlgo::CheckPhyState (Ptr device, WifiPhyState expectedState) +{ + WifiPhyState currentState; + PointerValue ptr; + Ptr phy = DynamicCast (device->GetPhy ()); + phy->GetAttribute ("State", ptr); + Ptr state = DynamicCast (ptr.Get ()); + currentState = state->GetState (); + NS_TEST_ASSERT_MSG_EQ (currentState, expectedState, "PHY State " << currentState << " does not match expected state " << expectedState << " at " << Simulator::Now ()); +} + +void +TestInterBssConstantObssPdAlgo::RunOne (void) +{ + ResetResults (); + + Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_MaxAmpduSize", UintegerValue (0)); + + NodeContainer wifiStaNodes; + wifiStaNodes.Create (2); + + NodeContainer wifiApNodes; + wifiApNodes.Create (2); + + Ptr lossModel = CreateObject (); + lossModel->SetDefaultLoss (200); // set default loss to 200 dB (no link) + + SpectrumWifiPhyHelper phy = SpectrumWifiPhyHelper::Default (); + Ptr channel = CreateObject (); + channel->SetPropagationDelayModel (CreateObject ()); + channel->AddPropagationLossModel (lossModel); + phy.SetChannel (channel); + phy.Set ("TxPowerStart", DoubleValue (m_txPowerDbm)); + phy.Set ("TxPowerEnd", DoubleValue (m_txPowerDbm)); + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211ax_5GHZ); + wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode", StringValue ("HeMcs0"), + "ControlMode", StringValue ("HeMcs0")); + + wifi.SetObssPdAlgorithm ("ns3::ConstantObssPdAlgorithm", + "ObssPdLevel", DoubleValue (m_obssPdLevelDbm)); + + WifiMacHelper mac; + Ssid ssid = Ssid ("ns-3-ssid"); + mac.SetType ("ns3::StaWifiMac", + "Ssid", SsidValue (ssid)); + m_staDevices = wifi.Install (phy, mac, wifiStaNodes); + + mac.SetType ("ns3::ApWifiMac", + "Ssid", SsidValue (ssid)); + m_apDevices = wifi.Install (phy, mac, wifiApNodes); + + for (uint32_t i = 0; i < m_apDevices.GetN (); i++) + { + Ptr device = DynamicCast (m_apDevices.Get (i)); + Ptr heConfiguration = device->GetHeConfiguration (); + if (i == 0) + { + heConfiguration->SetAttribute ("BssColor", UintegerValue (m_bssColor1)); + } + else + { + heConfiguration->SetAttribute ("BssColor", UintegerValue (m_bssColor2)); + } + } + for (uint32_t i = 0; i < m_staDevices.GetN (); i++) + { + Ptr device = DynamicCast (m_staDevices.Get (i)); + Ptr heConfiguration = device->GetHeConfiguration (); + } + + MobilityHelper mobility; + Ptr positionAlloc = AllocatePositions (10, 50, 10); //distances do not really matter since we set RSSI per TX-RX pair to have full control + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiApNodes); + mobility.Install (wifiStaNodes); + + lossModel->SetLoss (wifiStaNodes.Get (0)->GetObject (), wifiApNodes.Get (0)->GetObject (), m_txPowerDbm + 30); //Low attenuation for IBSS transmissions + lossModel->SetLoss (wifiStaNodes.Get (1)->GetObject (), wifiApNodes.Get (1)->GetObject (), m_txPowerDbm + 30); //Low attenuation for IBSS transmissions + lossModel->SetLoss (wifiStaNodes.Get (1)->GetObject (), wifiApNodes.Get (0)->GetObject (), m_txPowerDbm - m_obssRxPowerDbm); //Force received RSSI to be equal to m_obssRxPowerDbm + lossModel->SetLoss (wifiStaNodes.Get (0)->GetObject (), wifiApNodes.Get (1)->GetObject (), m_txPowerDbm - m_obssRxPowerDbm); //Force received RSSI to be equal to m_obssRxPowerDbm + lossModel->SetLoss (wifiApNodes.Get (0)->GetObject (), wifiApNodes.Get (1)->GetObject (), m_txPowerDbm - m_obssRxPowerDbm); //Force received RSSI to be equal to m_obssRxPowerDbm + + Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin", MakeCallback (&TestInterBssConstantObssPdAlgo::NotifyPhyTxBegin, this)); + Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd", MakeCallback (&TestInterBssConstantObssPdAlgo::NotifyPhyRxEnd, this)); + + SetupSimulation (); + + Simulator::Run (); + Simulator::Destroy (); + + CheckResults (); +} + +void +TestInterBssConstantObssPdAlgo::DoRun (void) +{ + //Test case 1: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm + m_obssPdLevelDbm = -72; + m_obssRxPowerDbm = -82; + m_bssColor1 = 1; + m_bssColor2 = 2; + RunOne (); + + //Test case 2: CCA CS Threshold < m_obssPdLevelDbm < m_obssRxPowerDbm + m_obssPdLevelDbm = -72; + m_obssRxPowerDbm = -62; + m_bssColor1 = 1; + m_bssColor2 = 2; + RunOne (); + + //Test case 3: CCA CS Threshold = < m_obssPdLevelDbm = m_obssRxPowerDbm + m_obssPdLevelDbm = -72; + m_obssRxPowerDbm = -72; + m_bssColor1 = 1; + m_bssColor2 = 2; + RunOne (); + + //Test case 4: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm with BSS color 2 set to 0 + m_obssPdLevelDbm = -72; + m_obssRxPowerDbm = -82; + m_bssColor1 = 1; + m_bssColor2 = 0; + RunOne (); + + //Test case 5: CCA CS Threshold = m_obssRxPowerDbm < m_obssPdLevelDbm with BSS color 1 set to 0 + m_obssPdLevelDbm = -72; + m_obssRxPowerDbm = -82; + m_bssColor1 = 0; + m_bssColor2 = 2; + RunOne (); +} + +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Inter BSS Test Suite + */ + +class InterBssTestSuite : public TestSuite +{ +public: + InterBssTestSuite (); +}; + +InterBssTestSuite::InterBssTestSuite () + : TestSuite ("wifi-inter-bss", UNIT) +{ + AddTestCase (new TestInterBssConstantObssPdAlgo, TestCase::QUICK); +} + +// Do not forget to allocate an instance of this TestSuite +static InterBssTestSuite interBssTestSuite; diff --git a/src/wifi/test/wifi-test.cc b/src/wifi/test/wifi-test.cc index cb6fb3357..37c02ed20 100644 --- a/src/wifi/test/wifi-test.cc +++ b/src/wifi/test/wifi-test.cc @@ -444,8 +444,9 @@ private: /** * Notify Phy transmit begin * \param p the packet + * \param txPowerW the tx power */ - void NotifyPhyTxBegin (Ptr p); + void NotifyPhyTxBegin (Ptr p, double txPowerW); }; DcfImmediateAccessBroadcastTestCase::DcfImmediateAccessBroadcastTestCase () @@ -454,7 +455,7 @@ DcfImmediateAccessBroadcastTestCase::DcfImmediateAccessBroadcastTestCase () } void -DcfImmediateAccessBroadcastTestCase::NotifyPhyTxBegin (Ptr p) +DcfImmediateAccessBroadcastTestCase::NotifyPhyTxBegin (Ptr p, double txPowerW) { if (m_numSentPackets == 0) { @@ -1598,7 +1599,7 @@ StaWifiMacScanningTestCase::TurnApOff (Ptr apNode) { Ptr netDevice = DynamicCast (apNode->GetDevice (0)); Ptr phy = netDevice->GetPhy (); - phy->SetOffMode(); + phy->SetOffMode (); } NodeContainer @@ -1657,7 +1658,7 @@ StaWifiMacScanningTestCase::DoRun (void) { RngSeedManager::SetSeed (1); RngSeedManager::SetRun (1); - + NodeContainer nodes = Setup (false, false); Ptr nearestAp = nodes.Get (2); Mac48Address nearestApAddr = DynamicCast (nearestAp->GetDevice (0))->GetMac ()->GetAddress (); @@ -1808,24 +1809,24 @@ Bug2470TestCase::AddbaStateChangedCallback (std::string context, Time t, Mac48Ad { switch (state) { - case OriginatorBlockAckAgreement::INACTIVE: - m_addbaInactiveCount++; - break; - case OriginatorBlockAckAgreement::ESTABLISHED: - m_addbaEstablishedCount++; - break; - case OriginatorBlockAckAgreement::PENDING: - m_addbaPendingCount++; - break; - case OriginatorBlockAckAgreement::REJECTED: - m_addbaRejectedCount++; - break; - case OriginatorBlockAckAgreement::NO_REPLY: - m_addbaNoReplyCount++; - break; - case OriginatorBlockAckAgreement::RESET: - m_addbaResetCount++; - break; + case OriginatorBlockAckAgreement::INACTIVE: + m_addbaInactiveCount++; + break; + case OriginatorBlockAckAgreement::ESTABLISHED: + m_addbaEstablishedCount++; + break; + case OriginatorBlockAckAgreement::PENDING: + m_addbaPendingCount++; + break; + case OriginatorBlockAckAgreement::REJECTED: + m_addbaRejectedCount++; + break; + case OriginatorBlockAckAgreement::NO_REPLY: + m_addbaNoReplyCount++; + break; + case OriginatorBlockAckAgreement::RESET: + m_addbaResetCount++; + break; } } diff --git a/src/wifi/wscript b/src/wifi/wscript index 565db3fb3..9ec68f373 100644 --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -95,6 +95,8 @@ def build(bld): 'model/wifi-psdu.cc', 'model/ht-configuration.cc', 'model/vht-configuration.cc', + 'model/obss-pd-algorithm.cc', + 'model/constant-obss-pd-algorithm.cc', 'helper/wifi-radio-energy-model-helper.cc', 'helper/athstats-helper.cc', 'helper/wifi-helper.cc', @@ -116,6 +118,7 @@ def build(bld): 'test/wifi-transmit-mask-test.cc', 'test/wifi-phy-thresholds-test.cc', 'test/wifi-phy-reception-test.cc', + 'test/inter-bss-test-suite.cc', ] headers = bld(features='ns3header') @@ -219,6 +222,8 @@ def build(bld): 'model/wifi-mpdu-type.h', 'model/ht-configuration.h', 'model/vht-configuration.h', + 'model/obss-pd-algorithm.h', + 'model/constant-obss-pd-algorithm.h', 'helper/wifi-radio-energy-model-helper.h', 'helper/athstats-helper.h', 'helper/wifi-helper.h',