Skip to content

Last Update: 2026-09-29

ns-3 による Wi-Fi シミュレーション


ns-3

ns-3 は GNU GPLv2 ライセンスで使えるネットワークシミュレーター。 ここでは、ns-3.44 と可視化用のアプリとして NetAnim 3.108 を使ってる。

インストールガイドでは、いろんな OS にインストールできるように書いてあって、macOS と Ubuntu Desktop で試したけど、NetAnim を使うなら Ubuntu Desktop にインストールする方がいいと思う(macOS だと、Wi-Fi フレームの可視化がうまくできなかった)。

Wi-Fi のシミュレーションの結果は、パケットキャプチャファイルとして出力できるし、NetAnim を使ってアニメーションとしても出力できる。さらに、FlowMonitor を使えば、スループット・遅延・パケットロス割合の統計情報も出力できる。

ns-3 を使うメリット

  • 実機だと設定が難しかったり、そもそも設定できないパラメーターがあっても、ns-3 なら調整できる可能性が広がる
  • 現実世界で Wi-Fi のスループットとかを計測しようとすると、当然ほかの Wi-Fi 電波が干渉してしまうけど、ns-3 なら物理的な干渉を排除できるので再現性が高い
  • 学術研究目的でも使えるらしいけど、そこまでじゃなくても、IEEE 802.11 MAC の仕様を学習する目的でも使える

※ ns-3 の Wi-Fi のスコープとか制限は Scope and Limitations に書いてある。例えば 4-Way Handshake はシミュレーションでは観察できないけど、Wi-Fi 接続が完了した後のスループットとかを観察するなら問題ない


ns-3 のインストール

Ubuntu 22.04.5 LTS にインストールした時のコマンド。
cf. https://www.nsnam.org/docs/release/3.44/installation/html/quick-start.html
cf. https://www.nsnam.org/docs/release/3.44/installation/html/linux.html

ishigaki@ishigaki-NS3:~$ sudo apt update

ishigaki@ishigaki-NS3:~$ sudo apt install build-essential libsqlite3-dev libboost-all-dev libssl-dev git python3-setuptools castxml

ishigaki@ishigaki-NS3:~$ sudo apt install gir1.2-goocanvas-2.0 gir1.2-gtk-3.0 libgirepository1.0-dev python3-dev python3-gi python3-gi-cairo python3-pip python3-pygraphviz python3-pygccxml

ishigaki@ishigaki-NS3:~$ sudo apt install g++ pkg-config sqlite3 mercurial ipython3 openmpi-bin openmpi-common openmpi-doc libopenmpi-dev autoconf cvs bzr unrar gdb valgrind uncrustify doxygen graphviz imagemagick python3-sphinx dia tcpdump libxml2 libxml2-dev cmake libc6-dev libc6-dev-i386 automake

ishigaki@ishigaki-NS3:~$ sudo apt install libclang-14-dev llvm-14-dev

ishigaki@ishigaki-NS3:~$ sudo apt install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools

ishigaki@ishigaki-NS3:~$ wget -c https://www.nsnam.org/releases/ns-allinone-3.44.tar.bz2

ishigaki@ishigaki-NS3:~$ tar -xvjf ns-allinone-3.44.tar.bz2

ishigaki@ishigaki-NS3:~$ cd ns-allinone-3.44/ns-3.44/

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ cat VERSION 
3.44

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 configure --enable-examples --enable-tests

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 build

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run hello-simulator
Hello Simulator

NetAnim のインストール

すでに netanim-3.109 がダウンロードできてそう(↓)だけど、NetAnim は参考書籍: Advanced Network Simulations Simplified とバージョンを合わせたいので、netanim-3.108 が欲しい。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l ../netanim-3.109/
total 24
-rw-rw-r-- 1 ishigaki ishigaki 6752  3月 10 08:55 CMakeLists.txt
drwxrwxr-x 2 ishigaki ishigaki 4096  7月  8 17:00 data
-rw-rw-r-- 1 ishigaki ishigaki 3331  3月 10 08:55 RELEASE_NOTES.md
drwxrwxr-x 2 ishigaki ishigaki 4096  7月  8 17:00 resources
drwxrwxr-x 3 ishigaki ishigaki 4096  7月  8 17:00 src

上の続きで、NetAnim をインストールした時のコマンド。
cf. https://www.nsnam.org/wiki/NetAnim_3.108

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ hg clone http://code.nsnam.org/netanim
real URL is https://code.nsnam.org/netanim
destination directory: netanim
requesting all changes
adding changesets
adding manifests
adding file changes
added 305 changesets with 1609 changes to 228 files
new changesets 9307cbf67965:7b4d3db98f92
updating to branch default
195 files updated, 0 files merged, 0 files removed, 0 files unresolved

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ cd netanim/

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ hg tags
tip                              304:7b4d3db98f92
netanim-3.108                    303:2ce82d2b8afd
netanim-3.107                    295:03c27126bae3
netanim-3.106                    285:43f60d3846ec
netanim-3.105                    252:c9866156ebf3

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ hg id -t
tip

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ hg update netanim-3.108
1 files updated, 0 files merged, 0 files removed, 0 files unresolved

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ hg id -t
netanim-3.108

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ make clean
make: *** No rule to make target 'clean'.  Stop.

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ qmake NetAnim.pro
Info: creating stash file /home/ishigaki/ns-allinone-3.44/ns-3.44/netanim/.qmake.stash

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ ls -l Makefile
-rw-rw-r-- 1 ishigaki ishigaki 75494  7月  9 08:46 Makefile

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ make -j$(nproc)

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ ls -l NetAnim
-rwxrwxr-x 1 ishigaki ishigaki 2898528  7月  9 08:48 NetAnim

サンプルシミュレーションの実行

ns-3 にはサンプルシミュレーションもたくさん同梱されていて、シミュレーションコードを書く前に、サンプルではどのように書かれているかをみておく方がいいかも。
まずはそのうちの 1 つを実行してみる。下記の examples/wireless/wifi-80211e-txop.cc は、IEEE 802.11e の TXOP limit を変えると、スループットがどう変わるかを比べるサンプル。

examples/wireless/wifi-80211e-txop.cc
/*
 * Copyright (c) 2016 Sébastien Deronne
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
 */

#include "ns3/command-line.h"
#include "ns3/internet-stack-helper.h"
#include "ns3/ipv4-address-helper.h"
#include "ns3/log.h"
#include "ns3/mobility-helper.h"
#include "ns3/on-off-helper.h"
#include "ns3/pointer.h"
#include "ns3/qos-txop.h"
#include "ns3/ssid.h"
#include "ns3/string.h"
#include "ns3/udp-client-server-helper.h"
#include "ns3/udp-server.h"
#include "ns3/wifi-mac.h"
#include "ns3/wifi-net-device.h"
#include "ns3/yans-wifi-channel.h"
#include "ns3/yans-wifi-helper.h"

// This is an example that illustrates 802.11 QoS for different Access Categories.
// It defines 4 independent Wi-Fi networks (working on different logical channels
// on the same "ns3::YansWifiPhy" channel object).
// Each network contains one access point and one station. Each station continuously
// transmits data packets to its respective AP.
//
// Network topology (numbers in parentheses are channel numbers):
//
//  BSS A (36)        BSS B (40)       BSS C (44)        BSS D (48)
//   *      *          *      *         *      *          *      *
//   |      |          |      |         |      |          |      |
//  AP A   STA A      AP B   STA B     AP C   STA C      AP D   STA D
//
// The configuration is the following on the 4 networks:
// - STA A sends AC_BE traffic to AP A with default AC_BE TXOP value of 0 (1 MSDU);
// - STA B sends AC_BE traffic to AP B with non-default AC_BE TXOP of 4096 us;
// - STA C sends AC_VI traffic to AP C with default AC_VI TXOP of 4096 us;
// - STA D sends AC_VI traffic to AP D with non-default AC_VI TXOP value of 0 (1 MSDU);
//
// The user can select the distance between the stations and the APs, can enable/disable the RTS/CTS
// mechanism and can choose the payload size and the simulation duration. Example: ./ns3 run
// "wifi-80211e-txop --distance=10 --simulationTime=20s --payloadSize=1000"
//
// The output prints the throughput measured for the 4 cases/networks described above. When TXOP is
// enabled, results show increased throughput since the channel is granted for a longer duration.
// TXOP is enabled by default for AC_VI and AC_VO, so that they can use the channel for a longer
// duration than AC_BE and AC_BK.

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("80211eTxop");

/**
 * Keeps the maximum duration among all TXOPs
 */
struct TxopDurationTracer
{
    /**
     * Callback connected to TXOP duration trace source.
     *
     * @param startTime TXOP start time
     * @param duration TXOP duration
     * @param linkId the ID of the link
     */
    void Trace(Time startTime, Time duration, uint8_t linkId);
    Time m_max; //!< maximum TXOP duration
};

void
TxopDurationTracer::Trace(Time startTime, Time duration, uint8_t linkId)
{
    if (duration > m_max)
    {
        m_max = duration;
    }
}

int
main(int argc, char* argv[])
{
    uint32_t payloadSize{1472}; // bytes
    Time simulationTime{"10s"};
    meter_u distance{5};
    bool enablePcap{false};
    bool verifyResults{false}; // used for regression
    Time txopLimit{"4096us"};

    CommandLine cmd(__FILE__);
    cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
    cmd.AddValue("distance",
                 "Distance in meters between the station and the access point",
                 distance);
    cmd.AddValue("enablePcap", "Enable/disable pcap file generation", enablePcap);
    cmd.AddValue("verifyResults",
                 "Enable/disable results verification at the end of the simulation",
                 verifyResults);
    cmd.Parse(argc, argv);

    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(4);
    NodeContainer wifiApNodes;
    wifiApNodes.Create(4);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
    phy.SetChannel(channel.Create());

    WifiHelper wifi;
    wifi.SetStandard(WIFI_STANDARD_80211a);
    wifi.SetRemoteStationManager("ns3::IdealWifiManager");
    WifiMacHelper mac;

    NetDeviceContainer staDeviceA;
    NetDeviceContainer staDeviceB;
    NetDeviceContainer staDeviceC;
    NetDeviceContainer staDeviceD;
    NetDeviceContainer apDeviceA;
    NetDeviceContainer apDeviceB;
    NetDeviceContainer apDeviceC;
    NetDeviceContainer apDeviceD;
    Ssid ssid;

    // Network A
    ssid = Ssid("network-A");
    phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
    mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));
    staDeviceA = wifi.Install(phy, mac, wifiStaNodes.Get(0));

    mac.SetType("ns3::ApWifiMac",
                "QosSupported",
                BooleanValue(true),
                "Ssid",
                SsidValue(ssid),
                "EnableBeaconJitter",
                BooleanValue(false));
    apDeviceA = wifi.Install(phy, mac, wifiApNodes.Get(0));

    // Network B
    ssid = Ssid("network-B");
    phy.Set("ChannelSettings", StringValue("{40, 20, BAND_5GHZ, 0}"));
    mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));

    staDeviceB = wifi.Install(phy, mac, wifiStaNodes.Get(1));

    mac.SetType("ns3::ApWifiMac",
                "QosSupported",
                BooleanValue(true),
                "Ssid",
                SsidValue(ssid),
                "EnableBeaconJitter",
                BooleanValue(false));
    apDeviceB = wifi.Install(phy, mac, wifiApNodes.Get(1));

    // Modify EDCA configuration (TXOP limit) for AC_BE
    Ptr<NetDevice> dev = wifiApNodes.Get(1)->GetDevice(0);
    Ptr<WifiNetDevice> wifi_dev = DynamicCast<WifiNetDevice>(dev);
    Ptr<WifiMac> wifi_mac = wifi_dev->GetMac();
    PointerValue ptr;
    Ptr<QosTxop> edca;
    wifi_mac->GetAttribute("BE_Txop", ptr);
    edca = ptr.Get<QosTxop>();
    edca->SetTxopLimit(txopLimit);

    // Trace TXOP duration for BE on STA1
    dev = wifiStaNodes.Get(1)->GetDevice(0);
    wifi_dev = DynamicCast<WifiNetDevice>(dev);
    wifi_mac = wifi_dev->GetMac();
    wifi_mac->GetAttribute("BE_Txop", ptr);
    edca = ptr.Get<QosTxop>();
    TxopDurationTracer beTxopTracer;
    edca->TraceConnectWithoutContext("TxopTrace",
                                     MakeCallback(&TxopDurationTracer::Trace, &beTxopTracer));

    // Network C
    ssid = Ssid("network-C");
    phy.Set("ChannelSettings", StringValue("{44, 20, BAND_5GHZ, 0}"));
    mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));

    staDeviceC = wifi.Install(phy, mac, wifiStaNodes.Get(2));

    mac.SetType("ns3::ApWifiMac",
                "QosSupported",
                BooleanValue(true),
                "Ssid",
                SsidValue(ssid),
                "EnableBeaconJitter",
                BooleanValue(false));
    apDeviceC = wifi.Install(phy, mac, wifiApNodes.Get(2));

    // Trace TXOP duration for VI on STA2
    dev = wifiStaNodes.Get(2)->GetDevice(0);
    wifi_dev = DynamicCast<WifiNetDevice>(dev);
    wifi_mac = wifi_dev->GetMac();
    wifi_mac->GetAttribute("VI_Txop", ptr);
    edca = ptr.Get<QosTxop>();
    TxopDurationTracer viTxopTracer;
    edca->TraceConnectWithoutContext("TxopTrace",
                                     MakeCallback(&TxopDurationTracer::Trace, &viTxopTracer));

    // Network D
    ssid = Ssid("network-D");
    phy.Set("ChannelSettings", StringValue("{48, 20, BAND_5GHZ, 0}"));
    mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));

    staDeviceD = wifi.Install(phy, mac, wifiStaNodes.Get(3));

    mac.SetType("ns3::ApWifiMac",
                "QosSupported",
                BooleanValue(true),
                "Ssid",
                SsidValue(ssid),
                "EnableBeaconJitter",
                BooleanValue(false));
    apDeviceD = wifi.Install(phy, mac, wifiApNodes.Get(3));

    // Modify EDCA configuration (TXOP limit) for AC_VO
    dev = wifiApNodes.Get(3)->GetDevice(0);
    wifi_dev = DynamicCast<WifiNetDevice>(dev);
    wifi_mac = wifi_dev->GetMac();
    wifi_mac->GetAttribute("VI_Txop", ptr);
    edca = ptr.Get<QosTxop>();
    edca->SetTxopLimit(MicroSeconds(0));

    /* Setting mobility model */
    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");

    // Set position for APs
    positionAlloc->Add(Vector(0.0, 0.0, 0.0));
    positionAlloc->Add(Vector(10.0, 0.0, 0.0));
    positionAlloc->Add(Vector(20.0, 0.0, 0.0));
    positionAlloc->Add(Vector(30.0, 0.0, 0.0));
    // Set position for STAs
    positionAlloc->Add(Vector(distance, 0.0, 0.0));
    positionAlloc->Add(Vector(10 + distance, 0.0, 0.0));
    positionAlloc->Add(Vector(20 + distance, 0.0, 0.0));
    positionAlloc->Add(Vector(30 + distance, 0.0, 0.0));
    // Remark: while we set these positions 10 meters apart, the networks do not interact
    // and the only variable that affects transmission performance is the distance.

    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNodes);
    mobility.Install(wifiStaNodes);

    /* Internet stack */
    InternetStackHelper stack;
    stack.Install(wifiApNodes);
    stack.Install(wifiStaNodes);

    Ipv4AddressHelper address;
    address.SetBase("192.168.1.0", "255.255.255.0");
    Ipv4InterfaceContainer StaInterfaceA;
    StaInterfaceA = address.Assign(staDeviceA);
    Ipv4InterfaceContainer ApInterfaceA;
    ApInterfaceA = address.Assign(apDeviceA);

    address.SetBase("192.168.2.0", "255.255.255.0");
    Ipv4InterfaceContainer StaInterfaceB;
    StaInterfaceB = address.Assign(staDeviceB);
    Ipv4InterfaceContainer ApInterfaceB;
    ApInterfaceB = address.Assign(apDeviceB);

    address.SetBase("192.168.3.0", "255.255.255.0");
    Ipv4InterfaceContainer StaInterfaceC;
    StaInterfaceC = address.Assign(staDeviceC);
    Ipv4InterfaceContainer ApInterfaceC;
    ApInterfaceC = address.Assign(apDeviceC);

    address.SetBase("192.168.4.0", "255.255.255.0");
    Ipv4InterfaceContainer StaInterfaceD;
    StaInterfaceD = address.Assign(staDeviceD);
    Ipv4InterfaceContainer ApInterfaceD;
    ApInterfaceD = address.Assign(apDeviceD);

    /* Setting applications */
    uint16_t port = 5001;
    UdpServerHelper serverA(port);
    ApplicationContainer serverAppA = serverA.Install(wifiApNodes.Get(0));
    serverAppA.Start(Seconds(0));
    serverAppA.Stop(simulationTime + Seconds(1));

    InetSocketAddress destA(ApInterfaceA.GetAddress(0), port);

    OnOffHelper clientA("ns3::UdpSocketFactory", destA);
    clientA.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
    clientA.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
    clientA.SetAttribute("DataRate", StringValue("100000kb/s"));
    clientA.SetAttribute("PacketSize", UintegerValue(payloadSize));
    clientA.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE

    ApplicationContainer clientAppA = clientA.Install(wifiStaNodes.Get(0));
    clientAppA.Start(Seconds(1));
    clientAppA.Stop(simulationTime + Seconds(1));

    UdpServerHelper serverB(port);
    ApplicationContainer serverAppB = serverB.Install(wifiApNodes.Get(1));
    serverAppB.Start(Seconds(0));
    serverAppB.Stop(simulationTime + Seconds(1));

    InetSocketAddress destB(ApInterfaceB.GetAddress(0), port);

    OnOffHelper clientB("ns3::UdpSocketFactory", destB);
    clientB.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
    clientB.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
    clientB.SetAttribute("DataRate", StringValue("100000kb/s"));
    clientB.SetAttribute("PacketSize", UintegerValue(payloadSize));
    clientB.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE

    ApplicationContainer clientAppB = clientB.Install(wifiStaNodes.Get(1));
    clientAppB.Start(Seconds(1));
    clientAppB.Stop(simulationTime + Seconds(1));

    UdpServerHelper serverC(port);
    ApplicationContainer serverAppC = serverC.Install(wifiApNodes.Get(2));
    serverAppC.Start(Seconds(0));
    serverAppC.Stop(simulationTime + Seconds(1));

    InetSocketAddress destC(ApInterfaceC.GetAddress(0), port);

    OnOffHelper clientC("ns3::UdpSocketFactory", destC);
    clientC.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
    clientC.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
    clientC.SetAttribute("DataRate", StringValue("100000kb/s"));
    clientC.SetAttribute("PacketSize", UintegerValue(payloadSize));
    clientC.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI

    ApplicationContainer clientAppC = clientC.Install(wifiStaNodes.Get(2));
    clientAppC.Start(Seconds(1));
    clientAppC.Stop(simulationTime + Seconds(1));

    UdpServerHelper serverD(port);
    ApplicationContainer serverAppD = serverD.Install(wifiApNodes.Get(3));
    serverAppD.Start(Seconds(0));
    serverAppD.Stop(simulationTime + Seconds(1));

    InetSocketAddress destD(ApInterfaceD.GetAddress(0), port);

    OnOffHelper clientD("ns3::UdpSocketFactory", destD);
    clientD.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
    clientD.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
    clientD.SetAttribute("DataRate", StringValue("100000kb/s"));
    clientD.SetAttribute("PacketSize", UintegerValue(payloadSize));
    clientD.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI

    ApplicationContainer clientAppD = clientD.Install(wifiStaNodes.Get(3));
    clientAppD.Start(Seconds(1));
    clientAppD.Stop(simulationTime + Seconds(1));

    if (enablePcap)
    {
        phy.EnablePcap("AP_A", apDeviceA.Get(0));
        phy.EnablePcap("STA_A", staDeviceA.Get(0));
        phy.EnablePcap("AP_B", apDeviceB.Get(0));
        phy.EnablePcap("STA_B", staDeviceB.Get(0));
        phy.EnablePcap("AP_C", apDeviceC.Get(0));
        phy.EnablePcap("STA_C", staDeviceC.Get(0));
        phy.EnablePcap("AP_D", apDeviceD.Get(0));
        phy.EnablePcap("STA_D", staDeviceD.Get(0));
    }

    Simulator::Stop(simulationTime + Seconds(1));
    Simulator::Run();

    /* Show results */
    double totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
    double totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
    double totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
    double totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();

    Simulator::Destroy();

    auto throughput = totalPacketsThroughA * payloadSize * 8 / simulationTime.GetMicroSeconds();
    std::cout << "AC_BE with default TXOP limit (0ms): " << '\n'
              << "  Throughput = " << throughput << " Mbit/s" << '\n';
    if (verifyResults && (throughput < 28 || throughput > 29))
    {
        NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
        exit(1);
    }

    throughput = totalPacketsThroughB * payloadSize * 8 / simulationTime.GetMicroSeconds();
    std::cout << "AC_BE with non-default TXOP limit (4.096ms): " << '\n'
              << "  Throughput = " << throughput << " Mbit/s" << '\n';
    if (verifyResults && (throughput < 36.5 || throughput > 37))
    {
        NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
        exit(1);
    }
    std::cout << "  Maximum TXOP duration = " << beTxopTracer.m_max.GetMicroSeconds() << " us"
              << '\n';
    if (verifyResults &&
        (beTxopTracer.m_max < MicroSeconds(3008) || beTxopTracer.m_max > txopLimit))
    {
        NS_LOG_ERROR("Maximum TXOP duration " << beTxopTracer.m_max
                                              << " is not in the expected boundaries!");
        exit(1);
    }

    throughput = totalPacketsThroughC * payloadSize * 8 / simulationTime.GetMicroSeconds();
    std::cout << "AC_VI with default TXOP limit (4.096ms): " << '\n'
              << "  Throughput = " << throughput << " Mbit/s" << '\n';
    if (verifyResults && (throughput < 36.5 || throughput > 37.5))
    {
        NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
        exit(1);
    }
    std::cout << "  Maximum TXOP duration = " << viTxopTracer.m_max.GetMicroSeconds() << " us"
              << '\n';
    if (verifyResults &&
        (viTxopTracer.m_max < MicroSeconds(3008) || viTxopTracer.m_max > txopLimit))
    {
        NS_LOG_ERROR("Maximum TXOP duration " << viTxopTracer.m_max
                                              << " is not in the expected boundaries!");
        exit(1);
    }

    throughput = totalPacketsThroughD * payloadSize * 8 / simulationTime.GetMicroSeconds();
    std::cout << "AC_VI with non-default TXOP limit (0ms): " << '\n'
              << "  Throughput = " << throughput << " Mbit/s" << '\n';
    if (verifyResults && (throughput < 31.5 || throughput > 32.5))
    {
        NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
        exit(1);
    }

    return 0;
}

サンプルは ./ns3 run にファイルのパスを渡せば実行できる(ビルドが必要なら先にビルドしてくれる)。

実行結果

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run examples/wireless/wifi-80211e-txop.cc 
AC_BE with default TXOP limit (0ms): 
  Throughput = 28.8877 Mbit/s
AC_BE with non-default TXOP limit (4.096ms): 
  Throughput = 36.8224 Mbit/s
  Maximum TXOP duration = 4056 us
AC_VI with default TXOP limit (4.096ms): 
  Throughput = 37.211 Mbit/s
  Maximum TXOP duration = 4056 us
AC_VI with non-default TXOP limit (0ms): 
  Throughput = 32.5076 Mbit/s

シミュレーション結果の出力

シミュレーションの実行結果を出力するために必要なコードを見ていく。
元にするコードは下記の scratch/wireless-simple.cc で、出力は何もない。 シミュレーション内容は、

1 つの AP を中心として 10m 離れた円周上に、36°ごとに動かない STA が 10 個並んでる状況

で、

それぞれの STA が 802.11ac/80MHz/2SS で接続して、60Mbps で AP に UDP データを 10 秒間送信し続ける

ようにしてる。イメージ図は下記の通り(NetAnim で出力)。

AP を中心に 10 台の STA が円周上に並んだ配置

scratch/wireless-simple.cc
#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("WirelessSimple");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    std::string DataRate = "60Mbps";

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);

    mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));
    Simulator::Run();
    Simulator::Destroy();
    return 0;
}

FlowMonitor

FlowMonitor を使えばシミュレーションにおける、スループット・遅延・パケットロス割合の統計情報を確認できる。
下記の scratch/wireless-flowmonitor.cc のハイライト部分が scratch/wireless-simple.cc に追加したコード。

scratch/wireless-flowmonitor.cc
#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>
#include "ns3/flow-monitor.h" 
#include "ns3/flow-monitor-helper.h" 

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("WirelessFlowMonitor");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    std::string DataRate = "60Mbps";

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);

    mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Flowmonitor
    ////

    Ptr<FlowMonitor> flowmon;
    FlowMonitorHelper flowmonHelper;
    flowmon = flowmonHelper.InstallAll();

    Simulator::Run();
    flowmon->SerializeToXmlFile("wireless-flowmonitor.xml", true, true);
    Simulator::Destroy();
    return 0;
}
  • ns3/flow-monitor.h と ns3/flow-monitor-helper.h をインクルード
    • API Reference: flow-monitor.h, flow-monitor-helper.h
    • ちなみに、ヘッダファイルとして ns3/flow-monitor-module.h を include すれば、上 2 つが含まれているので 1 行で済む
  • ログコンポーネント名を WirelessFlowMonitor に変更(絶対に必要ってわけではないけど変えておく)
  • Simulator::Run() の前に、FlowMonitorHelper::InstallAll() で全ノードに FlowMonitor をインストール
  • Simulator::Run() の後に、SerializeToXmlFile() で統計情報を wireless-flowmonitor.xml に出力(2 つの true は、ヒストグラムとプローブの情報も出力する指定)

scratch/wireless-flowmonitor.cc を実行すると、XML ファイルが出力される。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run scratch/wireless-flowmonitor.cc

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l wireless-flowmonitor.xml 
-rw-rw-r-- 1 ishigaki ishigaki 987940  9月 29 11:18 wireless-flowmonitor.xml

