Skip to content

IIITV-5G-and-Edge-Computing-Activity/2024GR30CS462-net-slicing-5g

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lab Project Network Slicing in 5g Drones

2024GR37CS462

Vaibhav Kumar Jonwal
202251150

Azim Khorajiya
202251169

Yash Hire
202252319

Sakshi Dhoni
202252335

Nihalmayi
202251149

Contents

  1. NS-3 (Setup)
    1. Installation
  • Download NS-3
  • Installing Dependencies
  • Building NS-3
  1. NetSimulyzer (Setup)
    1. Installation
  • Downloading NetSimulyzer NS-3 module
  • Installing Dependencies
  • Building NS-3 for NetSimulyzer
  • Installing NetSimulyzer Software
  1. Drone Simulation
    1. Setup Code & Simulation
  • Write Code
  • Running Simulation
  1. 5G Integration
    1. Setup Code
  • 5G-LENA Setup
  • Write Code
  1. Slicing Integration
    1. Setup Code
  • Write Code
  1. Running Simulation
    1. All Simulations

NS-3 Setup

Installation

  1. Downloading NS-3

(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

  1. Install Dependencies

    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%)

  1. Building NS-3

    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)

NetSimulyzer Setup

Installation

  1. Downloading NetSimulyzer NS-3 module

    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

  1. Install Dependencies

    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)

  1. Building NS-3 for NetSimulyzer

    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

  1. 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]

Drone Simulation

Setup Code & Simulation

  1. Write Code

    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]

  1. Running Simulation

    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]

5g Integration

Setup Code

  1. 5G-LENA Setup

    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]

  1. Write Code

    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]

Slicing Integration

Setup Code

  1. Write Code

    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]

Running Simulation

All Simulations

  1. Wifi

![][image51]

![][image52]

  1. 5g nr

![][image53]

  1. Sliced

![][image54]

Thank You

[image20]: <data:image/png;base64,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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published