/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2020 Institute for the Wireless Internet of Things, Northeastern University, Boston, MA
* Copyright (c) 2021 University of Washington: for HierarchicalMobilityModel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Michele Polese <michele.polese@gmail.com>
* Heavily edited by Tom Henderson (to reuse HierachicalMobilityModel)
*/
/**
* This example shows how to use the ns3::HierarchicalMobilityModel
* to construct a Reference Point Group Mobility model (RPGM) model
* as described in "A survey of mobility models for ad hoc network
* research" by Tracy Camp, Jeff Boleng, and Vanessa Davies, Wireless
* Communications and Mobile Computing, 2002: vol. 2, pp. 2483-502.
* 此示例说明如何使用 ns3::HierarchicalMobilityModel 构建参考点组移动模型 (RPGM) 模型。
*
* The HierarchicalMobilityModel is composed of two mobility models;
* a parent and a child. The position of the child is expressed
* in reference to the position of the parent. For group mobility,
* each node in the group installs the same parent mobility model
* and different child mobility models.
* HierarchicalMobilityModel 由两个移动模型组成; 父移动模型和子移动模型。
* 子模型的位置是参照父模型的位置来表达的。
* 对于群组移动,群组中的每个节点安装相同的父移动模型和不同的子移动模型。
*
* There is no node associated with the parent (reference) model.
* Instead, all nodes are associated with a hiearchical mobility model
* containing both the parent and child models, and the position of
* the node is the vector sum of these parent and child positions.
* 没有与父(参考)模型关联的节点。
* 相反,所有节点都与包含父模型和子模型的分层移动模型相关联,并且节点的位置是这些父子位置的向量和。
* Jerry:即节点与分层移动模型相关联,不直接与父或者子移动模型关联。而节点的移动方式是有父子两个模型综合作用的结果。
*
* Standard ns-3 mobility model course change output is traced in
* 'reference-point-course-change.mob' file. This file only traces
* position when there is a course change. A second trace is produced
* by this example: a time-series of node positions sampled every second.
* This file is 'reference-point-time-series.mob' and can be plotted
* with the 'reference-point-group-mobility-animation.sh' program.
* 标准 ns-3 移动模型课程更改输出在“reference-point-course-change.mob”文件中进行跟踪。 该文件仅在路线发生变化时跟踪位置。
* 这个例子产生了第二条轨迹:每秒采样的节点位置的时间序列。
* 该文件是“reference-point-time-series.mob”,可以使用“reference-point-group-mobility-animation.sh”程序绘制。
*
* There is a bit of randomness in the child mobility models (random
* walk within a 10m x 10m box surrounding the parent mobility position);
* slightly different output can be rendered by changing the ns-3 'RunNumber'
* value (see the documentation on ns-3 random variables).
* 子移动模型有一点随机性(在父移动位置周围 10m x 10m 的盒子内随机行走);
* 通过更改 ns-3 'RunNumber' 值可以呈现稍微不同的输出(请参阅有关 ns-3 随机变量的文档)。
*
* There is one program option: 'useHelper'. This is simply for code
* demonstration purposes; it selects the branch of code that is used
* to either configure the mobility using a helper object, or
* to directly configure using CreateObject<> () and handling of pointers.
* The traces generated should be the same.
* 有一个程序选项:“useHelper”。 这只是为了代码演示的目的;
* 它选择用于使用辅助(helper)对象配置移动性或使用 CreateObject<> () 直接配置和处理指针的代码分支。
* 生成的trace 应该是一样的。
*/
#include <iostream>
#include "ns3/core-module.h"
#include <ns3/mobility-module.h>
#include "ns3/network-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("ReferencePointGroupMobilityExample");
std::ofstream g_timeSeries;
void PrintPosition(Ptr<Node> node) {
if (node == nullptr)
return;
Ptr<MobilityModel> model = node->GetObject<MobilityModel>();
if (model == nullptr)
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;
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.
/*
* 参考(父)移动模型从坐标(10,10)开始,顺时针走到每个航路点,绕两圈。
* 每个航路点之间的行驶时间为 100 秒,因此由于矩形路径,速度在两个值之间交替。
* 个人理解:因为四个点的距离是不一样的,但两点间移动所需时间是一致的,则速度会有两种,且根据距离的变化而在这两种之间切换。
*/
// 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.
/*
* 该移动模型的位置不代表任何实际节点; 它形成了节点的子移动模型位置偏移的参考点。
*/
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.
/**
* 每个 HierachicalMobilityModel 都包含上述模型作为 Parent,以及一个用户定义的模型作为 Child。
* 每个节点实例化两个 MobilityModel 对象(一个分层模型和一个子模型),并且在所有节点之间重用一个父模型。
*/
// The program now branches into two: one using the low-level API, and
// one using the GroupMobilityHelper. Both branches result in equivalent
// configuration.
/*
* 该程序现在分为两种:一种使用低级 API,另一种使用 GroupMobilityHelper。
* 两个分支都产生相同的配置。
*/
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),第一个节点(节点 0)的移动模型
// HierarchicalMobilityModel,分层移动模型
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.
/*
* 第一个节点(节点 0)的子移动模型。 这可以是任何其他移动模型类型;
* 对于这个例子,我们重用了随机游走,但使用了一个 10m x 10m 的小边界框。
*/
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=5]"));
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
* Jerry:即本else{}中的代码与if{}中的代码实现同等效果
*/
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.
/*
* helper 提供了一种方法来设置参考移动模型以供对象工厂构造,但在这种情况下,
* 由于我们使用的是 WaypointMobilityModel,这需要我们直接在对象上添加航点,
* 因此我们只需传入指针即可。
*/
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.
/*
* WaypointMobilityModel 不需要位置分配器(它可以使用它的第一个航路点),
* 但通常可以将 GroupMobilityHelper 配置为接受参考模型的 PositionAllocator 配置。
*/
// 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
/*
* 安装后,使用 helper 进行与上述(if{...})等效的流分配
*/
group.AssignStreams(n, streamIndex);//如果AssignStreams在Install之前调用,将不会有任何效果。
}
// 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();
}
1.代码源自:NS-3 3.35 源码包:sr/mobility/examples/reference-point-group-mobility-example.cc
2.个人理解该示例主要是演示分层移动模型和能实现同等效果的GroupMobilityHelper(代码更简洁)的使用、trace 文件的生成及可视化绘图(.sh脚本读取.mob生成.png图)。分层移动节点结合了父移动模型和子移动模型,父移动模型主要控制节点的大体的移动方向,子移动模型负责微调。GroupMobilityHelper 达到了同样的效果。
3.执行该程序两种方式,第一种eclipse 下Run->External Tools ->自定义run(后文会结合图详细介绍),第二种命令行方式./waf --run reference-point-group-mobility-example --vis ,实际两种是一回事儿。
会生成两个trace 文件:
- reference-point-course-change.mob ,只有在节点路线发生变化时NS3 才会将节点位置写入到该文件中。
- reference-point-time-series.mob ,NS3 每秒将采样的节点位置的时间序列写入该文件。
第二个文件, 可以通过src/mobility/examples/reference-point-group-mobility-animate.sh 脚本(后文会结合图介绍)进行读取并生成大量.png 图片,每张图展示节点每隔一秒钟的节点位置。
运行脚本读取第二个文件reference-point-time-series.mob 的命令如下:
neusoft001@ubuntu:/usr/local/eclipse/projects20220106/NS-3_20220111$ ./src/mobility/examples/reference-point-group-mobility-animate.sh
该脚本会读取reference-point-time-series.mob 文件。
注意.sh脚本和.mob 文件所在的位置。.sh 脚本文件在src/mobility/examples/ 下,生成的reference-point-time-series.mob 在eclipse 项目的根目录下。
4.节点移动轨迹:
父节点的移动路径是按照WaypointMobilityModel 规划好的,在整个游走范围内,分4个点,如下所示,父节点从(0,0)点出发按矩形路线顺时针移动,绕两圈。
// (0,50) (100,50)
// +-------------------------+
// | .(10,40) (90,40). |
// | |
// | |
// | .(10,10) (90,10). |
// | |
// +-------------------------+
// (0,0) (100,0)
5.遗留问题
暂时未整明白AssignStreams()函数是干嘛用的?望路过的懂得的老师,帮忙解答一下。先谢过了。
6.运行,eclipse 下Run->External Tools ->自定义run,如图:
自定义run(我这里自定义名为waf_run_vis)的配置如图:
在自定义run 配置界面中点击Run 按钮或者直接点击eclipse 下Run->External Tools ->waf_run_vis 运行程序reference-point-group-mobility-example,如图,在弹框内输入reference-point-group-mobility-example(不带.cc扩展名):
点击OK 按钮:
点击vis 仿真界面中的Simulator(F3) 按钮开始仿真:
我们看到左侧工程浏览区域里生成了两个trace 文件:
两个trace 文件的内容:
执行脚本,读取reference-point-time-series.mob trace文件生成png图片:
NS-3 3.35 源码包(编译后的源码包拷贝到eclipse 工程下了)中的 ./src/mobility/examples/reference-point-group-mobility-animate.sh
会生成很多.png 文件, 逐个打开png文件,我们将看到三个节点的位置变化情况: