buildings: (merge !125) Add random walk mobility model that avoids buildings

* Adds example, unit test, and bash script to plot results
This commit is contained in:
Michele Polese
2019-10-24 14:24:56 +02:00
committed by Tom Henderson
parent 059640f466
commit 9f805877ea
9 changed files with 920 additions and 1 deletions

View File

@@ -74,9 +74,10 @@ allows to choose between Block Ack policy and Implicit Block Ack Request policy
allows to request an acknowledgment after a configurable number of MPDUs have been
transmitted.</li>
<li>The MaxSize attribute is removed from the QueueBase base class and moved to subclasses. A new MaxSize attribute is therefore added to the DropTailQueue class, while the MaxQueueSize attribute of the WifiMacQueue class is renamed as MaxSize for API consistency.</li>
<li> A new sequence and timestamp header variant for applications has been added. The SeqTsEchoHeader contains an additional timestamp field for use in echoing a timestamp back to a sender.</li>
<li> TCP-based applications (OnOffApplication, BulkSendApplication, and PacketSink) support a new header to convey sequence number, timestamp, and size data. Use is controlled by the "EnableSeqTsSizeHeader" attribute.</li>
<li>Added a new trace source <b>PhyRxPayloadBegin</b> in WifiPhy for tracing begin of PSDU reception.</li>
<li> A new sequence and timestamp header variant for applications has been added. The SeqTsEchoHeader contains an additional timestamp field for use in echoing a timestamp back to a sender.</li>
<li>Added the class <b>RandomWalk2dOutdoorMobilityModel</b> that models a random walk which does not enter any building.</li>
</ul>
<h2>Changes to existing API:</h2>
<ul>

View File

@@ -28,6 +28,7 @@ New user-visible features
- (propagation) 3GPP TR 38.901 pathloss and channel condition models added
- (spectrum) Addition three-gpp-channel-model (part of Integration of the 3GPP TR 38.901 fast fading model)
- (antenna) Addition of three-gpp-antenna-array-model (part of Integration of the 3GPP TR 38.901 fast fading model)
- (buildings) added a random walk mobility model which does not enter in any building
- (core) CommandLine can now add the Usage message to the Doxygen for the program; see CommandLine for details.
Bugs fixed

View File

