diff --git a/src/wifi/examples/frame-capture-model-validation.cc b/src/wifi/examples/frame-capture-model-validation.cc new file mode 100644 --- /dev/null +++ b/src/wifi/examples/frame-capture-model-validation.cc @@ -0,0 +1,68 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) Crash Avoidance Metrics Partnership (CAMP) VSC3 + * + * 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: Bin Cheng + */ + +// + +#include "ns3/core-module.h" +#include "ns3/frame-capture-model.h" +#include "ns3/gnuplot.h" + +using namespace ns3; + +int main (int argc, char *argv[]) +{ + std::ofstream preambleCaptureFile ("preamble-capture-success-rate.plt"); + std::ofstream payloadCaptureFile ("payload-capture-success-rate.plt"); + + Gnuplot preambleCapturePlot = Gnuplot ("preamble-capture-success-rate.eps"); + Gnuplot payloadCapturePlot = Gnuplot ("payload-capture-success-rate.eps"); + + Ptr captureModel = CreateObject (); + Gnuplot2dDataset preambleCaptureData ("Preamble-Capture"); + Gnuplot2dDataset payloadCaptureData ("Payload-Capture"); + + for (double sinr = 0.0; sinr <= 15.0; sinr += 0.1) + { + double preambleRate = captureModel->CalculatePreambleCaptureProbability (std::pow (10.0, sinr / 10.0)); + preambleCaptureData.Add (sinr, preambleRate); + double payloadRate = captureModel->CalculatePayloadCaptureProbability (std::pow (10.0, sinr / 10.0)); + payloadCaptureData.Add (sinr, payloadRate); + } + + preambleCapturePlot.AddDataset (preambleCaptureData); + payloadCapturePlot.AddDataset (payloadCaptureData); + + preambleCapturePlot.SetTerminal ("postscript eps color enh \"Times-BoldItalic\""); + preambleCapturePlot.SetLegend ("SINR(dB)", "Preamble Capture Success Rate"); + preambleCapturePlot.SetExtra ("set xrange [0:15]\n\ +set yrange [0:1.1]\n\ +set style line 1 linewidth 8" ); + preambleCapturePlot.GenerateOutput (preambleCaptureFile); + preambleCaptureFile.close (); + + payloadCapturePlot.SetTerminal ("postscript eps color enh \"Times-BoldItalic\""); + payloadCapturePlot.SetLegend ("SNR(dB)", "Payload Capture Success Rate"); + payloadCapturePlot.SetExtra ("set xrange [0:15]\n\ +set yrange [0:1.1]\n\ +set style line 1 linewidth 8" ); + + payloadCapturePlot.GenerateOutput (payloadCaptureFile); + payloadCaptureFile.close (); +} diff --git a/src/wifi/examples/test-interference-helper.cc b/src/wifi/examples/test-interference-helper.cc --- a/src/wifi/examples/test-interference-helper.cc +++ b/src/wifi/examples/test-interference-helper.cc @@ -54,6 +54,7 @@ #include "ns3/propagation-loss-model.h" #include "ns3/propagation-delay-model.h" #include "ns3/yans-error-rate-model.h" +#include "ns3/nist-error-rate-model.h" #include "ns3/constant-position-mobility-model.h" using namespace ns3; @@ -71,10 +72,14 @@ std::string txModeB; uint32_t txPowerLevelA; uint32_t txPowerLevelB; + double txPowerA; + double txPowerB; uint32_t packetSizeA; uint32_t packetSizeB; WifiPhyStandard standard; WifiPreamble preamble; + bool enableFrameCapture; + int numSentPackets; }; InterferenceExperiment (); @@ -96,6 +101,8 @@ txVector.SetTxPowerLevel (m_input.txPowerLevelA); txVector.SetMode (WifiMode (m_input.txModeA)); txVector.SetPreambleType (m_input.preamble); + m_txA->SetTxPowerStart (m_input.txPowerA); + m_txA->SetTxPowerEnd (m_input.txPowerA); m_txA->SendPacket (p, txVector); } @@ -107,6 +114,8 @@ txVector.SetTxPowerLevel (m_input.txPowerLevelB); txVector.SetMode (WifiMode (m_input.txModeB)); txVector.SetPreambleType (m_input.preamble); + m_txB->SetTxPowerStart (m_input.txPowerB); + m_txB->SetTxPowerEnd (m_input.txPowerB); m_txB->SendPacket (p, txVector); } @@ -121,10 +130,14 @@ txModeB ("OfdmRate54Mbps"), txPowerLevelA (0), txPowerLevelB (0), + txPowerA (20), + txPowerB (20), packetSizeA (1500), packetSizeB (1500), standard (WIFI_PHY_STANDARD_80211a), - preamble (WIFI_PREAMBLE_LONG) + preamble (WIFI_PREAMBLE_LONG), + enableFrameCapture (false), + numSentPackets (1) { } @@ -152,7 +165,7 @@ m_txB = CreateObject (); Ptr rx = CreateObject (); - Ptr error = CreateObject (); + Ptr error = CreateObject (); m_txA->SetErrorRateModel (error); m_txB->SetErrorRateModel (error); rx->SetErrorRateModel (error); @@ -167,8 +180,19 @@ m_txB->ConfigureStandard (input.standard); rx->ConfigureStandard (input.standard); - Simulator::Schedule (Seconds (0), &InterferenceExperiment::SendA, this); - Simulator::Schedule (Seconds (0) + input.interval, &InterferenceExperiment::SendB, this); + m_txA->SetAttribute ("PreambleCaptureEnabled", BooleanValue (input.enableFrameCapture)); + m_txB->SetAttribute ("PreambleCaptureEnabled", BooleanValue (input.enableFrameCapture)); + rx->SetAttribute ("PreambleCaptureEnabled", BooleanValue (input.enableFrameCapture)); + m_txA->SetAttribute ("PayloadCaptureEnabled", BooleanValue (input.enableFrameCapture)); + m_txB->SetAttribute ("PayloadCaptureEnabled", BooleanValue (input.enableFrameCapture)); + rx->SetAttribute ("PayloadCaptureEnabled", BooleanValue (input.enableFrameCapture)); + + for (int n = 0; n < input.numSentPackets; ++n) + { + double start = 0.1 * n; + Simulator::Schedule (Seconds (start), &InterferenceExperiment::SendA, this); + Simulator::Schedule (Seconds (start) + input.interval, &InterferenceExperiment::SendB, this); + } Simulator::Run (); Simulator::Destroy (); @@ -181,6 +205,7 @@ std::string str_standard = "WIFI_PHY_STANDARD_80211a"; std::string str_preamble = "WIFI_PREAMBLE_LONG"; double delay = 0; //microseconds + bool enableMultipleFrameCaptureTests = false; // If this is true, run tests for different frame capture cases CommandLine cmd; cmd.AddValue ("delay", "Delay in microseconds between frame transmission from sender A and frame transmission from sender B", delay); @@ -188,15 +213,19 @@ cmd.AddValue ("xB", "The position of transmitter B (> 0)", input.xB); cmd.AddValue ("packetSizeA", "Packet size in bytes of transmitter A", input.packetSizeA); cmd.AddValue ("packetSizeB", "Packet size in bytes of transmitter B", input.packetSizeB); - cmd.AddValue ("txPowerA", "TX power level of transmitter A", input.txPowerLevelA); - cmd.AddValue ("txPowerB", "TX power level of transmitter B", input.txPowerLevelB); + cmd.AddValue ("txPowerLevelA", "TX power level of transmitter A", input.txPowerLevelA); + cmd.AddValue ("txPowerLevelB", "TX power level of transmitter B", input.txPowerLevelB); + cmd.AddValue ("txPowerA", "Tx power of transmitter A", input.txPowerA); + cmd.AddValue ("txPowerB", "Tx power of transmitter B", input.txPowerB); cmd.AddValue ("txModeA", "Wifi mode used for payload transmission of sender A", input.txModeA); cmd.AddValue ("txModeB", "Wifi mode used for payload transmission of sender B", input.txModeB); cmd.AddValue ("standard", "IEEE 802.11 flavor", str_standard); cmd.AddValue ("preamble", "Type of preamble", str_preamble); + cmd.AddValue ("enableFrameCapture", "Enable frame capture capability", input.enableFrameCapture); + cmd.AddValue ("enableMultipleFrameCaptureTests", "Enable test frame capture in difference scenarios", enableMultipleFrameCaptureTests); cmd.Parse (argc, argv); - LogComponentEnable ("YansWifiPhy", LOG_LEVEL_ALL); + LogComponentEnable ("WifiPhy", LOG_LEVEL_ALL); LogComponentEnable ("InterferenceHelper", LOG_LEVEL_ALL); input.interval = MicroSeconds (delay); @@ -258,8 +287,80 @@ return 0; } - InterferenceExperiment experiment; - experiment.Run (input); + input.enableFrameCapture = true; + enableMultipleFrameCaptureTests = true; + if (input.enableFrameCapture && enableMultipleFrameCaptureTests) + { + InterferenceExperiment experiment; + // There are two categories, 4 cases in the frame capture scenario. Two categories are the recovery + // and the capture. The recovery means that the earlier arrived packet trends to be received. With + // newly arrived packet as interference, a recovery probability is calculated, which determines whether + // the reception of the packet can be continued. The capture means the later arrived packet tends to be + // received. A capture probability is calculated to determine whether the receiver can switch to the new packet + // For each category, two packets may collides at the preamble portion or the payload portion. + + // Note that different txPower of packet A and B can generate different SINR situations at the receiver + int testIndex = 1; + if (testIndex == 1) + { + // test 1: gradually increase the tx power of the first sent packet (packet A) + // in order to check: with newly arrived interference, under what condition, the packet + // can still be recovery at the receiver, collision at the preamble portion of the packet + input.interval = MicroSeconds (10); // two packets collides at the preamble portion of the first packet + input.numSentPackets = 1000; + for (double powerGap = 0.0; powerGap <= 15.0; powerGap += 0.2) + { + input.txPowerA = input.txPowerB + powerGap; + experiment.Run (input); + } + + } + else if (testIndex == 2) + { + // test 2: gradually increase the tx power of the first sent packet (packet A) + // in order to check: with newly arrived interference, under what condition, the packet + // can still be recovery at the receiver, collision at the payload portion of the packet + input.interval = MicroSeconds (100); // two packets collides at the payload portion of the first packet + input.numSentPackets = 1000; + for (double powerGap = 0.0; powerGap <= 15.0; powerGap += 0.2) + { + input.txPowerA = input.txPowerB + powerGap; + experiment.Run (input); + } + } + else if (testIndex == 3) + { + // test 3: gradually increase the tx power of the late sent packet (packet B) + // in order to check: under what condition, the receiver can switch to the new packet, + // collision at preamble portion of the packet + input.interval = MicroSeconds (10); // two packets collides at the preamble portion of the first packet + input.numSentPackets = 1000; + for (double powerGap = 0.0; powerGap <= 15.0; powerGap += 0.2) + { + input.txPowerB = input.txPowerA + powerGap; + experiment.Run (input); + } + } + else if (testIndex == 4) + { + // test 4 : gradually increase the tx power of the late sent packet (packet B) + // in order to check: under what condition, the receiver can switch to the new packet + // collision at payload portion of the packet + input.interval = MicroSeconds (100); // two packets collides at the payload portion of the first packet + input.numSentPackets = 1000; + for (double powerGap = 0.0; powerGap <= 15.0; powerGap += 0.2) + { + input.txPowerB = input.txPowerA + powerGap; + experiment.Run (input); + } + } + + } + else + { + InterferenceExperiment experiment; + experiment.Run (input); + } return 0; } diff --git a/src/wifi/examples/wscript b/src/wifi/examples/wscript --- a/src/wifi/examples/wscript +++ b/src/wifi/examples/wscript @@ -11,7 +11,7 @@ obj = bld.create_ns3_program('test-interference-helper', ['core', 'mobility', 'network', 'wifi']) obj.source = 'test-interference-helper.cc' - + obj = bld.create_ns3_program('ideal-wifi-manager-example', ['core', 'network', 'wifi', 'stats', 'mobility', 'propagation']) obj.source = 'ideal-wifi-manager-example.cc' @@ -23,3 +23,8 @@ obj = bld.create_ns3_program('wifi-phy-configuration', ['core', 'network', 'config-store', 'wifi']) obj.source = 'wifi-phy-configuration.cc' + + obj = bld.create_ns3_program('frame-capture-model-validation', + ['core', 'wifi']) + obj.source = 'frame-capture-model-validation.cc' + diff --git a/src/wifi/model/frame-capture-model.cc b/src/wifi/model/frame-capture-model.cc new file mode 100644 --- /dev/null +++ b/src/wifi/model/frame-capture-model.cc @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) Crash Avoidance Metrics Partnership (CAMP) VSC3 + * + * 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: Bin Cheng + */ + + +#include "frame-capture-model.h" +#include +#include +#include "wifi-utils.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (FrameCaptureModel); + +TypeId +FrameCaptureModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::FrameCaptureModel") + .SetParent () + .SetGroupName ("Wifi") + .AddConstructor () + ; + return tid; +} + +FrameCaptureModel::FrameCaptureModel () +{ +} + +double +FrameCaptureModel::CalculatePreambleCaptureProbability (double sinr) +{ + double z = std::sqrt (sinr / 4.0); + double p = 0.5 * erfc (z); + if (p == 0.0) + { + return 1.0; + } + double pe = CalculatePe (p); + pe = std::min (pe, 1.0); + double prob = std::pow (1 - pe, 240); + return prob; +} + +double +FrameCaptureModel::CalculatePayloadCaptureProbability (double sinr) +{ + double sinrDb = RatioToDb (sinr); + double prob = 0.4989 * erf ((sinrDb - 9.356) / 0.8722) + 0.4989; + prob = std::max (prob, 0.0); + prob = std::min (prob, 1.0); + return prob; +} + +double +FrameCaptureModel::CalculatePe (double p) +{ + double D = std::sqrt (4.0 * p * (1.0 - p)); + double pe = 1.0; + pe = 0.5 * (36.0 * std::pow (D, 10) + + 211.0 * std::pow (D, 12) + + 1404.0 * std::pow (D, 14) + + 11633.0 * std::pow (D, 16) + + 77433.0 * std::pow (D, 18) + + 502690.0 * std::pow (D, 20) + + 3322763.0 * std::pow (D, 22) + + 21292910.0 * std::pow (D, 24) + + 134365911.0 * std::pow (D, 26)); + return pe; +} + +} // //namespace ns3 diff --git a/src/wifi/model/frame-capture-model.h b/src/wifi/model/frame-capture-model.h new file mode 100644 --- /dev/null +++ b/src/wifi/model/frame-capture-model.h @@ -0,0 +1,72 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) Crash Avoidance Metrics Partnership (CAMP) VSC3 + * + * 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: Bin Cheng + * + */ + + +#ifndef FRAME_CAPTURE_MODEL_H +#define FRAME_CAPTURE_MODEL_H + +#include "ns3/object.h" + +namespace ns3 { + +/** + * \ingroup wifi + * \brief models for switching between two receptions + */ +class FrameCaptureModel : public Object +{ +public: + static TypeId GetTypeId (void); + FrameCaptureModel (); + + /** + * Given a sinr value, calculate the probability of a successful + * reception switch at the preamble/header portion of a packet + * + * \param the current sinr value + * + * \return the successful probability of the reception switch + */ + double CalculatePreambleCaptureProbability (double sinr); + + /** + * Given a sinr value, calculate the probability of a successful + * reception switch at the payload portion of a packet + * + * \param the current sinr value + * + * \return the successful probability of the reception switch + */ + double CalculatePayloadCaptureProbability (double sinr); +private: + /** + * Calculate a coded bit error rate + * + * \param p + * + * \return BER + */ + double CalculatePe (double p); +}; + +} //namespace ns3 + +#endif /* FRAME_CAPTURE_MODEL_H */ diff --git a/src/wifi/model/interference-helper.cc b/src/wifi/model/interference-helper.cc --- a/src/wifi/model/interference-helper.cc +++ b/src/wifi/model/interference-helper.cc @@ -251,14 +251,20 @@ InterferenceHelper::CalculateNoiseInterferenceW (Ptr event, NiChanges *ni) const { double noiseInterference = m_firstPower; - NS_ASSERT (m_rxing); - for (NiChanges::const_iterator i = m_niChanges.begin () + 1; i != m_niChanges.end (); i++) + for (NiChanges::const_iterator i = m_niChanges.begin (); i != m_niChanges.end (); ++i) { - if ((event->GetEndTime () == i->GetTime ()) && event->GetRxPowerW () == -i->GetDelta ()) + if (i->GetTime () < event->GetStartTime ()) + { + noiseInterference += i->GetDelta (); + } + else if (i->GetTime () > event->GetStartTime () && i->GetTime () < event->GetEndTime ()) + { + ni->push_back (*i); + } + else if (event->GetEndTime () == i->GetTime () && event->GetRxPowerW () == -i->GetDelta ()) { break; } - ni->push_back (*i); } ni->insert (ni->begin (), NiChange (event->GetStartTime (), noiseInterference)); ni->push_back (NiChange (event->GetEndTime (), 0)); @@ -865,4 +871,16 @@ m_rxing = false; } +double +InterferenceHelper::CalculatePreambleCaptureProbability (double sinr) +{ + return m_frameCaptureModel->CalculatePreambleCaptureProbability (sinr); +} + +double +InterferenceHelper::CalculatePayloadCaptureProbability (double sinr) +{ + return m_frameCaptureModel->CalculatePayloadCaptureProbability (sinr); +} + } //namespace ns3 diff --git a/src/wifi/model/interference-helper.h b/src/wifi/model/interference-helper.h --- a/src/wifi/model/interference-helper.h +++ b/src/wifi/model/interference-helper.h @@ -24,6 +24,7 @@ #include "ns3/nstime.h" #include "wifi-tx-vector.h" #include "error-rate-model.h" +#include "frame-capture-model.h" namespace ns3 { @@ -206,7 +207,21 @@ * Erase all events. */ void EraseEvents (void); - + // following methods used to support frame capture capability + /** + * Calculate the successful probability for preamble capture + * \param sinr the sinr value at the current time + * + * \return the probability of the successful preamble capture with the given sinr + */ + double CalculatePreambleCaptureProbability (double sinr); + /** + * Calculate the successful probability for payload capture + * \param sinr the sinr value at the current time + * + * \return the probability of the successful payload capture with the given sinr + */ + double CalculatePayloadCaptureProbability (double sinr); private: /** @@ -322,6 +337,9 @@ NiChanges m_niChanges; double m_firstPower; bool m_rxing; + // following variables used for frame capture capability + Ptr m_frameCaptureModel; + /// Returns an iterator to the first nichange, which is later than moment NiChanges::iterator GetPosition (Time moment); /** diff --git a/src/wifi/model/wifi-phy-state-helper.cc b/src/wifi/model/wifi-phy-state-helper.cc --- a/src/wifi/model/wifi-phy-state-helper.cc +++ b/src/wifi/model/wifi-phy-state-helper.cc @@ -541,4 +541,19 @@ } } +void +WifiPhyStateHelper::SwitchFromRxAbort (Ptr packet, double snr) +{ + NS_ASSERT (IsStateRx ()); + NS_ASSERT (m_rxing); + m_rxErrorTrace (packet, snr); + NotifyRxEndError (); + m_endRx = Simulator::Now (); + DoSwitchFromRx (); + NS_ASSERT (!IsStateRx ()); + if (!m_rxErrorCallback.IsNull ()) + { + m_rxErrorCallback (packet, snr); + } +} } //namespace ns3 diff --git a/src/wifi/model/wifi-phy-state-helper.h b/src/wifi/model/wifi-phy-state-helper.h --- a/src/wifi/model/wifi-phy-state-helper.h +++ b/src/wifi/model/wifi-phy-state-helper.h @@ -181,7 +181,10 @@ * \param duration the duration of CCA busy state */ void SwitchFromSleep (Time duration); - + /** + * Abort current reception + */ + void SwitchFromRxAbort (Ptr packet, double snr); /** \todo Why is this public? */ TracedCallback m_stateLogger; diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -308,6 +308,16 @@ MakeBooleanAccessor (&WifiPhy::GetShortPlcpPreambleSupported, &WifiPhy::SetShortPlcpPreambleSupported), MakeBooleanChecker ()) + .AddAttribute ("PreambleCaptureEnabled", + "Whether or not to enable capture at the preamble portion of the packet.", + BooleanValue (false), + MakeBooleanAccessor (&WifiPhy::m_doPreambleCapture), + MakeBooleanChecker ()) + .AddAttribute ("PayloadCaptureEnabled", + "Whether or not to enable capture at the payload portion of the packet", + BooleanValue (false), + MakeBooleanAccessor (&WifiPhy::m_doPayloadCapture), + MakeBooleanChecker ()) .AddTraceSource ("PhyTxBegin", "Trace source indicating a packet " "has begun transmitting over the channel medium", @@ -883,9 +893,9 @@ { // erase all HtMcs modes from deviceMcsSet size_t index = m_deviceMcsSet.size () - 1; - for (std::vector::reverse_iterator rit = m_deviceMcsSet.rbegin (); rit != m_deviceMcsSet.rend(); ++rit, --index) + for (std::vector::reverse_iterator rit = m_deviceMcsSet.rbegin (); rit != m_deviceMcsSet.rend (); ++rit, --index) { - if (m_deviceMcsSet[index].GetModulationClass ()== WIFI_MOD_CLASS_HT) + if (m_deviceMcsSet[index].GetModulationClass () == WIFI_MOD_CLASS_HT) { m_deviceMcsSet.erase (m_deviceMcsSet.begin () + index); } @@ -999,8 +1009,8 @@ { if (it->second == f) { - found = true; - break; + found = true; + break; } ++it; } @@ -1945,12 +1955,12 @@ //check tables 20-35 and 20-36 in the .11n standard to get cases when nes = 2 double Nes = 1; if (payloadMode.GetUniqueName () == "HtMcs21" - || payloadMode.GetUniqueName () == "HtMcs22" - || payloadMode.GetUniqueName () == "HtMcs23" - || payloadMode.GetUniqueName () == "HtMcs28" - || payloadMode.GetUniqueName () == "HtMcs29" - || payloadMode.GetUniqueName () == "HtMcs30" - || payloadMode.GetUniqueName () == "HtMcs31") + || payloadMode.GetUniqueName () == "HtMcs22" + || payloadMode.GetUniqueName () == "HtMcs23" + || payloadMode.GetUniqueName () == "HtMcs28" + || payloadMode.GetUniqueName () == "HtMcs29" + || payloadMode.GetUniqueName () == "HtMcs30" + || payloadMode.GetUniqueName () == "HtMcs31") { Nes = 2; } @@ -2125,7 +2135,7 @@ Time WifiPhy::CalculatePlcpPreambleAndHeaderDuration (WifiTxVector txVector) { - WifiPreamble preamble = txVector.GetPreambleType(); + WifiPreamble preamble = txVector.GetPreambleType (); Time duration = GetPlcpPreambleDuration (txVector) + GetPlcpHeaderDuration (txVector) + GetPlcpHtSigHeaderDuration (preamble) @@ -2213,7 +2223,7 @@ * - we are idle */ NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ()); - + if (txVector.GetNss () > GetMaxSupportedTxSpatialStreams ()) { NS_FATAL_ERROR ("Unsupported number of spatial streams!"); @@ -2252,7 +2262,7 @@ newPacket->RemovePacketTag (oldtag); WifiPhyTag tag (txVector, mpdutype); newPacket->AddPacketTag (tag); - + StartTx (newPacket, txVector, txDuration); } @@ -2264,7 +2274,7 @@ NS_LOG_FUNCTION (this << packet << WToDbm (rxPowerW) << rxDuration); AmpduTag ampduTag; Time endRx = Simulator::Now () + rxDuration; - + WifiPhyTag tag; bool found = packet->RemovePacketTag (tag); if (!found) @@ -2274,17 +2284,17 @@ } WifiTxVector txVector = tag.GetWifiTxVector (); - + if (txVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT && (txVector.GetNss () != (1 + (txVector.GetMode ().GetMcsValue () / 8)))) { NS_FATAL_ERROR ("MCS value does not match NSS value: MCS = " << (uint16_t)txVector.GetMode ().GetMcsValue () << ", NSS = " << (uint16_t)txVector.GetNss ()); } - + if (txVector.GetNss () > GetMaxSupportedRxSpatialStreams ()) - { + { NS_FATAL_ERROR ("Reception ends in failure because of an unsupported number of spatial streams"); - } + } WifiPreamble preamble = txVector.GetPreambleType (); MpduType mpdutype = tag.GetMpduType (); @@ -2314,20 +2324,47 @@ { //that packet will be noise _after_ the completion of the //channel switching. - goto maybeCcaBusy; + CalculateCcaBusyDuration (); } break; case WifiPhy::RX: - NS_LOG_DEBUG ("drop packet because already in Rx (power=" << - rxPowerW << "W)"); - NotifyRxDrop (packet); - if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) - { - //that packet will be noise _after_ the reception of the - //currently-received packet. - goto maybeCcaBusy; - } - break; + { + NS_ASSERT (m_rxPacketEvent != NULL); + if (m_doPreambleCapture == false + || m_doPayloadCapture == false + || preamble == WIFI_PREAMBLE_NONE) + { + NS_LOG_DEBUG ("cannot perform frame capture capture"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + CalculateCcaBusyDuration (); + } + break; + } + + Time currentRxStage = Simulator::Now () - m_rxPacketEvent->GetStartTime (); + bool doReceptionSwitch = false; + if (m_rxPreambleType != WIFI_PREAMBLE_NONE + && currentRxStage < preambleAndHeaderDuration) // still receiving the preamble and plcp header portion of the old packet + { + doReceptionSwitch = CheckPreambleCapture (packet, event); + } + else + { + doReceptionSwitch = CheckPayloadCapture (packet, event); + } + if (doReceptionSwitch) + { + NS_LOG_INFO ("The receiver switches to the new packet (rxPowerDbm " << WToDbm (event->GetRxPowerW ()) << ")"); + m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, &WifiPhy::StartReceivePacket, this, + packet, txVector, mpdutype, event); + m_endRxEvent = Simulator::Schedule (rxDuration, &WifiPhy::EndReceive, this, + packet, preamble, mpdutype, event); + m_rxPreambleType = preamble; + } + break; + } case WifiPhy::TX: NS_LOG_DEBUG ("drop packet because already in Tx (power=" << rxPowerW << "W)"); @@ -2336,7 +2373,7 @@ { //that packet will be noise _after_ the transmission of the //currently-transmitted packet. - goto maybeCcaBusy; + CalculateCcaBusyDuration (); } break; case WifiPhy::CCA_BUSY: @@ -2349,7 +2386,7 @@ m_mpdusNum = 0; NS_LOG_DEBUG ("drop packet because no PLCP preamble/header has been received"); NotifyRxDrop (packet); - goto maybeCcaBusy; + CalculateCcaBusyDuration (); } else if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0) { @@ -2387,6 +2424,9 @@ NS_ASSERT (m_endPlcpRxEvent.IsExpired ()); NotifyRxBegin (packet); m_interference.NotifyRxStart (); + m_rxPacket = packet; + m_rxPacketEvent = event; + m_rxPreambleType = preamble; if (preamble != WIFI_PREAMBLE_NONE) { @@ -2405,7 +2445,7 @@ rxPowerW << "<" << GetEdThresholdW () << ")"); NotifyRxDrop (packet); m_plcpSuccess = false; - goto maybeCcaBusy; + CalculateCcaBusyDuration (); } break; case WifiPhy::SLEEP: @@ -2416,12 +2456,16 @@ } return; - -maybeCcaBusy: - //We are here because we have received the first bit of a packet and we are - //not going to be able to synchronize on it - //In this model, CCA becomes busy when the aggregation of all signals as - //tracked by the InterferenceHelper class is higher than the CcaBusyThreshold +} + +void +WifiPhy::CalculateCcaBusyDuration () +{ +// maybeCcaBusy: +//We are here because we have received the first bit of a packet and we are +//not going to be able to synchronize on it +//In this model, CCA becomes busy when the aggregation of all signals as +//tracked by the InterferenceHelper class is higher than the CcaBusyThreshold Time delayUntilCcaEnd = m_interference.GetEnergyDuration (DbmToW (GetCcaMode1Threshold ())); if (!delayUntilCcaEnd.IsZero ()) @@ -2430,6 +2474,143 @@ } } +bool +WifiPhy::CheckPreambleCapture (Ptr packet, Ptr event) +{ + NS_LOG_FUNCTION (this << packet << event); + NS_LOG_DEBUG (Simulator::Now () << ", preamble capture check: old reception event start at " + << m_rxPacketEvent->GetStartTime () + << ", old preamble type " << m_rxPreambleType + << ", end at " << m_rxPacketEvent->GetEndTime () + << ", old rxPower " << m_rxPacketEvent->GetRxPowerW ()); + bool result = false; + Time endRx = event->GetEndTime (); + InterferenceHelper::SnrPer snrPer; + snrPer = m_interference.CalculatePlcpHeaderSnrPer (m_rxPacketEvent); // check whether the plcp header can still decoded + NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); + if (m_random->GetValue () > snrPer.per) // the reception of the old packet can be continued + { + NS_ASSERT (m_endPlcpRxEvent.IsRunning ()); + NS_LOG_INFO (Simulator::Now () << " preamble capture check: dropping newly arrived packet" + << ", because already sync to a stronger enough signal"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + CalculateCcaBusyDuration (); + } + } + else // the reception of the old packet cannot be continued + { + NS_LOG_INFO (Simulator::Now () << " preamble capture check: dropping currently received packet"); + AbortCurrentReception (m_rxPacket, snrPer.snr); + + NS_ASSERT (m_endPlcpRxEvent.IsExpired () && m_endRxEvent.IsExpired ()); + NS_LOG_INFO (Simulator::Now () << " preamble capture check: switch to new packet"); + + InterferenceHelper::SnrPer snrPerForNewPkt; + snrPerForNewPkt = m_interference.CalculatePlcpHeaderSnrPer (event); + double prob = m_interference.CalculatePreambleCaptureProbability (snrPerForNewPkt.snr); + if (m_random->GetValue () < prob) + { + SwitchReception (packet, event); + result = true; + } + else + { + NS_LOG_INFO (Simulator::Now () << " preamble capture: signal is too low for capture"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + CalculateCcaBusyDuration (); + } + } + } + return result; +} + +bool +WifiPhy::CheckPayloadCapture (Ptr packet, Ptr event) +{ + NS_LOG_FUNCTION (this << packet << event); + NS_LOG_DEBUG (Simulator::Now () << ", payload capture check: old reception event start at " + << m_rxPacketEvent->GetStartTime () + << ", end at " << m_rxPacketEvent->GetEndTime () + << ", old rxPower " << m_rxPacketEvent->GetRxPowerW ()); + bool result = false; + Time endRx = event->GetEndTime (); + InterferenceHelper::SnrPer snrPer; + snrPer = m_interference.CalculatePlcpPayloadSnrPer (m_rxPacketEvent); // check whether the plcp header can still decoded + NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); + if (m_random->GetValue () > snrPer.per) // the reception of the old packet can be continued + { + NS_ASSERT (m_endRxEvent.IsRunning ()); + NS_LOG_INFO (Simulator::Now () << " payload capture check: dropping newly arrived packet" + << ", because already sync to a stronger enough signal"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + CalculateCcaBusyDuration (); + } + } + else // the reception of the old packet cannot be continued + { + NS_LOG_INFO (Simulator::Now () << " preamble capture check: dropping currently received packet"); + AbortCurrentReception (m_rxPacket, snrPer.snr); + + NS_ASSERT (m_endPlcpRxEvent.IsExpired () && m_endRxEvent.IsExpired ()); + NS_LOG_INFO (Simulator::Now () << " payload capture check: switch to new packet"); + + InterferenceHelper::SnrPer snrPerForNewPkt; + snrPerForNewPkt = m_interference.CalculatePlcpPayloadSnrPer (event); + double prob = m_interference.CalculatePayloadCaptureProbability (snrPerForNewPkt.snr); + if (m_random->GetValue () < prob) + { + SwitchReception (packet, event); + result = true; + } + else + { + NS_LOG_INFO (Simulator::Now () << " payload capture: signal is too low for capture"); + NotifyRxDrop (packet); + if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) + { + CalculateCcaBusyDuration (); + } + } + } + return result; +} + +void +WifiPhy::AbortCurrentReception (Ptr packet, double sinr) +{ + NS_LOG_FUNCTION (this << packet << sinr); + if (m_endPlcpRxEvent.IsRunning ()) + { + m_endPlcpRxEvent.Cancel (); + } + if (m_endRxEvent.IsRunning ()) + { + m_endRxEvent.Cancel (); + } + m_interference.NotifyRxEnd (); + m_state->SwitchFromRxAbort (packet, sinr); + m_rxPacket = NULL; + m_rxPacketEvent = NULL; + m_rxPreambleType = WIFI_PREAMBLE_NONE; +} + +void +WifiPhy::SwitchReception (Ptr packet, Ptr event) +{ + NS_LOG_FUNCTION (this << packet << event); + m_rxPacket = packet; + m_rxPacketEvent = event; + m_state->SwitchToRx (event->GetDuration ()); + NotifyRxBegin (packet); + m_interference.NotifyRxStart (); +} + void WifiPhy::StartReceivePacket (Ptr packet, WifiTxVector txVector, @@ -2452,6 +2633,7 @@ { NS_LOG_DEBUG ("receiving plcp payload"); //endReceive is already scheduled m_plcpSuccess = true; + NS_LOG_INFO ("decode plcp successfully (rxPowerDbm " << WToDbm (event->GetRxPowerW ()) << ")"); } else //mode is not allowed { @@ -2495,6 +2677,7 @@ aMpdu.mpduRefNumber = m_rxMpduReferenceNumber; NotifyMonitorSniffRx (packet, GetFrequency (), event->GetTxVector (), aMpdu, signalNoise); m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector ()); + NS_LOG_INFO ("decode payload successfully (rxPowerDbm " << WToDbm (event->GetRxPowerW ()) << ")"); } else { @@ -3311,7 +3494,7 @@ WifiPhy::IsValidTxVector (WifiTxVector txVector) { uint8_t chWidth = txVector.GetChannelWidth (); - uint8_t nss = txVector.GetNss(); + uint8_t nss = txVector.GetNss (); std::string modeName = txVector.GetMode ().GetUniqueName (); if (chWidth == 20) diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -1516,7 +1516,6 @@ */ virtual std::vector GetSupportedChannelWidthSet (void) const; - protected: // Inherited virtual void DoInitialize (void); @@ -1733,7 +1732,48 @@ * of its size. */ TracedCallback, uint16_t, WifiTxVector, MpduInfo> m_phyMonitorSniffTxTrace; - + + /** + * Due to newly arrived signal, the old reception cannot be continued and has to be abort + * + * \param packet, the packet which has to be aborted + * \param sinr, the sinr of the aborted packet + */ + void AbortCurrentReception (Ptr packet, double sinr); + + /** + * Calculate the duration of CCA busy + */ + void CalculateCcaBusyDuration (void); + + /** + * Check whether preamble capture can be triggered + * + * \param packet the newly arrived packet which needs to be check for capture + * \param event the receiving event associated with the receiving packet + * + * \return whether the capture, i.e., reception switching, has been successful + */ + bool CheckPreambleCapture (Ptr packet, Ptr event); + + /** + * Check whether payload capture can be triggered + * + * \param packet the newly arrived packet which needs to be check for capture + * \param event the receiving event associated with the receiving packet + * + * \return whether the capture, i.e., reception switching, has been successful + */ + bool CheckPayloadCapture (Ptr packet, Ptr event); + + /** + * The new packet passes the check and the receiver is going to switch to the new packet + * + * \param packet the packet will be switched to + * \param event receiving event associated with the packet + */ + void SwitchReception (Ptr packet, Ptr event); + /** * This vector holds the set of transmission modes that this * WifiPhy(-derived class) can support. In conversation we call this @@ -1816,6 +1856,13 @@ Ptr m_device; //!< Pointer to the device Ptr m_mobility; //!< Pointer to the mobility model + + // following variables used to support frame capture capability + Ptr m_rxPacket; // The packet that is currently being received by the receiver + Ptr m_rxPacketEvent; // The event that indicates the current receiving event + bool m_doPreambleCapture; // The flag indicates whether the capture at the preamble portion of the packet is enabled or not + bool m_doPayloadCapture; // The flag indicates whether the capture at the payload(data) portion of the packet is enabled or not + WifiPreamble m_rxPreambleType; // The preamble type of the currently receiving frame }; /** diff --git a/src/wifi/wscript b/src/wifi/wscript --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -82,6 +82,7 @@ 'model/vht-operation.cc', 'model/dsss-parameter-set.cc', 'model/edca-parameter-set.cc', + 'model/frame-capture-model.cc', 'helper/wifi-radio-energy-model-helper.cc', 'helper/vht-wifi-mac-helper.cc', 'helper/ht-wifi-mac-helper.cc', @@ -188,6 +189,7 @@ 'model/vht-operation.h', 'model/dsss-parameter-set.h', 'model/edca-parameter-set.h', + 'model/frame-capture-model.h', 'helper/wifi-radio-energy-model-helper.h', 'helper/vht-wifi-mac-helper.h', 'helper/ht-wifi-mac-helper.h',