Loading...

# 8.ns3 wifi 设备定向发送的实现

在本节中,将介绍 ns3 中 wifi 设备定向发送的实现方案

# 起因

由于研究需求,需要用到节点具有定向发送,全向接收的功能,但 ns3 自带的功能没有定向实现,所以就写了一种定向的实现方法。

# 修改思路

第一想法是修改天线模块的代码,使其完成定向的功能,但是看了以下源码,感觉实现难度较大,修改比较困难,故 pass
第二想法是修改物理层或者数据链路层,在节点收到数据包时,底层判断发送节点的位置与接收节点的位置,只接收从指定方向传来的数据包,从而实现定向接收的功能。

于是就开始找数据发送的函数,与数据接收的处理函数,
最终发现在 yans-wifi-channel.cc 里发现有 send 函数和 receive 函数
yans-wifi-channel.cc :

void
 YansWifiChannel::Send (Ptr<YansWifiPhy> sender, Ptr<const WifiPpdu> ppdu, double txPowerDbm) const
 {
   NS_LOG_FUNCTION (this << sender << ppdu << txPowerDbm);
   Ptr<MobilityModel> senderMobility = sender->GetMobility ();
   NS_ASSERT (senderMobility != 0);
   for (PhyList::const_iterator i = m_phyList.begin (); i != m_phyList.end (); i++)
     {
       if (sender != (*i))
         {
           //For now don't account for inter channel interference nor channel bonding
           if ((*i)->GetChannelNumber () != sender->GetChannelNumber ())
             {
               continue;
             }
           Ptr<MobilityModel> receiverMobility = (*i)->GetMobility ()->GetObject<MobilityModel> ();
           Time delay = m_delay->GetDelay (senderMobility, receiverMobility);
           double rxPowerDbm = m_loss->CalcRxPower (txPowerDbm, senderMobility, receiverMobility);
           NS_LOG_DEBUG ("propagation: txPower=" << txPowerDbm << "dbm, rxPower=" << rxPowerDbm << "dbm, " <<
                         "distance=" << senderMobility->GetDistanceFrom (receiverMobility) << "m, delay=" << delay);
           Ptr<WifiPpdu> copy = Copy (ppdu);
           Ptr<NetDevice> dstNetDevice = (*i)->GetDevice ();
           uint32_t dstNode;
           if (dstNetDevice == 0)
             {
               dstNode = 0xffffffff;
             }
           else
             {
               dstNode = dstNetDevice->GetNode ()->GetId ();
             }
           Simulator::ScheduleWithContext (dstNode,
                                           delay, &YansWifiChannel::Receive,
                                           (*i), copy, rxPowerDbm);
         }
     }
 }
 void
 YansWifiChannel::Receive (Ptr<YansWifiPhy> phy, Ptr<WifiPpdu> ppdu, double rxPowerDbm)
 {
   NS_LOG_FUNCTION (phy << ppdu << rxPowerDbm);
   // Do no further processing if signal is too weak
   // Current implementation assumes constant RX power over the PPDU duration
   if ((rxPowerDbm + phy->GetRxGain ()) < phy->GetRxSensitivity ())
     {
       NS_LOG_INFO ("Received signal too weak to process: " << rxPowerDbm << " dBm");
       return;
     }
   RxPowerWattPerChannelBand rxPowerW;
   rxPowerW.insert ({std::make_pair (0, 0), (DbmToW (rxPowerDbm + phy->GetRxGain ()))}); //dummy band for YANS
   phy->StartReceivePreamble (ppdu, rxPowerW);
 }

阅读源码可以发现, ns3 中发送数据包的流程如下,遍历与发送数据包的节点物理层 ( YanWifiPhy ) 相连的节点。根据每个邻居节点与发送节点之间的距离和衰减模型中定义的公式来计算衰减。然后回调 receive 函数,来判断衰减后是否可以被接收。这为我们的想法提供了很好的条件。因为发送和接收节点的位置信息是可以由 MobilityModel 得到的,而控制是否接收该数据包,也可以通过修改衰减或者之间控制是否进行回调来解决。

# 第一版代码

所以自然而然的,第一版定向天线的代码就出来了
只需要在 send 函数里,计算以下发送节点与接收节点之间形成的方向向量与自定义的坐标轴之间的夹角,然后,控制指定方向内的向量衰竭结果不变,其余方向的衰减结果减去一个大值即可。即通过衰减来实现其他方向的节点无法收到数据