この XML ファイルを解析するためのスクリプトも用意されている: src/flow-monitor/examples/flowmon-parse-results.py

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ cp src/flow-monitor/examples/flowmon-parse-results.py ./

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py wireless-flowmonitor.xml
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 43540.35 kbit/s
    Mean Delay: 939.42 ms
    Packet Loss Ratio: 10.48 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 40591.64 kbit/s
    Mean Delay: 1639.61 ms
    Packet Loss Ratio: 15.09 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 46450.95 kbit/s
    Mean Delay: 949.07 ms
    Packet Loss Ratio: 5.11 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 47989.28 kbit/s
    Mean Delay: 1030.76 ms
    Packet Loss Ratio: 4.80 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 40844.72 kbit/s
    Mean Delay: 1148.10 ms
    Packet Loss Ratio: 14.06 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 39389.14 kbit/s
    Mean Delay: 1630.52 ms
    Packet Loss Ratio: 17.49 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 45360.11 kbit/s
    Mean Delay: 776.08 ms
    Packet Loss Ratio: 6.59 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53580.87 kbit/s
    Mean Delay: 1023.71 ms
    Packet Loss Ratio: 4.75 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 51312.00 kbit/s
    Mean Delay: 551.39 ms
    Packet Loss Ratio: 5.30 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 45108.38 kbit/s
    Mean Delay: 1411.62 ms
    Packet Loss Ratio: 6.83 %

FlowMonitor を使えば、上のように各 STA からのパケットの受信スループットとかを計測できる。

PCAP

PCAP ファイルを出力できれば Wireshark でフレームを観察できるので、シミュレーションの出力としてはもっとも有益だと思う。
下記の scratch/wireless-pcap.cc のハイライト部分が scratch/wireless-simple.cc に追加したコード。

scratch/wireless-pcap.cc
#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("WirelessPcap");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    std::string DataRate = "60Mbps";

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);
    phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
    phy.EnablePcap("AP.pcap", apDevices.Get(0), false, true);

    mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));
    Simulator::Run();
    Simulator::Destroy();
    return 0;
}
  • ログコンポーネント名を WirelessPcap に変更(絶対に必要ってわけではないけど変えておく)
  • SetPcapDataLinkType() で、PCAP のデータリンクタイプを DLT_IEEE802_11_RADIO(Radiotap ヘッダ付きの 802.11 フレーム)に設定
  • EnablePcap() で、AP が送受信したフレームを AP.pcap に出力(4 つ目の true は、ファイル名をそのまま AP.pcap にする指定)

※ コード中の phy は YansWifiPhyHelper 型のオブジェクトで、上の 2 つは継承元の WifiPhyHelper と PcapHelperForDevice のメンバー関数

scratch/wireless-pcap.cc を実行すると、PCAP ファイルが出力される。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run scratch/wireless-pcap.cc

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l AP.pcap 
-rw-rw-r-- 1 ishigaki ishigaki 281129131  9月 29 11:25 AP.pcap

この PCAP ファイルを Wireshark で開いてみる。

Wireshark で開いた AP.pcap

PCAP ファイルがあれば、AP が送信したフレームと、AP が受信できたフレームを確認できる。

ちなみに、scratch/wireless-pcap.cc で、

phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11_RADIO);

の行をコメントアウトしたり、

phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11);

に変更したりすると、PCAP ファイルは下のように、Radiotap Header と 802.11 radio information がなくなって、Wi-Fi フレームっぽくなくなる。

DLT_IEEE802_11 で出力した AP.pcap

NetAnim

NetAnim を使えばシミュレーション自体を可視化できる。Ubuntu で実行すれば、Wi-Fi フレームも可視化できた。
下記の scratch/wireless-netanim.cc のハイライト部分が scratch/wireless-simple.cc に追加したコード。

scratch/wireless-netanim.cc
#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>
#include "ns3/animation-interface.h" 

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("WirelessNetAnim");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    std::string DataRate = "60Mbps";

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);

    mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Animation
    ////

    AnimationInterface anim("wireless-netanim.xml");
    anim.EnablePacketMetadata();

    Simulator::Run();
    Simulator::Destroy();
    return 0;
}
  • ns3/animation-interface.h をインクルード
    • ちなみに、ヘッダファイルとして ns3/netanim-module.h を include しても、中身は animation-interface.h だけ
  • ログコンポーネント名を WirelessNetAnim に変更(絶対に必要ってわけではないけど変えておく)
  • Simulator::Run() の前に、AnimationInterface で NetAnim 用の XML ファイル wireless-netanim.xml を出力するように設定
  • EnablePacketMetadata() で、パケットのメタデータも XML ファイルに書き込む

scratch/wireless-netanim.cc を実行すると、XML ファイルが出力される。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run scratch/wireless-netanim.cc 
Max Packets per trace file exceeded

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l wireless-netanim.xml
-rw-rw-r-- 1 ishigaki ishigaki 10993688  9月 29 11:44 wireless-netanim.xml

※ Max Packets per trace file exceeded は、XML ファイルに書き込んだパケット数がデフォルトの上限(100,000)に達したので、そこで書き込みを止めたというメッセージ。 上限は SetMaxPktsPerTraceFile() で変えられるけど、XML ファイルが大きくなりすぎると NetAnim で開けなくなる(試しに上限を 6,000,000 にしたら、10 秒分すべて書き込めたけど、XML ファイルが 581 MiB になって開けなかった)。

この XML ファイルを NetAnim で開くと、シミュレーションの結果を可視化できる。

  • NetAnim 起動

    ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ cd netanim/
    
    ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44/netanim$ ./NetAnim
    
  • NetAnim 起動後、wireless-netanim.xml を開く

  • 再生ボタン(▶)を押すと、シミュレーションがアニメーションで再生される

NetAnim を使えば、各ノードの配置を確認できるようになる。 あと、動画として表現できるので、発表する時とかこのページに載せる時とか、視線を集められるかな・・・

デフォルトだと、AP も STA も区別なく赤丸🔴で示されていて、分かりづらい。 下記の scratch/wireless-netanim-pic.cc では、用意しておいた画像で各ノードを表現できる。 ハイライト部分が scratch/wireless-netanim.cc に追加したコード。

scratch/wireless-netanim-pic.cc
#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>
#include "ns3/animation-interface.h" 

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("WirelessNetAnimPic");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    std::string DataRate = "60Mbps";

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);

    mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Animation
    ////

    AnimationInterface anim("wireless-netanim.xml");

    uint32_t apImageId = anim.AddResource("AP.png");
    uint32_t apNodeId = wifiApNode.Get(0)->GetId();
    anim.UpdateNodeDescription(apNodeId, "AP");
    anim.UpdateNodeImage(apNodeId, apImageId);
    anim.UpdateNodeSize(apNodeId, 1.0, 1.0);

    uint32_t staImageId = anim.AddResource("STA.png");
    for (uint32_t i = 0; i < wifiStaNodes.GetN(); ++i)
    {
        uint32_t nodeId = wifiStaNodes.Get(i)->GetId();
        std::ostringstream oss;
        oss << "STA-" << i;
        anim.UpdateNodeDescription(nodeId, oss.str());
        anim.UpdateNodeImage(nodeId, staImageId);
        anim.UpdateNodeSize(nodeId, 1.0, 1.0);
    }

    anim.EnablePacketMetadata();

    Simulator::Run();
    Simulator::Destroy();
    return 0;
}
  • ログコンポーネント名を WirelessNetAnimPic に変更(絶対に必要ってわけではないけど変えておく)
  • AddResource() で、AP 用の画像 AP.png と STA 用の画像 STA.png を登録
    • API Reference: AddResource()
    • 画像ファイルは、./NetAnim コマンドを実行するディレクトリからの相対パスで指定する
  • UpdateNodeDescription() で、各ノードに表示する名前を AP、STA-0〜STA-9 に設定
  • UpdateNodeImage() で、各ノードを登録した画像で表示
  • UpdateNodeSize() で、各ノードのサイズを設定(ここでは 1.0 × 1.0)
    • API Reference: UpdateNodeSize()
    • UpdateNodeSize() はやらないと、0 番(STA-0)の画像だけでかくなって、それ以降(STA-1〜STA-9)の画像は普通のサイズになるっていうことがあったので、サイズ変更する必要がなくても初期化する的な感じでやっておくのがいいかも

scratch/wireless-netanim-pic.cc を実行したら、下図のように AP と STA の画像が表示される。

AP と STA を画像で表示した NetAnim


シミュレーションによる Frame Aggregation の検証

Frame Aggregation ってどれくらい Wi-Fi ネットワークのスループットに影響があるのか気になったのでシミュレーションしてみる。 シミュレーションのシナリオは上にある図と同じ状況にしておく。

  • 1 つの AP を中心として 10m 離れた円周上に、36°ごとに動かない STA が 10 個並んでる状況

  • それぞれの STA が 802.11ac/80MHz/2SS で接続して、60Mbps で AP に UDP データを 10 秒間送信し続ける

A-MSDU のシミュレーション

A-MSDU を使う場合と使わない場合でどれだけスループットに影響が出るか、比較してみる。
A-MSDU 以外はすべて同じ条件とするので、単純に A-MSDU だけの影響が出てくるはず。

作成したシミュレーションコード: scratch/A-MSDU_simulation.cc

scratch/A-MSDU_simulation.cc
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * A-MSDU_simulation.cc
 *
 * This ns-3 simulation demonstrates the effect of enabling or disabling A-MSDU aggregation
 * in an IEEE 802.11ac Wi-Fi network using the VHT (Very High Throughput) mode.
 *
 * Simulation Scenario:
 * - One AP and multiple STA nodes (default 10 STAs)
 * - All STAs send UDP traffic to the AP using OnOff applications
 * - Nodes are arranged in a circle around the AP
 * - FlowMonitor is used to collect statistics
 * - NetAnim output is generated for visualization
 * - The simulation can be configured to disable A-MSDU via command line
 *
 * Key Features:
 * - Supports IEEE 802.11ac with VHT MCS9 (Short GI enabled)
 * - Allows toggling of A-MSDU using "--amsduDisable=true" 
 * - Generates PCAP, FlowMonitor XML, and NetAnim XML outputs
 *
 * Command Line Usage:
 *   ./ns3 run "scratch/A-MSDU_simulation.cc" 
 *   ./ns3 run "scratch/A-MSDU_simulation.cc --amsduDisable=true" 
 *
 * Output Files:
 *   A-MSDU_AP.pcap or A-MSDU_AP_amsduDisable.pcap
 *   A-MSDU_Flow.xml or A-MSDU_Flow_amsduDisable.xml
 *   A-MSDU_NetAnim.xml or A-MSDU_NetAnim_amsduDisable.xml
 *
 * Author: TASUKU ISHIGAKI
 * Date: August 2025
 */

#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 
#include <string>
#include <sstream>
#include "ns3/flow-monitor-module.h" 
#include "ns3/netanim-module.h" 

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("A-MSDU_simulation");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    uint32_t MaxAmpduSize = 1048575; // Fixed Parameter
    uint32_t MaxAmsduSize = 7935;
    std::string DataRate = "60Mbps";
    std::string pcapFile = "A-MSDU_AP.pcap";
    std::string flowmonFile = "A-MSDU_Flow.xml";
    std::string netanimFile = "A-MSDU_NetAnim.xml";
    bool amsduDisable{false};

    CommandLine cmd(__FILE__);
    cmd.AddValue("amsduDisable", "Run this simulation without A-MSDU", amsduDisable);
    cmd.Parse(argc, argv);

    if (amsduDisable)
    {
        MaxAmsduSize = 0;
        pcapFile = "A-MSDU_AP_amsduDisable.pcap";
        flowmonFile = "A-MSDU_Flow_amsduDisable.xml";
        netanimFile = "A-MSDU_NetAnim_amsduDisable.xml"; 
    }

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi; 
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9")
    );
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac",
                "Ssid", SsidValue(ssid),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize)); 
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);
    phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
    phy.EnablePcap(pcapFile, apDevices.Get(0), false, true);

    mac.SetType("ns3::StaWifiMac",
                "Ssid", SsidValue(ssid),
                "ActiveProbing", BooleanValue(false),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    //// 

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center+x, center+y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    //// 

    InternetStackHelper stack;
    stack.Install(allNodes);

    //// 
    // Install Ipv4 addresses
    //// 

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    //// 

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("Tos", UintegerValue(0x00)); // AC_BE
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Flowmonitor
    ////

    Ptr<FlowMonitor> flowmon;
    FlowMonitorHelper flowmonHelper;
    flowmon = flowmonHelper.InstallAll();

    ////
    // Animation
    ////

    AnimationInterface anim(netanimFile);

    uint32_t apImageId = anim.AddResource("AP.png");
    uint32_t apNodeId = wifiApNode.Get(0)->GetId();
    anim.UpdateNodeDescription(apNodeId, "AP");
    anim.UpdateNodeImage(apNodeId, apImageId);
    anim.UpdateNodeSize(apNodeId, 1.0, 1.0);

    uint32_t staImageId = anim.AddResource("STA.png");
    for (uint32_t i = 0; i < wifiStaNodes.GetN(); ++i)
    {
        uint32_t nodeId = wifiStaNodes.Get(i)->GetId();
        std::ostringstream oss;
        oss << "STA-" << i;
        anim.UpdateNodeDescription(nodeId, oss.str());
        anim.UpdateNodeImage(nodeId, staImageId);
        anim.UpdateNodeSize(nodeId, 1.0, 1.0);
    }

    anim.EnablePacketMetadata();

    Simulator::Run();
    flowmon->SerializeToXmlFile(flowmonFile, true, true);
    Simulator::Destroy();
    return 0;
}
  • UDP パケットはすべて AC_BE に設定(onOff.SetAttribute("Tos", UintegerValue(0x00));)
  • どちらの環境でも A-MPDU は使えるようにしておく("BE_MaxAmpduSize", UintegerValue(MaxAmpduSize)、MaxAmpduSize = 1048575)
    • 1048575 は VHT の A-MPDU の最大長(デフォルトは 65535)
  • A-MSDU の最大長は 7935(uint32_t MaxAmsduSize = 7935;)、--amsduDisable=true のときは 0(A-MSDU を使わない)