@@ -0,0 +1,130 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
* Copyright (c) 2019, University of Padova, Dep. of Information Engineering, SIGNET lab
*
* 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: Nicola Baldo <nbaldo@cttc.es> for the code adapted from the lena-dual-stripe.cc example
* Author: Michele Polese <michele.polese@gmail.com> for this version
*/
#include "ns3/buildings-module.h"
#include "ns3/mobility-module.h"
#include "ns3/core-module.h"
#include "ns3/network-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("OutdoorRandomWalkExample");
void
PrintGnuplottableBuildingListToFile (std::string filename)
{
std::ofstream outFile;
outFile.open (filename.c_str (), std::ios_base::out | std::ios_base::trunc);
if (!outFile.is_open ())
{
NS_LOG_ERROR ("Can't open file " << filename);
return;
}
uint32_t index = 0;
for (BuildingList::Iterator it = BuildingList::Begin (); it != BuildingList::End (); ++it)
{
++index;
Box box = (*it)->GetBoundaries ();
outFile << "set object " << index
<< " rect from " << box.xMin << "," << box.yMin
<< " to " << box.xMax << "," << box.yMax
<< std::endl;
}
}
/**
* This is an example on how to use the RandomWalk2dOutdoorMobilityModel class.
* The script outdoor-random-walk-example.sh can be used to visualize the
* positions visited by the random walk.
*/
int
main (int argc, char *argv[])
{
LogComponentEnable ("RandomWalk2dOutdoor", LOG_LEVEL_LOGIC);
CommandLine cmd (__FILE__);
cmd.Parse (argc, argv);
// create a grid of buildings
double buildingSizeX = 100; // m
double buildingSizeY = 50; // m
double streetWidth = 25; // m
double buildingHeight = 10; // m
uint32_t numBuildingsX = 10;
uint32_t numBuildingsY = 10;
double maxAxisX = (buildingSizeX + streetWidth) * numBuildingsX;
double maxAxisY = (buildingSizeY + streetWidth) * numBuildingsY;
std::vector<Ptr<Building> > buildingVector;
for (uint32_t buildingIdX = 0; buildingIdX < numBuildingsX; ++buildingIdX)
{
for (uint32_t buildingIdY = 0; buildingIdY < numBuildingsY; ++buildingIdY)
{
Ptr < Building > building;
building = CreateObject<Building> ();
building->SetBoundaries (Box (buildingIdX * (buildingSizeX + streetWidth),
buildingIdX * (buildingSizeX + streetWidth) + buildingSizeX,
buildingIdY * (buildingSizeY + streetWidth),
buildingIdY * (buildingSizeY + streetWidth) + buildingSizeY,
0.0, buildingHeight));
building->SetNRoomsX (1);
building->SetNRoomsY (1);
building->SetNFloors (1);
buildingVector.push_back (building);
}
}
// print the list of buildings to file
PrintGnuplottableBuildingListToFile ("buildings.txt");
// create one node
NodeContainer nodes;
nodes.Create (1);
// set the RandomWalk2dOutdoorMobilityModel mobility model
MobilityHelper mobility;
mobility.SetMobilityModel ("ns3::RandomWalk2dOutdoorMobilityModel",
"Bounds", RectangleValue (
Rectangle (-streetWidth, maxAxisX, -streetWidth, maxAxisY)));
// create an OutdoorPositionAllocator and set its boundaries to match those of the mobility model
Ptr<OutdoorPositionAllocator> position = CreateObject<OutdoorPositionAllocator> ();
Ptr<UniformRandomVariable> xPos = CreateObject<UniformRandomVariable>();
xPos->SetAttribute ("Min", DoubleValue (-streetWidth));
xPos->SetAttribute ("Max", DoubleValue (maxAxisX));
Ptr<UniformRandomVariable> yPos = CreateObject<UniformRandomVariable>();
yPos->SetAttribute ("Min", DoubleValue (-streetWidth));
yPos->SetAttribute ("Max", DoubleValue (maxAxisY));
position->SetAttribute ("X", PointerValue (xPos));
position->SetAttribute ("Y", PointerValue (yPos));
mobility.SetPositionAllocator (position);
// install the mobility model
mobility.Install (nodes.Get (0));
// enable the traces for the mobility model
AsciiTraceHelper ascii;
MobilityHelper::EnableAsciiAll (ascii.CreateFileStream ("mobility-trace-example.mob"));
Simulator::Stop (Seconds (1e4));
Simulator::Run ();
Simulator::Destroy ();
}

View File

@@ -0,0 +1,41 @@
#!/bin/bash
# Copyright (c) 2019, University of Padova, Dep. of Information Engineering, SIGNET lab
#
# 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>
#
# Plot the traces generated by outdoor-random-walk-example.cc
#
cat mobility-trace-example.mob | awk -F " " '{ print $3 }' | awk -F "=" '{ print $2 }' | awk -F ":" '{ print $1" "$2 }' > pos.txt
cat >aa <<EOL
set terminal postscript eps noenhanced color
set output 'map.eps'
set view map
set xlabel 'X [m]'
set ylabel 'Y [m]'
set xrange [-25:1300]
set yrange [-25:800]
set style fill transparent solid 0.5
unset key
set style fill transparent solid 0.35 noborder
set style circle radius 5
plot "pos.txt" with circles lc rgb "blue"
EOL
gnuplot buildings.txt aa
rm aa
rm pos.txt

View File

@@ -4,3 +4,6 @@ def build(bld):
obj = bld.create_ns3_program('buildings-pathloss-profiler',
['buildings'])
obj.source = 'buildings-pathloss-profiler.cc'
obj = bld.create_ns3_program('outdoor-random-walk-example',
['buildings'])
obj.source = 'outdoor-random-walk-example.cc'

View File