void
YansWifiChannel::Send (Ptr<YansWifiPhy> sender, Ptr<const WifiPpdu> ppdu, double txPowerDbm) const
{
  NS_LOG_FUNCTION (this << sender << ppdu << txPowerDbm);
  Ptr<MobilityModel> senderMobility = sender->GetMobility ();
  NS_ASSERT (senderMobility != 0);
  for (PhyList::const_iterator i = m_phyList.begin (); i != m_phyList.end (); i++)
    {
      if (sender != (*i))
        {
          //For now don't account for inter channel interference nor channel bonding
          if ((*i)->GetChannelNumber () != sender->GetChannelNumber ())
            {
              continue;
            }
          Ptr<MobilityModel> receiverMobility = (*i)->GetMobility ()->GetObject<MobilityModel> ();
          Time delay = m_delay->GetDelay (senderMobility, receiverMobility);
          double rxPowerDbm = m_loss->CalcRxPower (txPowerDbm, senderMobility, receiverMobility);
          NS_LOG_DEBUG ("propagation: txPower=" << txPowerDbm << "dbm, rxPower=" << rxPowerDbm << "dbm, " <<
                        "distance=" << senderMobility->GetDistanceFrom (receiverMobility) << "m, delay=" << delay);
          //motified by yeyu
          // 发送节点的位置
          Vector sendVector=senderMobility->GetPosition();
          Vector sendVelocityVector=senderMobility->GetVelocity();
          // 接收节点的位置
          Vector receiverVector=receiverMobility->GetPosition();
          Vector receiverVelocityVector=receiverMobility->GetVelocity();
          NS_LOG_INFO("发送节点坐标:"<<sendVector<<"  速度矢量:"<<sendVelocityVector);
          NS_LOG_INFO("接收节点坐标:"<<receiverVector<<"  速度矢量:"<<receiverVelocityVector);
         // double angel=atan(receiverVector.x-sendVector.x,receiverVector.y-sendVector.y);
         double tan=(receiverVector.y-sendVector.y)/(receiverVector.x-sendVector.x); 
          double angel=atan((receiverVector.y-sendVector.y)/(receiverVector.x-sendVector.x));
          angel=angel*180/M_PI;
          if(angel<0){
            angel=angel+360;
          }
          double angelLimit=sender->getAngel();
          int canSend=NondirectionalLoss(angel,angelLimit);
          NS_LOG_INFO("tan:"<<tan<<" angel: "<<angel<<" canSend:"<<canSend<< "angel limit:"<< angelLimit);
          // 上下左右,每个方向 2*theta 度的接收角 (theta<45)
         // rxPowerDbm=rxPowerDbm-NondirectionalLoss(angel,5);
        if(canSend!=0){
            NS_LOG_INFO("不在指定方向内,跳过"); 
            continue;
        }
          //motified by yeyu
          Ptr<WifiPpdu> copy = Copy (ppdu);
          Ptr<NetDevice> dstNetDevice = (*i)->GetDevice ();
          uint32_t dstNode;
          if (dstNetDevice == 0)
            {
              dstNode = 0xffffffff;
            }
          else
            {
              dstNode = dstNetDevice->GetNode ()->GetId ();
            }
          Simulator::ScheduleWithContext (dstNode,
                                          delay, &YansWifiChannel::Receive,
                                          (*i), copy, rxPowerDbm);
        }
    }
}

其中 NondirectionalLoss 是自定义的控制接收角度的函数,规定向下为 0 度,逆时针方向增长,angel 范围 0-360 度,theta 是上下左右四个方向接收角度的一半

int NondirectionalLoss(double angel,double theta){
    if((theta<angel && angel <90-theta)or(90+theta<angel && angel<180-theta)or(180+theta<angel && angel<270-theta)or(270+theta<angel && angel<360-theta)){
        return 999999;
    }
    return 0;
}

这样修改完之后,确实可以定向发送,但是存在一个问题,所有的节点都是这样。没法单独设置单个节点。显然不能满足需求。于是接下来需要进一步修改。

# 改进方案

观察 send 函数,可以发现它是遍历 YansWifiPhy , 大胆猜测,每个节点都有与之对应的 YansWifiPhy 。经过验证确实如此。
那么下面的任务就简单了,修改 YansWifiPhy 的源码,添加几个自定义的变量,对外提供对应的 get,set 函数。就可以修改指定节点的发送范围。

但是又出现了新的问题,如何获得单个节点的 YansWifiPhy 呢?
由于 ns3 封装的很好,不提供对单个节点 YansWifiPhy 的访问。
一个想法是找到绑定 nodeYansWifiPhy 的地方,自己提供对外访问的方法。
于是就找到了 YansWifiHelper , 从源码可以看出,就是这了,每个 node 都有与之对应的 YansWifiPhyHelper

