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