구현

문제 해결을 위한 시뮬레이션 제작 및 Tracing source 추출-추가 구현

Beige00 2024. 3. 28. 14:22

구현의 목표

- 구현을 마치고, 해당 코드에서 뽑아낸 데이터를 기반으로 Feature Selection을 하면서 뭔가 이상함을 느꼈다.

우선 최종으로 포스팅한 코드에서 단순히 시뮬레이션을 100번 반복해서 100개의 csv를 뽑아내게 바꿨었는데,

해당 100개의 csv를 80개를 train, 20개를 test로 지정한 DT에서 Y-val인 Packet Drop (PhyRxDrop으로 측정함) 과 Neighbor Node와의 관계가 0.88이 나와버린 것이다.

조금 생각을 해봤는데, 우선 내가 측정하고 싶은건 "프토토콜의 변경으로 인한 PDR의 감소"인데 Phy에서 찍은거 자체가 말이 안되는 것 같다.

또한, NNeighbor가 많다면 자신이 path로 이용될 확률이 높아 그냥 drop 패킷 수가 높게 찍힐 수 있다.

중요한건 "몇 개"가 들어와서 "몇 개"가 떨어졌나에 주목하는 Packet Drop Ratio이라고 결론지었다.

 

그에 맞게 PDR을 수집하도록 코드를 구성해보았다.

더보기
#include <sstream>
#include <fstream>
#include <ns3/network-module.h>
#include <ns3/core-module.h>
#include <ns3/applications-module.h>
#include <ns3/mobility-module.h>
#include <ns3/internet-module.h>
#include <ns3/yans-wifi-helper.h>
#include "ns3/energy-module.h"
#include "ns3/wifi-radio-energy-model-helper.h"
#include "ns3/device-energy-model.h"
#include "ns3/adhoc-wifi-mac.h"
#include "ns3/aodv-helper.h"
#include "ns3/wifi-mac-queue.h"
#include <regex>
#include <cmath>
#include <vector>
#include <string>

#define TxRange 350
#define TotalTime 250
#define nodeNum 30
#define sinkNum 5
#define QueueLenS "5p"
#define QueueLen 5
#define IterNum 100
#define dataMode "VhtMcs8"
#define phyMode "OfdmRate54Mbps"

using namespace ns3;

int ja=0;



int ios = 0;
int PDC[nodeNum];
int PRC[nodeNum];

void 
makeCsvFile(const std::vector<std::vector<std::string>>& data,std::ofstream* file1){
    for(const auto& row : data){
        for(auto it = row.begin(); it!=row.end(); ++it){
            for(char c : *it){
                file1->put(c);
            }
            if(next(it)!=row.end()){
                file1->put(',');
            }
        }
        file1->put('\n');
    }
}

Vector 
Normalize(const Vector& velocity){
    double magnitude = std::sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
    // 크기가 0인 벡터는 정규화할 수 없으므로, 원본 벡터를 반환
    if (magnitude == 0)
    {
        return velocity;
    }
    return ns3::Vector(velocity.x / magnitude, velocity.y / magnitude, velocity.z / magnitude);
}

double distance(double x1, double y1, double x2, double y2){
    return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
}

double CalculateRelativeSpeed(double vAx, double vAy, double vBx, double vBy) {
    // 상대 속도 벡터의 각 성분을 계산
    double relativeVx = vBx - vAx;
    double relativeVy = vBy - vAy;

    return sqrt(pow(relativeVx, 2) + pow(relativeVy, 2));
}

void MacRx(NetDeviceContainer* n,std::string context, Ptr<const Packet> packet){
    std::regex rege("/NodeList/(\\d+)/");
    std::smatch match;
    std::regex_search(context,match,rege);
    int index = std::stoi(match[1].str());
    PointerValue ptr;
    n->Get(index)->GetAttribute("Mac",ptr);
    Ptr<AdhocWifiMac> mac = ptr.Get<AdhocWifiMac>();
    Ptr<WifiMacQueue> txop = mac->GetTxopQueue(AC_BE);

    if(txop->GetNPackets()>=QueueLen){
        PDC[index]+=1;
    }
    PRC[index]+=1;
}