@@ -0,0 +1,438 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
* Copyright (c) 2019 University of Padova
*
* 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Author: Michele Polese <michele.polese@gmail.com>
*/
#include "random-walk-2d-outdoor-mobility-model.h"
#include "ns3/enum.h"
#include "ns3/double.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/building.h"
#include "ns3/building-list.h"
#include <cmath>
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("RandomWalk2dOutdoor");
NS_OBJECT_ENSURE_REGISTERED (RandomWalk2dOutdoorMobilityModel);
TypeId
RandomWalk2dOutdoorMobilityModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::RandomWalk2dOutdoorMobilityModel")
.SetParent<MobilityModel> ()
.SetGroupName ("Mobility")
.AddConstructor<RandomWalk2dOutdoorMobilityModel> ()
.AddAttribute ("Bounds",
"Bounds of the area to cruise.",
RectangleValue (Rectangle (0.0, 100.0, 0.0, 100.0)),
MakeRectangleAccessor (&RandomWalk2dOutdoorMobilityModel::m_bounds),
MakeRectangleChecker ())
.AddAttribute ("Time",
"Change current direction and speed after moving for this delay.",
TimeValue (Seconds (20.0)),
MakeTimeAccessor (&RandomWalk2dOutdoorMobilityModel::m_modeTime),
MakeTimeChecker ())
.AddAttribute ("Distance",
"Change current direction and speed after moving for this distance.",
DoubleValue (30.0),
MakeDoubleAccessor (&RandomWalk2dOutdoorMobilityModel::m_modeDistance),
MakeDoubleChecker<double> ())
.AddAttribute ("Mode",
"The mode indicates the condition used to "
"change the current speed and direction",
EnumValue (RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE),
MakeEnumAccessor (&RandomWalk2dOutdoorMobilityModel::m_mode),
MakeEnumChecker (RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE, "Distance",
RandomWalk2dOutdoorMobilityModel::MODE_TIME, "Time"))
.AddAttribute ("Direction",
"A random variable used to pick the direction (radians).",
StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=6.283184]"),
MakePointerAccessor (&RandomWalk2dOutdoorMobilityModel::m_direction),
MakePointerChecker<RandomVariableStream> ())
.AddAttribute ("Speed",
"A random variable used to pick the speed (m/s)."
"The default value is taken from Figure 1 of the paper"
"Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.",
StringValue ("ns3::NormalRandomVariable[Mean=1.53|Variance=0.040401]"),
MakePointerAccessor (&RandomWalk2dOutdoorMobilityModel::m_speed),
MakePointerChecker<RandomVariableStream> ())
.AddAttribute ("Tolerance",
"Tolerance for the intersection point with buildings (m)."
"It represents a small distance from where the building limit"
"is actually placed, for example to represent a sidewalk.",
DoubleValue (1e-6),
MakeDoubleAccessor (&RandomWalk2dOutdoorMobilityModel::m_epsilon),
MakeDoubleChecker<double> ())
.AddAttribute ("MaxIterations",
"Maximum number of attempts to find an alternative next position"
"if the original one is inside a building.",
UintegerValue (100),
MakeUintegerAccessor (&RandomWalk2dOutdoorMobilityModel::m_maxIter),
MakeUintegerChecker<uint32_t> ())
;
return tid;
}
void
RandomWalk2dOutdoorMobilityModel::DoInitialize (void)
{
DoInitializePrivate ();
MobilityModel::DoInitialize ();
}
void
RandomWalk2dOutdoorMobilityModel::DoInitializePrivate (void)
{
m_helper.Update ();
double speed = m_speed->GetValue ();
double direction = m_direction->GetValue ();
Vector vector (std::cos (direction) * speed,
std::sin (direction) * speed,
0.0);
m_helper.SetVelocity (vector);
m_helper.Unpause ();
Time delayLeft;
if (m_mode == RandomWalk2dOutdoorMobilityModel::MODE_TIME)
{
delayLeft = m_modeTime;
}
else
{
delayLeft = Seconds (m_modeDistance / speed);
}
DoWalk (delayLeft);
}
void
RandomWalk2dOutdoorMobilityModel::DoWalk (Time delayLeft)
{
NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
Vector position = m_helper.GetCurrentPosition ();
Vector speed = m_helper.GetVelocity ();
Vector nextPosition = position;
nextPosition.x += speed.x * delayLeft.GetSeconds ();
nextPosition.y += speed.y * delayLeft.GetSeconds ();
m_event.Cancel ();
// check if the nextPosition is inside a building, or if the line
// from position to the next position intersects a building
auto outdoorBuilding = IsLineClearOfBuildings (position, nextPosition);
bool outdoor = std::get<0> (outdoorBuilding);
Ptr<Building> building = std::get<1> (outdoorBuilding);
if (m_bounds.IsInside (nextPosition))
{
if (outdoor)
{
m_event = Simulator::Schedule (delayLeft, &RandomWalk2dOutdoorMobilityModel::DoInitializePrivate, this);
}
else
{
NS_LOG_LOGIC ("NextPosition would lead into a building");
nextPosition = CalculateIntersectionFromOutside (position, nextPosition, building->GetBoundaries ());
Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::AvoidBuilding, this,
delayLeft - delay,
nextPosition
);
}
}
else
{
NS_LOG_LOGIC ("Out of bounding box");
nextPosition = m_bounds.CalculateIntersection (position, speed);
// check that this nextPosition is outdoor
auto outdoorBuilding = IsLineClearOfBuildings (position, nextPosition);
bool outdoor = std::get<0> (outdoorBuilding);
Ptr<Building> building = std::get<1> (outdoorBuilding);
if (outdoor)
{
Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::Rebound, this,
delayLeft - delay);
}
else
{
NS_LOG_LOGIC ("NextPosition would lead into a building");
nextPosition = CalculateIntersectionFromOutside (position, nextPosition, building->GetBoundaries ());
Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::AvoidBuilding, this,
delayLeft - delay,
nextPosition
);
}
}
NS_LOG_LOGIC ("Position " << position << " NextPosition " << nextPosition);
// store the previous position
m_prevPosition = position;
NotifyCourseChange ();
}
std::pair<bool, Ptr<Building> >
RandomWalk2dOutdoorMobilityModel::IsLineClearOfBuildings ( Vector currentPosition, Vector nextPosition ) const
{
NS_LOG_FUNCTION (this << currentPosition << nextPosition);
bool intersectBuilding = false;
double minIntersectionDistance = std::numeric_limits<double>::max ();
Ptr<Building> minIntersectionDistanceBuilding;
for (BuildingList::Iterator bit = BuildingList::Begin (); bit != BuildingList::End (); ++bit)
{
// check if this building intersects the line between the current and next positions
// this checks also if the next position is inside the building
if ((*bit)->IsIntersect (currentPosition, nextPosition))
{
NS_LOG_LOGIC ("Building " << (*bit)->GetBoundaries ()
<< " intersects the line between " << currentPosition
<< " and " << nextPosition);
auto intersection = CalculateIntersectionFromOutside (
currentPosition, nextPosition, (*bit)->GetBoundaries ());
double distance = CalculateDistance (intersection, currentPosition);
intersectBuilding = true;
if (distance < minIntersectionDistance)
{
minIntersectionDistance = distance;
minIntersectionDistanceBuilding = (*bit);
}
}
}
return std::make_pair (!intersectBuilding, minIntersectionDistanceBuilding);
}
Vector
RandomWalk2dOutdoorMobilityModel::CalculateIntersectionFromOutside (const Vector &current, const Vector &next, Box boundaries) const
{
NS_LOG_FUNCTION (this << " current " << current << " next " << next);
bool inside = boundaries.IsInside (current);
NS_ASSERT (!inside);
// get the closest side
Rectangle rect = Rectangle (boundaries.xMin, boundaries.xMax, boundaries.yMin, boundaries.yMax);
NS_LOG_INFO ("rect " << rect);
Rectangle::Side closestSide = rect.GetClosestSide (current);
double xIntersect = 0;
double yIntersect = 0;
switch (closestSide)
{
case Rectangle::RIGHT:
NS_LOG_INFO ("The closest side is RIGHT");
NS_ABORT_MSG_IF (next.x - current.x == 0, "x position not updated");
xIntersect = boundaries.xMax + m_epsilon;
yIntersect =
(next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
break;
case Rectangle::LEFT:
NS_LOG_INFO ("The closest side is LEFT");
xIntersect = boundaries.xMin - m_epsilon;
NS_ABORT_MSG_IF (next.x - current.x == 0, "x position not updated");
yIntersect =
(next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
break;
case Rectangle::TOP:
NS_LOG_INFO ("The closest side is TOP");
yIntersect = boundaries.yMax + m_epsilon;
NS_ABORT_MSG_IF (next.y - current.y == 0, "y position not updated");
xIntersect =
(next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
break;
case Rectangle::BOTTOM:
NS_LOG_INFO ("The closest side is BOTTOM");
yIntersect = boundaries.yMin - m_epsilon;
NS_ABORT_MSG_IF (next.y - current.y == 0, "y position not updated");
xIntersect =
(next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
break;
}
NS_LOG_INFO ("xIntersect " << xIntersect << " yIntersect " << yIntersect);
return Vector (xIntersect, yIntersect, 0);
}
void
RandomWalk2dOutdoorMobilityModel::Rebound (Time delayLeft)
{
NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
m_helper.UpdateWithBounds (m_bounds);
Vector position = m_helper.GetCurrentPosition ();
Vector speed = m_helper.GetVelocity ();
switch (m_bounds.GetClosestSide (position))
{
case Rectangle::RIGHT:
NS_LOG_INFO ("The closest side is RIGHT");
case Rectangle::LEFT:
NS_LOG_INFO ("The closest side is LEFT");
speed.x = -speed.x;
break;
case Rectangle::TOP:
NS_LOG_INFO ("The closest side is TOP");
case Rectangle::BOTTOM:
NS_LOG_INFO ("The closest side is BOTTOM");
speed.y = -speed.y;
break;
}
m_helper.SetVelocity (speed);
m_helper.Unpause ();
DoWalk (delayLeft);
}
void
RandomWalk2dOutdoorMobilityModel::AvoidBuilding (Time delayLeft, Vector intersectPosition)
{
NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
m_helper.Update ();
bool nextWouldBeInside = true;
uint32_t iter = 0;
while (nextWouldBeInside && iter < m_maxIter)
{
NS_LOG_INFO ("The next position would be inside a building, compute an alternative");
iter++;
double speed = m_speed->GetValue ();
double direction = m_direction->GetValue ();
Vector velocityVector (std::cos (direction) * speed,
std::sin (direction) * speed,
0.0);
m_helper.SetVelocity (velocityVector);
Vector nextPosition = intersectPosition;
nextPosition.x += velocityVector.x * delayLeft.GetSeconds ();
nextPosition.y += velocityVector.y * delayLeft.GetSeconds ();
// check if this is inside the current buildingBox
auto outdoorBuilding = IsLineClearOfBuildings (intersectPosition, nextPosition);
bool outdoor = std::get<0> (outdoorBuilding);
if (!outdoor)
{
NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
<< nextPosition << " " << outdoor << " building " << std::get<1> (outdoorBuilding)->GetBoundaries ());
}
else
{
NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
<< nextPosition << " " << outdoor);
}
if (outdoor && m_bounds.IsInside (nextPosition))
{
nextWouldBeInside = false;
}
}
// after m_maxIter iterations, the positions tested are all inside
// to avoid increasing m_maxIter too much, it is possible to perform a step back
// to the previous position and continue from there
if (iter >= m_maxIter)
{
NS_LOG_INFO ("Move back to the previous position");
// compute the difference between the previous position and the intersection
Vector posDiff = m_prevPosition - intersectPosition;
// compute the distance
double distance = CalculateDistance (m_prevPosition, intersectPosition);
double speed = distance / delayLeft.GetSeconds (); // compute the speed
NS_LOG_LOGIC ("prev " << m_prevPosition
<< " intersectPosition " << intersectPosition
<< " diff " << posDiff << " dist " << distance
);
Vector velocityVector (posDiff.x / distance * speed,
posDiff.y / distance * speed,
0.0);
m_helper.SetVelocity (velocityVector);
Vector nextPosition = intersectPosition;
nextPosition.x += velocityVector.x * delayLeft.GetSeconds ();
nextPosition.y += velocityVector.y * delayLeft.GetSeconds ();
// check if the path is clear
auto outdoorBuilding = IsLineClearOfBuildings (intersectPosition, nextPosition);
bool outdoor = std::get<0> (outdoorBuilding);
if (!outdoor)
{
NS_LOG_LOGIC ("The position is still inside after "
<< m_maxIter + 1 << " iterations, loop intersect "
<< intersectPosition << " nextPosition "
<< nextPosition << " " << outdoor
<< " building " << std::get<1> (outdoorBuilding)->GetBoundaries ());
// This error may be due to buildings being attached to one another, or to the boundary of the scenario.
NS_FATAL_ERROR ("Not able to find an outdoor position. Try to increase the attribute MaxIterations and check the position of the buildings in the scenario.");
}
else
{
NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
<< nextPosition << " " << outdoor);
}
}
m_helper.Unpause ();
DoWalk (delayLeft);
}
void
RandomWalk2dOutdoorMobilityModel::DoDispose (void)
{
// chain up
MobilityModel::DoDispose ();
}
Vector
RandomWalk2dOutdoorMobilityModel::DoGetPosition (void) const
{
m_helper.UpdateWithBounds (m_bounds);
return m_helper.GetCurrentPosition ();
}
void
RandomWalk2dOutdoorMobilityModel::DoSetPosition (const Vector &position)
{
NS_ASSERT (m_bounds.IsInside (position));
m_helper.SetPosition (position);
Simulator::Remove (m_event);
m_event = Simulator::ScheduleNow (&RandomWalk2dOutdoorMobilityModel::DoInitializePrivate, this);
}
Vector
RandomWalk2dOutdoorMobilityModel::DoGetVelocity (void) const
{
return m_helper.GetVelocity ();
}
int64_t
RandomWalk2dOutdoorMobilityModel::DoAssignStreams (int64_t stream)
{
m_speed->SetStream (stream);
m_direction->SetStream (stream + 1);
return 2;
}
} // namespace ns3