scratch/A-MSDU_simulation.cc を実行すると、シミュレーション結果(PCAP, FlowMonitor, NetAnim)が出力されるので、出力ファイルを比較することで違いを見つける。

A-MSDU を有効にしたシミュレーション

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "scratch/A-MSDU_simulation.cc"

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_AP.pcap
-rw-rw-r-- 1 ishigaki ishigaki 708453296  9月 29 14:53 A-MSDU_AP.pcap

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_Flow.xml 
-rw-rw-r-- 1 ishigaki ishigaki 937331  9月 29 14:53 A-MSDU_Flow.xml

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_NetAnim.xml 
-rw-rw-r-- 1 ishigaki ishigaki 27693845  9月 29 14:52 A-MSDU_NetAnim.xml

PCAP ファイルを Wireshark で開くと、A-MSDU サブフレームが観察できるので、A-MSDU は使えてることがわかる。

A-MSDU_AP.pcap の A-MSDU サブフレーム

FlowMonitor でスループットを見てみる: A-MPDU 有効 と同じ結果
平均スループット(10 フローの RX bitrate の平均)は 56.1 Mbps。

flowmon-parse-results.py の実行結果(A-MSDU 有効)
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py A-MSDU_Flow.xml 
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53402.83 kbit/s
    Mean Delay: 318.23 ms
    Packet Loss Ratio: 0.38 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 58907.01 kbit/s
    Mean Delay: 203.31 ms
    Packet Loss Ratio: 0.07 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 58314.17 kbit/s
    Mean Delay: 299.00 ms
    Packet Loss Ratio: 0.28 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 59014.38 kbit/s
    Mean Delay: 426.02 ms
    Packet Loss Ratio: 1.55 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53792.42 kbit/s
    Mean Delay: 287.62 ms
    Packet Loss Ratio: 0.49 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53024.70 kbit/s
    Mean Delay: 587.06 ms
    Packet Loss Ratio: 1.40 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 60342.05 kbit/s
    Mean Delay: 233.29 ms
    Packet Loss Ratio: 0.27 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 54480.35 kbit/s
    Mean Delay: 356.23 ms
    Packet Loss Ratio: 0.17 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 54061.14 kbit/s
    Mean Delay: 785.39 ms
    Packet Loss Ratio: 3.43 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 55809.12 kbit/s
    Mean Delay: 377.11 ms
    Packet Loss Ratio: 0.54 %

A-MSDU を無効にしたシミュレーション

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "scratch/A-MSDU_simulation.cc --amsduDisable=true"

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_AP_amsduDisable.pcap 
-rw-rw-r-- 1 ishigaki ishigaki 652588350  9月 29 15:00 A-MSDU_AP_amsduDisable.pcap

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_Flow_amsduDisable.xml 
-rw-rw-r-- 1 ishigaki ishigaki 944325  9月 29 15:00 A-MSDU_Flow_amsduDisable.xml

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MSDU_NetAnim_amsduDisable.xml 
-rw-rw-r-- 1 ishigaki ishigaki 11725225  9月 29 14:58 A-MSDU_NetAnim_amsduDisable.xml

PCAP ファイルを Wireshark で開いて、wlan.qos.amsdupresent == 1 で絞り込むと 0 件なので、A-MSDU は使われていないことがわかる。

A-MSDU_AP_amsduDisable.pcap を wlan.qos.amsdupresent == 1 で絞り込んだ結果

FlowMonitor でスループットを見てみる。
平均スループット(10 フローの RX bitrate の平均)は 49.1 Mbps。

flowmon-parse-results.py の実行結果(A-MSDU 無効)
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py A-MSDU_Flow_amsduDisable.xml 
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 40323.65 kbit/s
    Mean Delay: 1650.81 ms
    Packet Loss Ratio: 14.48 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 48754.83 kbit/s
    Mean Delay: 930.81 ms
    Packet Loss Ratio: 5.32 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 44704.88 kbit/s
    Mean Delay: 739.49 ms
    Packet Loss Ratio: 5.73 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 46061.49 kbit/s
    Mean Delay: 1572.14 ms
    Packet Loss Ratio: 7.18 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 51962.78 kbit/s
    Mean Delay: 801.46 ms
    Packet Loss Ratio: 4.92 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 55892.61 kbit/s
    Mean Delay: 404.08 ms
    Packet Loss Ratio: 1.73 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 48891.62 kbit/s
    Mean Delay: 589.37 ms
    Packet Loss Ratio: 3.79 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 54176.02 kbit/s
    Mean Delay: 790.88 ms
    Packet Loss Ratio: 2.60 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 51069.14 kbit/s
    Mean Delay: 531.26 ms
    Packet Loss Ratio: 3.97 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 49589.71 kbit/s
    Mean Delay: 799.59 ms
    Packet Loss Ratio: 4.14 %

結果の考察

  • A-MSDU を無効にすると、平均スループットは 56.1 Mbps → 49.1 Mbps に下がった(約 12%)
    • 10 フローの合計でも 561.1 Mbps → 491.4 Mbps
  • 平均遅延は 387.3 ms → 881.0 ms、パケットロス率の平均は 0.86 % → 5.39 % に悪化した
    • STA ごとのばらつきも大きくなった(スループットの最小〜最大: 53.0〜60.3 Mbps → 40.3〜55.9 Mbps)
  • PCAP を見ると、A-MSDU 有効では 1 つの QoS Data フレームの中に A-MSDU サブフレームが並んでいて、A-MSDU 無効では wlan.qos.amsdupresent == 1 で絞り込んでも 0 件だった
  • A-MSDU なら、複数の MSDU で MAC ヘッダー・FCS・A-MPDU のデリミターを共有できる
    • ただ、ヘッダーの節約だけだと MSDU 1 つあたり十数バイト(1% 未満)なので、スループットの差(約 12%)はそれだけでは説明できない
    • VHT の Block Ack で一度にやりとりできる MPDU の数は最大 64 なので、A-MSDU がないと 1 回の送信(A-MPDU)で運べるデータ量が少なくなっているのかも

A-MPDU のシミュレーション

A-MPDU を使う場合と使わない場合でどれだけスループットに影響が出るか、比較してみる。 A-MPDU 以外はすべて同じ条件とするので、単純に A-MPDU だけの影響が出てくるはず。

作成したシミュレーションコード: scratch/A-MPDU_simulation.cc

scratch/A-MPDU_simulation.cc
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * A-MPDU_simulation.cc
 *
 * This ns-3 simulation demonstrates the effect of enabling or disabling A-MPDU aggregation
 * in an IEEE 802.11ac Wi-Fi network using the VHT (Very High Throughput) mode.
 *
 * Simulation Scenario:
 * - One AP and multiple STA nodes (default 10 STAs)
 * - All STAs send UDP traffic to the AP using OnOff applications
 * - Nodes are arranged in a circle around the AP
 * - FlowMonitor is used to collect statistics
 * - NetAnim output is generated for visualization
 * - The simulation can be configured to disable A-MPDU via command line
 *
 * Key Features:
 * - Supports IEEE 802.11ac with VHT MCS9 (Short GI enabled)
 * - Allows toggling of A-MPDU using "--ampduDisable=true" 
 * - Generates PCAP, FlowMonitor XML, and NetAnim XML outputs
 *
 * Command Line Usage:
 *   ./ns3 run "scratch/A-MPDU_simulation.cc" 
 *   ./ns3 run "scratch/A-MPDU_simulation.cc --ampduDisable=true" 
 *
 * Output Files:
 *   A-MPDU_AP.pcap or A-MPDU_AP_ampduDisable.pcap
 *   A-MPDU_Flow.xml or A-MPDU_Flow_ampduDisable.xml
 *   A-MPDU_NetAnim.xml or A-MPDU_NetAnim_ampduDisable.xml
 *
 * Author: TASUKU ISHIGAKI
 * Date: August 2025
 */

#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/flow-monitor-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/netanim-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 

#include <sstream>
#include <string>

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("A-MPDU_simulation");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    uint32_t MaxAmsduSize = 7935; // Fixed Parameter
    uint32_t MaxAmpduSize = 1048575;
    std::string DataRate = "60Mbps";
    std::string pcapFile = "A-MPDU_AP.pcap";
    std::string flowmonFile = "A-MPDU_Flow.xml";
    std::string netanimFile = "A-MPDU_NetAnim.xml";
    bool ampduDisable{false};

    CommandLine cmd(__FILE__);
    cmd.AddValue("ampduDisable", "Run this simulation without A-MPDU", ampduDisable);
    cmd.Parse(argc, argv);

    if (ampduDisable)
    {
        MaxAmpduSize = 0;
        pcapFile = "A-MPDU_AP_ampduDisable.pcap";
        flowmonFile = "A-MPDU_Flow_ampduDisable.xml";
        netanimFile = "A-MPDU_NetAnim_ampduDisable.xml";
    }

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi;
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9"));
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac",
                "Ssid", SsidValue(ssid),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize));
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);
    phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
    phy.EnablePcap(pcapFile, apDevices.Get(0), false, true);

    mac.SetType("ns3::StaWifiMac",
                "Ssid", SsidValue(ssid),
                "ActiveProbing", BooleanValue(false),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    ////

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center + x, center + y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    ////

    InternetStackHelper stack;
    stack.Install(allNodes);

    ////
    // Install Ipv4 addresses
    ////

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    ////

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("Tos", UintegerValue(0x00)); // AC_BE
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Flowmonitor
    ////

    Ptr<FlowMonitor> flowmon;
    FlowMonitorHelper flowmonHelper;
    flowmon = flowmonHelper.InstallAll();

    ////
    // Animation
    ////

    AnimationInterface anim(netanimFile);

    uint32_t apImageId = anim.AddResource("AP.png");
    uint32_t apNodeId = wifiApNode.Get(0)->GetId();
    anim.UpdateNodeDescription(apNodeId, "AP");
    anim.UpdateNodeImage(apNodeId, apImageId);
    anim.UpdateNodeSize(apNodeId, 1.0, 1.0);

    uint32_t staImageId = anim.AddResource("STA.png");
    for (uint32_t i = 0; i < wifiStaNodes.GetN(); ++i)
    {
        uint32_t nodeId = wifiStaNodes.Get(i)->GetId();
        std::ostringstream oss;
        oss << "STA-" << i;
        anim.UpdateNodeDescription(nodeId, oss.str());
        anim.UpdateNodeImage(nodeId, staImageId);
        anim.UpdateNodeSize(nodeId, 1.0, 1.0);
    }

    anim.EnablePacketMetadata();

    Simulator::Run();
    flowmon->SerializeToXmlFile(flowmonFile, true, true);
    Simulator::Destroy();
    return 0;
}
  • UDP パケットはすべて AC_BE に設定(onOff.SetAttribute("Tos", UintegerValue(0x00));)
  • どちらの環境でも A-MSDU は使えるようにしておく("BE_MaxAmsduSize", UintegerValue(MaxAmsduSize)、MaxAmsduSize = 7935)
    • A-MSDU のシミュレーションと同じく、Aruba のアクセスポイントの実機に合わせて 7935
  • A-MPDU の最大長は 1048575(uint32_t MaxAmpduSize = 1048575;)、--ampduDisable=true のときは 0(A-MPDU を使わない)

このシミュレーションで送信する UDP パケットはすべて AC_BE で、AC_BE の TXOP limit はデフォルトの 0 のまま変更していないので、1 回チャネルを獲得しても続けて送れるのはフレーム交換 1 回分だけ(TXOP で連続して送ることはしない)、という前提になっている。(= BlockAck フレームが返ってくるのは、A-MPDU に対してのみ。TXOP の間に複数のフレームが送信されたら、BlockAck フレームが返ってくることもあるけど、このシミュレーションでは複数のフレームは送信できない)

TXOP 以前にそもそも QoS に対応しているかっていうのは、User Documentation に記載があって、802.11ac(VHT)を使うようにしたら勝手に QoS 使うようになる。

when selecting 802.11ac as the desired wifi standard, 802.11e/WMM-style QoS, 802.11n-style High Throughput (HT) and 802.11ac-style Very High Throughput (VHT) support gets enabled.

scratch/A-MPDU_simulation.cc を実行すると、シミュレーション結果(PCAP, FlowMonitor, NetAnim)が出力されるので、出力ファイルを比較することで違いを見つける。

A-MPDU を有効にしたシミュレーション

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "scratch/A-MPDU_simulation.cc"

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_AP.pcap 
-rw-rw-r-- 1 ishigaki ishigaki 708453296  9月 29 15:48 A-MPDU_AP.pcap

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_Flow.xml 
-rw-rw-r-- 1 ishigaki ishigaki 937331  9月 29 15:48 A-MPDU_Flow.xml

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_NetAnim.xml 
-rw-rw-r-- 1 ishigaki ishigaki 27693845  9月 29 15:47 A-MPDU_NetAnim.xml

PCAP ファイルを Wireshark で開くと、A-MPDU フレームが観察できるので、A-MPDU は使えてることがわかる。

A-MPDU_AP.pcap のパケット一覧

A-MPDU_AP.pcap の Radiotap ヘッダーの A-MPDU status

FlowMonitor でスループットを見てみる: A-MSDU 有効 と同じ結果
平均スループット(10 フローの RX bitrate の平均)は 56.1 Mbps。

