Wireless
08/12/2021, bởi Thầy TiiL trong mục: NS3We next present the wireless simulation of 31.6 Wireless Simulation. The full script is at wireless.cc; the animation output for the netanim
player is at wireless.xml. As before, we have one mover
node moving horizontally 150 meters above a row of five fixed nodes spaced 200 meters apart. The limit of transmission is set to be 250 meters, meaning that a fixed node goes out of range of the mover
node just as the latter passes over directly above the next fixed node. As before, we use Ad hoc On-demand Distance Vector (AODV) as the routing protocol. When the mover
passes over fixed node N, it goes out of range of fixed node N-1, at which point AODV finds a new route to mover
through fixed node N.
As in ns-2, wireless simulations tend to require considerably more configuration than point-to-point simulations. We now review the source code line-by-line. We start with two callback functions and the global variables they will need to access.
using namespace ns3; Ptr<ConstantVelocityMobilityModel> cvmm; double position_interval = 1.0; std::string tracebase = "scratch/wireless"; // two callbacks void printPosition() { Vector thePos = cvmm->GetPosition(); Simulator::Schedule(Seconds(position_interval), &printPosition); std::cout << "position: " << thePos << std::endl; } void stopMover() { cvmm -> SetVelocity(Vector(0,0,0)); }
Next comes the data rate:
int main (int argc, char *argv[]) { std::string phyMode = "DsssRate1Mbps";
The phyMode
string represents the Wi-Fi data rate (and modulation technique). DSSS rates are DsssRate1Mbps
, DsssRate2Mbps
, DsssRate5_5Mbps
and DsssRate11Mbps
. Also available are ErpOfdmRate
constants to 54 Mbps and OfdmRate
constants to 150 Mbps with a 40 MHz band-width (GetOfdmRate150MbpsBW40MHz
). All these are defined in src/wifi/model/wifi-phy.cc.
Next are the variables that determine the layout and network behavior. The factor
variable allows slowing down the speed of the mover
node but correspondingly extending the runtime (though the new-route-discovery time is not scaled):
int bottomrow = 5; // number of bottom-row nodes int spacing = 200; // between bottom-row nodes int mheight = 150; // height of mover above bottom row int brheight = 50; // height of bottom row int X = (bottomrow-1)*spacing+1; // X is the horizontal dimension of the field int packetsize = 500; double factor = 1.0; // allows slowing down rate and extending runtime; same total # of packets int endtime = (int)100*factor; double speed = (X-1.0)/endtime; double bitrate = 80*1000.0/factor; // *average* transmission rate, in bits/sec uint32_t interval = 1000*packetsize*8/bitrate*1000; // in microsec uint32_t packetcount = 1000000*endtime/ interval; std::cout << "interval = " << interval <<", rate=" << bitrate << ", packetcount=" << packetcount << std::endl;
There are some niceties in calculating the packet transmission interval above; if we do it instead as 1000000*packetsize*8/bitrate then we sometimes run into 32-bit overflow problems or integer-division-roundoff problems.
Now we configure some Wi-Fi settings.
/ disable fragmentation for frames below 2200 bytes Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200")); // turn off RTS/CTS for frames below 2200 bytes Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200")); // Set non-unicast data rate to be the same as that of unicast Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue (phyMode));
Here we create the mover
node with CreateObject<Node>()
, but the fixed nodes are created via a NodeContainer
, as is more typical with larger simulations
// Create nodes NodeContainer fixedpos; fixedpos.Create(bottomrow); Ptr<Node> lowerleft = fixedpos.Get(0); Ptr<Node> mover = CreateObject<Node>();
Now we put together a set of “helper” objects for more Wi-Fi configuration. We must configure both the PHY (physical) and MAC layers.
// The below set of helpers will help us to put together the desired Wi-Fi behavior WifiHelper wifi; wifi.SetStandard (WIFI_PHY_STANDARD_80211b); wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); // Use AARF rate control
The AARF rate changes can be viewed by enabling the appropriate logging with, at the shell level before ./waf
, NS_LOG=AarfWifiManager=level_debug
. We are not otherwise interested in rate scaling (4.2.2 Dynamic Rate Scaling) here, though.
The PHY layer helper is YansWifiPhyHelper
. The YANS project (Yet Another Network Simulator) was an influential precursor to ns-3; see [LH06]. Note the AddPropagationLoss
configuration, where we set the Wi-Fi range to 250 meters. The MAC layer helper is NqosWifiMacHelper
; the “nqos” means “no quality-of-service”, ie no use of Wi-Fi PCF (4.2.7 Wi-Fi Polling Mode).
// The PHY layer here is "yans" YansWifiPhyHelper wifiPhyHelper = YansWifiPhyHelper::Default (); // for .pcap tracing // wifiPhyHelper.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO); YansWifiChannelHelper wifiChannelHelper; // *not* ::Default() ! wifiChannelHelper.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel"); // pld: default? // the following has an absolute cutoff at distance > 250 wifiChannelHelper.AddPropagationLoss ("ns3::RangePropagationLossModel", "MaxRange", DoubleValue(250)); Ptr<YansWifiChannel> pchan = wifiChannelHelper.Create (); wifiPhyHelper.SetChannel (pchan); // Add a non-QoS upper-MAC layer "AdhocWifiMac", and set rate control NqosWifiMacHelper wifiMacHelper = NqosWifiMacHelper::Default (); wifiMacHelper.SetType ("ns3::AdhocWifiMac"); NetDeviceContainer devices = wifi.Install (wifiPhyHelper, wifiMacHelper, fixedpos); devices.Add (wifi.Install (wifiPhyHelper, wifiMacHelper, mover));
At this point the basic Wi-Fi configuration is done! The next step is to work on the positions and motion. First we establish the positions of the fixed nodes.
MobilityHelper sessile; // for fixed nodes Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> (); int Xpos = 0; for (int i=0; i<bottomrow; i++) { positionAlloc->Add(Vector(Xpos, brheight, 0.0)); Xpos += spacing; } sessile.SetPositionAllocator (positionAlloc); sessile.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); sessile.Install (fixedpos);
Next we set up the mover
node. ConstantVelocityMobilityModel
is a subclass of MobilityModel
. At the end we print out a couple things just for confirmation.
Vector pos (0, mheight+brheight, 0); Vector vel (speed, 0, 0); MobilityHelper mobile; mobile.SetMobilityModel("ns3::ConstantVelocityMobilityModel"); // no Attributes mobile.Install(mover); cvmm = mover->GetObject<ConstantVelocityMobilityModel> (); cvmm->SetPosition(pos); cvmm->SetVelocity(vel); std::cout << "position: " << cvmm->GetPosition() << " velocity: " << cvmm->GetVelocity() << std::endl; std::cout << "mover mobility model: " << mobile.GetMobilityModelType() << std::endl;
Now we configure Ad hoc On-demand Distance Vector routing.
AodvHelper aodv; OlsrHelper olsr; Ipv4ListRoutingHelper listrouting; //listrouting.Add(olsr, 10); // generates less traffic listrouting.Add(aodv, 10); // fastest to find new routes
Uncommenting the olsr
line (and commenting out the last line) is all that is necessary to change to OLSR routing. OLSR is slower to find new routes, but sends less traffic.
Now we set up the IP addresses. This is straightforward as all the nodes are on a single subnet.
InternetStackHelper internet; internet.SetRoutingHelper(listrouting); internet.Install (fixedpos); internet.Install (mover); Ipv4AddressHelper ipv4; NS_LOG_INFO ("Assign IP Addresses."); ipv4.SetBase ("10.1.1.0", "255.255.255.0"); // there is only one subnet Ipv4InterfaceContainer i = ipv4.Assign (devices);
Now we create a receiving application UdpServer
on node mover
, and a sending application UdpClient
on the lower-left node. These applications generate their own sequence numbers, which show up in the ns-3 tracefiles marked with ns3::SeqTsHeader
. As in 32.2 A Single TCP Sender, we use Config::SetDefault()
and CreateObject<>()
to construct the applications.
uint16_t port = 80; // create a receiving application (UdpServer) on node mover Address sinkaddr(InetSocketAddress (Ipv4Address::GetAny (), port)); Config::SetDefault("ns3::UdpServer::Port", UintegerValue(port)); Ptr<UdpServer> UdpRecvApp = CreateObject<UdpServer>(); UdpRecvApp->SetStartTime(Seconds(0.0)); UdpRecvApp->SetStopTime(Seconds(endtime+60)); mover->AddApplication(UdpRecvApp); Ptr<Ipv4> m4 = mover->GetObject<Ipv4>(); Ipv4Address Maddr = m4->GetAddress(1,0).GetLocal(); std::cout << "IPv4 address of mover: " << Maddr << std::endl; Address moverAddress (InetSocketAddress (Maddr, port));
Here is the UdpClient
sending application:
Config::SetDefault("ns3::UdpClient::MaxPackets", UintegerValue(packetcount)); Config::SetDefault("ns3::UdpClient::PacketSize", UintegerValue(packetsize)); Config::SetDefault("ns3::UdpClient::Interval", TimeValue (MicroSeconds (interval))); Ptr<UdpClient> UdpSendApp = CreateObject<UdpClient>(); UdpSendApp -> SetRemote(Maddr, port); UdpSendApp -> SetStartTime(Seconds(0.0)); UdpSendApp -> SetStopTime(Seconds(endtime)); lowerleft->AddApplication(UdpSendApp);
We now set up tracing. The first, commented-out line enables pcap-format tracing, which we do not need here. The YansWifiPhyHelper
object supports tracing only of “receive” (r) and “transmit” (t) records; the PointtoPointHelper
of 32.2 A Single TCP Sender also traced enqueue and drop records.
//wifiPhyHelper.EnablePcap (tracebase, devices); AsciiTraceHelper ascii; wifiPhyHelper.EnableAsciiAll (ascii.CreateFileStream (tracebase + ".tr")); // create animation file, to be run with 'netanim' AnimationInterface anim (tracebase + ".xml"); anim.SetMobilityPollInterval(Seconds(0.1));
If we view the animation with netanim
, the moving node’s motion is clear. The mover
node, however, sometimes appears to transmit back to both the fixed-row node below left and the fixed-row node below right. These transmissions represent the Wi-Fi link-layer ACKs; they appear to be sent to two fixed-row nodes because what netanim
is actually displaying with its blue links is transmission every other node in range.
We can also “view” the motion in text format by uncommenting the first line below.
//Simulator::Schedule(Seconds(position_interval), &printPosition); Simulator::Schedule(Seconds(endtime), &stopMover);
Finally it is time to run the simulator, and print some final output.
Simulator::Stop(Seconds (endtime+60)); Simulator::Run (); Simulator::Destroy (); int pktsRecd = UdpRecvApp->GetReceived(); std::cout << "packets received: " << pktsRecd << std::endl; std::cout << "packets recorded as lost: " << (UdpRecvApp->GetLost()) << std::endl; std::cout << "packets actually lost: " << (packetcount - pktsRecd) << std::endl; return 0; }
32.3.1 Tracefile Analysis
The tracefile provides no enqueue records, and Wi-Fi doesn’t have fixed links; how can we verify that packets are being forwarded correctly? One thing we can do with the tracefile is to look at each value of the UdpServer
application sequence number, and record
- when it was received by node
mover
- when it was transmitted by any fixed-row node
If we do this, we get output like the following:
packet 0 received at 0.0248642, forwarded by 0 at 0.0201597 packet 1 received at 0.0547045, forwarded by 0 at 0.05 ... packet 499 received at 24.9506, forwarded by 0 at 24.95 packet 500 NOT recd, forwarded by 0 at 25, forwarded by 0 at 25.0019, forwarded by 0 at 25.0035, forwarded by 0 at 25.0071, forwarded by 0 at 25.0097, forwarded by 0 at 25.0159, forwarded by 0 at 25.0281 packet 501 received at 25.0864, forwarded by 0 at 25.0767, forwarded by 1 at 25.0817 packet 502 received at 25.1098, forwarded by 0 at 25.1, forwarded by 1 at 25.1051 ... packet 1000 NOT recd, forwarded by 0 at 50, forwarded by 1 at 50.001, forwarded by 1 at 50.003, forwarded by 1 at 50.0059, forwarded by 1 at 50.0087, forwarded by 1 at 50.0151, forwarded by 1 at 50.0239, forwarded by 1 at 50.0341 packet 1001 received at 50.082, forwarded by 0 at 50.0683, forwarded by 1 at 50.0722, forwarded by 2 at 50.0773 packet 1002 received at 50.1107, forwarded by 0 at 50.1, forwarded by 1 at 50.101, forwarded by 2 at 50.106 ... packet 1499 received at 74.9525, forwarded by 0 at 74.95, forwarded by 1 at 74.951, forwarded by 2 at 74.9519 packet 1500 NOT recd, forwarded by 0 at 75, forwarded by 1 at 75.001, forwarded by 2 at 75.0019, forwarded by 2 at 75.0039, forwarded by 2 at 75.005, forwarded by 2 at 75.0084, forwarded by 2 at 75.0124, forwarded by 2 at 75.0277, forwarded by 2 at 75.0361 packet 1501 NOT recd, forwarded by 0 at 75.05 packet 1502 received at 75.1484, forwarded by 0 at 75.1287, forwarded by 1 at 75.1299, forwarded by 1 at 75.1314, forwarded by 1 at 75.1326, forwarded by 2 at 75.1386, forwarded by 3 at 75.1437 packet 1503 received at 75.1621, forwarded by 0 at 75.15, forwarded by 1 at 75.151, forwarded by 2 at 75.1523, forwarded by 3 at 75.1574 ...
That is, packets 0-499 were transmitted only by node 0. Packet 500 was never received by mover
, but there were seven transmission attempts; these seven attempts follow the rules described in 4.2.1 Wi-Fi and Collisions. Packets starting at 501 were transmitted by node 0 and then later by node 1. Similarly, packet 1000 was lost, and after that each packet arriving at mover
was first transmitted by nodes 0, 1 and 2, in that order. In other words, packets are indeed being forwarded rightward along the line of fixed-row nodes until a node is reached that is in range of mover
.
32.3.2 AODV Performance¶
f we change the line
listrouting.Add(aodv, 10);
to
listrouting.Add(dsdv, 10);
we find that the loss count goes from 4 packets out of 2000 to 398 out of 2000; for OLSR routing the loss count is 426. As we discussed in 31.6 Wireless Simulation, the loss of one data packet triggers the AODV implementation to look for a new route. The DSDV and OLSR implementations, on the other hand, only look for new routes at regularly spaced intervals.
32.4 Exercises
In preparation.