void 
TracingParameter(NetDeviceContainer n, std::ofstream* os,std::vector<std::vector<std::string>> Data){

    double variance[nodeNum]={};
    double nodeX[nodeNum];
    double nodeY[nodeNum];
    double spdX[nodeNum];
    double spdY[nodeNum];
    int NN[nodeNum];
    int GNN[nodeNum];
    double mean1[nodeNum]={};

    
    
    //각 노드들의 데이터 긁어오기, 0=PacketSinkApp, 1=OnOffApp
    for(int i=0; i<nodeNum; i++){
        //node들의 에너지 잔량,속도, 방향, 위치 정보 수집(Node x, Node y)
        Ptr<Node> node = n.Get(i)->GetNode();
        Ptr<MobilityModel> mobility = node->GetObject<MobilityModel>();
        ApplicationContainer app = node->GetApplication(0);

        Vector pos = mobility->GetPosition();
        Vector velocity = mobility->GetVelocity();

        
        nodeX[i] = pos.x;
        nodeY[i] = pos.y;
        spdX[i] = velocity.x;
        spdY[i] = velocity.y;
    }
    
    //Node Strength 계산
    for(int i=0; i<nodeNum; i++){
        double totalLET=0;
        int GNNN = 0;
        int NNodeNum = 0;
        double LET[nodeNum];
        std::fill(LET,LET+nodeNum,-1000);
        for(int j=0; j<nodeNum; j++){
            //처리해줘야할 노드만 처리
            if(i==j) continue;
            double dis = distance(nodeX[i],nodeY[i],nodeX[j],nodeY[j]);
            if(dis<=TxRange){
                NNodeNum++;
                if((spdX[i]*spdX[j]+spdY[i]*spdY[j])>=0){
                    GNNN++;
                }//가까워짐
                else{
                    LET[j] = dis / (CalculateRelativeSpeed(spdX[i],spdY[i],spdX[j],spdY[j]));
                }
            }
        }//이 시점에서 모든 node i 에 대한 LET 정보 갱신 완료.
        if(GNNN!=NNodeNum){
            for(int k=0; k<nodeNum; k++){
                if(LET[k] == -1000) continue;
                else totalLET += LET[k];
        }
        double mean = totalLET / (NNodeNum-GNNN);
        for(int k=0; k<nodeNum; k++){
            if(LET[k] == -1000) continue;
            variance[i] += (LET[k]-mean)*(LET[k]-mean);
        }
        variance[i] /= (NNodeNum-GNNN);
        variance[i] = sqrt(variance[i]);
        mean1[i]=mean;
        }
        GNN[i] = GNNN;
        NN[i] = NNodeNum;
    }



    //Write Info
    for(int i=0; i<nodeNum; i++){
        double PDR = (double)(PDC[i])/(double)(PRC[i]);
        Data.push_back({std::to_string(Simulator::Now().GetSeconds()),
        std::to_string(i+1),
        std::to_string(nodeX[i]),
        std::to_string(nodeY[i]),
        std::to_string(mean1[i]),
        std::to_string(variance[i]),
        std::to_string(NN[i]),
        std::to_string(GNN[i]),
        std::to_string(abs(spdX[i])+abs(spdY[i])),
        std::to_string(PDR*100)
        });
    }

    makeCsvFile(Data,os);
    Data.clear();
    std::cout<<Simulator::Now().GetSeconds()<<std::endl;
    Simulator::Schedule(Seconds(1),&TracingParameter,n,os,Data);
}