flowmon-parse-results.py の実行結果(A-MPDU 有効)
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py A-MPDU_Flow.xml 
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53402.83 kbit/s
    Mean Delay: 318.23 ms
    Packet Loss Ratio: 0.38 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 58907.01 kbit/s
    Mean Delay: 203.31 ms
    Packet Loss Ratio: 0.07 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 58314.17 kbit/s
    Mean Delay: 299.00 ms
    Packet Loss Ratio: 0.28 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 59014.38 kbit/s
    Mean Delay: 426.02 ms
    Packet Loss Ratio: 1.55 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53792.42 kbit/s
    Mean Delay: 287.62 ms
    Packet Loss Ratio: 0.49 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 53024.70 kbit/s
    Mean Delay: 587.06 ms
    Packet Loss Ratio: 1.40 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 60342.05 kbit/s
    Mean Delay: 233.29 ms
    Packet Loss Ratio: 0.27 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 54480.35 kbit/s
    Mean Delay: 356.23 ms
    Packet Loss Ratio: 0.17 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 54061.14 kbit/s
    Mean Delay: 785.39 ms
    Packet Loss Ratio: 3.43 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 55809.12 kbit/s
    Mean Delay: 377.11 ms
    Packet Loss Ratio: 0.54 %

A-MPDU を無効にしたシミュレーション

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "scratch/A-MPDU_simulation.cc --ampduDisable=true"

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_AP_ampduDisable.pcap 
-rw-rw-r-- 1 ishigaki ishigaki 287437929  9月 29 15:50 A-MPDU_AP_ampduDisable.pcap

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_Flow_ampduDisable.xml 
-rw-rw-r-- 1 ishigaki ishigaki 1274660  9月 29 15:50 A-MPDU_Flow_ampduDisable.xml

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ls -l A-MPDU_NetAnim_ampduDisable.xml 
-rw-rw-r-- 1 ishigaki ishigaki 18747006  9月 29 15:48 A-MPDU_NetAnim_ampduDisable.xml

PCAP ファイルを見ると、A-MPDU は観察できなくて、Data フレームごとに Ack フレームが返ってきてるのがわかる。

A-MPDU_AP_ampduDisable.pcap のパケット一覧

A-MPDU_AP_ampduDisable.pcap を radiotap.ampdu.flags.last == 0 で絞り込んだ結果

FlowMonitor でスループットを見てみる。
平均スループット(10 フローの RX bitrate の平均)は 22.3 Mbps。

flowmon-parse-results.py の実行結果(A-MPDU 無効)
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py A-MPDU_Flow_ampduDisable.xml 
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 22596.81 kbit/s
    Mean Delay: 2828.56 ms
    Packet Loss Ratio: 53.17 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 21505.92 kbit/s
    Mean Delay: 3140.37 ms
    Packet Loss Ratio: 55.48 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 22826.80 kbit/s
    Mean Delay: 2987.98 ms
    Packet Loss Ratio: 52.40 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 22803.29 kbit/s
    Mean Delay: 2891.42 ms
    Packet Loss Ratio: 52.68 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 21048.54 kbit/s
    Mean Delay: 2879.34 ms
    Packet Loss Ratio: 56.27 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 22587.80 kbit/s
    Mean Delay: 2737.41 ms
    Packet Loss Ratio: 52.95 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 21863.21 kbit/s
    Mean Delay: 2860.07 ms
    Packet Loss Ratio: 54.54 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 23088.89 kbit/s
    Mean Delay: 2997.79 ms
    Packet Loss Ratio: 51.96 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 23348.65 kbit/s
    Mean Delay: 2893.04 ms
    Packet Loss Ratio: 51.63 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 21332.26 kbit/s
    Mean Delay: 3042.72 ms
    Packet Loss Ratio: 56.10 %

結果の考察

  • A-MPDU を無効にすると、平均スループットは 56.1 Mbps → 22.3 Mbps に下がった(約 40%)
    • 10 フローの合計でも 561.1 Mbps → 223.0 Mbps
  • 平均遅延は 387.3 ms → 2925.9 ms、パケットロス率の平均は 0.86 % → 53.72 % に悪化した
    • どの STA も 61.1 Mbps(IP 層)で送り続けているので、送りきれなかった分が遅延とロスとして出てきている
  • PCAP を見ると、A-MPDU 無効では Data フレーム(A-MSDU)を 1 つ送るたびに Ack が返ってきていて、A-MPDU 有効では複数の MPDU をまとめて送って BlockAck フレームでまとめて確認応答している
  • 送信 1 回ごとに、チャネルアクセスの待ち時間(AIFS・バックオフ)、プリアンブル、SIFS、Ack といったオーバーヘッドがかかる
    • A-MPDU なら、このオーバーヘッドを複数の MPDU で分け合えるので、データを送っている時間の割合が大きくなる
  • A-MPDU は QoS Data フレームの送信だけでなく、ACK も効率化できる
    • A-MPDU 無効では MPDU を 1 つ送るたびに Ack が返ってくるけど、A-MPDU 有効では A-MPDU 全体に対して BlockAck フレームが 1 つ返ってくるだけで済む
    • このシミュレーションでは TXOP limit が 0 なので、ACK を効率化できるのは A-MPDU に対する BlockAck フレームだけ
  • A-MSDU の比較(56.1 Mbps → 49.1 Mbps)より、A-MPDU の方が影響がずっと大きい
    • A-MSDU を無効にしても A-MPDU で MPDU をまとめられるけど、A-MPDU を無効にすると 1 回の送信で送れるのは A-MSDU 1 つ(最大 7935 バイト)だけになる

A-MSDU も A-MPDU も無効にしたシミュレーション

下記の scratch/bothDisable.cc で、A-MSDU も A-MPDU も無効にしてシミュレーションしてみた。

scratch/bothDisable.cc
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * bothDisable.cc
 *
 * This ns-3 simulation demonstrates a Wi-Fi network scenario in which
 * both A-MSDU and A-MPDU aggregation are disabled, providing a baseline
 * for performance comparison against aggregation-enabled cases.
 *
 * Simulation Scenario:
 * - One AP and multiple STA nodes (default 10 STAs)
 * - All STAs send UDP traffic to the AP using OnOff applications
 * - Nodes are arranged in a circle around the AP
 * - FlowMonitor is used to collect statistics
 * - NetAnim output is generated for visualization 
 * - No MAC aggregation: BE_MaxAmsduSize = 0, BE_MaxAmpduSize = 0
 *
 * Key Features:
 * - IEEE 802.11ac (80 MHz, 2x2 MIMO, VHT MCS9, Short GI)
 * - Aggregation completely disabled (A-MSDU and A-MPDU)
 * - Generates PCAP, FlowMonitor XML, and NetAnim XML outputs
 *
 * Command Line Usage:
 *   ./ns3 run "scratch/bothDisable.cc" 
 *
 * Output Files:
 *   bothDisable_AP.pcap
 *   bothDisable_Flow.xml
 *   bothDisable_NetAnim.xml
 *
 * Author: TASUKU ISHIGAKI
 * Date: August 2025
 */

#include "ns3/applications-module.h" 
#include "ns3/core-module.h" 
#include "ns3/csma-module.h" 
#include "ns3/flow-monitor-module.h" 
#include "ns3/internet-module.h" 
#include "ns3/mobility-module.h" 
#include "ns3/netanim-module.h" 
#include "ns3/network-module.h" 
#include "ns3/ssid.h" 
#include "ns3/yans-wifi-helper.h" 

#include <sstream>
#include <string>

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("bothDisable_simulation");

int
main(int argc, char* argv[])
{
    ////
    // Nodes, Devices, Topologies
    ////

    uint32_t nWifi = 10;
    double center = 10.0;
    double radius = 10.0;
    uint32_t MaxAmsduSize = 0; // Fixed Parameter
    uint32_t MaxAmpduSize = 0; // Fixed Parameter
    std::string DataRate = "60Mbps";
    std::string pcapFile = "bothDisable_AP.pcap";
    std::string flowmonFile = "bothDisable_Flow.xml";
    std::string netanimFile = "bothDisable_NetAnim.xml";
    bool ampduDisable{false};

    CommandLine cmd(__FILE__);
    cmd.AddValue("ampduDisable", "Run this simulation without A-MPDU", ampduDisable);
    cmd.Parse(argc, argv);

    NodeContainer allNodes;
    NodeContainer wifiStaNodes;
    wifiStaNodes.Create(nWifi);
    allNodes.Add(wifiStaNodes);
    NodeContainer wifiApNode;
    wifiApNode.Create(1);
    allNodes.Add(wifiApNode);

    YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
    YansWifiPhyHelper phy;
    phy.SetChannel(channel.Create());
    phy.Set("Antennas", UintegerValue(2));
    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
    phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));

    WifiHelper wifi;
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                 "DataMode", StringValue("VhtMcs9"),
                                 "ControlMode", StringValue("VhtMcs9"));
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    WifiMacHelper mac;
    Ssid ssid = Ssid("ishigaki-wlan");

    mac.SetType("ns3::ApWifiMac",
                "Ssid", SsidValue(ssid),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize));
    NetDeviceContainer apDevices;
    apDevices = wifi.Install(phy, mac, wifiApNode);
    phy.SetPcapDataLinkType(YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
    phy.EnablePcap(pcapFile, apDevices.Get(0), false, true);

    mac.SetType("ns3::StaWifiMac",
                "Ssid", SsidValue(ssid),
                "ActiveProbing", BooleanValue(false),
                "BE_MaxAmsduSize", UintegerValue(MaxAmsduSize),
                "BE_MaxAmpduSize", UintegerValue(MaxAmpduSize));
    NetDeviceContainer staDevices;
    staDevices = wifi.Install(phy, mac, wifiStaNodes);

    ////
    // Mobility
    ////

    MobilityHelper mobility;
    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
    positionAlloc->Add(Vector(center, center, 0.0));
    // Set position for STAs
    for (uint32_t i = 0; i < nWifi; ++i)
    {
        double angle = 2 * M_PI * i / nWifi;
        double x = radius * std::cos(angle);
        double y = radius * std::sin(angle);
        positionAlloc->Add(Vector(center + x, center + y, 0.0));
    }
    mobility.SetPositionAllocator(positionAlloc);
    mobility.Install(wifiApNode);
    mobility.Install(wifiStaNodes);

    ////
    // Install internet stack
    ////

    InternetStackHelper stack;
    stack.Install(allNodes);

    ////
    // Install Ipv4 addresses
    ////

    Ipv4AddressHelper address;

    //// AP, STAs IP
    address.SetBase("192.168.0.0", "255.255.255.0");
    Ipv4InterfaceContainer apInterface;
    apInterface = address.Assign(apDevices);
    Ipv4InterfaceContainer staInterfaces;
    staInterfaces = address.Assign(staDevices);

    ////
    // Install applications
    ////

    uint16_t port = 9;
    Address sinkAddress(InetSocketAddress(apInterface.GetAddress(0), port));
    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", sinkAddress);
    ApplicationContainer sinkApps = sinkHelper.Install(wifiApNode.Get(0));
    sinkApps.Start(Seconds(1.0));
    sinkApps.Stop(Seconds(12.0));
    OnOffHelper onOff("ns3::UdpSocketFactory", sinkAddress);
    onOff.SetAttribute("DataRate", StringValue(DataRate));
    onOff.SetAttribute("PacketSize", UintegerValue(1472));
    onOff.SetAttribute("Tos", UintegerValue(0x00)); // AC_BE
    onOff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
    onOff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
    onOff.SetAttribute("StartTime", TimeValue(Seconds(2.0)));
    onOff.SetAttribute("StopTime", TimeValue(Seconds(12.0)));
    ApplicationContainer clientApps = onOff.Install(wifiStaNodes);

    Simulator::Stop(Seconds(12));

    ////
    // Flowmonitor
    ////

    Ptr<FlowMonitor> flowmon;
    FlowMonitorHelper flowmonHelper;
    flowmon = flowmonHelper.InstallAll();

    ////
    // Animation
    ////

    AnimationInterface anim(netanimFile);

    uint32_t apImageId = anim.AddResource("AP.png");
    uint32_t apNodeId = wifiApNode.Get(0)->GetId();
    anim.UpdateNodeDescription(apNodeId, "AP");
    anim.UpdateNodeImage(apNodeId, apImageId);
    anim.UpdateNodeSize(apNodeId, 1.0, 1.0);

    uint32_t staImageId = anim.AddResource("STA.png");
    for (uint32_t i = 0; i < wifiStaNodes.GetN(); ++i)
    {
        uint32_t nodeId = wifiStaNodes.Get(i)->GetId();
        std::ostringstream oss;
        oss << "STA-" << i;
        anim.UpdateNodeDescription(nodeId, oss.str());
        anim.UpdateNodeImage(nodeId, staImageId);
        anim.UpdateNodeSize(nodeId, 1.0, 1.0);
    }

    anim.EnablePacketMetadata();

    Simulator::Run();
    flowmon->SerializeToXmlFile(flowmonFile, true, true);
    Simulator::Destroy();
    return 0;
}

FlowMonitor の結果

