2024GR37CS462
Vaibhav Kumar Jonwal
202251150
Azim Khorajiya
202251169
Yash Hire
202252319
Sakshi Dhoni
202252335
Nihalmayi
202251149
- NS-3 (Setup)
- Installation
- Download NS-3
- Installing Dependencies
- Building NS-3
- NetSimulyzer (Setup)
- Installation
- Downloading NetSimulyzer NS-3 module
- Installing Dependencies
- Building NS-3 for NetSimulyzer
- Installing NetSimulyzer Software
- Drone Simulation
- Setup Code & Simulation
- Write Code
- Running Simulation
- 5G Integration
- Setup Code
- 5G-LENA Setup
- Write Code
- Slicing Integration
- Setup Code
- Write Code
- Running Simulation
- All Simulations
(We will use ns-3.42 for compatibility with 5g-lena)
Step1: Go to Link: https://www.nsnam.org/releases/ns-3-42/
Step2: Click on this link or from website as shown in the below image to download the zipped file from the ns3 website.
Step3: Make your project directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
mkdir project
Step4: Move the file to your project directory
(Consider we are at /username directory)
Go to Terminal:
cd Downloads
mv ns-allinone-3.42.tar.bz2 ~/Desktop/project
Step5: Go to project Directory and extract the file
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
sudo apt update && sudo apt install bzip2
tar \-xvjf ns-allinone-3.42.tar.bz2
-
Install all the dependencies required to build
(Consider we are at /username directory)
Go to Terminal:
sudo apt install g++ python3 cmake ninja-build git gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3 tcpdump wireshark sqlite3 libsqlite3-dev qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools openmpi-bin openmpi-common openmpi-doc libopenmpi-dev doxygen graphviz imagemagick python3-sphinx dia texlive dvipng latexmk texlive-extra-utils texlive-latex-extra texlive-font-utils libeigen3-dev gsl-bin libgsl-dev libgslcblas0 libxml2 libxml2-dev libgtk-3-dev lxc-utils lxc-templates vtun uml-utilities ebtables bridge-utils libboost-all-dev ccache
(Type Y and continue to Download)
(Opt any option as per your preference)
(Wait until the progress hits 100%)
-
Step1: Go to ns-allinone-3.42 directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
cd ns-allinone-3.42
Step2: Build NS-3
(Consider we are at /ns-allinone-3.42 directory)
Go to Terminal:
./build.py --enable-examples --enable-tests
(Wait until it completes 1940/1940)
Step3: Check the Built
(Consider we are at /ns-allinone-3.42 directory)
Go to Terminal:
cd ns-3.42
./ns3 run hello-simulator
(It is showing Hello Simulator)
-
Step1: Go to /contrib directory
(Consider we are at /ns-3.42 directory)
Go to Terminal:
cd contrib
Step2: Go to /contrib directory
(Consider we are at /ns-3.42 directory)
Go to Terminal:
wget https://github.com/usnistgov/NetSimulyzer-ns3-module/archive/master.zip -O NetSimulyzer-ns3-module-master.zip
Step3: Unzip downloaded file
(Consider we are at /contrib directory)
Go to Terminal:
unzip NetSimulyzer-ns3-module-master.zip
Step3: Rename the resulting directory to netsimulyze
(As ns-3 will not accept a module named differently than its directory.)
(Consider we are at /contrib directory)
Go to Terminal:
mv NetSimulyzer-ns3-module-master netsimulyzer
-
Install all dependencies for NetSimulyzer
(Consider we are at /username directory)
Go to Terminal:
sudo apt install cmake pkg-config qtbase5-dev libqt5charts5-dev g++ python3 cmake ninja-build git gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3 tcpdump wireshark sqlite3 libsqlite3-dev qtchooser qt5-qmake qtbase5-dev-tools openmpi-bin openmpi-common openmpi-doc libopenmpi-dev doxygen graphviz imagemagick python3-sphinx dia texlive dvipng latexmk texlive-extra-utils texlive-latex-extra texlive-font-utils libeigen3-dev gsl-bin libgsl-dev libgslcblas0 libxml2 libxml2-dev libgtk-3-dev lxc-utils lxc-templates vtun uml-utilities ebtables bridge-utils libboost-all-dev
(Press Y to continue)
-
Step1: Go to ns-allinone-3.42 directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
cd ns-allinone-3.42
Step2: Build NS-3
(Consider we are at /ns-allinone-3.42 directory)
Go to Terminal:
./build.py --enable-examples --enable-tests
(Wait until it completes 53/53)
![][image20]
Step3: Check the Built
(Consider we are at /ns-allinone-3.42 directory)
Go to Terminal:
cd ns-3.42
./ns3 run contrib/netsimulyzer/examples mobility-buildings-example.cc
-
Installing NetSimulyzer Software
Step1: Go to project directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
![][image21]
Step2: Clone the NetSimulyzer Repo
(Consider we are at /project directory)
Go to Terminal:
clone \--recursive https://github.com/usnistgov/NetSimulyzer.git
![][image22]
Step3: Make /build directory
(Consider we are at /project directory)
Go to Terminal:
cd NetSimulyzer
mkdir build
cd build
![][image23]
Step4: Build Software
(Consider we are at /build directory)
Go to Terminal:
cmake \-DCMAKE\_BUILD\_TYPE=Release ..
![][image24]
(Error Occurred, we will solve the error by installing required dependencies)
sudo apt install libassimp-dev
![][image25]
sudo apt install qt6-base-dev qt6-base-dev-tools
![][image26]
(Now Again)
cmake -DCMAKE_BUILD_TYPE=Release ..
![][image27]
cmake --build .
![][image28]
(Wait until the build)
![][image29]
Step5: Check NetSimulyzer
(Consider we are at /build directory)
Go to Terminal:
cd NetSimulyzer
./netsimulyzer
![][image30]
-
Step1: Go to /scratch directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
cd ns-allinone-3.42
cd ns-3.42
cd scratch
![][image31]
Code
#include "ns3/aodv-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/network-module.h"
#include "ns3/ping-helper.h"
#include "ns3/point-to-point-module.h"
#include "ns3/yans-wifi-helper.h"
#include <ns3/netsimulyzer-module.h>
#include <cmath>
#include <iostream>
using namespace ns3;
/**
* @defgroup aodv-examples AODV Examples
* @ingroup aodv
* @ingroup examples
*/
/**
* @ingroup aodv-examples
* @ingroup examples
* @brief Test script.
*
* This script creates 1-dimensional grid topology and then ping last node from the first one:
*
* [10.0.0.1] <-- step --> [10.0.0.2] <-- step --> [10.0.0.3] <-- step --> [10.0.0.4]
*
* ping 10.0.0.4
*
* When 1/3 of simulation time has elapsed, one of the nodes is moved out of
* range, thereby breaking the topology. By default, this will result in
* stopping ping replies reception after sequence number 33. If the step size is reduced
* to cover the gap, then also the following pings can be received.
*/
class AodvExample
{
public:
AodvExample();
/\*\*
\* @brief Configure script parameters
\* @param argc is the command line argument count
\* @param argv is the command line arguments
\* @return true on successful configuration
\*/
bool Configure(int argc, char\*\* argv);
/// Run simulation
void Run();
/\*\*
\* Report results
\* @param os the output stream
\*/
void Report(std::ostream& os);
private:
// parameters
/// Number of nodes
uint32\_t size;
/// Distance between nodes, meters
double step;
/// Simulation time, seconds
double totalTime;
/// Write per-device PCAP traces if true
bool pcap;
/// Print routes if true
bool printRoutes;
// network
/// nodes used in the example
NodeContainer nodes;
/// devices used in the example
NetDeviceContainer devices;
/// interfaces used in the example
Ipv4InterfaceContainer interfaces;
private:
/// Create the nodes
void CreateNodes();
/// Create the devices
void CreateDevices();
/// Create the network
void InstallInternetStack();
/// Create the simulation applications
void InstallApplications();
};
int
main(int argc, char** argv)
{
AodvExample test;
if (\!test.Configure(argc, argv))
{
NS\_FATAL\_ERROR("Configuration failed. Aborted.");
}
test.Run();
test.Report(std::cout);
return 0;
}
//-----------------------------------------------------------------------------
AodvExample::AodvExample()
: size(10),
step(5),
totalTime(100),
pcap(true),
printRoutes(true)
{
}
bool
AodvExample::Configure(int argc, char** argv)
{
// Enable AODV logs by default. Comment this if too noisy
// LogComponentEnable("AodvRoutingProtocol", LOG\_LEVEL\_ALL);
SeedManager::SetSeed(12345);
CommandLine cmd(\_\_FILE\_\_);
cmd.AddValue("pcap", "Write PCAP traces.", pcap);
cmd.AddValue("printRoutes", "Print routing table dumps.", printRoutes);
cmd.AddValue("size", "Number of nodes.", size);
cmd.AddValue("time", "Simulation time, s.", totalTime);
cmd.AddValue("step", "Grid step, m", step);
cmd.Parse(argc, argv);
return true;
}
void
AodvExample::Run()
{
// Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", UintegerValue (1)); //
// enable rts cts all the time.
CreateNodes();
CreateDevices();
InstallInternetStack();
InstallApplications();
std::cout \<\< "Starting simulation for " \<\< totalTime \<\< " s ...\\n";
// AnimationInterface anim("testing.xml");
Simulator::Stop(Seconds(totalTime));
Simulator::Run();
Simulator::Destroy();
}
void
AodvExample::Report(std::ostream&)
{
}
void
AodvExample::CreateNodes()
{
auto orchestrator = CreateObject<netsimulyzer::Orchestrator> ("testing.json");
netsimulyzer::NodeConfigurationHelper nodeHelper{orchestrator};
nodeHelper.Set ("Model", netsimulyzer::models::QUADCOPTER_UAV_VALUE);
// Shows every Node in the scenario
for (auto node = NodeList::Begin (); node != NodeList::End (); node++)
nodeHelper.Install (\*node);
std::cout \<\< "Creating " \<\< (unsigned)size \<\< " nodes " \<\< step \<\< " m apart.\\n";
nodes.Create(size);
// Name nodes
for (uint32\_t i \= 0; i \< size; \++i)
{
std::ostringstream os;
os \<\< "node-" \<\< i;
Names::Add(os.str(), nodes.Get(i));
}
nodeHelper.Install (nodes);
// Create static grid
MobilityHelper mobility;
mobility.SetPositionAllocator("ns3::GridPositionAllocator",
"MinX",
DoubleValue(0.0),
"MinY",
DoubleValue(0.0),
"Z",
DoubleValue(15.0),
"DeltaX",
DoubleValue(step),
"DeltaY",
DoubleValue(0),
"GridWidth",
UintegerValue(size),
"LayoutType",
StringValue("RowFirst"));
mobility.SetMobilityModel("ns3::GaussMarkovMobilityModel"),
"Bounds", BoxValue(Box(-5, 5, \-5, 5, 0, 15)),
"TimeStep", TimeValue(Seconds(0.05)),
"Alpha", DoubleValue(0.85),
"MeanVelocity", StringValue("ns3::UniformRandomVariable\[Min=5|Max=20\]"),
"MeanDirection", StringValue("ns3::UniformRandomVariable\[Min=0|Max=6.283185307\]"),
"MeanPitch", StringValue("ns3::UniformRandomVariable\[Min=0.05|Max=0.05\]"),
"NormalVelocity", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.0|Bound=0.0\]"),
"NormalDirection", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.2|Bound=0.4\]"),
"NormalPitch", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.02|Bound=0.04\]");
mobility.Install(nodes);
}
void
AodvExample::CreateDevices()
{
WifiMacHelper wifiMac;
wifiMac.SetType("ns3::AdhocWifiMac");
YansWifiPhyHelper wifiPhy;
YansWifiChannelHelper wifiChannel \= YansWifiChannelHelper::Default();
wifiPhy.SetChannel(wifiChannel.Create());
WifiHelper wifi;
wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
"DataMode",
StringValue("OfdmRate6Mbps"),
"RtsCtsThreshold",
UintegerValue(0));
devices \= wifi.Install(wifiPhy, wifiMac, nodes);
if (pcap)
{
wifiPhy.EnablePcapAll(std::string("aodv"));
}
}
void
AodvExample::InstallInternetStack()
{
AodvHelper aodv;
// you can configure AODV attributes here using aodv.Set(name, value)
InternetStackHelper stack;
stack.SetRoutingHelper(aodv); // has effect on the next Install ()
stack.Install(nodes);
Ipv4AddressHelper address;
address.SetBase("10.0.0.0", "255.0.0.0");
interfaces \= address.Assign(devices);
if (printRoutes)
{
Ptr\<OutputStreamWrapper\> routingStream \=
Create\<OutputStreamWrapper\>("aodv.routes", std::ios::out);
Ipv4RoutingHelper::PrintRoutingTableAllAt(Seconds(8), routingStream);
}
}
void
AodvExample::InstallApplications()
{
PingHelper ping(interfaces.GetAddress(size \- 1));
ping.SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::VERBOSE));
ApplicationContainer p \= ping.Install(nodes.Get(0));
p.Start(Seconds(0));
p.Stop(Seconds(totalTime) \- Seconds(0.001));
// move node away
Ptr\<Node\> node \= nodes.Get(size / 2);
Ptr\<MobilityModel\> mob \= node-\>GetObject\<MobilityModel\>();
Simulator::Schedule(Seconds(totalTime / 3),
\&MobilityModel::SetPosition,
mob,
Vector(1e5, 1e5, 1e5));
}
Step2: Write code
(Consider we are at /scratch directory)
Go to Terminal:
nano test.cc
![][image32]
(Paste the code provided above)
Press: Ctrl+x
Write: Y
Press: Enter
![][image33]
Step2: Run Code
(Consider we are at /scratch directory)
Go to Terminal:
cd ..
./ns3 run scratch/test.cc
![][image34]
![][image35]
(Now we can find there is a testing.json file in the /ns-3.42 directory)
![][image36]
-
Step1: Run NetSimulyzer
(Consider we are at /username directory)
Go to Terminal:
cd Desktop/project/NetSimulyzer/build
./netsimulyzer
![][image30]
Step2: Load The testing.json File
![][image37]
![][image38]
(Open)
Step3: Play the simulation
![][image39]
-
Step1: Go to /contrib directory & Clone nr repo
(Consider we are at /username directory)
Go to Terminal:
cd Desktop/project/ns-allinone-3.42/ns-3.42/contrib
git clone https://gitlab.com/cttc-lena/nr.git
![][image40]
Step2: Configure
(Consider we are at /contrib directory)
Go to Terminal:
cd ..
./ns3 configure --enable-examples --enable-tests
![][image41]
Step3: Build
(Consider we are at /ns-3.42 directory)
Go to Terminal:
cd ..
./build.py –enable-examples –enable-tests
![][image42]
-
Step1: Go to /scratch directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
cd project
cd ns-allinone-3.42
cd ns-3.42/scratch
![][image31]
Step2: Write code
(Consider we are at /scratch directory)
Go to Terminal:
nano test5g.cc
![][image43]
(Paste the code provided below)
Press: Ctrl+x
Write: Y
Press: Enter
![][image44]
Code
#include "ns3/aodv-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/network-module.h"
#include "ns3/ping-helper.h"
#include "ns3/point-to-point-module.h"
// Remove WiFi headers
// #include "ns3/yans-wifi-helper.h"
// Add 5G NR headers
#include "ns3/nr-module.h"
#include "ns3/eps-bearer-tag.h"
#include "ns3/lte-module.h"
#include <ns3/netsimulyzer-module.h>
#include <cmath>
#include <iostream>
using namespace ns3;
/**
* @brief Drone simulation with 5G connectivity.
*
* This script creates a 5G network with drones as UEs (User Equipment)
* and a gNB (5G base station).
*/
class DroneWith5GExample
{
public:
DroneWith5GExample();
bool Configure(int argc, char\*\* argv);
void Run();
void Report(std::ostream& os);
private:
// parameters
uint32\_t numDrones; // Number of drone UEs
double simTime; // Simulation time in seconds
bool pcap; // Write PCAP traces if true
bool printRoutes; // Print routing tables if true
double gNbHeight; // Height of the gNB in meters
double droneMinHeight; // Minimum height of drones in meters
double droneMaxHeight; // Maximum height of drones in meters
double areaSizeX; // X dimension of the simulation area
double areaSizeY; // Y dimension of the simulation area
// network
NodeContainer droneUEs; // Drone nodes acting as UEs
NodeContainer gNbNodes; // gNB nodes (base stations)
NetDeviceContainer ueDevices; // UE devices
NetDeviceContainer gNbDevices; // gNB devices
Ipv4InterfaceContainer ueIfaces; // UE interfaces
Ipv4InterfaceContainer gNbIfaces; // gNB interfaces
private:
void CreateNodes();
void ConfigureMobility();
void Install5GDevices();
void InstallInternetStack();
void InstallApplications();
};
int
main(int argc, char** argv)
{
DroneWith5GExample test;
if (\!test.Configure(argc, argv))
{
NS\_FATAL\_ERROR("Configuration failed. Aborted.");
}
test.Run();
test.Report(std::cout);
return 0;
}
//-----------------------------------------------------------------------------
DroneWith5GExample::DroneWith5GExample()
: numDrones(10),
simTime(100),
pcap(true),
printRoutes(true),
gNbHeight(30.0),
droneMinHeight(10.0),
droneMaxHeight(50.0),
areaSizeX(500.0),
areaSizeY(500.0)
{
}
bool
DroneWith5GExample::Configure(int argc, char** argv)
{
SeedManager::SetSeed(12345);
CommandLine cmd(FILE);
cmd.AddValue("pcap", "Write PCAP traces.", pcap);
cmd.AddValue("printRoutes", "Print routing table dumps.", printRoutes);
cmd.AddValue("numDrones", "Number of drone UEs.", numDrones);
cmd.AddValue("simTime", "Simulation time, s.", simTime);
cmd.AddValue("gNbHeight", "Height of gNB, m.", gNbHeight);
cmd.AddValue("droneMinHeight", "Minimum height of drones, m.", droneMinHeight);
cmd.AddValue("droneMaxHeight", "Maximum height of drones, m.", droneMaxHeight);
cmd.AddValue("areaSizeX", "X dimension of the simulation area, m.", areaSizeX);
cmd.AddValue("areaSizeY", "Y dimension of the simulation area, m.", areaSizeY);
cmd.Parse(argc, argv);
return true;
}
void
DroneWith5GExample::Run()
{
CreateNodes();
ConfigureMobility();
Install5GDevices();
InstallInternetStack();
InstallApplications();
std::cout \<\< "Starting simulation for " \<\< simTime \<\< " s ...\\n";
// Setup netsimulyzer for visualization
auto orchestrator \= CreateObject\<netsimulyzer::Orchestrator\>("drone\_5g\_simulation.json");
netsimulyzer::NodeConfigurationHelper nodeHelper{orchestrator};
nodeHelper.Set("Model", netsimulyzer::models::QUADCOPTER\_UAV\_VALUE);
// Visualize drones
nodeHelper.Install(droneUEs);
// Use a different model for gNBs
nodeHelper.Set("Model", netsimulyzer::models::CELL\_TOWER\_VALUE);
nodeHelper.Install(gNbNodes);
Simulator::Stop(Seconds(simTime));
Simulator::Run();
Simulator::Destroy();
}
void
DroneWith5GExample::Report(std::ostream& os)
{
os \<\< "Simulation completed with " \<\< numDrones \<\< " drones and "
\<\< gNbNodes.GetN() \<\< " gNBs." \<\< std::endl;
}
void
DroneWith5GExample::CreateNodes()
{
std::cout \<\< "Creating " \<\< numDrones \<\< " drone UEs and 1 gNB." \<\< std::endl;
// Create drone UEs
droneUEs.Create(numDrones);
// Create gNB node(s)
gNbNodes.Create(1);
// Name nodes
for (uint32\_t i \= 0; i \< numDrones; \++i)
{
std::ostringstream os;
os \<\< "drone-" \<\< i;
Names::Add(os.str(), droneUEs.Get(i));
}
Names::Add("gNB-0", gNbNodes.Get(0));
}
void
DroneWith5GExample::ConfigureMobility()
{
// Set positions for gNBs (fixed)
MobilityHelper gNbMobility;
Ptr\<ListPositionAllocator\> gNbPositionAlloc \= CreateObject\<ListPositionAllocator\>();
// Position the gNB in the center of the area at specified height
gNbPositionAlloc-\>Add(Vector(areaSizeX / 2.0, areaSizeY / 2.0, gNbHeight));
gNbMobility.SetPositionAllocator(gNbPositionAlloc);
gNbMobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
gNbMobility.Install(gNbNodes);
// Set mobility model for drones
MobilityHelper droneMobility;
// Initial positions of drones (random within the area)
Ptr\<RandomBoxPositionAllocator\> dronePositionAlloc \= CreateObject\<RandomBoxPositionAllocator\>();
Ptr\<UniformRandomVariable\> xPos \= CreateObject\<UniformRandomVariable\>();
xPos-\>SetAttribute("Min", DoubleValue(0.0));
xPos-\>SetAttribute("Max", DoubleValue(areaSizeX));
Ptr\<UniformRandomVariable\> yPos \= CreateObject\<UniformRandomVariable\>();
yPos-\>SetAttribute("Min", DoubleValue(0.0));
yPos-\>SetAttribute("Max", DoubleValue(areaSizeY));
Ptr\<UniformRandomVariable\> zPos \= CreateObject\<UniformRandomVariable\>();
zPos-\>SetAttribute("Min", DoubleValue(droneMinHeight));
zPos-\>SetAttribute("Max", DoubleValue(droneMaxHeight));
dronePositionAlloc-\>SetX(xPos);
dronePositionAlloc-\>SetY(yPos);
dronePositionAlloc-\>SetZ(zPos);
droneMobility.SetPositionAllocator(dronePositionAlloc);
// Gauss-Markov mobility model for drones
droneMobility.SetMobilityModel("ns3::GaussMarkovMobilityModel",
"Bounds", BoxValue(Box(0, areaSizeX, 0, areaSizeY, droneMinHeight, droneMaxHeight)),
"TimeStep", TimeValue(Seconds(0.1)),
"Alpha", DoubleValue(0.85),
"MeanVelocity", StringValue("ns3::UniformRandomVariable\[Min=3|Max=10\]"),
"MeanDirection", StringValue("ns3::UniformRandomVariable\[Min=0|Max=6.283185307\]"),
"MeanPitch", StringValue("ns3::UniformRandomVariable\[Min=-0.2|Max=0.2\]"),
"NormalVelocity", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=2.0|Bound=4.0\]"),
"NormalDirection", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.2|Bound=0.4\]"),
"NormalPitch", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.02|Bound=0.04\]"));
droneMobility.Install(droneUEs);
}
void
DroneWith5GExample::Install5GDevices()
{
// Set up the 5G helper
Ptr\<NrHelper\> nrHelper \= CreateObject\<NrHelper\>();
Ptr\<NrPointToPointEpcHelper\> epcHelper \= CreateObject\<NrPointToPointEpcHelper\>();
nrHelper-\>SetEpcHelper(epcHelper);
// Configure bandwidth and frequency
BandwidthPartInfoPtrVector allBwps;
CcBwpCreator ccBwpCreator;
// Component carrier configuration
const uint8\_t numCcPerBand \= 1; // Number of component carriers per band
CcBwpCreator::SimpleOperationBandConf bandConf(28e9, 100e6, numCcPerBand, BandwidthPartInfo::UMi\_StreetCanyon);
// Configure both gNBs and UEs with the same configuration
OperationBandInfo band \= ccBwpCreator.CreateOperationBandContiguousCc(bandConf);
// Configure the gNB device
nrHelper-\>SetGnbPhyAttribute("TxPower", DoubleValue(43.0)); // in dBm
nrHelper-\>SetGnbPhyAttribute("Numerology", UintegerValue(0));
nrHelper-\>SetGnbAntennaAttribute("NumRows", UintegerValue(4));
nrHelper-\>SetGnbAntennaAttribute("NumColumns", UintegerValue(4));
// Configure the UE device
nrHelper-\>SetUePhyAttribute("TxPower", DoubleValue(23.0)); // in dBm
nrHelper-\>SetUePhyAttribute("Numerology", UintegerValue(0));
// Configure the antenna for the UEs
nrHelper-\>SetUeAntennaAttribute("NumRows", UintegerValue(2));
nrHelper-\>SetUeAntennaAttribute("NumColumns", UintegerValue(2));
// Install the 5G devices
NetDeviceContainer enbNetDev \= nrHelper-\>InstallGnbDevice(gNbNodes, band);
NetDeviceContainer ueNetDev \= nrHelper-\>InstallUeDevice(droneUEs, band);
gNbDevices \= enbNetDev;
ueDevices \= ueNetDev;
// Attach UEs to the closest gNB
nrHelper-\>AttachToClosestEnb(ueNetDev, enbNetDev);
// Enable traces if pcap is true
if (pcap)
{
// Enable PCAP traces
nrHelper-\>EnableTraces();
}
}
void
DroneWith5GExample::InstallInternetStack()
{
// Install the Internet stack on the UEs
InternetStackHelper internet;
internet.Install(droneUEs);
// Assign IP addresses to UE devices
Ipv4AddressHelper ipv4h;
ipv4h.SetBase("10.0.0.0", "255.0.0.0");
ueIfaces \= ipv4h.Assign(ueDevices);
// Get the default gateway address for routing
Ipv4StaticRoutingHelper ipv4RoutingHelper;
Ptr\<Ipv4\> ipv4 \= droneUEs.Get(0)-\>GetObject\<Ipv4\>();
Ptr\<Ipv4StaticRouting\> staticRouting \= ipv4RoutingHelper.GetStaticRouting(ipv4);
staticRouting-\>SetDefaultRoute(epcHelper-\>GetUeDefaultGatewayAddress(), 1);
if (printRoutes)
{
Ptr\<OutputStreamWrapper\> routingStream \=
Create\<OutputStreamWrapper\>("drone\_5g.routes", std::ios::out);
Ipv4RoutingHelper::PrintRoutingTableAllAt(Seconds(5), routingStream);
}
}
void
DroneWith5GExample::InstallApplications()
{
// Install ping application to test connectivity
// Let's ping from the first drone to the last drone
if (numDrones \> 1\)
{
uint32\_t lastDroneIndex \= numDrones \- 1;
PingHelper ping(ueIfaces.GetAddress(lastDroneIndex));
ping.SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::VERBOSE));
ApplicationContainer pingApps \= ping.Install(droneUEs.Get(0));
pingApps.Start(Seconds(1.0));
pingApps.Stop(Seconds(simTime \- 1.0));
}
// Additional applications can be added here for testing data transmission
// For example, UDP client/server applications can be used to test throughput
}
Step3: Run Code
(Consider we are at /scratch directory)
Go to Terminal:
cd ..
./ns3 run scratch/test5g.cc
![][image45]
![][image46]
-
Step1: Go to /scratch directory
(Consider we are at /username directory)
Go to Terminal:
cd Desktop
cd project
cd project
cd ns-allinone-3.42
cd ns-3.42
cd scratch
![][image31]
Step2: Write code
(Consider we are at /scratch directory)
Go to Terminal:
![][image47]
(Paste the code provided below)
Press: Ctrl+x
Write: Y
Press: Enter
![][image48]
Code
#include "ns3/aodv-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/network-module.h"
#include "ns3/ping-helper.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/nr-module.h"
#include "ns3/eps-bearer-tag.h"
#include "ns3/lte-module.h"
#include <ns3/netsimulyzer-module.h>
#include <cmath>
#include <iostream>
#include <map>
#include <string>
using namespace ns3;
/**
* @brief Drone simulation with 5G network slicing.
*
* This script creates a 5G network with drones as UEs (User Equipment)
* and a gNB (5G base station) with network slicing capabilities.
*
* Three network slices are implemented:
* 1. eMBB (enhanced Mobile Broadband) - for high data rate applications
* 2. URLLC (Ultra-Reliable Low-Latency Communications) - for critical control
* 3. mMTC (massive Machine Type Communications) - for telemetry data
*/
class DroneNetworkSlicingExample
{
public:
DroneNetworkSlicingExample();
bool Configure(int argc, char\*\* argv);
void Run();
void Report(std::ostream& os);
private:
// Slice types
enum SliceType {
EMBB, // Enhanced Mobile Broadband
URLLC, // Ultra-Reliable Low-Latency Communications
MMTC // Massive Machine Type Communications
};
// parameters
uint32\_t numDrones; // Number of drone UEs
double simTime; // Simulation time in seconds
bool pcap; // Write PCAP traces if true
bool printRoutes; // Print routing tables if true
double gNbHeight; // Height of the gNB in meters
double droneMinHeight; // Minimum height of drones in meters
double droneMaxHeight; // Maximum height of drones in meters
double areaSizeX; // X dimension of the simulation area
double areaSizeY; // Y dimension of the simulation area
// Slicing parameters
uint32\_t numEmbbDrones; // Number of drones in eMBB slice
uint32\_t numUrllcDrones; // Number of drones in URLLC slice
uint32\_t numMmtcDrones; // Number of drones in mMTC slice
// network
NodeContainer droneUEs; // All drone nodes acting as UEs
NodeContainer gNbNodes; // gNB nodes (base stations)
NodeContainer embbDrones; // Drones in eMBB slice
NodeContainer urllcDrones; // Drones in URLLC slice
NodeContainer mmtcDrones; // Drones in mMTC slice
NetDeviceContainer ueDevices; // All UE devices
NetDeviceContainer gNbDevices; // gNB devices
NetDeviceContainer embbDevices; // eMBB slice devices
NetDeviceContainer urllcDevices; // URLLC slice devices
NetDeviceContainer mmtcDevices; // mMTC slice devices
Ipv4InterfaceContainer ueIfaces; // UE interfaces
Ipv4InterfaceContainer gNbIfaces; // gNB interfaces
// Map to keep track of which drones belong to which slice
std::map\<uint32\_t, SliceType\> droneSliceMap;
// EPC helper for accessing core network
Ptr\<NrPointToPointEpcHelper\> epcHelper;
// Flow monitor for traffic analysis
Ptr\<FlowMonitor\> flowMonitor;
FlowMonitorHelper flowHelper;
private:
void CreateNodes();
void ConfigureMobility();
void Install5GDevices();
void InstallInternetStack();
void ConfigureNetworkSlices();
void InstallApplications();
void InstallEmbbApplications();
void InstallUrllcApplications();
void InstallMmtcApplications();
EpsBearer CreateBearerForSlice(SliceType slice);
};
int
main(int argc, char** argv)
{
DroneNetworkSlicingExample test;
if (\!test.Configure(argc, argv))
{
NS\_FATAL\_ERROR("Configuration failed. Aborted.");
}
test.Run();
test.Report(std::cout);
return 0;
}
//-----------------------------------------------------------------------------
DroneNetworkSlicingExample::DroneNetworkSlicingExample()
: numDrones(30),
simTime(100),
pcap(true),
printRoutes(true),
gNbHeight(30.0),
droneMinHeight(10.0),
droneMaxHeight(50.0),
areaSizeX(500.0),
areaSizeY(500.0),
numEmbbDrones(10),
numUrllcDrones(10),
numMmtcDrones(10)
{
}
bool
DroneNetworkSlicingExample::Configure(int argc, char** argv)
{
SeedManager::SetSeed(12345);
CommandLine cmd(FILE);
cmd.AddValue("pcap", "Write PCAP traces.", pcap);
cmd.AddValue("printRoutes", "Print routing table dumps.", printRoutes);
cmd.AddValue("numDrones", "Number of drone UEs.", numDrones);
cmd.AddValue("numEmbbDrones", "Number of drones in eMBB slice.", numEmbbDrones);
cmd.AddValue("numUrllcDrones", "Number of drones in URLLC slice.", numUrllcDrones);
cmd.AddValue("numMmtcDrones", "Number of drones in mMTC slice.", numMmtcDrones);
cmd.AddValue("simTime", "Simulation time, s.", simTime);
cmd.AddValue("gNbHeight", "Height of gNB, m.", gNbHeight);
cmd.AddValue("droneMinHeight", "Minimum height of drones, m.", droneMinHeight);
cmd.AddValue("droneMaxHeight", "Maximum height of drones, m.", droneMaxHeight);
cmd.AddValue("areaSizeX", "X dimension of the simulation area, m.", areaSizeX);
cmd.AddValue("areaSizeY", "Y dimension of the simulation area, m.", areaSizeY);
cmd.Parse(argc, argv);
// Ensure the total number of drones matches the sum of drones in each slice
if (numEmbbDrones \+ numUrllcDrones \+ numMmtcDrones \!= numDrones)
{
std::cerr \<\< "ERROR: The sum of drones in all slices must equal numDrones\!" \<\< std::endl;
std::cerr \<\< "numEmbbDrones \+ numUrllcDrones \+ numMmtcDrones \= "
\<\< numEmbbDrones \+ numUrllcDrones \+ numMmtcDrones \<\< std::endl;
std::cerr \<\< "numDrones \= " \<\< numDrones \<\< std::endl;
return false;
}
return true;
}
void
DroneNetworkSlicingExample::Run()
{
CreateNodes();
ConfigureMobility();
Install5GDevices();
InstallInternetStack();
ConfigureNetworkSlices();
InstallApplications();
std::cout \<\< "Starting simulation for " \<\< simTime \<\< " s with "
\<\< numDrones \<\< " drones in 3 network slices..." \<\< std::endl;
// Setup netsimulyzer for visualization
auto orchestrator \= CreateObject\<netsimulyzer::Orchestrator\>("drone\_network\_slicing.json");
netsimulyzer::NodeConfigurationHelper nodeHelper{orchestrator};
// Configure visualization for eMBB drones (red)
nodeHelper.Set("Model", netsimulyzer::models::QUADCOPTER\_UAV\_VALUE);
nodeHelper.Set("Color", Vector(1.0, 0.0, 0.0)); // Red for eMBB
nodeHelper.Install(embbDrones);
// Configure visualization for URLLC drones (blue)
nodeHelper.Set("Color", Vector(0.0, 0.0, 1.0)); // Blue for URLLC
nodeHelper.Install(urllcDrones);
// Configure visualization for mMTC drones (green)
nodeHelper.Set("Color", Vector(0.0, 1.0, 0.0)); // Green for mMTC
nodeHelper.Install(mmtcDrones);
// Configure visualization for gNBs
nodeHelper.Set("Model", netsimulyzer::models::CELL\_TOWER\_VALUE);
nodeHelper.Set("Color", Vector(0.5, 0.5, 0.5)); // Gray for gNBs
nodeHelper.Install(gNbNodes);
// Enable flow monitoring
flowMonitor \= flowHelper.InstallAll();
// Schedule flow monitor output
Simulator::Schedule(Seconds(simTime \- 1.0),
\&DroneNetworkSlicingExample::Report,
this,
std::ref(std::cout));
Simulator::Stop(Seconds(simTime));
Simulator::Run();
Simulator::Destroy();
}
void
DroneNetworkSlicingExample::Report(std::ostream& os)
{
os \<\< "\\n--- Network Slicing Performance Report \---\\n";
// Print flow monitor statistics
flowMonitor-\>CheckForLostPackets();
Ptr\<Ipv4FlowClassifier\> classifier \= DynamicCast\<Ipv4FlowClassifier\>(flowHelper.GetClassifier());
std::map\<FlowId, FlowMonitor::FlowStats\> stats \= flowMonitor-\>GetFlowStats();
os \<\< "Flow\\tSlice\\tSrc\\tDst\\tTx Packets\\tRx Packets\\tLost\\tDelay (ms)\\tJitter (ms)\\tThroughput (Mbps)\\n";
double totalEmbbThroughput \= 0.0;
double totalUrllcThroughput \= 0.0;
double totalMmtcThroughput \= 0.0;
double avgEmbbDelay \= 0.0;
double avgUrllcDelay \= 0.0;
double avgMmtcDelay \= 0.0;
int embbFlowCount \= 0;
int urllcFlowCount \= 0;
int mmtcFlowCount \= 0;
for (std::map\<FlowId, FlowMonitor::FlowStats\>::const\_iterator i \= stats.begin(); i \!= stats.end(); \++i)
{
Ipv4FlowClassifier::FiveTuple t \= classifier-\>FindFlow(i-\>first);
// Skip flows that don't have received packets
if (i-\>second.rxPackets \== 0\)
continue;
// Calculate metrics
double throughput \= i-\>second.rxBytes \* 8.0 / (i-\>second.timeLastRxPacket.GetSeconds() \- i-\>second.timeFirstTxPacket.GetSeconds()) / 1000000.0;
double delay \= i-\>second.delaySum.GetMilliSeconds() / i-\>second.rxPackets;
double jitter \= i-\>second.jitterSum.GetMilliSeconds() / i-\>second.rxPackets;
// Determine which slice this flow belongs to by checking the source IP
std::string sliceName;
uint32\_t nodeId \= t.sourceAddress.Get() & 0xFF; // Extract node ID from IP
if (droneSliceMap.find(nodeId) \!= droneSliceMap.end())
{
SliceType sliceType \= droneSliceMap\[nodeId\];
switch (sliceType)
{
case EMBB:
sliceName \= "eMBB";
totalEmbbThroughput \+= throughput;
avgEmbbDelay \+= delay;
embbFlowCount++;
break;
case URLLC:
sliceName \= "URLLC";
totalUrllcThroughput \+= throughput;
avgUrllcDelay \+= delay;
urllcFlowCount++;
break;
case MMTC:
sliceName \= "mMTC";
totalMmtcThroughput \+= throughput;
avgMmtcDelay \+= delay;
mmtcFlowCount++;
break;
default:
sliceName \= "Unknown";
break;
}
}
else
{
sliceName \= "Unknown";
}
os \<\< i-\>first \<\< "\\t"
\<\< sliceName \<\< "\\t"
\<\< t.sourceAddress \<\< "\\t"
\<\< t.destinationAddress \<\< "\\t"
\<\< i-\>second.txPackets \<\< "\\t"
\<\< i-\>second.rxPackets \<\< "\\t"
\<\< i-\>second.lostPackets \<\< "\\t"
\<\< delay \<\< "\\t"
\<\< jitter \<\< "\\t"
\<\< throughput \<\< "\\n";
}
// Calculate and print average metrics per slice
os \<\< "\\n--- Average Metrics Per Slice \---\\n";
if (embbFlowCount \> 0\)
{
avgEmbbDelay /= embbFlowCount;
os \<\< "eMBB: Throughput \= " \<\< totalEmbbThroughput \<\< " Mbps, Avg Delay \= " \<\< avgEmbbDelay \<\< " ms\\n";
}
if (urllcFlowCount \> 0\)
{
avgUrllcDelay /= urllcFlowCount;
os \<\< "URLLC: Throughput \= " \<\< totalUrllcThroughput \<\< " Mbps, Avg Delay \= " \<\< avgUrllcDelay \<\< " ms\\n";
}
if (mmtcFlowCount \> 0\)
{
avgMmtcDelay /= mmtcFlowCount;
os \<\< "mMTC: Throughput \= " \<\< totalMmtcThroughput \<\< " Mbps, Avg Delay \= " \<\< avgMmtcDelay \<\< " ms\\n";
}
os \<\< "-----------------------------------\\n";
}
void
DroneNetworkSlicingExample::CreateNodes()
{
std::cout \<\< "Creating " \<\< numDrones \<\< " drone UEs and 1 gNB." \<\< std::endl;
// Create drone UEs
droneUEs.Create(numDrones);
// Create gNB node(s)
gNbNodes.Create(1);
// Assign drones to slices
uint32\_t currentIndex \= 0;
// eMBB slice
for (uint32\_t i \= 0; i \< numEmbbDrones; \++i, \++currentIndex)
{
embbDrones.Add(droneUEs.Get(currentIndex));
droneSliceMap\[currentIndex\] \= EMBB;
std::ostringstream os;
os \<\< "embb-drone-" \<\< i;
Names::Add(os.str(), droneUEs.Get(currentIndex));
}
// URLLC slice
for (uint32\_t i \= 0; i \< numUrllcDrones; \++i, \++currentIndex)
{
urllcDrones.Add(droneUEs.Get(currentIndex));
droneSliceMap\[currentIndex\] \= URLLC;
std::ostringstream os;
os \<\< "urllc-drone-" \<\< i;
Names::Add(os.str(), droneUEs.Get(currentIndex));
}
// mMTC slice
for (uint32\_t i \= 0; i \< numMmtcDrones; \++i, \++currentIndex)
{
mmtcDrones.Add(droneUEs.Get(currentIndex));
droneSliceMap\[currentIndex\] \= MMTC;
std::ostringstream os;
os \<\< "mmtc-drone-" \<\< i;
Names::Add(os.str(), droneUEs.Get(currentIndex));
}
Names::Add("gNB-0", gNbNodes.Get(0));
}
void
DroneNetworkSlicingExample::ConfigureMobility()
{
// Set positions for gNBs (fixed)
MobilityHelper gNbMobility;
Ptr\<ListPositionAllocator\> gNbPositionAlloc \= CreateObject\<ListPositionAllocator\>();
// Position the gNB in the center of the area at specified height
gNbPositionAlloc-\>Add(Vector(areaSizeX / 2.0, areaSizeY / 2.0, gNbHeight));
gNbMobility.SetPositionAllocator(gNbPositionAlloc);
gNbMobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
gNbMobility.Install(gNbNodes);
// Set mobility model for drones \- use different mobility patterns for each slice
// 1\. eMBB drones \- higher altitude, wider area coverage
MobilityHelper embbMobility;
Ptr\<RandomBoxPositionAllocator\> embbPositionAlloc \= CreateObject\<RandomBoxPositionAllocator\>();
Ptr\<UniformRandomVariable\> embbXPos \= CreateObject\<UniformRandomVariable\>();
embbXPos-\>SetAttribute("Min", DoubleValue(0.0));
embbXPos-\>SetAttribute("Max", DoubleValue(areaSizeX));
Ptr\<UniformRandomVariable\> embbYPos \= CreateObject\<UniformRandomVariable\>();
embbYPos-\>SetAttribute("Min", DoubleValue(0.0));
embbYPos-\>SetAttribute("Max", DoubleValue(areaSizeY));
Ptr\<UniformRandomVariable\> embbZPos \= CreateObject\<UniformRandomVariable\>();
embbZPos-\>SetAttribute("Min", DoubleValue(droneMaxHeight \* 0.7));
embbZPos-\>SetAttribute("Max", DoubleValue(droneMaxHeight));
embbPositionAlloc-\>SetX(embbXPos);
embbPositionAlloc-\>SetY(embbYPos);
embbPositionAlloc-\>SetZ(embbZPos);
embbMobility.SetPositionAllocator(embbPositionAlloc);
embbMobility.SetMobilityModel("ns3::GaussMarkovMobilityModel",
"Bounds", BoxValue(Box(0, areaSizeX, 0, areaSizeY, droneMaxHeight \* 0.7, droneMaxHeight)),
"TimeStep", TimeValue(Seconds(0.5)),
"Alpha", DoubleValue(0.85),
"MeanVelocity", StringValue("ns3::UniformRandomVariable\[Min=5|Max=15\]"),
"MeanDirection", StringValue("ns3::UniformRandomVariable\[Min=0|Max=6.283185307\]"),
"MeanPitch", StringValue("ns3::UniformRandomVariable\[Min=-0.1|Max=0.1\]"),
"NormalVelocity", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=2.0|Bound=4.0\]"),
"NormalDirection", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.2|Bound=0.4\]"),
"NormalPitch", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.02|Bound=0.04\]"));
embbMobility.Install(embbDrones);
// 2\. URLLC drones \- medium altitude, faster movement for critical missions
MobilityHelper urllcMobility;
Ptr\<RandomBoxPositionAllocator\> urllcPositionAlloc \= CreateObject\<RandomBoxPositionAllocator\>();
Ptr\<UniformRandomVariable\> urllcXPos \= CreateObject\<UniformRandomVariable\>();
urllcXPos-\>SetAttribute("Min", DoubleValue(areaSizeX \* 0.2));
urllcXPos-\>SetAttribute("Max", DoubleValue(areaSizeX \* 0.8));
Ptr\<UniformRandomVariable\> urllcYPos \= CreateObject\<UniformRandomVariable\>();
urllcYPos-\>SetAttribute("Min", DoubleValue(areaSizeY \* 0.2));
urllcYPos-\>SetAttribute("Max", DoubleValue(areaSizeY \* 0.8));
Ptr\<UniformRandomVariable\> urllcZPos \= CreateObject\<UniformRandomVariable\>();
urllcZPos-\>SetAttribute("Min", DoubleValue((droneMinHeight \+ droneMaxHeight) \* 0.4));
urllcZPos-\>SetAttribute("Max", DoubleValue((droneMinHeight \+ droneMaxHeight) \* 0.6));
urllcPositionAlloc-\>SetX(urllcXPos);
urllcPositionAlloc-\>SetY(urllcYPos);
urllcPositionAlloc-\>SetZ(urllcZPos);
urllcMobility.SetPositionAllocator(urllcPositionAlloc);
urllcMobility.SetMobilityModel("ns3::GaussMarkovMobilityModel",
"Bounds", BoxValue(Box(0, areaSizeX, 0, areaSizeY, droneMinHeight, droneMaxHeight)),
"TimeStep", TimeValue(Seconds(0.1)),
"Alpha", DoubleValue(0.75),
"MeanVelocity", StringValue("ns3::UniformRandomVariable\[Min=10|Max=20\]"),
"MeanDirection", StringValue("ns3::UniformRandomVariable\[Min=0|Max=6.283185307\]"),
"MeanPitch", StringValue("ns3::UniformRandomVariable\[Min=-0.2|Max=0.2\]"),
"NormalVelocity", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=3.0|Bound=6.0\]"),
"NormalDirection", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.3|Bound=0.6\]"),
"NormalPitch", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.03|Bound=0.06\]"));
urllcMobility.Install(urllcDrones);
// 3\. mMTC drones \- lower altitude, slower movement for sensor data collection
MobilityHelper mmtcMobility;
Ptr\<RandomBoxPositionAllocator\> mmtcPositionAlloc \= CreateObject\<RandomBoxPositionAllocator\>();
Ptr\<UniformRandomVariable\> mmtcXPos \= CreateObject\<UniformRandomVariable\>();
mmtcXPos-\>SetAttribute("Min", DoubleValue(0.0));
mmtcXPos-\>SetAttribute("Max", DoubleValue(areaSizeX));
Ptr\<UniformRandomVariable\> mmtcYPos \= CreateObject\<UniformRandomVariable\>();
mmtcYPos-\>SetAttribute("Min", DoubleValue(0.0));
mmtcYPos-\>SetAttribute("Max", DoubleValue(areaSizeY));
Ptr\<UniformRandomVariable\> mmtcZPos \= CreateObject\<UniformRandomVariable\>();
mmtcZPos-\>SetAttribute("Min", DoubleValue(droneMinHeight));
mmtcZPos-\>SetAttribute("Max", DoubleValue(droneMinHeight \* 1.5));
mmtcPositionAlloc-\>SetX(mmtcXPos);
mmtcPositionAlloc-\>SetY(mmtcYPos);
mmtcPositionAlloc-\>SetZ(mmtcZPos);
mmtcMobility.SetPositionAllocator(mmtcPositionAlloc);
mmtcMobility.SetMobilityModel("ns3::GaussMarkovMobilityModel",
"Bounds", BoxValue(Box(0, areaSizeX, 0, areaSizeY, droneMinHeight, droneMinHeight \* 1.5)),
"TimeStep", TimeValue(Seconds(1.0)),
"Alpha", DoubleValue(0.95),
"MeanVelocity", StringValue("ns3::UniformRandomVariable\[Min=1|Max=5\]"),
"MeanDirection", StringValue("ns3::UniformRandomVariable\[Min=0|Max=6.283185307\]"),
"MeanPitch", StringValue("ns3::UniformRandomVariable\[Min=-0.05|Max=0.05\]"),
"NormalVelocity", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=1.0|Bound=2.0\]"),
"NormalDirection", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.1|Bound=0.2\]"),
"NormalPitch", StringValue("ns3::NormalRandomVariable\[Mean=0.0|Variance=0.01|Bound=0.02\]"));
mmtcMobility.Install(mmtcDrones);
}
void
DroneNetworkSlicingExample::Install5GDevices()
{
// Set up the 5G helper
Ptr\<NrHelper\> nrHelper \= CreateObject\<NrHelper\>();
epcHelper \= CreateObject\<NrPointToPointEpcHelper\>();
nrHelper-\>SetEpcHelper(epcHelper);
// Configure bandwidth and frequency
BandwidthPartInfoPtrVector allBwps;
CcBwpCreator ccBwpCreator;
// Component carrier configuration
const uint8\_t numCcPerBand \= 1; // Number of component carriers per band
// For 5G NR FR2 band n257 (28 GHz)
CcBwpCreator::SimpleOperationBandConf bandConf(28e9, 100e6, numCcPerBand, BandwidthPartInfo::UMi\_StreetCanyon);
// Configure both gNBs and UEs with the same configuration
OperationBandInfo band \= ccBwpCreator.CreateOperationBandContiguousCc(bandConf);
// Configure the gNB device
nrHelper-\>SetGnbPhyAttribute("TxPower", DoubleValue(46.0)); // in dBm
nrHelper-\>SetGnbPhyAttribute("Numerology", UintegerValue(2)); // Numerology 2 (60 kHz SCS)
nrHelper-\>SetGnbAntennaAttribute("NumRows", UintegerValue(8));
nrHelper-\>SetGnbAntennaAttribute("NumColumns", UintegerValue(8));
nrHelper-\>SetGnbAntennaAttribute("AntennaElement", StringValue("IsotropicAntennaModel"));
// Configure the UE device
nrHelper-\>SetUePhyAttribute("TxPower", DoubleValue(23.0)); // in dBm
nrHelper-\>SetUePhyAttribute("Numerology", UintegerValue(2)); // Numerology 2 (60 kHz SCS)
// Configure the antenna for the UEs
nrHelper-\>SetUeAntennaAttribute("NumRows", UintegerValue(2));
nrHelper-\>SetUeAntennaAttribute("NumColumns", UintegerValue(2));
nrHelper-\>SetUeAntennaAttribute("AntennaElement", StringValue("IsotropicAntennaModel"));
// Install the 5G devices
NetDeviceContainer enbNetDev \= nrHelper-\>InstallGnbDevice(gNbNodes, band);
NetDeviceContainer ueNetDev \= nrHelper-\>InstallUeDevice(droneUEs, band);
gNbDevices \= enbNetDev;
ueDevices \= ueNetDev;
// Separate devices by slice for easier management
for (uint32\_t i \= 0; i \< numDrones; i++)
{
Ptr\<NetDevice\> device \= ueNetDev.Get(i);
if (droneSliceMap.find(i) \!= droneSliceMap.end())
{
SliceType sliceType \= droneSliceMap\[i\];
switch (sliceType)
{
case EMBB:
embbDevices.Add(device);
break;
case URLLC:
urllcDevices.Add(device);
break;
case MMTC:
mmtcDevices.Add(device);
break;
}
}
}
// Attach UEs to the closest gNB
nrHelper-\>AttachToClosestEnb(ueNetDev, enbNetDev);
// Enable traces if pcap is true
if (pcap)
{
// Enable PCAP traces
nrHelper-\>EnableTraces();
}
}
void
DroneNetworkSlicingExample::InstallInternetStack()
{
// Install the Internet stack on the UEs
InternetStackHelper internet;
internet.Install(droneUEs);
// Assign IP addresses to UE devices
Ipv4AddressHelper ipv4h;
ipv4h.SetBase("10.0.0.0", "255.0.0.0");
ueIfaces \= ipv4h.Assign(ueDevices);
// Get the default gateway address for routing
Ipv4StaticRoutingHelper ipv4RoutingHelper;
for (uint32\_t i \= 0; i \< droneUEs.GetN(); i++)
{
Ptr\<Ipv4\> ipv4 \= droneUEs.Get(i)-\>GetObject\<Ipv4\>();
Ptr\<Ipv4StaticRouting\> staticRouting \= ipv4RoutingHelper.GetStaticRouting(ipv4);
staticRouting-\>SetDefaultRoute(epcHelper-\>GetUeDefaultGatewayAddress(), 1);
}
if (printRoutes)
{
Ptr\<OutputStreamWrapper\> routingStream \=
Create\<OutputStreamWrapper\>("drone\_network\_slicing.routes", std::ios::out);
Ipv4RoutingHelper::PrintRoutingTableAllAt(Seconds(5), routingStream);
}
}
EpsBearer
DroneNetworkSlicingExample::CreateBearerForSlice(SliceType slice)
{
EpsBearer::Qci qci;
GbrQosInformation qosInfo;
bool isGbr \= false;
switch (slice)
{
case EMBB:
// Enhanced Mobile Broadband \- high throughput, moderate latency
qci \= EpsBearer::GBR\_CONV\_VIDEO; // Video streaming
qosInfo.gbrDl \= 10000000; // 10 Mbps DL GBR
qosInfo.gbrUl \= 5000000; // 5 Mbps UL GBR
qosInfo.mbrDl \= 100000000; // 100 Mbps DL MBR
qosInfo.mbrUl \= 50000000; // 50 Mbps UL MBR
isGbr \= true;
break;
case URLLC:
// Ultra-Reliable Low-Latency \- low latency, high reliability
qci \= EpsBearer::GBR\_MC\_PUSH\_TO\_TALK; // Mission critical PTT voice
qosInfo.gbrDl \= 1000000; // 1 Mbps DL GBR
qosInfo.gbrUl \= 1000000; // 1 Mbps UL GBR
qosInfo.mbrDl \= 10000000; // 10 Mbps DL MBR
qosInfo.mbrUl \= 10000000; // 10 Mbps UL MBR
isGbr \= true;
break;
case MMTC:
// Massive Machine Type Communications \- many devices, low data rates
qci \= EpsBearer::NGBR\_IOT; // Non-GBR IoT data
isGbr \= false;
break;
default:
// Default bearer
qci \= EpsBearer::NGBR\_VIDEO\_TCP\_DEFAULT;
isGbr \= false;
break;
}
if (isGbr)
{
return EpsBearer(qci, qosInfo);
}
else
{
return EpsBearer(qci);
}
}
void
DroneNetworkSlicingExample::ConfigureNetworkSlices()
{
std::cout \<\< "Configuring network slices..." \<\< std::endl;
// Get the EPC PGW (Packet Gateway)
Ptr\<Node\> pgw \= epcHelper-\>GetPgwNode();
// For each UE, create a dedicated bearer based on its slice
for (uint32\_t i \= 0; i \< numDrones; i++)
{
if (droneSliceMap.find(i) \!= droneSliceMap.end())
{
SliceType sliceType \= droneSliceMap\[i\];
EpsBearer bearer \= CreateBearerForSlice(sliceType);
// Create dedicated bearer for the UE
Ptr\<NetDevice\> ueDevice \= ueDevices.Get(i);
Ptr\<NetDevice\> enbDevice \= gNbDevices.Get(0); // Assuming single gNB
// Activate bearer
nrHelper-\>ActivateDedicatedEpsBearer(ueDevice, bearer, EpcTft::Default());
}
}
}
void
DroneNetworkSlicingExample::InstallApplications()
{
// Install applications for each slice type
InstallEmbbApplications();
InstallUrllcApplications();
InstallMmtcApplications();
}
void
DroneNetworkSlicingExample::InstallEmbbApplications()
{
// For eMBB slice, we'll set up high-throughput applications (video streaming)
// Remote host for server applications
Ptr\<Node\> remoteHost \= epcHelper-\>GetPgwNode();
// Install UDP server on remote host
uint16\_t dlPort \= 1000;
ApplicationContainer serverApps;
// Setup high-bandwidth UDP server for video streaming
for (uint32\_t i \= 0; i \< embbDrones.GetN(); i++)
{
// Video streaming server (downlink)
UdpServerHelper dlServer(dlPort \+ i);
serverApps.Add(dlServer.Install(remoteHost));
// Video streaming client on drone (downlink)
UdpClientHelper dlClient(epcHelper-\>GetUeDefaultGatewayAddress(), dlPort \+ i);
dlClient.SetAttribute("MaxPackets", UintegerValue(1000000));
dlClient.SetAttribute("Interval", TimeValue(Seconds(0.01))); // 100 pkts/sec
dlClient.SetAttribute("PacketSize", UintegerValue(1400)); // 1400 bytes
ApplicationContainer clientApps \= dlClient.Install(embbDrones.Get(i));
clientApps.Start(Seconds(1.0));
clientApps.Stop(Seconds(simTime \- 1.0));
}
serverApps.Start(Seconds(0.5));
serverApps.Stop(Seconds(simTime \- 0.5));
}
void
DroneNetworkSlicingExample::InstallUrllcApplications()
{
// For URLLC slice, we'll set up low-latency applications (drone control)
// Remote host for server applications
Ptr\<Node\> remoteHost \= epcHelper-\>GetPgwNode();
// Install UDP server on remote host
uint16\_t dlPort \= 2000;
uint16\_t ulPort \= 3000;
ApplicationContainer serverApps;
// Setup low-latency UDP applications for drone control
for (uint32\_t i \= 0; i \< urllcDrones.GetN(); i++)
{
// Control command server (downlink)
UdpServerHelper dlServer(dlPort \+ i);
serverApps.Add(dlServer.Install(remoteHost));
// Telemetry server (uplink)
UdpServerHelper ulServer(ulPort \+ i);
serverApps.Add(ulServer.Install(remoteHost));
// Control command client on drone (downlink)
UdpClientHelper dlClient(epcHelper-\>GetUeDefaultGatewayAddress(), dlPort \+ i);
dlClient.SetAttribute("MaxPackets", UintegerValue(1000000));
dlClient.SetAttribute("Interval", TimeValue(Seconds(0.005))); // 200 pkts/sec
dlClient.SetAttribute("PacketSize", UintegerValue(64)); // Small packets
// Telemetry client on drone (uplink)
UdpClientHelper ulClient(epcHelper-\>GetUeDefaultGatewayAddress(), ulPort \+ i);
ulClient.SetAttribute("MaxPackets", UintegerValue(1000000));
ulClient.SetAttribute("Interval", TimeValue(Seconds(0.005))); // 200 pkts/sec
ulClient.SetAttribute("PacketSize", UintegerValue(64)); // Small packets
ApplicationContainer clientDlApps \= dlClient.Install(urllcDrones.Get(i));
ApplicationContainer clientUlApps \= ulClient.Install(urllcDrones.Get(i));
clientDlApps.Start(Seconds(1.0));
clientDlApps.Stop(Seconds(simTime \- 1.0));
clientUlApps.Start(Seconds(1.1));
clientUlApps.Stop(Seconds(simTime \- 0.9));
}
serverApps.Start(Seconds(0.5));
serverApps.Stop(Seconds(simTime \- 0.5));
}
void
DroneNetworkSlicingExample::InstallMmtcApplications()
{
// For mMTC slice, we'll set up many small, infrequent transmissions (sensor data)
// Remote host for server applications
Ptr\<Node\> remoteHost \= epcHelper-\>GetPgwNode();
// Install UDP server on remote host
uint16\_t sensorPort \= 4000;
ApplicationContainer serverApps;
// Setup sensor data transmission (many small packets, infrequent)
for (uint32\_t i \= 0; i \< mmtcDrones.GetN(); i++)
{
// Sensor data collection server
UdpServerHelper sensorServer(sensorPort \+ i);
serverApps.Add(sensorServer.Install(remoteHost));
// Sensor data client on drone
UdpClientHelper sensorClient(epcHelper-\>GetUeDefaultGatewayAddress(), sensorPort \+ i);
sensorClient.SetAttribute("MaxPackets", UintegerValue(1000000));
// Random interval between 1-5 seconds to simulate diverse IoT patterns
Ptr\<UniformRandomVariable\> interval \= CreateObject\<UniformRandomVariable\>();
interval-\>SetAttribute("Min", DoubleValue(1.0));
interval-\>SetAttribute("Max", DoubleValue(5.0));
// Set interval for sensor data
double sendInterval \= interval-\>GetValue();
sensorClient.SetAttribute("Interval", TimeValue(Seconds(sendInterval)));
sensorClient.SetAttribute("PacketSize", UintegerValue(100)); // Small sensor readings
ApplicationContainer clientApps \= sensorClient.Install(mmtcDrones.Get(i));
clientApps.Start(Seconds(1.0 \+ i \* 0.1)); // Stagger start times
clientApps.Stop(Seconds(simTime \- 1.0));
}
serverApps.Start(Seconds(0.5));
serverApps.Stop(Seconds(simTime \- 0.5));
}
Step3: Run Code
(Consider we are at /scratch directory)
Go to Terminal:
cd ..
./ns3 run scratch/test_slicing.cc
![][image49]
![][image50]
- Wifi
![][image51]
![][image52]
- 5g nr
![][image53]
- Sliced
![][image54]
Thank You
[image20]: <data:image/png;base64,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