int 
main(int argc, char* argv[]){

    for(ja = 0; ja<IterNum; ja++){
        std::ostringstream oss1;
        oss1<<"/home/user/ns-allinone-3.41/ns-3.41/Result/result"<<ja<<".csv";

        std::ofstream file1 (oss1.str());
        std::vector<std::vector<std::string>> Data;

        Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
        x->SetAttribute("Min",DoubleValue(0));
        RngSeedManager::SetSeed(ja+1);
        RngSeedManager::SetRun(10);

    
    Data.push_back({"Second","NodeID","X","Y","AverageLET","Variance","NNeighbor","GoodNeighbor","Speed","PacketDrop"});
    

    NodeContainer AdhocNodes;
    AdhocNodes.Create(nodeNum);

    NetDeviceContainer AdhocDevices;

    MobilityHelper mobility;
    ObjectFactory points;
    points.SetTypeId("ns3::RandomRectanglePositionAllocator");
    points.Set("X",StringValue("ns3::UniformRandomVariable[Min=-350.0|Max=350.0]"));
    points.Set("Y",StringValue("ns3::UniformRandomVariable[Min=-350.0|Max=350.0]"));
    Ptr<PositionAllocator> waypos = points.Create() -> GetObject<PositionAllocator>();

    mobility.SetMobilityModel("ns3::RandomWaypointMobilityModel",
    "Speed",StringValue("ns3::UniformRandomVariable[Min=0.0|Max=10]"),
    "Pause",StringValue("ns3::UniformRandomVariable[Min=0.0|Max=2]"),
    "PositionAllocator",PointerValue(waypos));

    mobility.SetPositionAllocator("ns3::RandomRectanglePositionAllocator",
    "X",StringValue("ns3::UniformRandomVariable[Min=-350.0|Max=350.0]"),
    "Y",StringValue("ns3::UniformRandomVariable[Min=-350.0|Max=350.0]"));

    mobility.Install(AdhocNodes);
    //속도 pause time 방향 범위 내 랜덤.



    WifiHelper wifi;
    wifi.SetStandard(WIFI_STANDARD_80211ac);
    YansWifiPhyHelper phy;
    YansWifiChannelHelper channel;
    phy.EnableAscii("my-wifi-trace-file",AdhocNodes);


    WifiMacHelper mac;
    mac.SetType("ns3::AdhocWifiMac");
    
    phy.SetErrorRateModel("ns3::YansErrorRateModel");
    channel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel");
    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager","DataMode",StringValue(dataMode),"ControlMode",StringValue(phyMode));
    channel.AddPropagationLoss("ns3::RangePropagationLossModel","MaxRange",DoubleValue(TxRange));
    phy.SetChannel(channel.Create());
    AdhocDevices.Add(wifi.Install(phy,mac,AdhocNodes));

    InternetStackHelper internet;
    AodvHelper aodv;
    internet.SetRoutingHelper(aodv);
    internet.Install(AdhocNodes);
    
    Ipv4AddressHelper ipv4;
    ipv4.SetBase("10.1.1.0","255.255.255.0");
    Ipv4InterfaceContainer ipv4Interface = ipv4.Assign(AdhocDevices);

    uint64_t port = 9;
    ApplicationContainer sink_app;

    for(int i=0; i<sinkNum; i++){
        PacketSinkHelper packetSink("ns3::UdpSocketFactory",InetSocketAddress(Ipv4Address::GetAny(),port));
        sink_app.Add(packetSink.Install(AdhocNodes.Get(i)));
    }
    sink_app.Start(Seconds(0.0));
    sink_app.Stop(Seconds(TotalTime));

    
    for(int i=0; i<sinkNum; i++){
        for(int j=0; j<nodeNum; j++){
            if(i==j) continue;
            InetSocketAddress sinkSocket (ipv4Interface.GetAddress(i),port);
            OnOffHelper onoff("ns3::UdpSocketFactory",sinkSocket);
            onoff.SetAttribute("StartTime",TimeValue(Seconds(3)));
            onoff.SetAttribute("StopTime",TimeValue(Seconds(TotalTime)));
            onoff.SetAttribute("OnTime", StringValue("ns3::UniformRandomVariable[Min=0.5|Max=1.5]")); // 전송 지속 시간
            onoff.SetAttribute("OffTime", StringValue("ns3::UniformRandomVariable[Min=0|Max=0.5]")); // 전송 중단 시간
            onoff.SetAttribute("DataRate", DataRateValue(10000)); // 데이터 전송률
            onoff.Install(AdhocNodes.Get(j));
        }
    }


    Simulator::Stop(Seconds(TotalTime));
    
    for(int i=0; i<nodeNum; i++){
        //Mac 버퍼 크기 줄이기
        PointerValue ptr;
        AdhocDevices.Get(i)->GetAttribute("Mac",ptr);
        Ptr<AdhocWifiMac> mac = ptr.Get<AdhocWifiMac>();
        Ptr<WifiMacQueue> txop = mac->GetTxopQueue(AC_BE);
        txop->SetMaxSize(QueueSize(QueueLenS));


        std::ostringstream oss1;
        oss1<<"/NodeList/"<<i<<"/DeviceList/0/$ns3::WifiNetDevice/Mac/MacRx";
        Config::Connect (oss1.str(), MakeBoundCallback (&MacRx,&AdhocDevices));
    }

    Simulator::Schedule(Seconds(3),&TracingParameter,AdhocDevices,&file1,Data);
    Simulator::Run();
    Simulator::Destroy();

    std::fill(PDC,PDC+nodeNum,0);
    std::fill(PRC,PRC+nodeNum,0);

    file1.close();

    }
}

이렇게 구현하는게 맞는 접근인지는 모르겠다.

MacRx에 Callback을 연결하고, MacRx 발생 시, 발생한 Device의 Txop(AC_BE) Queue Length를 조회하여, 이미 MaxLen일 시 PDC +1, PRC +1을 해주고, 아닐 시 그냥 PRC만 +1 해주는 방식으로 Packet Drop, Packet Receive를 측정하여 노드당 PDR을 측정하게 바꾸었다.

일단 이 코드를 통해 수집된 100개의 Result.csv로 다시 학습을 하여 Feature Selection을 수행해보겠다.