flowmon-parse-results.py の実行結果(A-MSDU も A-MPDU も無効)
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ python3 flowmon-parse-results.py bothDisable_Flow.xml 
Reading XML file  . done.
FlowID: 1 (UDP 192.168.0.2/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5926.06 kbit/s
    Mean Delay: 3925.27 ms
    Packet Loss Ratio: 86.11 %
FlowID: 2 (UDP 192.168.0.3/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5239.12 kbit/s
    Mean Delay: 3948.45 ms
    Packet Loss Ratio: 87.41 %
FlowID: 3 (UDP 192.168.0.4/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5736.86 kbit/s
    Mean Delay: 3960.88 ms
    Packet Loss Ratio: 86.37 %
FlowID: 4 (UDP 192.168.0.5/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 6023.11 kbit/s
    Mean Delay: 3695.83 ms
    Packet Loss Ratio: 85.85 %
FlowID: 5 (UDP 192.168.0.6/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5718.66 kbit/s
    Mean Delay: 3705.87 ms
    Packet Loss Ratio: 86.36 %
FlowID: 6 (UDP 192.168.0.7/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5426.03 kbit/s
    Mean Delay: 3836.12 ms
    Packet Loss Ratio: 87.02 %
FlowID: 7 (UDP 192.168.0.8/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5699.42 kbit/s
    Mean Delay: 3679.12 ms
    Packet Loss Ratio: 86.46 %
FlowID: 8 (UDP 192.168.0.9/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5688.84 kbit/s
    Mean Delay: 3742.42 ms
    Packet Loss Ratio: 86.49 %
FlowID: 9 (UDP 192.168.0.10/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5911.20 kbit/s
    Mean Delay: 4012.88 ms
    Packet Loss Ratio: 86.00 %
FlowID: 10 (UDP 192.168.0.11/49153 --> 192.168.0.1/9)
    TX bitrate: 61142.42 kbit/s
    RX bitrate: 5553.54 kbit/s
    Mean Delay: 3955.41 ms
    Packet Loss Ratio: 86.72 %

Frame Aggregation の検証のまとめ

シミュレーションの結果をまとめると、下の表のようになる。 どの条件でも STA は同じ 61.14 Mbps(IP 層)で送り続けているので、受信スループットとパケットロスの違いが、そのまま Frame Aggregation の効果になっている。

BE_MaxAmsduSize BE_MaxAmpduSize 平均送信スループット 平均受信スループット 平均パケットロス
7935 1048575 61.14 Mbps 56.11 Mbps 0.86 %
0 1048575 61.14 Mbps 49.14 Mbps 5.39 %
7935 0 61.14 Mbps 22.30 Mbps 53.72 %
0 0 61.14 Mbps 5.69 Mbps 86.48 %
  • A-MSDU と A-MPDU の両方を使うと、平均受信スループットは 56.11 Mbps で、4 つの中で一番高い(送信の約 92%)
  • どちらか片方だけ無効にすると、A-MSDU 無効で 49.14 Mbps(約 12% 低下)、A-MPDU 無効で 22.30 Mbps(約 60% 低下)になって、A-MPDU の方が影響がずっと大きい
  • 両方とも無効にすると 5.69 Mbps まで下がって、両方使ったときの約 1/10 になる
  • A-MSDU の効果は、A-MPDU があるかどうかで大きく変わる
    • A-MPDU 有効のときは、A-MSDU があると 49.14 Mbps → 56.11 Mbps(約 1.1 倍)
    • A-MPDU 無効のときは、A-MSDU があると 5.69 Mbps → 22.30 Mbps(約 3.9 倍)
    • A-MPDU がないと 1 回の送信で送れる MPDU は 1 つだけなので、その 1 つに MSDU を 5 つ詰められる A-MSDU の効果が大きく出ている

引数と属性の調べ方

コードを実行するときに、--PrintHelp をつければ、そのコードを実行するときに使える引数を調べられる。 例えば、examples/wireless/wifi-vht-network.cc だと、下記のように STA と AP の距離・シミュレーション時間・UDP or TCP などなど選択して実行できることがわかる。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "examples/wireless/wifi-vht-network.cc --PrintHelp"
wifi-vht-network [Program Options] [General Arguments]

Program Options:
    --distance:               Distance in meters between the station and the access point [1]
    --simulationTime:         Simulation time [+10s]
    --udp:                    UDP if set to 1, TCP otherwise [true]
    --useRts:                 Enable/disable RTS/CTS [false]
    --use80Plus80:            Enable/disable use of 80+80 MHz [false]
    --mcs:                    list of comma separated MCS values to test; if unset, all MCS values (0-9) are tested
    --phyModel:               PHY model to use (Yans or Spectrum). If 80+80 MHz is enabled, then Spectrum is automatically selected [Yans]
    --channelWidth:           if set, limit testing to a specific channel width expressed in MHz (20, 40, 80 or 160 MHz) [-1]
    --guardInterval:          if set, limit testing to a specific guard interval duration expressed in nanoseconds (800 or 400 ns) [-1]
    --minExpectedThroughput:  if set, simulation fails if the lowest throughput is below this value [0]
    --maxExpectedThroughput:  if set, simulation fails if the highest throughput is above this value [0]

General Arguments:
    --PrintGlobals:              Print the list of globals.
    --PrintGroups:               Print the list of groups.
    --PrintGroup=[group]:        Print all TypeIds of group.
    --PrintTypeIds:              Print all TypeIds.
    --PrintAttributes=[typeid]:  Print all attributes of typeid.
    --PrintVersion:              Print the ns-3 version.
    --PrintHelp:                 Print this help message.

コードを実行するときに、--PrintTypeIds をつければ、そのプログラムに組み込まれた ns-3 のライブラリにあるクラスの一覧を表示できる。

--PrintTypeIds の実行結果
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "examples/wireless/wifi-vht-network.cc --PrintTypeIds"
Registered TypeIds:
    ns3::AarfWifiManager
    ns3::AarfcdWifiManager
    ns3::AdhocWifiMac
    ns3::AdvancedApEmlsrManager
    ns3::AdvancedEmlsrManager
    ns3::AlohaNoackMacHeader
    ns3::AlohaNoackNetDevice
    ns3::AlwaysLosChannelConditionModel
    ns3::AmpduSubframeHeader
    ns3::AmpduTag
    ns3::AmrrWifiManager
    ns3::AmsduSubframeHeader
    ns3::AntennaModel
    ns3::ApEmlsrManager
    ns3::ApWifiMac
    ns3::AparfWifiManager
    ns3::Application
    ns3::ApplicationPacketProbe
    ns3::ArfWifiManager
    ns3::ArpCache
    ns3::ArpHeader
    ns3::ArpL3Protocol
    ns3::AthstatsWifiTraceSink
    ns3::BernoulliRandomVariable
    ns3::BinaryErrorModel
    ns3::BinomialRandomVariable
    ns3::BlockAckManager
    ns3::BooleanProbe
    ns3::BridgeChannel
    ns3::BridgeNetDevice
    ns3::BulkSendApplication
    ns3::BurstErrorModel
    ns3::CalendarScheduler
    ns3::CaraWifiManager
    ns3::Channel
    ns3::ChannelAccessManager
    ns3::ChannelCondition
    ns3::ChannelConditionModel
    ns3::ChannelListPriv
    ns3::Chunk
    ns3::CircularApertureAntennaModel
    ns3::CoDelQueueDisc
    ns3::CobaltQueueDisc
    ns3::ConstantAccelerationMobilityModel
    ns3::ConstantObssPdAlgorithm
    ns3::ConstantPositionMobilityModel
    ns3::ConstantRandomVariable
    ns3::ConstantRateWifiManager
    ns3::ConstantSpectrumPropagationLossModel
    ns3::ConstantSpeedPropagationDelayModel
    ns3::ConstantVelocityMobilityModel
    ns3::CosineAntennaModel
    ns3::Cost231PropagationLossModel
    ns3::CounterCalculator<uint32_t>
    ns3::CtrlBAckRequestHeader
    ns3::CtrlBAckResponseHeader
    ns3::CtrlTriggerHeader
    ns3::DataCollectionObject
    ns3::DefaultApEmlsrManager
    ns3::DefaultEmlsrManager
    ns3::DefaultSimulatorImpl
    ns3::DeterministicRandomVariable
    ns3::DeviceNameTag
    ns3::DoubleProbe
    ns3::DropTailQueue<Packet>
    ns3::DropTailQueue<QueueDiscItem>
    ns3::DynamicQueueLimits
    ns3::EhtConfiguration
    ns3::EhtFrameExchangeManager
    ns3::EmlsrManager
    ns3::EmpiricalRandomVariable
    ns3::ErlangRandomVariable
    ns3::ErrorChannel
    ns3::ErrorModel
    ns3::ErrorRateModel
    ns3::EthernetHeader
    ns3::EthernetTrailer
    ns3::ExponentialRandomVariable
    ns3::FcfsWifiQueueScheduler
    ns3::FifoQueueDisc
    ns3::FileAggregator
    ns3::FilsDiscHeader
    ns3::FixedRssLossModel
    ns3::FlowIdTag
    ns3::FqCoDelFlow
    ns3::FqCoDelQueueDisc
    ns3::FqCobaltFlow
    ns3::FqCobaltQueueDisc
    ns3::FqPieFlow
    ns3::FqPieQueueDisc
    ns3::FrameCaptureModel
    ns3::FrameExchangeManager
    ns3::FriisPropagationLossModel
    ns3::FriisSpectrumPropagationLossModel
    ns3::GammaRandomVariable
    ns3::GaussMarkovMobilityModel
    ns3::GcrManager
    ns3::GeocentricConstantPositionMobilityModel
    ns3::GlobalRouter
    ns3::GnuplotAggregator
    ns3::GridPositionAllocator
    ns3::HalfDuplexIdealPhy
    ns3::HeConfiguration
    ns3::HeFrameExchangeManager
    ns3::Header
    ns3::HeapScheduler
    ns3::HierarchicalMobilityModel
    ns3::HtConfiguration
    ns3::HtFrameExchangeManager
    ns3::Icmpv4DestinationUnreachable
    ns3::Icmpv4Echo
    ns3::Icmpv4Header
    ns3::Icmpv4L4Protocol
    ns3::Icmpv4TimeExceeded
    ns3::Icmpv6DestinationUnreachable
    ns3::Icmpv6Echo
    ns3::Icmpv6Header
    ns3::Icmpv6L4Protocol
    ns3::Icmpv6NA
    ns3::Icmpv6NS
    ns3::Icmpv6OptionHeader
    ns3::Icmpv6OptionLinkLayerAddress
    ns3::Icmpv6OptionMtu
    ns3::Icmpv6OptionPrefixInformation
    ns3::Icmpv6OptionRedirected
    ns3::Icmpv6ParameterError
    ns3::Icmpv6RA
    ns3::Icmpv6RS
    ns3::Icmpv6Redirection
    ns3::Icmpv6TimeExceeded
    ns3::Icmpv6TooBig
    ns3::IdealWifiManager
    ns3::InterferenceHelper
    ns3::IpL4Protocol
    ns3::Ipv4
    ns3::Ipv4GlobalRouting
    ns3::Ipv4Header
    ns3::Ipv4Interface
    ns3::Ipv4L3Protocol
    ns3::Ipv4ListRouting
    ns3::Ipv4PacketFilter
    ns3::Ipv4PacketProbe
    ns3::Ipv4RawSocketFactory
    ns3::Ipv4RawSocketImpl
    ns3::Ipv4RoutingProtocol
    ns3::Ipv4StaticRouting
    ns3::Ipv6
    ns3::Ipv6Extension
    ns3::Ipv6ExtensionAH
    ns3::Ipv6ExtensionAHHeader
    ns3::Ipv6ExtensionDemux
    ns3::Ipv6ExtensionDestination
    ns3::Ipv6ExtensionDestinationHeader
    ns3::Ipv6ExtensionESP
    ns3::Ipv6ExtensionESPHeader
    ns3::Ipv6ExtensionFragment
    ns3::Ipv6ExtensionFragmentHeader
    ns3::Ipv6ExtensionHeader
    ns3::Ipv6ExtensionHopByHop
    ns3::Ipv6ExtensionHopByHopHeader
    ns3::Ipv6ExtensionLooseRouting
    ns3::Ipv6ExtensionLooseRoutingHeader
    ns3::Ipv6ExtensionRouting
    ns3::Ipv6ExtensionRoutingDemux
    ns3::Ipv6ExtensionRoutingHeader
    ns3::Ipv6Header
    ns3::Ipv6Interface
    ns3::Ipv6L3Protocol
    ns3::Ipv6ListRouting
    ns3::Ipv6Option
    ns3::Ipv6OptionDemux
    ns3::Ipv6OptionHeader
    ns3::Ipv6OptionJumbogram
    ns3::Ipv6OptionJumbogramHeader
    ns3::Ipv6OptionPad1
    ns3::Ipv6OptionPad1Header
    ns3::Ipv6OptionPadn
    ns3::Ipv6OptionPadnHeader
    ns3::Ipv6OptionRouterAlert
    ns3::Ipv6OptionRouterAlertHeader
    ns3::Ipv6PacketFilter
    ns3::Ipv6PacketProbe
    ns3::Ipv6PmtuCache
    ns3::Ipv6RawSocketFactory
    ns3::Ipv6RawSocketImpl
    ns3::Ipv6RoutingProtocol
    ns3::Ipv6StaticRouting
    ns3::IsotropicAntennaModel
    ns3::ItuR1411LosPropagationLossModel
    ns3::ItuR1411NlosOverRooftopPropagationLossModel
    ns3::JakesProcess
    ns3::JakesPropagationLossModel
    ns3::Kun2600MhzPropagationLossModel
    ns3::LaplacianRandomVariable
    ns3::LargestExtremeValueRandomVariable
    ns3::LinearWifiTxCurrentModel
    ns3::ListErrorModel
    ns3::ListPositionAllocator
    ns3::ListScheduler
    ns3::LlcSnapHeader
    ns3::LogDistancePropagationLossModel
    ns3::LogNormalRandomVariable
    ns3::LoopbackNetDevice
    ns3::MapScheduler
    ns3::MatrixPropagationLossModel
    ns3::MgtAddBaRequestHeader
    ns3::MgtAddBaResponseHeader
    ns3::MgtAssocRequestHeader
    ns3::MgtAssocResponseHeader
    ns3::MgtBeaconHeader
    ns3::MgtDelBaHeader
    ns3::MgtEmlOperatingModeNotification
    ns3::MgtProbeRequestHeader
    ns3::MgtProbeResponseHeader
    ns3::MgtReassocRequestHeader
    ns3::MinstrelHtWifiManager
    ns3::MinstrelWifiManager
    ns3::MobilityModel
    ns3::MpduAggregator
    ns3::MqQueueDisc
    ns3::MsduAggregator
    ns3::MuSnrTag
    ns3::MultiModelSpectrumChannel
    ns3::MultiUserScheduler
    ns3::NakagamiPropagationLossModel
    ns3::NdiscCache
    ns3::NetDevice
    ns3::NetDeviceQueue
    ns3::NetDeviceQueueInterface
    ns3::NeverLosChannelConditionModel
    ns3::NeverLosVehicleChannelConditionModel
    ns3::NistErrorRateModel
    ns3::Node
    ns3::NodeListPriv
    ns3::NonCommunicatingNetDevice
    ns3::NormalRandomVariable
    ns3::Object
    ns3::ObjectBase
    ns3::ObssPdAlgorithm
    ns3::OkumuraHataPropagationLossModel
    ns3::OnOffApplication
    ns3::OnoeWifiManager
    ns3::PacketBurst
    ns3::PacketFilter
    ns3::PacketProbe
    ns3::PacketSink
    ns3::PacketSocket
    ns3::PacketSocketClient
    ns3::PacketSocketFactory
    ns3::PacketSocketServer
    ns3::PacketSocketTag
    ns3::ParabolicAntennaModel
    ns3::ParetoRandomVariable
    ns3::ParfWifiManager
    ns3::PbbPacket
    ns3::PcapFileWrapper
    ns3::PfifoFastQueueDisc
    ns3::PhasedArrayModel
    ns3::PhasedArraySpectrumPropagationLossModel
    ns3::PieQueueDisc
    ns3::PositionAllocator
    ns3::PreambleDetectionModel
    ns3::PrioQueueDisc
    ns3::PriorityQueueScheduler
    ns3::ProbabilisticV2vHighwayChannelConditionModel
    ns3::ProbabilisticV2vUrbanChannelConditionModel
    ns3::Probe
    ns3::PropagationDelayModel
    ns3::PropagationLossModel
    ns3::QosFrameExchangeManager
    ns3::QosTxop
    ns3::Queue<Packet>
    ns3::Queue<QueueDiscItem>
    ns3::Queue<WifiMpdu,WifiMacQueueContainer>
    ns3::QueueBase
    ns3::QueueDisc
    ns3::QueueDiscClass
    ns3::QueueLimits
    ns3::RadiotapHeader
    ns3::RandomBoxPositionAllocator
    ns3::RandomDirection2dMobilityModel
    ns3::RandomDiscPositionAllocator
    ns3::RandomPropagationDelayModel
    ns3::RandomPropagationLossModel
    ns3::RandomRectanglePositionAllocator
    ns3::RandomVariableStream
    ns3::RandomWalk2dMobilityModel
    ns3::RandomWaypointMobilityModel
    ns3::RangePropagationLossModel
    ns3::RateErrorModel
    ns3::RealtimeSimulatorImpl
    ns3::ReceiveListErrorModel
    ns3::RedQueueDisc
    ns3::Rip
    ns3::RipHeader
    ns3::RipNg
    ns3::RipNgHeader
    ns3::RipNgRte
    ns3::RipRte
    ns3::RrMultiUserScheduler
    ns3::RraaWifiManager
    ns3::RrpaaWifiManager
    ns3::RttEstimator
    ns3::RttMeanDeviation
    ns3::Scheduler
    ns3::SeqTsEchoHeader
    ns3::SeqTsHeader
    ns3::SeqTsSizeHeader
    ns3::SequentialRandomVariable
    ns3::ShannonSpectrumErrorModel
    ns3::SimpleChannel
    ns3::SimpleFrameCaptureModel
    ns3::SimpleNetDevice
    ns3::SimpleTag
    ns3::SimulatorImpl
    ns3::SingleModelSpectrumChannel
    ns3::SinkApplication
    ns3::SllHeader
    ns3::SnrTag
    ns3::Socket
    ns3::SocketFactory
    ns3::SocketIpTtlTag
    ns3::SocketIpv6HopLimitTag
    ns3::SocketSetDontFragmentTag
    ns3::SourceApplication
    ns3::SpectrumAnalyzer
    ns3::SpectrumChannel
    ns3::SpectrumErrorModel
    ns3::SpectrumPhy
    ns3::SpectrumPropagationLossModel
    ns3::SpectrumTransmitFilter
    ns3::SpectrumWifiPhy
    ns3::StaWifiMac
    ns3::SteadyStateRandomWaypointMobilityModel
    ns3::Synchronizer
    ns3::TableBasedErrorRateModel
    ns3::Tag
    ns3::TbfQueueDisc
    ns3::TcpBbr
    ns3::TcpBic
    ns3::TcpClassicRecovery
    ns3::TcpCongestionOps
    ns3::TcpCubic
    ns3::TcpDctcp
    ns3::TcpHeader
    ns3::TcpHighSpeed
    ns3::TcpHtcp
    ns3::TcpHybla
    ns3::TcpIllinois
    ns3::TcpL4Protocol
    ns3::TcpLedbat
    ns3::TcpLinuxReno
    ns3::TcpLp
    ns3::TcpNewReno
    ns3::TcpOption
    ns3::TcpOptionEnd
    ns3::TcpOptionMSS
    ns3::TcpOptionNOP
    ns3::TcpOptionSack
    ns3::TcpOptionSackPermitted
    ns3::TcpOptionTS
    ns3::TcpOptionUnknown
    ns3::TcpOptionWinScale
    ns3::TcpPrrRecovery
    ns3::TcpRateLinux
    ns3::TcpRateOps
    ns3::TcpRecoveryOps
    ns3::TcpRxBuffer
    ns3::TcpScalable
    ns3::TcpSocket
    ns3::TcpSocketBase
    ns3::TcpSocketFactory
    ns3::TcpSocketState
    ns3::TcpTxBuffer
    ns3::TcpVegas
    ns3::TcpVeno
    ns3::TcpWestwoodPlus
    ns3::TcpYeah
    ns3::ThompsonSamplingWifiManager
    ns3::ThreeGppAntennaModel
    ns3::ThreeGppChannelConditionModel
    ns3::ThreeGppChannelModel
    ns3::ThreeGppHttpClient
    ns3::ThreeGppHttpHeader
    ns3::ThreeGppHttpServer
    ns3::ThreeGppHttpVariables
    ns3::ThreeGppIndoorMixedOfficeChannelConditionModel
    ns3::ThreeGppIndoorOfficePropagationLossModel
    ns3::ThreeGppIndoorOpenOfficeChannelConditionModel
    ns3::ThreeGppNTNDenseUrbanChannelConditionModel
    ns3::ThreeGppNTNDenseUrbanPropagationLossModel
    ns3::ThreeGppNTNRuralChannelConditionModel
    ns3::ThreeGppNTNRuralPropagationLossModel
    ns3::ThreeGppNTNSuburbanChannelConditionModel
    ns3::ThreeGppNTNSuburbanPropagationLossModel
    ns3::ThreeGppNTNUrbanChannelConditionModel
    ns3::ThreeGppNTNUrbanPropagationLossModel
    ns3::ThreeGppPropagationLossModel
    ns3::ThreeGppRmaChannelConditionModel
    ns3::ThreeGppRmaPropagationLossModel
    ns3::ThreeGppSpectrumPropagationLossModel
    ns3::ThreeGppUmaChannelConditionModel
    ns3::ThreeGppUmaPropagationLossModel
    ns3::ThreeGppUmiStreetCanyonChannelConditionModel
    ns3::ThreeGppUmiStreetCanyonPropagationLossModel
    ns3::ThreeGppV2vHighwayPropagationLossModel
    ns3::ThreeGppV2vUrbanPropagationLossModel
    ns3::ThreeLogDistancePropagationLossModel
    ns3::ThresholdPreambleDetectionModel
    ns3::TimeProbe
    ns3::TimeSeriesAdaptor
    ns3::TimestampTag
    ns3::TraceFadingLossModel
    ns3::TrafficControlLayer
    ns3::Trailer
    ns3::TriangularRandomVariable
    ns3::TvSpectrumTransmitter
    ns3::TwoRayGroundPropagationLossModel
    ns3::TwoRaySpectrumPropagationLossModel
    ns3::Txop
    ns3::UdpClient
    ns3::UdpEchoClient
    ns3::UdpEchoServer
    ns3::UdpHeader
    ns3::UdpL4Protocol
    ns3::UdpServer
    ns3::UdpSocket
    ns3::UdpSocketFactory
    ns3::UdpSocketImpl
    ns3::UdpTraceClient
    ns3::Uinteger16Probe
    ns3::Uinteger32Probe
    ns3::Uinteger8Probe
    ns3::UniformDiscPositionAllocator
    ns3::UniformPlanarArray
    ns3::UniformRandomVariable
    ns3::VhtConfiguration
    ns3::VhtFrameExchangeManager
    ns3::WallClockSynchronizer
    ns3::WaveformGenerator
    ns3::WaypointMobilityModel
    ns3::WeibullRandomVariable
    ns3::WifiAckManager
    ns3::WifiAssocManager
    ns3::WifiBandwidthFilter
    ns3::WifiDefaultAckManager
    ns3::WifiDefaultAssocManager
    ns3::WifiDefaultGcrManager
    ns3::WifiDefaultProtectionManager
    ns3::WifiMac
    ns3::WifiMacHeader
    ns3::WifiMacQueue
    ns3::WifiMacQueueScheduler
    ns3::WifiMacQueueSchedulerImpl
    ns3::WifiMacTrailer
    ns3::WifiNetDevice
    ns3::WifiPhy
    ns3::WifiPhyRxTraceSink
    ns3::WifiPhyStateHelper
    ns3::WifiProtectionManager
    ns3::WifiRadioEnergyModel
    ns3::WifiRemoteStationManager
    ns3::WifiSpectrumPhyInterface
    ns3::WifiTxCurrentModel
    ns3::YansErrorRateModel
    ns3::YansWifiChannel
    ns3::YansWifiPhy
    ns3::ZetaRandomVariable
    ns3::ZipfRandomVariable
    ns3::energy::BasicEnergyHarvester
    ns3::energy::BasicEnergySource
    ns3::energy::DeviceEnergyModel
    ns3::energy::EnergyHarvester
    ns3::energy::EnergyHarvesterContainer
    ns3::energy::EnergySource
    ns3::energy::EnergySourceContainer
    ns3::energy::GenericBatteryModel
    ns3::energy::LiIonEnergySource
    ns3::energy::RvBatteryModel
    ns3::energy::SimpleDeviceEnergyModel

例えば、ApWifiMac っていうのがある。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "examples/wireless/wifi-vht-network.cc --PrintTypeIds" | grep ApWifiMac
    ns3::ApWifiMac

これについて調べようと思ったら、--PrintAttributes=ns3::ApWifiMac をつけたら、コードを作成したときには気にしていない属性のデフォルト値とかも確認できる。

--PrintAttributes=ns3::ApWifiMac の実行結果
ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "examples/wireless/wifi-vht-network.cc --PrintAttributes=ns3::ApWifiMac"
Attributes for TypeId ns3::ApWifiMac
    --ns3::ApWifiMac::AifsnsForSta=[]
        The AIFSN values that the AP advertises in EDCA Parameter Set elements and the associated stations will use. The value of this attribute is an AC-indexed map containing the AIFSN values for given ACs for all the links (sorted in increasing order of link ID). If no values are provided for an AC, the same values used by the AP are advertised. In case a string is used to set this attribute, the string shall contain the pairs separated by a semicolon (;); in every pair, the AC index and the list of values are separated by a blank space, and the values of a list are separated by a comma (,) without spaces. E.g. "BE 3,3,3; VI 2,2,2" defines the AIFSN values for AC BE and AC VI for an AP MLD having three links.
    --ns3::ApWifiMac::BeaconGeneration=[true]
        Whether or not beacons are generated.
    --ns3::ApWifiMac::BeaconInterval=[+1.024e+08ns]
        Delay between two beacons
    --ns3::ApWifiMac::BeaconJitter=[ns3::UniformRandomVariable]
        A uniform random variable to cause the initial beacon starting time (after simulation time 0) to be distributed between 0 and the BeaconInterval.
    --ns3::ApWifiMac::BsrLifetime=[+2e+07ns]
        Lifetime of Buffer Status Reports received from stations.
    --ns3::ApWifiMac::CwMaxsForSta=[]
        The CW max values that the AP advertises in EDCA Parameter Set elements and the associated stations will use. The value of this attribute is an AC-indexed map containing the CW max values for given ACs for all the links (sorted in increasing order of link ID). If no values are provided for an AC, the same values used by the AP are advertised. In case a string is used to set this attribute, the string shall contain the pairs separated by a semicolon (;); in every pair, the AC index and the list of values are separated by a blank space, and the values of a list are separated by a comma (,) without spaces. E.g. "BE 31,31,31; VI 15,15,15" defines the CW max values for AC BE and AC VI for an AP MLD having three links.
    --ns3::ApWifiMac::CwMinsForSta=[]
        The CW min values that the AP advertises in EDCA Parameter Set elements and the associated stations will use. The value of this attribute is an AC-indexed map containing the CW min values for given ACs for all the links (sorted in increasing order of link ID). If no values are provided for an AC, the same values used by the AP are advertised. In case a string is used to set this attribute, the string shall contain the pairs separated by a semicolon (;); in every pair, the AC index and the list of values are separated by a blank space, and the values of a list are separated by a comma (,) without spaces. E.g. "BE 31,31,31; VI 15,15,15" defines the CW min values for AC BE and AC VI for an AP MLD having three links.
    --ns3::ApWifiMac::EnableBeaconJitter=[true]
        If beacons are enabled, whether to jitter the initial send event.
    --ns3::ApWifiMac::EnableNonErpProtection=[true]
        Whether or not protection mechanism should be used when non-ERP STAs are present within the BSS.This parameter is only used when ERP is supported by the AP.
    --ns3::ApWifiMac::FdBeaconInterval6GHz=[+0ns]
        Time between a Beacon frame and a FILS Discovery (FD) frame or between two FD frames to be sent on a 6GHz link. A value of zero disables the transmission of FD frames.
    --ns3::ApWifiMac::FdBeaconIntervalNon6GHz=[+0ns]
        Time between a Beacon frame and a FILS Discovery (FD) frame or between two FD frames to be sent on a non-6GHz link. A value of zero disables the transmission of FD frames.
    --ns3::ApWifiMac::GcrManager=[0]
        The GCR manager object.
    --ns3::ApWifiMac::SendUnsolProbeResp=[false]
        Send unsolicited broadcast Probe Response instead of FILS Discovery
    --ns3::ApWifiMac::TxopLimitsForSta=[]
        The TXOP limit values that the AP advertises in EDCA Parameter Set elements and the associated stations will use. The value of this attribute is an AC-indexed map containing the TXOP limit values for given ACs for all the links (sorted in increasing order of link ID). If no values are provided for an AC, the same values used by the AP are advertised. In case a string is used to set this attribute, the string shall contain the pairs separated by a semicolon (;); in every pair, the AC index and the list of values are separated by a blank space, and the values of a list are separated by a comma (,) without spaces. E.g. "BE 3200us,3200us,3200us; VI 2400us,2400us,2400us" defines the TXOP limit values for AC BE and AC VI for an AP MLD having three links.
Attributes defined in parent class ns3::WifiMac
    --ns3::WifiMac::BE_BlockAckInactivityTimeout=[0]
        Represents max time (blocks of 1024 microseconds) allowed for block ackinactivity for AC_BE. If this value isn't equal to 0 a timer start after that ablock ack setup is completed and will be reset every time that a block ackframe is received. If this value is 0, block ack inactivity timeout won't be used.
    --ns3::WifiMac::BE_BlockAckThreshold=[0]
        If number of packets in BE queue reaches this value, block ack mechanism is used. If this value is 0, block ack is never used.When A-MPDU is enabled, block ack mechanism is used regardless of this value.
    --ns3::WifiMac::BE_MaxAmpduSize=[65535]
        Maximum length in bytes of an A-MPDU for AC_BE access class (capped to 65535 for HT PPDUs, 1048575 for VHT PPDUs, 6500631 for HE PPDUs and 15523200 for EHT PPDUs). Value 0 means A-MPDU aggregation is disabled for that AC.
    --ns3::WifiMac::BE_MaxAmsduSize=[0]
        Maximum length in bytes of an A-MSDU for AC_BE access class (capped to 7935 for HT PPDUs and 11398 for VHT/HE/EHT PPDUs). Value 0 means A-MSDU aggregation is disabled for that AC.
    --ns3::WifiMac::BE_Txop=[0]
        Queue that manages packets belonging to AC_BE access class.
    --ns3::WifiMac::BK_BlockAckInactivityTimeout=[0]
        Represents max time (blocks of 1024 microseconds) allowed for block ackinactivity for AC_BK. If this value isn't equal to 0 a timer start after that ablock ack setup is completed and will be reset every time that a block ackframe is received. If this value is 0, block ack inactivity timeout won't be used.
    --ns3::WifiMac::BK_BlockAckThreshold=[0]
        If number of packets in BK queue reaches this value, block ack mechanism is used. If this value is 0, block ack is never used.When A-MPDU is enabled, block ack mechanism is used regardless of this value.
    --ns3::WifiMac::BK_MaxAmpduSize=[0]
        Maximum length in bytes of an A-MPDU for AC_BK access class (capped to 65535 for HT PPDUs, 1048575 for VHT PPDUs, 6500631 for HE PPDUs and 15523200 for EHT PPDUs). Value 0 means A-MPDU aggregation is disabled for that AC.
    --ns3::WifiMac::BK_MaxAmsduSize=[0]
        Maximum length in bytes of an A-MSDU for AC_BK access class (capped to 7935 for HT PPDUs and 11398 for VHT/HE/EHT PPDUs). Value 0 means A-MSDU aggregation is disabled for that AC.
    --ns3::WifiMac::BK_Txop=[0]
        Queue that manages packets belonging to AC_BK access class.
    --ns3::WifiMac::ChannelAccessManagers=[]
        The Channel Access Manager(s) attached to this device.
    --ns3::WifiMac::CtsToSelfSupported=[false]
        Use CTS to Self when using a rate that is not in the basic rate set.
    --ns3::WifiMac::FrameExchangeManagers=[]
        The Frame Exchange Manager(s) attached to this device.
    --ns3::WifiMac::FrameRetryLimit=[7]
        The maximum number of transmission attempts of a frame that are made before a failure condition is indicated. This corresponds to the dot11ShortRetryLimit parameter in the standard.
    --ns3::WifiMac::MpduBufferSize=[1024]
        The size (in number of MPDUs) of the buffer used for each BlockAck agreement in which this node is a recipient. The provided value is capped to the maximum allowed value based on the supported standard.
    --ns3::WifiMac::QosSupported=[false]
        This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA.
    --ns3::WifiMac::RobustAVStreamingSupported=[false]
        Whether or not Robust Audio Video Streaming is supported (only allowed for AP STAs or non-AP that are HT capable).
    --ns3::WifiMac::ShortSlotTimeSupported=[true]
        Whether or not short slot time is supported (only used by ERP APs or STAs).
    --ns3::WifiMac::Ssid=[ssid=default]
        The ssid we want to belong to.
    --ns3::WifiMac::Txop=[0]
        The Txop object.
    --ns3::WifiMac::VI_BlockAckInactivityTimeout=[0]
        Represents max time (blocks of 1024 microseconds) allowed for block ackinactivity for AC_VI. If this value isn't equal to 0 a timer start after that ablock ack setup is completed and will be reset every time that a block ackframe is received. If this value is 0, block ack inactivity timeout won't be used.
    --ns3::WifiMac::VI_BlockAckThreshold=[0]
        If number of packets in VI queue reaches this value, block ack mechanism is used. If this value is 0, block ack is never used.When A-MPDU is enabled, block ack mechanism is used regardless of this value.
    --ns3::WifiMac::VI_MaxAmpduSize=[65535]
        Maximum length in bytes of an A-MPDU for AC_VI access class (capped to 65535 for HT PPDUs, 1048575 for VHT PPDUs, 6500631 for HE PPDUs and 15523200 for EHT PPDUs). Value 0 means A-MPDU aggregation is disabled for that AC.
    --ns3::WifiMac::VI_MaxAmsduSize=[0]
        Maximum length in bytes of an A-MSDU for AC_VI access class (capped to 7935 for HT PPDUs and 11398 for VHT/HE/EHT PPDUs). Value 0 means A-MSDU aggregation is disabled for that AC.
    --ns3::WifiMac::VI_Txop=[0]
        Queue that manages packets belonging to AC_VI access class.
    --ns3::WifiMac::VO_BlockAckInactivityTimeout=[0]
        Represents max time (blocks of 1024 microseconds) allowed for block ackinactivity for AC_VO. If this value isn't equal to 0 a timer start after that ablock ack setup is completed and will be reset every time that a block ackframe is received. If this value is 0, block ack inactivity timeout won't be used.
    --ns3::WifiMac::VO_BlockAckThreshold=[0]
        If number of packets in VO queue reaches this value, block ack mechanism is used. If this value is 0, block ack is never used.When A-MPDU is enabled, block ack mechanism is used regardless of this value.
    --ns3::WifiMac::VO_MaxAmpduSize=[0]
        Maximum length in bytes of an A-MPDU for AC_VO access class (capped to 65535 for HT PPDUs, 1048575 for VHT PPDUs, 6500631 for HE PPDUs and 15523200 for EHT PPDUs). Value 0 means A-MPDU aggregation is disabled for that AC.
    --ns3::WifiMac::VO_MaxAmsduSize=[0]
        Maximum length in bytes of an A-MSDU for AC_VO access class (capped to 7935 for HT PPDUs and 11398 for VHT/HE/EHT PPDUs). Value 0 means A-MSDU aggregation is disabled for that AC.
    --ns3::WifiMac::VO_Txop=[0]
        Queue that manages packets belonging to AC_VO access class.

例えば、AC_BE における Block Ack と MaxAmpduSize について調べたいとなったとする。

ishigaki@ishigaki-NS3:~/ns-allinone-3.44/ns-3.44$ ./ns3 run "examples/wireless/wifi-vht-network.cc -PrintAttributes=ns3::ApWifiMac"
(出力は抜粋)
    --ns3::WifiMac::BE_BlockAckThreshold=[0]
        If number of packets in BE queue reaches this value, block ack mechanism is used. If this value is 0, block ack is never used.When A-MPDU is enabled, block ack mechanism is used regardless of this value.
    --ns3::WifiMac::BE_MaxAmpduSize=[65535]
        Maximum length in bytes of an A-MPDU for AC_BE access class (capped to 65535 for HT PPDUs, 1048575 for VHT PPDUs, 6500631 for HE PPDUs and 15523200 for EHT PPDUs). Value 0 means A-MPDU aggregation is disabled for that AC.

ここに書いてること:

  • BE_MaxAmpduSize: これが 0 だったら、AC_BE では A-MPDU は使わない
  • BE_MaxAmpduSize: デフォルト値は 65535 で、VHT(802.11ac)を使っても自動では大きくならない。VHT なら 1048575 まで設定できる
  • BE_BlockAckThreshold: デフォルト値では Block Ack は使われない 0 になってる。けど、A-MPDU が有効ならこの値に関係なく Block Ack が使われる

↑みたいに、自分がコードを書く以前にいろいろ決まっているので、着目したい部分については必ず確認しておいた方がいい。

自分のコードに関係する部分だけ調べる手順 by Claude Code Opus 5.5

API Reference はボリュームが多くて迷子になりやすいので、コマンドで調べる範囲を絞ってから見る。

  1. --PrintHelp で、そのプログラムが受け付ける引数を確認する
    • プログラム独自の引数(wifi-vht-network.cc なら --distance とか)は API Reference には載っていない
  2. 自分のコードに "ns3::..." の文字列で書いてあるクラス名を拾う

    grep -o '"ns3::[A-Za-z:]*"' scratch/A-MSDU_simulation.cc | sort -u
    
    • scratch/A-MSDU_simulation.cc なら、ns3::ApWifiMac、ns3::StaWifiMac、ns3::ConstantRateWifiManager、ns3::ConstantPositionMobilityModel、ns3::UdpSocketFactory の 5 つが出てくる
    • この名前はそのまま --PrintAttributes に渡せる
    • --PrintAttributes でそのクラスの属性を出して、grep で見たい部分だけに絞る
    ./ns3 run "scratch/A-MSDU_simulation.cc --PrintAttributes=ns3::ApWifiMac" | grep -A1 BE_
    
    • -A1 をつけると、属性名の次の行にある説明も一緒に出る
    • 親クラス(ApWifiMac なら WifiMac)の属性も出るので、クラス 1 つでかなりの範囲をカバーできる
    • コードに名前が出てこないクラスを探すときは、--PrintGroups でグループの一覧を出して、--PrintGroup=Wifi で Wi-Fi のクラスだけに絞る
    • --PrintTypeIds はプログラムに組み込まれた ns-3 のライブラリのクラスを全部出すので、wifi-vht-network.cc だと 480 個もある(CSMA や LTE のクラスは入っていないので、これでも ns-3 全体ではない)

ただし、コマンドだけではわからないこともある。

  • --PrintAttributes で出るのは属性のデフォルト値で、コードの中で SetType() などで設定した値ではない
  • コードに名前が出てこなくても、内部で使われているクラスがある
    • 例えば WifiMac の BE_Txop は、AC_BE のキューを管理する ns3::QosTxop を指している。この属性は --PrintAttributes=ns3::QosTxop で別に確認する
  • 属性の型と設定できる範囲、TraceSources は API Reference(例: ApWifiMac)にしか載っていない。コマンドでクラス名がわかっていれば、そのクラスのページに直接行ける

※ API Reference を見る前に全体をつかみたいときは、Wi-Fi User Documentation が入口になる


References

  1. ns-3 Project, "ns-3 Network Simulator", https://www.nsnam.org
  2. Anil Kumar Rangisetti (2023), Advanced Network Simulations Simplified, Packt
  3. 銭飛 (2014)、『ns3 によるネットワークシミュレーション』、森北出版