학부연구생

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

Beige00 2024. 3. 20. 14:35
#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 <regex>
#include <cmath>
#include <vector>
#include <string>

#define TxRange 250
#define TotalTime 200
#define nodeNum 20
#define sinkNum 5
#define dataMode "VhtMcs8"
#define phyMode "OfdmRate54Mbps"

using namespace ns3;

std::vector<std::vector<std::string>> Data;
std::ofstream file1 ("Result.csv");
std::ofstream file("NetInfo.txt");
std::ofstream Table("RoutingTable.txt");

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

void 
makeCsvFile(const std::vector<std::vector<std::string>>& data){
    for(const auto& row : data){
        for(auto it = row.begin(); it!=row.end(); ++it){
            file1<<*it;
            if(next(it)!=row.end()){
                file1<<",";
            }
        }
        file1<<std::endl;
    }
}

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 PhyRxDrop(std::string context, Ptr<const Packet> packet,WifiPhyRxfailureReason reason){
    std::regex rege("/NodeList/(\\d+)/");
    std::smatch match;
    std::regex_search(context,match,rege);
    int index = std::stoi(match[1].str());
    PDC[index]+=1;
    if(a[index]<10 && PDC[index]>=1000){
        a[index] = 1;
        file<<Simulator::Now().GetSeconds()<<"s : node "<<index<<": "<<reason<<std::endl;
    }
}

void 
TracingParameter(NetDeviceContainer n){

    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++){
        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(PDC[i])
        });
    }
    std::fill(PDC,PDC+nodeNum,0);
    std::fill(a,a+nodeNum,0);

    Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
    x->SetAttribute("Min",DoubleValue(0.5));
    x->SetAttribute("Max",DoubleValue(1.5));
    

    makeCsvFile(Data);
    Data.clear();
    std::cout<<Simulator::Now().GetSeconds()<<std::endl;
    Simulator::Schedule(Seconds(x->GetValue()),&TracingParameter,n);
}

int 
main(int argc, char* argv[]){
    Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
    x->SetAttribute("Min",DoubleValue(0));
    RngSeedManager::SetSeed(x->GetInteger());

    

    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=0.0|Max=700.0]"));
    points.Set("Y",StringValue("ns3::UniformRandomVariable[Min=0.0|Max=700.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=0|Max=700.0]"),
    "Y",StringValue("ns3::UniformRandomVariable[Min=0|Max=700.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));
    wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
    channel.AddPropagationLoss("ns3::RangePropagationLossModel","MaxRange",DoubleValue(TxRange));
    phy.SetChannel(channel.Create());
    AdhocDevices.Add(wifi.Install(phy,mac,AdhocNodes));

    InternetStackHelper internet;
    AodvHelper aodv;
    Ptr<OutputStreamWrapper> oss=Create<OutputStreamWrapper>(&Table);
    aodv.PrintRoutingTableAllEvery(Seconds(10.0),oss);
    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);
            // BulkSendHelper bulk("ns3::TcpSocketFactory",sinkSocket);
            // bulk.SetAttribute("StartTime",TimeValue(Seconds(3)));
            // bulk.SetAttribute("StopTime",TimeValue(Seconds(TotalTime-2)));
            // bulk.Install(AdhocNodes.Get(j));
            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=1]")); // 전송 중단 시간
            onoff.SetAttribute("DataRate", DataRateValue(100000)); // 데이터 전송률
            onoff.Install(AdhocNodes.Get(j));
        }
    }


    Simulator::Stop(Seconds(TotalTime));
    
    for(int i=0; i<nodeNum; i++){
        std::ostringstream oss;
        oss<<"/NodeList/"<<i<<"/DeviceList/0/$ns3::WifiNetDevice/Phys/0/PhyRxDrop";
        Config::Connect (oss.str(), MakeBoundCallback (&PhyRxDrop));
    }

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

    Table.close();
    file.close();
    file1.close();
}

 

일일히 전부 포스팅하지는 못했지만, 결과적으로 해당 코드를 통해 뽑아낸 Objective들은 다음과 같다.

내가 생각해본 NodeScore의 경우, 일단 스케일링 없이 LET와 NeighborNode들이 더해지는 것도 문제였고, 교수님의 의견은 더한단건 리스크가 큰 방법이라고 하셨다. 거기다가, 지금 우리는 딱히 Feature의 수를 압축해줘야하는 입장도 아니다.

따라서, AverageLET와 해당 LET 데이터들의 분산만을 주고, 그대로 학습을 진행하였다.

(계속 나의 발목을 잡은 오작동, 버그의 원인은 메모리 부족이 매우 컷다. Valgrind를 써도 누수가 없는 코드이니 그냥 메모리를 많이 먹는 것 같다. PacketSinkApplication은 최대한 줄이도록 하자. 또한 PacketSinkApplication 혹은 환경 자체의 Mobility가 크면 ns3 Aodv의 구현 상의 특성상 오류가 난다.

또한, Dsr routing을 하려고 하면 꼭 Energy model을 인터넷 프로토콜 설치 이전에 하자. 버그가 있다.)

그리고 계속하여 조건을 바꾸고 최적화해가며 뽑아낸 값들로 교수님과의 상담을 반복하며, 이웃 노드가 많다고 무조건 좋은 노드가 아니란 것을 파악했다.

즉, Aodv의 특성이든 기존 라우팅 프로토콜의 특성이든, 일단 주변 노드가 많다는건 경로로 이용될 가능성이 높다는 것이다.

따라서 노드의 위치 또한 Classification에 포함되주어야할 것 같다.

다만, 무조건 노드가 중앙에 있다고 노드로 많이 이용된다고 보긴 어려울 것 같다. 

결국 같이 움직이는 Adhoc Network node 군집군의 중심에 얼마나 가까이 위치할 지가 중요한데, 이것까지 가공해서 포함시킬지는 나중에 고민하고 너무 끌리는 감이 있어 일단 Colab에서 classification을 하는 방향으로 프로젝트를 진행할 것이다.

후에 Classification이 잘 되지 않는다거나 score가 낮은데 Classification의 문제라고 생각되면, 그 때 다시 이어서 고민해보고 포스팅하도록 하겠다.