View File

@@ -0,0 +1,135 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
* Copyright (c) 2019 University of Padova
*
* 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Author: Michele Polese <michele.polese@gmail.com>
*/
#ifndef RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
#define RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
#include "ns3/object.h"
#include "ns3/nstime.h"
#include "ns3/event-id.h"
#include "ns3/rectangle.h"
#include "ns3/random-variable-stream.h"
#include "ns3/mobility-model.h"
#include "ns3/constant-velocity-helper.h"
#include "ns3/building.h"
namespace ns3 {
/**
* \ingroup mobility
* \brief 2D random walk mobility model which avoids buildings.
*
* This class reuses most of the code of RandomWalk2dMobilityModel,
* but adds the awareness of buildings objects which are avoided
* by moving users.
* Each instance moves with a speed and direction chosen at random
* with the user-provided random variables until
* either a fixed distance has been walked or until a fixed amount
* of time. If we hit one of the boundaries (specified by a rectangle)
* of the model, we rebound on the boundary with a reflexive angle
* and speed. If we hit one of the buildings, we rebound with a random
* direction which makes sure that the next step does not enter the building.
*
* The default values for the random variable that describes the speed is
* taken from Figure 1 in the paper:
* Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.
*/
class RandomWalk2dOutdoorMobilityModel : public MobilityModel
{
public:
/**
* Register this type with the TypeId system.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/** An enum representing the different working modes of this module. */
enum Mode
{
MODE_DISTANCE,
MODE_TIME
};
private:
/**
* \brief Performs the rebound of the node if it reaches a boundary
* \param timeLeft The remaining time of the walk
*/
void Rebound (Time timeLeft);
/**
* \brief Avoid a building
* \param timeLeft The remaining time of the walk
* \param intersectPosition The position at which the building is intersected
*/
void AvoidBuilding (Time delayLeft, Vector intersectPosition);
/**
* Walk according to position and velocity, until distance is reached,
* time is reached, or intersection with the bounding box, or building
*/
void DoWalk (Time timeLeft);
/**
* Perform initialization of the object before MobilityModel::DoInitialize ()
*/
void DoInitializePrivate (void);
/**
* Check if there is a building between two positions (or if the nextPosition is inside a building).
* The code is taken from MmWave3gppBuildingsPropagationLossModel from the NYU/UNIPD ns-3 mmWave module
* \param currentPosition The current position of the node
* \param nextPosition The position to check
* \return a pair with a boolean (true if the line between the two position does not intersect building),
* and a pointer which is 0 if the boolean is true, or it points to the building which is intersected
*/
std::pair<bool, Ptr<Building> > IsLineClearOfBuildings (Vector currentPosition, Vector nextPosition ) const;
/**
* Compute the intersecting point of the box represented by boundaries and the line between current and next
* Notice that we only consider a 2d plane
* \param current The current position
* \param next The next position
* \param boundaries The boundaries of the building we will intersect
* \return a vector with the position of the intersection
*/
Vector CalculateIntersectionFromOutside (const Vector &current, const Vector &next, const Box boundaries) const;
virtual void DoDispose (void);
virtual void DoInitialize (void);
virtual Vector DoGetPosition (void) const;
virtual void DoSetPosition (const Vector &position);
virtual Vector DoGetVelocity (void) const;
virtual int64_t DoAssignStreams (int64_t);
ConstantVelocityHelper m_helper; //!< helper for this object
EventId m_event; //!< stored event ID
enum Mode m_mode; //!< whether in time or distance mode
double m_modeDistance; //!< Change direction and speed after this distance
Time m_modeTime; //!< Change current direction and speed after this delay
Ptr<RandomVariableStream> m_speed; //!< rv for picking speed
Ptr<RandomVariableStream> m_direction; //!< rv for picking direction
Rectangle m_bounds; //!< Bounds of the area to cruise
double m_epsilon; //!< Tolerance for the intersection point with buildings
uint32_t m_maxIter; //!< Maximum number of tries to find the next position
Vector m_prevPosition; //!< Store the previous position in case a step back is needed
};
} // namespace ns3
#endif /* RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H */

