该代码是一个用于模拟网络节点移动的示例程序。它使用了ns-3网络模拟器库,其中包含了一些用于处理核心功能、网络和移动性的头文件。
代码的主要功能如下:
- 创建了一个包含3个节点的节点容器。
- 定义了一个参考点(parent)的移动模型,它按照预定义的路径在一个矩形区域内移动。这个移动模型不代表实际的节点,只用作参考点。
- 使用层次化移动模型(HierarchicalMobilityModel)将参考点移动模型作为父模型,并创建了一个子模型(RandomWalk2dMobilityModel)作为每个节点的移动模型。
- 使用低级API或GroupMobilityHelper两种方式配置节点的移动模型。
- 配置节点的位置记录和追踪。
- 运行模拟并记录节点的位置和移动轨迹。
代码中的函数PrintPosition
用于将节点的位置信息写入时间序列文件。main
函数根据命令行参数配置模拟时间、打印次数和是否使用辅助函数。然后,它创建节点容器,并根据选择的方式配置节点的移动模型。最后,它启动模拟器并运行模拟。
这段代码展示了如何使用ns-3库来模拟网络节点的移动,并记录节点的位置信息。它可以作为学习和使用ns-3进行网络模拟的参考示例。
/\*\*
- 本示例展示了如何使用ns3::HierarchicalMobilityModel构建一个参考点组移动模型(Reference Point Group Mobility model,RPGM)模型,
- 此模型在"Wireless Communications and Mobile Computing, 2002: vol. 2, pp. 2483-502"一文中由Tracy Camp、Jeff Boleng和Vanessa Davies描述。
-
- HierarchicalMobilityModel由两个移动模型组成:父模型和子模型。子模型的位置是相对于父模型的位置而言的。对于群组移动,
- 群组中的每个节点都安装相同的父模型和不同的子模型。
-
- 父模型(参考模型)没有与之关联的节点。相反,所有节点都与包含父模型和子模型的层次移动模型关联,并且节点的位置是父模型位置和子模型位置的矢量和。
-
- 标准的ns-3移动模型在'reference-point-course-change.mob'文件中追踪课程变化的输出。该文件仅在发生课程变化时追踪位置。
- 该示例还生成第二个跟踪:每秒采样一次的节点位置的时间序列。该文件是'reference-point-time-series.mob',可以使用'reference-point-group-mobility-animation.sh'程序绘制出来。
-
- 子模型中存在一定的随机性(在围绕父模型位置的10m x 10m的方框内进行随机游走);通过更改ns-3的'RunNumber'值(请参阅ns-3随机变量的文档),
- 可以产生稍微不同的输出。
-
- 有一个程序选项:'useHelper'。这仅用于代码演示目的;它选择使用帮助对象配置移动性的代码分支,还是直接使用CreateObject\<>()进行配置和处理指针。
- 生成的跟踪应该是相同的。
\*/
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include <ns3/mobility-module.h>
#include <iostream>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("ReferencePointGroupMobilityExample");
/// The time series file.
std::ofstream g_timeSeries;
/**
* Print the node position to the time series file.
*
* \param node The node.
*/
void
PrintPosition(Ptr<Node> node)
{
if (!node)
{
return;
}
Ptr<MobilityModel> model = node->GetObject<MobilityModel>();
if (!model)
{
return;
}
NS_LOG_LOGIC("Node: " << node->GetId() << " Position: " << model->GetPosition());
g_timeSeries << Simulator::Now().GetSeconds() << " " << node->GetId() << " "
<< model->GetPosition() << std::endl;
}
int
main(int argc, char* argv[])
{
Time simTime = Seconds(800); // 模拟时间
uint32_t numPrints = 800; // 记录节点位置的次数
bool useHelper = false; // 是否使用Helper方法
CommandLine cmd(__FILE__);
cmd.AddValue("useHelper", "Whether to use helper code", useHelper);
cmd.Parse(argc, argv);
g_timeSeries.open("reference-point-time-series.mob");// 打开时间序列文件
NodeContainer n;
n.Create(3);
// The primary mobility model is the WaypointMobilityModel defined within
// this bounding box:
//
// (0,50) (100,50)
// +-------------------------+
// | .(10,40) (90,40). |
// | |
// | |
// | .(10,10) (90,10). |
// | |
// +-------------------------+
// (0,0) (100,0)
//
// The reference (parent) mobility model starts at coordinate (10,10
// and walks clockwise to each waypoint, making two laps. The time
// to travel between each waypoint is 100s, so the velocity alternates
// between two values due to the rectangular path.
// No actual node is represented by the position of this mobility
// model; it forms the reference point from which the node's child
// mobility model position is offset.
//
// 主要移动性模型是WaypointMobilityModel,定义了参考点的移动路径
// 参考点移动路径示意图见注释中的图形描述
Ptr<WaypointMobilityModel> waypointMm = CreateObject<WaypointMobilityModel>();
waypointMm->AddWaypoint(Waypoint(Seconds(0), Vector(10, 10, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(100), Vector(10, 40, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(200), Vector(90, 40, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(300), Vector(90, 10, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(400), Vector(10, 10, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(500), Vector(10, 40, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(600), Vector(90, 40, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(700), Vector(90, 10, 0)));
waypointMm->AddWaypoint(Waypoint(Seconds(800), Vector(10, 10, 0)));
// Each HierachicalMobilityModel contains the above model as the Parent,
// and a user defined model as the Child. Two MobilityModel objects are
// instantiated per node (one hierarchical, and one child model), and
// a single parent model is reused across all nodes.
// The program now branches into two: one using the low-level API, and
// one using the GroupMobilityHelper. Both branches result in equivalent
// configuration.
int64_t streamIndex = 1;
if (useHelper == false)
{
// Assign random variable stream numbers on the parent and each child
// 为参考点及每个节点的子移动性模型分配随机变量流编号
streamIndex += waypointMm->AssignStreams(streamIndex);
// Mobility model for the first node (node 0) 为第一个节点创建层次移动性模型
Ptr<HierarchicalMobilityModel> hierarchical0 = CreateObject<HierarchicalMobilityModel>();
hierarchical0->SetParent(waypointMm);
// Child Mobility model for the first node (node 0). This can be any
// other mobility model type; for this example, we reuse the random walk
// but with a small 10m x 10m bounding box.
// 为第一个节点创建子移动性模型(RandomWalk2dMobilityModel)
Ptr<RandomWalk2dMobilityModel> childRandomWalk0 = CreateObject<RandomWalk2dMobilityModel>();
// Position in reference to the original random walk
childRandomWalk0->SetAttribute("Bounds", RectangleValue(Rectangle(-5, 5, -5, 5)));
childRandomWalk0->SetAttribute("Speed",
StringValue("ns3::ConstantRandomVariable[Constant=0.1]"));
streamIndex += childRandomWalk0->AssignStreams(streamIndex);
hierarchical0->SetChild(childRandomWalk0);
n.Get(0)->AggregateObject(hierarchical0);
// Repeat for other two nodes
Ptr<HierarchicalMobilityModel> hierarchical1 = CreateObject<HierarchicalMobilityModel>();
hierarchical1->SetParent(waypointMm); // Same parent as before
Ptr<RandomWalk2dMobilityModel> childRandomWalk1 = CreateObject<RandomWalk2dMobilityModel>();
childRandomWalk1->SetAttribute("Bounds", RectangleValue(Rectangle(-5, 5, -5, 5)));
childRandomWalk1->SetAttribute("Speed",
StringValue("ns3::ConstantRandomVariable[Constant=0.1]"));
streamIndex += childRandomWalk1->AssignStreams(streamIndex);
hierarchical1->SetChild(childRandomWalk1);
n.Get(1)->AggregateObject(hierarchical1);
Ptr<HierarchicalMobilityModel> hierarchical2 = CreateObject<HierarchicalMobilityModel>();
hierarchical2->SetParent(waypointMm); // Same parent as before
Ptr<RandomWalk2dMobilityModel> childRandomWalk2 = CreateObject<RandomWalk2dMobilityModel>();
childRandomWalk2->SetAttribute("Bounds", RectangleValue(Rectangle(-5, 5, -5, 5)));
childRandomWalk2->SetAttribute("Speed",
StringValue("ns3::ConstantRandomVariable[Constant=0.1]"));
streamIndex += childRandomWalk2->AssignStreams(streamIndex);
hierarchical2->SetChild(childRandomWalk2);
n.Get(2)->AggregateObject(hierarchical2);
}
else
{
// This branch demonstrates an equivalent set of commands but using
// the GroupMobilityHelper
GroupMobilityHelper group;
// The helper provides a method to set the reference mobility model
// for construction by an object factory, but in this case, since we
// are using the WaypointMobilityModel, which requires us to add
// waypoints directly on the object, we will just pass in the pointer.
group.SetReferenceMobilityModel(waypointMm);
// The WaypointMobilityModel does not need a position allocator
// (it can use its first waypoint as such), but in general, the
// GroupMobilityHelper can be configured to accept configuration for
// a PositionAllocator for the reference model. We skip that here.
// Next, configure the member mobility model
group.SetMemberMobilityModel("ns3::RandomWalk2dMobilityModel",
"Bounds",
RectangleValue(Rectangle(-5, 5, -5, 5)),
"Speed",
StringValue("ns3::ConstantRandomVariable[Constant=0.1]"));
// Again, we could call 'SetMemberPositionAllocator' and provide a
// position allocator here for the member nodes, but none is provided
// in this example, so they will start at time zero with the same
// position as the reference node.
// Install to all three nodes
group.Install(n);
// After installation, use the helper to make the equivalent
// stream assignments as above
group.AssignStreams(n, streamIndex);
}
// Note: The tracing methods are static methods declared on the
// MobilityHelper class, not on the GroupMobilityHelper class
AsciiTraceHelper ascii;
MobilityHelper::EnableAsciiAll(ascii.CreateFileStream("reference-point-course-change.mob"));
// Use a logging PrintPosition() to record time-series position
for (unsigned int i = 0; i < numPrints; i++)
{
for (auto nodeIt = n.Begin(); nodeIt != n.End(); ++nodeIt)
{
Simulator::Schedule(NanoSeconds(i * simTime.GetNanoSeconds() / numPrints),
&PrintPosition,
(*nodeIt));
}
}
Simulator::Stop(simTime);
Simulator::Run();
g_timeSeries.close();
Simulator::Destroy();
}
评论区