diff --git a/examples/wireless/wifi-spectrum-saturation-example.cc b/examples/wireless/wifi-spectrum-saturation-example.cc index 8d72a2d..b88e109 100644 --- a/examples/wireless/wifi-spectrum-saturation-example.cc +++ b/examples/wireless/wifi-spectrum-saturation-example.cc @@ -198,8 +198,8 @@ int main (int argc, char *argv[]) //Bug 2460: CcaMode1Threshold default should be set to -62 dBm when using Spectrum Config::SetDefault ("ns3::WifiPhy::CcaMode1Threshold", DoubleValue (-62.0)); - Ptr spectrumChannel - = CreateObject (); + Ptr spectrumChannel + = CreateObject (); Ptr lossModel = CreateObject (); spectrumChannel->AddPropagationLossModel (lossModel); diff --git a/src/spectrum/model/multi-model-spectrum-channel.cc b/src/spectrum/model/multi-model-spectrum-channel.cc index 6f40d96..11d5b66 100644 --- a/src/spectrum/model/multi-model-spectrum-channel.cc +++ b/src/spectrum/model/multi-model-spectrum-channel.cc @@ -134,6 +134,12 @@ MultiModelSpectrumChannel::GetTypeId (void) "reported in this trace. ", MakeTraceSourceAccessor (&MultiModelSpectrumChannel::m_pathLossTrace), "ns3::SpectrumChannel::LossTracedCallback") + .AddTraceSource ("TxSigParams", + "This trace is fired whenever a signal is transmitted. " + "The sole parameter is a pointer to a copy of the " + "SpectrumSignalParameters provided by the transmitter.", + MakeTraceSourceAccessor (&MultiModelSpectrumChannel::m_txSigParamsTrace), + "ns3::MultiModelSpectrumChannel::SignalParametersTracedCallback") ; return tid; } @@ -261,7 +267,8 @@ MultiModelSpectrumChannel::StartTx (Ptr txParams) NS_ASSERT (txParams->txPhy); NS_ASSERT (txParams->psd); - + Ptr txParamsTrace = txParams->Copy (); // copy it since traced value cannot be const (because of potential underlying DynamicCasts) + m_txSigParamsTrace (txParamsTrace); Ptr txMobility = txParams->txPhy->GetMobility (); SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid (); diff --git a/src/spectrum/model/multi-model-spectrum-channel.h b/src/spectrum/model/multi-model-spectrum-channel.h index 07a4841..84fcd87 100644 --- a/src/spectrum/model/multi-model-spectrum-channel.h +++ b/src/spectrum/model/multi-model-spectrum-channel.h @@ -133,6 +133,12 @@ public: */ virtual Ptr GetSpectrumPropagationLossModel (void); + /** + * TracedCallback signature for Ptr. + * + * \param [in] params SpectrumSignalParameters instance. + */ + typedef void (* SignalParametersTracedCallback) (Ptr params); protected: void DoDispose (); @@ -207,6 +213,10 @@ private: * in a future release. */ TracedCallback, Ptr, double > m_pathLossTrace; + /** + * Traced callback for SpectrumSignalParameters in StartTx requests + */ + TracedCallback > m_txSigParamsTrace; }; diff --git a/src/spectrum/model/wifi-spectrum-value-helper.cc b/src/spectrum/model/wifi-spectrum-value-helper.cc index 5e2d603..10db345 100644 --- a/src/spectrum/model/wifi-spectrum-value-helper.cc +++ b/src/spectrum/model/wifi-spectrum-value-helper.cc @@ -164,7 +164,6 @@ WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity (uint32_t centerFreque switch (channelWidth) { case 20: - default: // 52 subcarriers (48 data + 4 pilot) // skip guard band and 6 subbands, then place power in 26 subbands, then // skip the center subband, then place power in 26 subbands, then skip @@ -197,6 +196,9 @@ WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity (uint32_t centerFreque start2 = stop1 + 2; stop2 = start2 + 8 - 1; break; + default: + NS_FATAL_ERROR ("Channel width should be correctly set."); + return 0; } NS_LOG_DEBUG ("Power per band " << txPowerPerBand); Values::iterator vit = c->ValuesBegin (); diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index e383fae..175c4f7 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -312,12 +312,27 @@ SpectrumWifiPhy::GetTxPowerSpectralDensity (uint16_t centerFrequency, uint8_t ch return v; } +uint32_t +SpectrumWifiPhy::GetCenterFrequencyForChannelWidth (WifiTxVector txVector) const +{ + NS_LOG_FUNCTION (txVector); + uint32_t centerFrequencyForSupportedWidth = GetFrequency (); + uint32_t supportedWidth = static_cast (GetChannelWidth ()); + uint32_t currentWidth = static_cast (txVector.GetChannelWidth ()); + if (currentWidth != supportedWidth) + { + uint32_t startingFrequency = centerFrequencyForSupportedWidth - (supportedWidth / 2); + return startingFrequency + (currentWidth / 2); // primary channel is in the lower part (for the time being) + } + return centerFrequencyForSupportedWidth; +} + 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 ()); - Ptr txPowerSpectrum = GetTxPowerSpectralDensity (GetFrequency (), GetChannelWidth (), txPowerWatts, txVector.GetMode ().GetModulationClass ()); + Ptr txPowerSpectrum = GetTxPowerSpectralDensity (GetCenterFrequencyForChannelWidth (txVector), txVector.GetChannelWidth (), txPowerWatts, txVector.GetMode ().GetModulationClass ()); Ptr txParams = Create (); txParams->duration = txDuration; txParams->psd = txPowerSpectrum; diff --git a/src/wifi/model/spectrum-wifi-phy.h b/src/wifi/model/spectrum-wifi-phy.h index 03deb9c..e497a81 100644 --- a/src/wifi/model/spectrum-wifi-phy.h +++ b/src/wifi/model/spectrum-wifi-phy.h @@ -100,6 +100,15 @@ public: * \param txDuration duration of the transmission. */ void StartTx (Ptr packet, WifiTxVector txVector, Time txDuration); + /** + * Get the center frequency of the channel corresponding the current TxVector rather than + * that of the supported channel width. + * Consider that this "primary channel" is on the lower part for the time being. + * + * \param txVector the TXVECTOR that has the channel width that is to be used + * \return the center frequency corresponding to the channel width to be used + */ + uint32_t GetCenterFrequencyForChannelWidth (WifiTxVector txVector) const; /** * Method to encapsulate the creation of the WifiSpectrumPhyInterface diff --git a/src/wifi/model/wifi-remote-station-manager.cc b/src/wifi/model/wifi-remote-station-manager.cc index 99e5191..f4ea467 100644 --- a/src/wifi/model/wifi-remote-station-manager.cc +++ b/src/wifi/model/wifi-remote-station-manager.cc @@ -814,6 +814,24 @@ WifiRemoteStationManager::PrepareForQueue (Mac48Address address, const WifiMacHe } WifiTxVector +WifiRemoteStationManager::AdjustChannelWidthToMode (WifiTxVector initialTxVector) const +{ + NS_LOG_FUNCTION (this << initialTxVector); + WifiModulationClass modulationClass = initialTxVector.GetMode ().GetModulationClass (); + uint8_t defaultChannelWidth = initialTxVector.GetChannelWidth (); + if (defaultChannelWidth > 20 && + (modulationClass == WifiModulationClass::WIFI_MOD_CLASS_OFDM || // all non-HT OFDM control and management frames + modulationClass == WifiModulationClass::WIFI_MOD_CLASS_ERP_OFDM)) // special case of beacons at 2.4 GHz + { + WifiTxVector updatedTxVector = initialTxVector; + updatedTxVector.SetChannelWidth (20); + NS_LOG_LOGIC ("Channel width in TXVECTOR has been updated to 20 MHz channel"); + return updatedTxVector; + } + return initialTxVector; +} + +WifiTxVector WifiRemoteStationManager::GetDataTxVector (Mac48Address address, const WifiMacHeader *header, Ptr packet) { NS_LOG_FUNCTION (this << address << *header << packet); @@ -829,7 +847,7 @@ WifiRemoteStationManager::GetDataTxVector (Mac48Address address, const WifiMacHe v.SetNss (1); v.SetNess (0); v.SetStbc (m_wifiPhy->GetStbc ()); - return v; + return AdjustChannelWidthToMode (v); } if (!IsLowLatency ()) { @@ -840,9 +858,9 @@ WifiRemoteStationManager::GetDataTxVector (Mac48Address address, const WifiMacHe //cast found to void, to suppress 'found' set but not used //compiler warning (void) found; - return datatag.GetDataTxVector (); + return AdjustChannelWidthToMode (datatag.GetDataTxVector ()); } - return DoGetDataTxVector (Lookup (address, header)); + return AdjustChannelWidthToMode (DoGetDataTxVector (Lookup (address, header))); } WifiTxVector @@ -859,9 +877,9 @@ WifiRemoteStationManager::GetCtsToSelfTxVector (const WifiMacHeader *header, //cast found to void, to suppress 'found' set but not used //compiler warning (void) found; - return ctstoselftag.GetCtsToSelfTxVector (); + return AdjustChannelWidthToMode (ctstoselftag.GetCtsToSelfTxVector ()); } - return DoGetCtsToSelfTxVector (); + return AdjustChannelWidthToMode (DoGetCtsToSelfTxVector ()); } WifiTxVector @@ -1469,7 +1487,7 @@ WifiRemoteStationManager::GetCtsTxVector (Mac48Address address, WifiMode rtsMode v.SetNss (DoGetCtsTxNss (address, ctsMode)); v.SetNess (DoGetCtsTxNess (address, ctsMode)); v.SetStbc (m_wifiPhy->GetStbc ()); - return v; + return AdjustChannelWidthToMode (v); } WifiTxVector @@ -1486,7 +1504,7 @@ WifiRemoteStationManager::GetAckTxVector (Mac48Address address, WifiMode dataMod v.SetNss (DoGetAckTxNss (address, ackMode)); v.SetNess (DoGetAckTxNess (address, ackMode)); v.SetStbc (m_wifiPhy->GetStbc ()); - return v; + return AdjustChannelWidthToMode (v); } WifiTxVector @@ -1503,7 +1521,7 @@ WifiRemoteStationManager::GetBlockAckTxVector (Mac48Address address, WifiMode bl v.SetNss (DoGetBlockAckTxNss (address, blockAckMode)); v.SetNess (DoGetBlockAckTxNess (address, blockAckMode)); v.SetStbc (m_wifiPhy->GetStbc ()); - return v; + return AdjustChannelWidthToMode (v); } uint8_t diff --git a/src/wifi/model/wifi-remote-station-manager.h b/src/wifi/model/wifi-remote-station-manager.h index 8189b5b..5b40c83 100644 --- a/src/wifi/model/wifi-remote-station-manager.h +++ b/src/wifi/model/wifi-remote-station-manager.h @@ -1445,6 +1445,15 @@ private: * \return the number of fragments needed */ uint32_t GetNFragments (const WifiMacHeader *header, Ptr packet); + /** + * Adjust the channel width to the selected mode (instead of letting the PHY's + * default channel width). This is especially useful when using non-HT modes + * with HT/VHT/HE capable stations (with default width above 20 MHz). + * + * \param initialTxVector TXVECTOR using the PHY's default channel width + * \return TXVECTOR with channel width adapted to the selected mode + */ + WifiTxVector AdjustChannelWidthToMode (WifiTxVector initialTxVector) const; /** * A vector of WifiRemoteStations diff --git a/src/wifi/test/wifi-test.cc b/src/wifi/test/wifi-test.cc index 1e10c6a..7622b02 100644 --- a/src/wifi/test/wifi-test.cc +++ b/src/wifi/test/wifi-test.cc @@ -37,6 +37,16 @@ #include "ns3/packet-socket-server.h" #include "ns3/packet-socket-client.h" #include "ns3/packet-socket-helper.h" +#include "ns3/spectrum-wifi-helper.h" +#include "ns3/spectrum-value.h" +#include "ns3/multi-model-spectrum-channel.h" +#include "ns3/udp-client-server-helper.h" +#include "ns3/wifi-spectrum-signal-parameters.h" +#include "ns3/wifi-phy-tag.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-address-helper.h" +#include +#include using namespace ns3; @@ -1154,6 +1164,198 @@ Bug2222TestCase::DoRun (void) NS_TEST_ASSERT_MSG_EQ (m_countInternalCollisions, 1, "unexpected number of internal collisions!"); } +//----------------------------------------------------------------------------- +/** + * Make sure that the correct channel width and center frequency have been set + * for OFDM basic rate transmissions and BSS channel widths larger than 20 MHz. + * + * The scenario considers a UDP transmission between a 40 MHz 802.11ac station and a + * 40 MHz 802.11ac access point. All transmission parameters are checked so as + * to ensure that only 2 {starting frequency, channelWidth, Number of subbands + * in SpectrumModel, modulation type} tuples are used. + * + * See \bugid{2483} + */ + +class Bug2483TestCase : public TestCase +{ +public: + Bug2483TestCase (); + virtual ~Bug2483TestCase (); + virtual void DoRun (void); + +private: + /** + * A tuple of {starting frequency, channelWidth, Number of subbands in SpectrumModel, modulation type} + */ + typedef std::tuple FreqWidthSubbandModulationTuple; + std::vector m_distinctTuples; ///< vector of distinct {starting frequency, channelWidth, Number of subbands in SpectrumModel, modulation type} tuples + + /** + * Stores the distinct {starting frequency, channelWidth, Number of subbands in SpectrumModel, modulation type} tuples + * that have been used during the testcase run. + * \param txParams spectrum signal parameters set by transmitter + */ + void StoreDistinctTuple (std::string context, Ptr txParams); + +}; + +Bug2483TestCase::Bug2483TestCase () + : TestCase ("Test case for Bug 2483") +{ +} + +Bug2483TestCase::~Bug2483TestCase () +{ +} + +void +Bug2483TestCase::StoreDistinctTuple (std::string context, Ptr txParams) +{ + // Extract starting frequency and number of subbands + Ptr c = txParams->psd->GetSpectrumModel (); + uint32_t numBands = c->GetNumBands (); + double startingFreq = c->Begin ()->fl; + + // Get channel bandwidth and modulation class + Ptr wifiTxParams = DynamicCast (txParams); + Ptr packet = wifiTxParams->packet->Copy (); + WifiPhyTag tag; + if (!packet->RemovePacketTag (tag)) + { + NS_FATAL_ERROR ("Received Wi-Fi Signal with no WifiPhyTag"); + return; + } + WifiTxVector txVector = tag.GetWifiTxVector (); + uint8_t channelWidth = txVector.GetChannelWidth (); + WifiModulationClass modulationClass = txVector.GetMode ().GetModulationClass (); + + // Build a tuple and check if seen before (if so store it) + FreqWidthSubbandModulationTuple tupleForCurrentTx = std::make_tuple (startingFreq, channelWidth, + numBands, modulationClass); + bool found = false; + for (std::vector::const_iterator it = m_distinctTuples.begin (); it != m_distinctTuples.end (); it++) + { + if (*it == tupleForCurrentTx) + { + found = true; + } + } + if (!found) + { + m_distinctTuples.push_back (tupleForCurrentTx); + } +} + + +void +Bug2483TestCase::DoRun (void) +{ + Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("500")); // so as to force RTS/CTS for data frames + Config::SetDefault ("ns3::WifiPhy::CcaMode1Threshold", DoubleValue (-62.0)); + + NodeContainer wifiStaNode; + wifiStaNode.Create (1); + + NodeContainer wifiApNode; + wifiApNode.Create (1); + + SpectrumWifiPhyHelper spectrumPhy = SpectrumWifiPhyHelper::Default (); + Ptr spectrumChannel = CreateObject (); + Ptr lossModel = CreateObject (); + lossModel->SetFrequency (5.180e9); + spectrumChannel->AddPropagationLossModel (lossModel); + + Ptr delayModel + = CreateObject (); + spectrumChannel->SetPropagationDelayModel (delayModel); + + spectrumPhy.SetChannel (spectrumChannel); + spectrumPhy.SetErrorRateModel ("ns3::NistErrorRateModel"); + spectrumPhy.Set ("Frequency", UintegerValue (5180)); + spectrumPhy.Set ("ChannelWidth", UintegerValue (40)); // at least 40 MHz expected here + spectrumPhy.Set ("TxPowerStart", DoubleValue (10)); + spectrumPhy.Set ("TxPowerEnd", DoubleValue (10)); + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211ac); + wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode", StringValue ("VhtMcs8"), + "ControlMode", StringValue ("VhtMcs8")); + + WifiMacHelper mac; + Ssid ssid = Ssid ("ns-3-ssid"); + mac.SetType ("ns3::StaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); + + NetDeviceContainer staDevice; + staDevice = wifi.Install (spectrumPhy, mac, wifiStaNode); + + mac.SetType ("ns3::ApWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true)); + + NetDeviceContainer apDevice; + apDevice = wifi.Install (spectrumPhy, mac, wifiApNode); + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (1.0, 0.0, 0.0)); // put close enough in order to use MCS + mobility.SetPositionAllocator (positionAlloc); + + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiApNode); + mobility.Install (wifiStaNode); + + InternetStackHelper stack; + stack.Install (wifiApNode); + stack.Install (wifiStaNode); + + Ipv4AddressHelper address; + address.SetBase ("192.168.1.0", "255.255.255.0"); + Ipv4InterfaceContainer staNodeInterface; + Ipv4InterfaceContainer apNodeInterface; + + staNodeInterface = address.Assign (staDevice); + apNodeInterface = address.Assign (apDevice); + + ApplicationContainer serverApp; + uint16_t port = 9; + UdpServerHelper server (port); + serverApp = server.Install (wifiStaNode.Get (0)); + serverApp.Start (Seconds (0.0)); + serverApp.Stop (Seconds (1.0)); + + UdpClientHelper client (staNodeInterface.GetAddress (0), port); + client.SetAttribute ("MaxPackets", UintegerValue (10)); // so as to have a short run + client.SetAttribute ("Interval", TimeValue (Time ("0.00001"))); + client.SetAttribute ("PacketSize", UintegerValue (1000)); + ApplicationContainer clientApp = client.Install (wifiApNode.Get (0)); + clientApp.Start (Seconds (0.5)); + clientApp.Stop (Seconds (1.0)); + + Config::Connect ("/ChannelList/*/$ns3::MultiModelSpectrumChannel/TxSigParams", MakeCallback (&Bug2483TestCase::StoreDistinctTuple, this)); + + Simulator::Stop (Seconds (1.1)); + Simulator::Run (); + + Simulator::Destroy (); + + // {starting frequency, channelWidth, Number of subbands in SpectrumModel, modulation type} tuples + uint8_t numberTuples = m_distinctTuples.size (); + NS_TEST_ASSERT_MSG_EQ (numberTuples, 2, "Only two distinct tuples expected"); + // Note that the first tuple should the one initiated by the beacon + NS_TEST_ASSERT_MSG_EQ (std::get<0> (m_distinctTuples[0]), std::get<0> (m_distinctTuples[1]), "Both tuples should have same starting frequency"); + NS_TEST_ASSERT_MSG_EQ (2 * std::get<1> (m_distinctTuples[0]), std::get<1> (m_distinctTuples[1]), "Second tuple's channel width should be double that of first"); + NS_TEST_ASSERT_MSG_EQ (std::get<2> (m_distinctTuples[0]), 129, "First tuple should have 129 subbands (64+DC, 20MHz+DC, inband and 32*2 out-of-band, 10MHz on each side)"); + NS_TEST_ASSERT_MSG_EQ (std::get<2> (m_distinctTuples[1]), 193, "Second tuple should have 193 subbands (128+DC, 40MHz+DC, inband and 32*2 out-of-band, 10MHz on each side)"); + NS_TEST_ASSERT_MSG_EQ (std::get<3> (m_distinctTuples[0]), WifiModulationClass::WIFI_MOD_CLASS_OFDM, "First tuple should be OFDM"); + NS_TEST_ASSERT_MSG_EQ (std::get<3> (m_distinctTuples[1]), WifiModulationClass::WIFI_MOD_CLASS_VHT, "Second tuple should be VHT_OFDM"); +} + /** * \ingroup wifi-test * \ingroup tests @@ -1176,6 +1378,7 @@ WifiTestSuite::WifiTestSuite () AddTestCase (new Bug730TestCase, TestCase::QUICK); //Bug 730 AddTestCase (new SetChannelFrequencyTest, TestCase::QUICK); AddTestCase (new Bug2222TestCase, TestCase::QUICK); //Bug 2222 + AddTestCase (new Bug2483TestCase, TestCase::QUICK); //Bug 2483 } static WifiTestSuite g_wifiTestSuite; ///< the test suite