Ptr<WifiPhy> YansWifiPhyHelper::Create (Ptr<Node> node, Ptr<NetDevice> device) const
{
  Ptr<YansWifiPhy> phy = m_phy.Create<YansWifiPhy> ();
  Ptr<ErrorRateModel> error = m_errorRateModel.Create<ErrorRateModel> ();
  phy->SetErrorRateModel (error);
  if (m_frameCaptureModel.IsTypeIdSet ())
    {
      Ptr<FrameCaptureModel> capture = m_frameCaptureModel.Create<FrameCaptureModel> ();
      phy->SetFrameCaptureModel (capture);
    }
  if (m_preambleDetectionModel.IsTypeIdSet ())
    {
      Ptr<PreambleDetectionModel> capture = m_preambleDetectionModel.Create<PreambleDetectionModel> ();
      phy->SetPreambleDetectionModel (capture);
    }
  phy->SetChannel (m_channel);
  phy->SetDevice (device);
  return phy;
}

那么接下来的事情就很简单了,在 YansWifiHelper 里添加一个存储 YansWifiPhyvector , 在 send 函数里将获得的 YansWifiPhy 添加到 vector 里,对外提供 get方法
理论上这样就可以了。但是事情并不像想象中的那么简单。
这样改完之后,并没有什么效果
经过一番查找。最后发现, YansWifiHelper 是继承 WifiHelper 的, YansWifiHelper 中的 Create 方法是由 WifiHelper 中的 install 方法调用的,并且返回的是 YansWifyPhy 的父类 WifiPhy

NetDeviceContainer
WifiHelper::Install (const WifiPhyHelper &phyHelper,
                     const WifiMacHelper &macHelper,
                     NodeContainer::Iterator first,
                     NodeContainer::Iterator last) const
{
  NetDeviceContainer devices;
  for (NodeContainer::Iterator i = first; i != last; ++i)
    {
      Ptr<Node> node = *i;
      Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice> ();
      auto it = wifiStandards.find (m_standard);
      if (it == wifiStandards.end ())
        {
          NS_FATAL_ERROR ("Selected standard is not defined!");
          return devices;
        }
      if (it->second.phyStandard >= WIFI_PHY_STANDARD_80211n)
        {
          Ptr<HtConfiguration> htConfiguration = CreateObject<HtConfiguration> ();
          device->SetHtConfiguration (htConfiguration);
        }
      if ((it->second.phyStandard >= WIFI_PHY_STANDARD_80211ac) && (it->second.phyBand != WIFI_PHY_BAND_2_4GHZ))
        {
          Ptr<VhtConfiguration> vhtConfiguration = CreateObject<VhtConfiguration> ();
          device->SetVhtConfiguration (vhtConfiguration);
        }
      if (it->second.phyStandard >= WIFI_PHY_STANDARD_80211ax)
        {
          Ptr<HeConfiguration> heConfiguration = CreateObject<HeConfiguration> ();
          device->SetHeConfiguration (heConfiguration);
        }
      Ptr<WifiRemoteStationManager> manager = m_stationManager.Create<WifiRemoteStationManager> ();
      Ptr<WifiMac> mac = macHelper.Create (device);
      Ptr<WifiPhy> phy = phyHelper.Create (node, device);
      //add by yeyu
      m_phyVector.push_back(phy);
      //add by yeyu
      mac->SetAddress (Mac48Address::Allocate ());
      mac->ConfigureStandard (m_standard);
      phy->ConfigureStandardAndBand (it->second.phyStandard, it->second.phyBand);
      device->SetMac (mac);
      device->SetPhy (phy);
      device->SetRemoteStationManager (manager);
      node->AddDevice (device);
      if ((it->second.phyStandard >= WIFI_PHY_STANDARD_80211ax) && (m_obssPdAlgorithm.IsTypeIdSet ()))
        {
          Ptr<ObssPdAlgorithm> obssPdAlgorithm = m_obssPdAlgorithm.Create<ObssPdAlgorithm> ();
          device->AggregateObject (obssPdAlgorithm);
          obssPdAlgorithm->ConnectWifiNetDevice (device);
        }
      devices.Add (device);
      NS_LOG_DEBUG ("node=" << node << ", mob=" << node->GetObject<MobilityModel> ());
      // Aggregate a NetDeviceQueueInterface object if a RegularWifiMac is installed
      Ptr<RegularWifiMac> rmac = DynamicCast<RegularWifiMac> (mac);
      if (rmac)
        {
          Ptr<NetDeviceQueueInterface> ndqi;
          BooleanValue qosSupported;
          PointerValue ptr;
          Ptr<WifiMacQueue> wmq;
          Ptr<WifiAckPolicySelector> ackSelector;
          rmac->GetAttributeFailSafe ("QosSupported", qosSupported);
          if (qosSupported.Get ())
            {
              ndqi = CreateObjectWithAttributes<NetDeviceQueueInterface> ("NTxQueues",
                                                                          UintegerValue (4));
              rmac->GetAttributeFailSafe ("BE_Txop", ptr);
              ackSelector = m_ackPolicySelector[AC_BE].Create<WifiAckPolicySelector> ();
              ackSelector->SetQosTxop (ptr.Get<QosTxop> ());
              ptr.Get<QosTxop> ()->SetAckPolicySelector (ackSelector);
              wmq = ptr.Get<QosTxop> ()->GetWifiMacQueue ();
              ndqi->GetTxQueue (0)->ConnectQueueTraces (wmq);
              rmac->GetAttributeFailSafe ("BK_Txop", ptr);
              ackSelector = m_ackPolicySelector[AC_BK].Create<WifiAckPolicySelector> ();
              ackSelector->SetQosTxop (ptr.Get<QosTxop> ());
              ptr.Get<QosTxop> ()->SetAckPolicySelector (ackSelector);
              wmq = ptr.Get<QosTxop> ()->GetWifiMacQueue ();
              ndqi->GetTxQueue (1)->ConnectQueueTraces (wmq);
              rmac->GetAttributeFailSafe ("VI_Txop", ptr);
              ackSelector = m_ackPolicySelector[AC_VI].Create<WifiAckPolicySelector> ();
              ackSelector->SetQosTxop (ptr.Get<QosTxop> ());
              ptr.Get<QosTxop> ()->SetAckPolicySelector (ackSelector);
              wmq = ptr.Get<QosTxop> ()->GetWifiMacQueue ();
              ndqi->GetTxQueue (2)->ConnectQueueTraces (wmq);
              rmac->GetAttributeFailSafe ("VO_Txop", ptr);
              ackSelector = m_ackPolicySelector[AC_VO].Create<WifiAckPolicySelector> ();
              ackSelector->SetQosTxop (ptr.Get<QosTxop> ());
              ptr.Get<QosTxop> ()->SetAckPolicySelector (ackSelector);
              wmq = ptr.Get<QosTxop> ()->GetWifiMacQueue ();
              ndqi->GetTxQueue (3)->ConnectQueueTraces (wmq);
              ndqi->SetSelectQueueCallback (m_selectQueueCallback);
            }
          else
            {
              ndqi = CreateObject<NetDeviceQueueInterface> ();
              rmac->GetAttributeFailSafe ("Txop", ptr);
              wmq = ptr.Get<Txop> ()->GetWifiMacQueue ();
              ndqi->GetTxQueue (0)->ConnectQueueTraces (wmq);
            }
          device->AggregateObject (ndqi);
        }
    }
  return devices;
}

