1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 Dan Broyles
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Dan Broyles <dbroyl01@ku.edu>
19  */
20 #include <cmath>
21 #include "ns3/simulator.h"
22 #include "ns3/double.h"
23 #include "ns3/pointer.h"
24 #include "ns3/string.h"
25 #include "gauss-markov-mobility-model.h"
26 #include "position-allocator.h"
27 
28 namespace ns3 {
29 
30 NS_OBJECT_ENSURE_REGISTERED (GaussMarkovMobilityModel);
31 
32 TypeId
GetTypeId(void)33 GaussMarkovMobilityModel::GetTypeId (void)
34 {
35   static TypeId tid = TypeId ("ns3::GaussMarkovMobilityModel")
36     .SetParent<MobilityModel> ()
37     .SetGroupName ("Mobility")
38     .AddConstructor<GaussMarkovMobilityModel> ()
39     .AddAttribute ("Bounds",
40                    "Bounds of the area to cruise.",
41                    BoxValue (Box (-100.0, 100.0, -100.0, 100.0, 0.0, 100.0)),
42                    MakeBoxAccessor (&GaussMarkovMobilityModel::m_bounds),
43                    MakeBoxChecker ())
44     .AddAttribute ("TimeStep",
45                    "Change current direction and speed after moving for this time.",
46                    TimeValue (Seconds (1.0)),
47                    MakeTimeAccessor (&GaussMarkovMobilityModel::m_timeStep),
48                    MakeTimeChecker ())
49     .AddAttribute ("Alpha",
50                    "A constant representing the tunable parameter in the Gauss-Markov model.",
51                    DoubleValue (1.0),
52                    MakeDoubleAccessor (&GaussMarkovMobilityModel::m_alpha),
53                    MakeDoubleChecker<double> ())
54     .AddAttribute ("MeanVelocity",
55                    "A random variable used to assign the average velocity.",
56                    StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=1.0]"),
57                    MakePointerAccessor (&GaussMarkovMobilityModel::m_rndMeanVelocity),
58                    MakePointerChecker<RandomVariableStream> ())
59     .AddAttribute ("MeanDirection",
60                    "A random variable used to assign the average direction.",
61                    StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=6.283185307]"),
62                    MakePointerAccessor (&GaussMarkovMobilityModel::m_rndMeanDirection),
63                    MakePointerChecker<RandomVariableStream> ())
64     .AddAttribute ("MeanPitch",
65                    "A random variable used to assign the average pitch.",
66                    StringValue ("ns3::ConstantRandomVariable[Constant=0.0]"),
67                    MakePointerAccessor (&GaussMarkovMobilityModel::m_rndMeanPitch),
68                    MakePointerChecker<RandomVariableStream> ())
69     .AddAttribute ("NormalVelocity",
70                    "A gaussian random variable used to calculate the next velocity value.",
71                    StringValue ("ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]"), // Defaults to zero mean, and std dev = 1, and bound to +-10 of the mean
72                    MakePointerAccessor (&GaussMarkovMobilityModel::m_normalVelocity),
73                    MakePointerChecker<NormalRandomVariable> ())
74     .AddAttribute ("NormalDirection",
75                    "A gaussian random variable used to calculate the next direction value.",
76                    StringValue ("ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]"),
77                    MakePointerAccessor (&GaussMarkovMobilityModel::m_normalDirection),
78                    MakePointerChecker<NormalRandomVariable> ())
79     .AddAttribute ("NormalPitch",
80                    "A gaussian random variable used to calculate the next pitch value.",
81                    StringValue ("ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]"),
82                    MakePointerAccessor (&GaussMarkovMobilityModel::m_normalPitch),
83                    MakePointerChecker<NormalRandomVariable> ());
84 
85   return tid;
86 }
87 
GaussMarkovMobilityModel()88 GaussMarkovMobilityModel::GaussMarkovMobilityModel ()
89 {
90   m_meanVelocity = 0.0;
91   m_meanDirection = 0.0;
92   m_meanPitch = 0.0;
93   m_event = Simulator::ScheduleNow (&GaussMarkovMobilityModel::Start, this);
94   m_helper.Unpause ();
95 }
96 
97 void
Start(void)98 GaussMarkovMobilityModel::Start (void)
99 {
100   if (m_meanVelocity == 0.0)
101     {
102       //Initialize the mean velocity, direction, and pitch variables
103       m_meanVelocity = m_rndMeanVelocity->GetValue ();
104       m_meanDirection = m_rndMeanDirection->GetValue ();
105       m_meanPitch = m_rndMeanPitch->GetValue ();
106       double cosD = std::cos (m_meanDirection);
107       double cosP = std::cos (m_meanPitch);
108       double sinD = std::sin (m_meanDirection);
109       double sinP = std::sin (m_meanPitch);
110       //Initialize the starting velocity, direction, and pitch to be identical to the mean ones
111       m_Velocity = m_meanVelocity;
112       m_Direction = m_meanDirection;
113       m_Pitch = m_meanPitch;
114       //Set the velocity vector to give to the constant velocity helper
115       m_helper.SetVelocity (Vector (m_Velocity*cosD*cosP, m_Velocity*sinD*cosP, m_Velocity*sinP));
116     }
117   m_helper.Update ();
118 
119   //Get the next values from the gaussian distributions for velocity, direction, and pitch
120   double rv = m_normalVelocity->GetValue ();
121   double rd = m_normalDirection->GetValue ();
122   double rp = m_normalPitch->GetValue ();
123 
124   //Calculate the NEW velocity, direction, and pitch values using the Gauss-Markov formula:
125   //newVal = alpha*oldVal + (1-alpha)*meanVal + sqrt(1-alpha^2)*rv
126   //where rv is a random number from a normal (gaussian) distribution
127   double one_minus_alpha = 1 - m_alpha;
128   double sqrt_alpha = std::sqrt (1 - m_alpha*m_alpha);
129   m_Velocity  = m_alpha * m_Velocity  + one_minus_alpha * m_meanVelocity  + sqrt_alpha * rv;
130   m_Direction = m_alpha * m_Direction + one_minus_alpha * m_meanDirection + sqrt_alpha * rd;
131   m_Pitch     = m_alpha * m_Pitch     + one_minus_alpha * m_meanPitch     + sqrt_alpha * rp;
132 
133   //Calculate the linear velocity vector to give to the constant velocity helper
134   double cosDir = std::cos (m_Direction);
135   double cosPit = std::cos (m_Pitch);
136   double sinDir = std::sin (m_Direction);
137   double sinPit = std::sin (m_Pitch);
138   double vx = m_Velocity * cosDir * cosPit;
139   double vy = m_Velocity * sinDir * cosPit;
140   double vz = m_Velocity * sinPit;
141   m_helper.SetVelocity (Vector (vx, vy, vz));
142 
143   m_helper.Unpause ();
144 
145   DoWalk (m_timeStep);
146 }
147 
148 void
DoWalk(Time delayLeft)149 GaussMarkovMobilityModel::DoWalk (Time delayLeft)
150 {
151   m_helper.UpdateWithBounds (m_bounds);
152   Vector position = m_helper.GetCurrentPosition ();
153   Vector speed = m_helper.GetVelocity ();
154   Vector nextPosition = position;
155   nextPosition.x += speed.x * delayLeft.GetSeconds ();
156   nextPosition.y += speed.y * delayLeft.GetSeconds ();
157   nextPosition.z += speed.z * delayLeft.GetSeconds ();
158   if (delayLeft.GetSeconds () < 0.0) delayLeft = Seconds (1.0);
159 
160   // Make sure that the position by the next time step is still within the boundary.
161   // If out of bounds, then alter the velocity vector and average direction to keep the position in bounds
162   if (m_bounds.IsInside (nextPosition))
163     {
164       m_event = Simulator::Schedule (delayLeft, &GaussMarkovMobilityModel::Start, this);
165     }
166   else
167     {
168       if (nextPosition.x > m_bounds.xMax || nextPosition.x < m_bounds.xMin)
169         {
170           speed.x = -speed.x;
171           m_meanDirection = M_PI - m_meanDirection;
172         }
173 
174       if (nextPosition.y > m_bounds.yMax || nextPosition.y < m_bounds.yMin)
175         {
176           speed.y = -speed.y;
177           m_meanDirection = -m_meanDirection;
178         }
179 
180       if (nextPosition.z > m_bounds.zMax || nextPosition.z < m_bounds.zMin)
181         {
182           speed.z = -speed.z;
183           m_meanPitch = -m_meanPitch;
184         }
185 
186       m_Direction = m_meanDirection;
187       m_Pitch = m_meanPitch;
188       m_helper.SetVelocity (speed);
189       m_helper.Unpause ();
190       m_event = Simulator::Schedule (delayLeft, &GaussMarkovMobilityModel::Start, this);
191     }
192   NotifyCourseChange ();
193 }
194 
195 void
DoDispose(void)196 GaussMarkovMobilityModel::DoDispose (void)
197 {
198   // chain up
199   MobilityModel::DoDispose ();
200 }
201 
202 Vector
DoGetPosition(void) const203 GaussMarkovMobilityModel::DoGetPosition (void) const
204 {
205   m_helper.Update ();
206   return m_helper.GetCurrentPosition ();
207 }
208 void
DoSetPosition(const Vector & position)209 GaussMarkovMobilityModel::DoSetPosition (const Vector &position)
210 {
211   m_helper.SetPosition (position);
212   m_event.Cancel ();
213   m_event = Simulator::ScheduleNow (&GaussMarkovMobilityModel::Start, this);
214 }
215 Vector
DoGetVelocity(void) const216 GaussMarkovMobilityModel::DoGetVelocity (void) const
217 {
218   return m_helper.GetVelocity ();
219 }
220 
221 int64_t
DoAssignStreams(int64_t stream)222 GaussMarkovMobilityModel::DoAssignStreams (int64_t stream)
223 {
224   m_rndMeanVelocity->SetStream (stream);
225   m_normalVelocity->SetStream (stream + 1);
226   m_rndMeanDirection->SetStream (stream + 2);
227   m_normalDirection->SetStream (stream + 3);
228   m_rndMeanPitch->SetStream (stream + 4);
229   m_normalPitch->SetStream (stream + 5);
230   return 6;
231 }
232 
233 } // namespace ns3
234