View File

@@ -0,0 +1,167 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
* University of Padova
*
* 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
*/
#include "ns3/abort.h"
#include "ns3/test.h"
#include "ns3/config.h"
#include "ns3/building.h"
#include "ns3/building-position-allocator.h"
#include "ns3/random-walk-2d-outdoor-mobility-model.h"
#include "ns3/mobility-helper.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/double.h"
#include "ns3/pointer.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("OutdoorRandomWalkTest");
/**
* Test case for the class OutdoorRandomWalkTestCase. It checks if the
* positions visited by the user are outside buildings
*/
class OutdoorRandomWalkTestCase : public TestCase
{
public:
/**
* Constructor
*/
OutdoorRandomWalkTestCase ();
/**
* Destructor
*/
virtual ~OutdoorRandomWalkTestCase ();
private:
/**
* Builds the simulation scenario and perform the tests
*/
virtual void DoRun (void);
void CheckPositionOutdoor (Ptr<RandomWalk2dOutdoorMobilityModel> model);
std::vector<Ptr<Building> > m_buildings;
};
OutdoorRandomWalkTestCase::OutdoorRandomWalkTestCase ()
: TestCase ("Test case for the BuildingsChannelConditionModel"), m_buildings ()
{}
OutdoorRandomWalkTestCase::~OutdoorRandomWalkTestCase ()
{}
void
OutdoorRandomWalkTestCase::CheckPositionOutdoor (Ptr<RandomWalk2dOutdoorMobilityModel> model)
{
auto position = model->GetPosition ();
for (auto building : m_buildings)
{
NS_TEST_ASSERT_MSG_EQ (building->IsInside (position), false, "Position " << position << " is inside");
}
}
void
OutdoorRandomWalkTestCase::DoRun (void)
{
// create a grid of buildings
double buildingSizeX = 100; // m
double buildingSizeY = 50; // m
double streetWidth = 25; // m
double buildingHeight = 10; // m
uint32_t numBuildingsX = 20;
uint32_t numBuildingsY = 20;
double maxAxisX = (buildingSizeX + streetWidth) * numBuildingsX;
double maxAxisY = (buildingSizeY + streetWidth) * numBuildingsY;
for (uint32_t buildingIdX = 0; buildingIdX < numBuildingsX; ++buildingIdX)
{
for (uint32_t buildingIdY = 0; buildingIdY < numBuildingsY; ++buildingIdY)
{
Ptr < Building > building;
building = CreateObject<Building> ();
building->SetBoundaries (Box (buildingIdX * (buildingSizeX + streetWidth),
buildingIdX * (buildingSizeX + streetWidth) + buildingSizeX,
buildingIdY * (buildingSizeY + streetWidth),
buildingIdY * (buildingSizeY + streetWidth) + buildingSizeY,
0.0, buildingHeight));
building->SetNRoomsX (1);
building->SetNRoomsY (1);
building->SetNFloors (1);
m_buildings.push_back (building);
}
}
// create one node
NodeContainer nodes;
nodes.Create (1);
// set the RandomWalk2dOutdoorMobilityModel mobility model
MobilityHelper mobility;
mobility.SetMobilityModel ("ns3::RandomWalk2dOutdoorMobilityModel",
"Bounds", RectangleValue (
Rectangle (-streetWidth, maxAxisX, -streetWidth, maxAxisY)));
// create an OutdoorPositionAllocator and set its boundaries to match those of the mobility model
Ptr<OutdoorPositionAllocator> position = CreateObject<OutdoorPositionAllocator> ();
Ptr<UniformRandomVariable> xPos = CreateObject<UniformRandomVariable>();
xPos->SetAttribute ("Min", DoubleValue (-streetWidth));
xPos->SetAttribute ("Max", DoubleValue (maxAxisX));
Ptr<UniformRandomVariable> yPos = CreateObject<UniformRandomVariable>();
yPos->SetAttribute ("Min", DoubleValue (-streetWidth));
yPos->SetAttribute ("Max", DoubleValue (maxAxisY));
position->SetAttribute ("X", PointerValue (xPos));
position->SetAttribute ("Y", PointerValue (yPos));
mobility.SetPositionAllocator (position);
// install the mobility model
mobility.Install (nodes.Get (0));
auto mobilityModel = nodes.Get (0)->GetObject<RandomWalk2dOutdoorMobilityModel>();
// get maxChecks positions, check if they are outdoors
double testStep = 10; // s
int maxChecks = 1000;
for (int i = 0; i < maxChecks; ++i)
{
Simulator::Schedule (Seconds (i * testStep),
&OutdoorRandomWalkTestCase::CheckPositionOutdoor, this, mobilityModel);
}
Simulator::Stop (Seconds (maxChecks * testStep + 1));
Simulator::Run ();
Simulator::Destroy ();
}
/**
* Test suite for the buildings channel condition model
*/
class OutdoorRandomWalkTestSuite : public TestSuite
{
public:
OutdoorRandomWalkTestSuite ();
};
OutdoorRandomWalkTestSuite::OutdoorRandomWalkTestSuite ()
: TestSuite ("outdoor-random-walk-model", UNIT)
{
AddTestCase (new OutdoorRandomWalkTestCase, TestCase::QUICK);
}
static OutdoorRandomWalkTestSuite OutdoorRandomWalkTestSuite;

View File

@@ -16,6 +16,7 @@ def build(bld):
'helper/building-position-allocator.cc',
'helper/building-allocator.cc',
'helper/buildings-helper.cc',
'model/random-walk-2d-outdoor-mobility-model.cc',
]
module_test = bld.create_ns3_module_test_library('buildings')
@@ -25,6 +26,7 @@ def build(bld):
'test/buildings-pathloss-test.cc',
'test/buildings-shadowing-test.cc',
'test/buildings-channel-condition-model-test.cc',
'test/outdoor-random-walk-test.cc',
]
# Tests encapsulating example programs should be listed here
@@ -48,6 +50,7 @@ def build(bld):
'helper/building-allocator.h',
'helper/building-position-allocator.h',
'helper/buildings-helper.h',
'model/random-walk-2d-outdoor-mobility-model.h',
]
if (bld.env['ENABLE_EXAMPLES']):