那么现在就很简单了,直接修改 WifiPhy , WifiHelper
WifiPhy.h 中添加下面代码

/*
   *motified by yeyu
   */
  //0<m_angel<45
   double m_angel;
   void setAngel(double angel);
   double getAngel();
 //motified by yeyu

WifiPhy.cc 中添加下面代码

//add by yeyu
void WifiPhy::setAngel(double angel){
    m_angel=angel;
}
double WifiPhy::getAngel(){
    return m_angel;
}
//add by yeyu

WifiHelper.h 中添加下面代码

//add by yeyu
#include <vector>
//add by yeyu
  /**
   *add by yeyu,
   * 存储节点与 Ptr<WiFiPhy > 的对应关系
   */
  mutable std::vector<Ptr<WifiPhy>> m_phyVector;

WifiHelper.cc 中添加下面代码

void
//add by yeyu
 std::vector<Ptr<WifiPhy>> WifiHelper::getPhyVector(){
    return m_phyVector;
 }
//add by yeyu

WifiHelper.cc 中的 send 函数修改如下

NetDeviceContainer
WifiHelper::Install (const WifiPhyHelper &phyHelper,
                     const WifiMacHelper &macHelper,
                     NodeContainer::Iterator first,
                     NodeContainer::Iterator last) const
{
      *// 上面默认代码
      //add by yeyu
      m_phyVector.push_back(phy);
      //add by yeyu
      *// 下面是默认代码
}

再加上 YansWifiChannelsend 函数里的修改,即可以实现自己想要的定向发送功能

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

jluyeyu 微信支付

微信支付

jluyeyu 支付宝

支付宝