9#include "ns3/boolean.h"
10#include "ns3/command-line.h"
11#include "ns3/config.h"
12#include "ns3/double.h"
13#include "ns3/eht-phy.h"
15#include "ns3/internet-stack-helper.h"
16#include "ns3/ipv4-address-helper.h"
18#include "ns3/mobility-helper.h"
19#include "ns3/multi-model-spectrum-channel.h"
20#include "ns3/on-off-helper.h"
21#include "ns3/packet-sink-helper.h"
22#include "ns3/packet-sink.h"
23#include "ns3/spectrum-wifi-helper.h"
25#include "ns3/string.h"
26#include "ns3/udp-client-server-helper.h"
27#include "ns3/udp-server.h"
28#include "ns3/uinteger.h"
29#include "ns3/wifi-acknowledgment.h"
30#include "ns3/yans-wifi-channel.h"
31#include "ns3/yans-wifi-helper.h"
68 std::vector<uint64_t> rxBytes(serverApp.
GetN(), 0);
103 auto newRxBytes =
GetRxBytes(udp, serverApp, payloadSize);
106 std::cout <<
"[" << (now - tputInterval).As(
Time::S) <<
" - " << now.
As(
Time::S)
107 <<
"] Per-STA Throughput (Mbit/s):";
109 for (std::size_t i = 0; i < newRxBytes.size(); i++)
111 std::cout <<
"\t\t(" << i <<
") "
114 std::cout << std::endl;
116 rxBytes.swap(newRxBytes);
132main(
int argc,
char* argv[])
137 bool use80Plus80{
false};
138 uint16_t mpduBufferSize{512};
139 std::string emlsrLinks;
140 uint16_t paddingDelayUsec{32};
141 uint16_t transitionDelayUsec{128};
142 uint16_t channelSwitchDelayUsec{100};
143 bool switchAuxPhy{
true};
144 uint16_t auxPhyChWidth{20};
145 bool auxPhyTxCapable{
true};
146 Time simulationTime{
"10s"};
149 double frequency2{0};
153 std::size_t nStations{1};
154 std::string dlAckSeqType{
"NO-OFDMA"};
155 bool enableUlOfdma{
false};
156 bool enableBsrp{
false};
160 Time tputInterval{0};
161 double minExpectedThroughput{0};
162 double maxExpectedThroughput{0};
163 Time accessReqInterval{0};
168 "Whether the first link operates in the 2.4, 5 or 6 GHz band (other values gets rejected)",
172 "Whether the second link operates in the 2.4, 5 or 6 GHz band (0 means the device has one "
173 "link, otherwise the band must be different than first link and third link)",
177 "Whether the third link operates in the 2.4, 5 or 6 GHz band (0 means the device has up to "
178 "two links, otherwise the band must be different than first link and second link)",
180 cmd.AddValue(
"emlsrLinks",
181 "The comma separated list of IDs of EMLSR links (for MLDs only)",
183 cmd.AddValue(
"emlsrPaddingDelay",
184 "The EMLSR padding delay in microseconds (0, 32, 64, 128 or 256)",
186 cmd.AddValue(
"emlsrTransitionDelay",
187 "The EMLSR transition delay in microseconds (0, 16, 32, 64, 128 or 256)",
188 transitionDelayUsec);
189 cmd.AddValue(
"emlsrAuxSwitch",
190 "Whether Aux PHY should switch channel to operate on the link on which "
191 "the Main PHY was operating before moving to the link of the Aux PHY. ",
193 cmd.AddValue(
"emlsrAuxChWidth",
194 "The maximum channel width (MHz) supported by Aux PHYs.",
196 cmd.AddValue(
"emlsrAuxTxCapable",
197 "Whether Aux PHYs are capable of transmitting.",
199 cmd.AddValue(
"channelSwitchDelay",
200 "The PHY channel switch delay in microseconds",
201 channelSwitchDelayUsec);
202 cmd.AddValue(
"distance",
203 "Distance in meters between the station and the access point",
205 cmd.AddValue(
"simulationTime",
"Simulation time", simulationTime);
206 cmd.AddValue(
"udp",
"UDP if set to 1, TCP otherwise", udp);
207 cmd.AddValue(
"downlink",
208 "Generate downlink flows if set to 1, uplink flows otherwise",
210 cmd.AddValue(
"useRts",
"Enable/disable RTS/CTS", useRts);
211 cmd.AddValue(
"use80Plus80",
"Enable/disable use of 80+80 MHz", use80Plus80);
212 cmd.AddValue(
"mpduBufferSize",
213 "Size (in number of MPDUs) of the BlockAck buffer",
215 cmd.AddValue(
"nStations",
"Number of non-AP EHT stations", nStations);
216 cmd.AddValue(
"dlAckType",
217 "Ack sequence type for DL OFDMA (NO-OFDMA, ACK-SU-FORMAT, MU-BAR, AGGR-MU-BAR)",
219 cmd.AddValue(
"enableUlOfdma",
220 "Enable UL OFDMA (useful if DL OFDMA is enabled and TCP is used)",
222 cmd.AddValue(
"enableBsrp",
223 "Enable BSRP (useful if DL and UL OFDMA are enabled and TCP is used)",
226 "muSchedAccessReqInterval",
227 "Duration of the interval between two requests for channel access made by the MU scheduler",
229 cmd.AddValue(
"mcs",
"if set, limit testing to a specific MCS (0-11)", mcs);
230 cmd.AddValue(
"payloadSize",
"The application payload size in bytes", payloadSize);
231 cmd.AddValue(
"tputInterval",
"duration of intervals for throughput measurement", tputInterval);
232 cmd.AddValue(
"minExpectedThroughput",
233 "if set, simulation fails if the lowest throughput is below this value",
234 minExpectedThroughput);
235 cmd.AddValue(
"maxExpectedThroughput",
236 "if set, simulation fails if the highest throughput is above this value",
237 maxExpectedThroughput);
238 cmd.Parse(argc, argv);
246 if (dlAckSeqType ==
"ACK-SU-FORMAT")
251 else if (dlAckSeqType ==
"MU-BAR")
256 else if (dlAckSeqType ==
"AGGR-MU-BAR")
261 else if (dlAckSeqType !=
"NO-OFDMA")
263 NS_ABORT_MSG(
"Invalid DL ack sequence type (must be NO-OFDMA, ACK-SU-FORMAT, MU-BAR or "
267 double prevThroughput[12] = {0};
269 std::cout <<
"MCS value"
275 <<
"Throughput" <<
'\n';
278 if (mcs >= 0 && mcs <= 13)
283 for (
int mcs = minMcs; mcs <= maxMcs; mcs++)
287 uint16_t maxChannelWidth =
288 (frequency != 2.4 && frequency2 != 2.4 && frequency3 != 2.4) ? 160 : 40;
289 int minGi = enableUlOfdma ? 1600 : 800;
290 for (
int channelWidth = 20; channelWidth <= maxChannelWidth;)
292 const auto is80Plus80 = (use80Plus80 && (channelWidth == 160));
293 const std::string widthStr = is80Plus80 ?
"80+80" : std::to_string(channelWidth);
294 const auto segmentWidthStr = is80Plus80 ?
"80" : widthStr;
295 for (
int gi = 3200; gi >= minGi;)
313 std::array<std::string, 3> channelStr;
314 std::array<FrequencyRange, 3> freqRanges;
316 std::string dataModeStr =
"EhtMcs" + std::to_string(mcs);
317 std::string ctrlRateStr;
320 if (frequency2 == frequency || frequency3 == frequency ||
321 (frequency3 != 0 && frequency3 == frequency2))
326 for (
auto freq : {frequency, frequency2, frequency3})
328 if (nLinks > 0 && freq == 0)
332 channelStr[nLinks] =
"{0, " + segmentWidthStr +
", ";
335 channelStr[nLinks] +=
"BAND_6GHZ, 0}";
339 wifi.SetRemoteStationManager(nLinks,
340 "ns3::ConstantRateWifiManager",
348 channelStr[nLinks] +=
"BAND_5GHZ, 0}";
350 ctrlRateStr =
"OfdmRate" + std::to_string(nonHtRefRateMbps) +
"Mbps";
351 wifi.SetRemoteStationManager(nLinks,
352 "ns3::ConstantRateWifiManager",
358 else if (freq == 2.4)
360 channelStr[nLinks] +=
"BAND_2_4GHZ, 0}";
364 ctrlRateStr =
"ErpOfdmRate" + std::to_string(nonHtRefRateMbps) +
"Mbps";
365 wifi.SetRemoteStationManager(nLinks,
366 "ns3::ConstantRateWifiManager",
379 channelStr[nLinks] += std::string(
";") + channelStr[nLinks];
385 if (nLinks > 1 && !emlsrLinks.empty())
396 mac.SetType(
"ns3::StaWifiMac",
"Ssid",
SsidValue(ssid));
397 mac.SetEmlsrManager(
"ns3::DefaultEmlsrManager",
402 "EmlsrTransitionDelay",
408 "AuxPhyChannelWidth",
410 for (uint8_t linkId = 0; linkId < nLinks; linkId++)
412 phy.Set(linkId,
"ChannelSettings",
StringValue(channelStr[linkId]));
416 spectrumChannel->AddPropagationLossModel(lossModel);
417 phy.AddChannel(spectrumChannel, freqRanges[linkId]);
421 if (dlAckSeqType !=
"NO-OFDMA")
423 mac.SetMultiUserScheduler(
"ns3::RrMultiUserScheduler",
431 mac.SetType(
"ns3::ApWifiMac",
432 "EnableBeaconJitter",
436 apDevice =
wifi.Install(phy, mac, wifiApNode);
438 int64_t streamNumber = 100;
444 "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HeConfiguration/GuardInterval",
446 Config::Set(
"/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MpduBufferSize",
453 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
454 positionAlloc->Add(Vector(distance, 0.0, 0.0));
455 mobility.SetPositionAllocator(positionAlloc);
457 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
464 stack.Install(wifiApNode);
465 stack.Install(wifiStaNodes);
466 streamNumber +=
stack.AssignStreams(wifiApNode, streamNumber);
467 streamNumber +=
stack.AssignStreams(wifiStaNodes, streamNumber);
470 address.SetBase(
"192.168.1.0",
"255.255.255.0");
474 staNodeInterfaces =
address.Assign(staDevices);
475 apNodeInterface =
address.Assign(apDevice);
479 auto serverNodes = downlink ? std::ref(wifiStaNodes) :
std::ref(
wifiApNode);
482 for (std::size_t i = 0; i < nStations; i++)
485 : apNodeInterface.Get(0));
496 serverApp =
server.Install(serverNodes.get());
497 streamNumber +=
server.AssignStreams(serverNodes.get(), streamNumber);
501 const auto packetInterval = payloadSize * 8.0 / maxLoad;
503 for (std::size_t i = 0; i < nStations; i++)
510 streamNumber +=
client.AssignStreams(clientNodes.
Get(i), streamNumber);
519 uint16_t
port = 50000;
523 streamNumber +=
packetSinkHelper.AssignStreams(serverNodes.get(), streamNumber);
528 for (std::size_t i = 0; i < nStations; i++)
531 onoff.SetAttribute(
"OnTime",
532 StringValue(
"ns3::ConstantRandomVariable[Constant=1]"));
533 onoff.SetAttribute(
"OffTime",
534 StringValue(
"ns3::ConstantRandomVariable[Constant=0]"));
539 onoff.SetAttribute(
"Remote", remoteAddress);
541 streamNumber +=
onoff.AssignStreams(clientNodes.
Get(i), streamNumber);
549 std::vector<uint64_t> cumulRxBytes(nStations, 0);
551 if (tputInterval.IsStrictlyPositive())
560 simulationTime +
Seconds(1.0));
570 auto tolerance = 0.10;
571 cumulRxBytes =
GetRxBytes(udp, serverApp, payloadSize);
572 auto rxBytes = std::accumulate(cumulRxBytes.cbegin(), cumulRxBytes.cend(), 0.0);
573 auto throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds();
577 std::cout << +mcs <<
"\t\t\t" << widthStr <<
" MHz\t\t"
578 << (widthStr.size() > 3 ?
"" :
"\t") << gi <<
" ns\t\t\t" <<
throughput
579 <<
" Mbit/s" << std::endl;
582 if (mcs == minMcs && channelWidth == 20 && gi == 3200)
584 if (
throughput * (1 + tolerance) < minExpectedThroughput)
591 if (mcs == maxMcs && channelWidth == maxChannelWidth && gi == 800)
593 if (maxExpectedThroughput > 0 &&
594 throughput > maxExpectedThroughput * (1 + tolerance))
611 if (
throughput * (1 + tolerance) > prevThroughput[index])
a polymophic address class
holds a vector of ns3::Application pointers.
void Start(Time start) const
Start all of the Applications in this container at the start time given as a parameter.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
void Stop(Time stop) const
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter.
uint32_t GetN() const
Get the number of Ptr<Application> stored in this container.
Parse command-line arguments.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
static uint64_t GetDataRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
Return the data rate corresponding to the supplied EHT MCS index, channel width, guard interval,...
static uint64_t GetNonHtReferenceRate(uint8_t mcsValue)
Calculate the rate in bps of the non-HT Reference Rate corresponding to the supplied HE MCS index.
Hold variables of type enum.
aggregate IP/TCP/UDP functionality to existing Nodes.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
static Ipv4Address GetAny()
holds a vector of std::pair of Ptr<Ipv4> and interface index.
std::pair< Ptr< Ipv4 >, uint32_t > Get(uint32_t i) const
Get the std::pair of an Ptr<Ipv4> and interface stored at the location specified by the index.
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
keep track of a set of node pointers.
void Add(const NodeContainer &nc)
Append the contents of another NodeContainer to the end of this container.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
A helper to make it easier to instantiate an ns3::OnOffApplication on a set of nodes.
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
static Time Now()
Return the current simulation virtual time.
static void Run()
Run the simulation.
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Hold variables of type string.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Create a client application which sends UDP packets carrying a 32bit sequence number and a 64 bit tim...
Create a server application which waits for input UDP packets and uses the information carried into t...
Hold an unsigned integer type.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
void SetDefault(std::string name, const AttributeValue &value)
void Set(std::string path, const AttributeValue &value)
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ
Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band.
void PrintIntermediateTput(std::vector< uint64_t > &rxBytes, bool udp, const ApplicationContainer &serverApp, uint32_t payloadSize, Time tputInterval, Time simulationTime)
Print average throughput over an intermediate time interval.
std::vector< uint64_t > GetRxBytes(bool udp, const ApplicationContainer &serverApp, uint32_t payloadSize)