SUMO - Simulation of Urban MObility
MSCFModel.cpp
Go to the documentation of this file.
1 /****************************************************************************/
12 // The car-following model abstraction
13 /****************************************************************************/
14 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
15 // Copyright (C) 2001-2017 DLR (http://www.dlr.de/) and contributors
16 /****************************************************************************/
17 //
18 // This file is part of SUMO.
19 // SUMO is free software: you can redistribute it and/or modify
20 // it under the terms of the GNU General Public License as published by
21 // the Free Software Foundation, either version 3 of the License, or
22 // (at your option) any later version.
23 //
24 /****************************************************************************/
25 
26 
27 // ===========================================================================
28 // included modules
29 // ===========================================================================
30 #ifdef _MSC_VER
31 #include <windows_config.h>
32 #else
33 #include <config.h>
34 #endif
35 
36 #include <cmath>
37 #include <microsim/MSGlobals.h>
38 #include <microsim/MSVehicleType.h>
39 #include <microsim/MSVehicle.h>
40 #include <microsim/MSLane.h>
42 #include "MSCFModel.h"
43 
44 
45 // ===========================================================================
46 // method definitions
47 // ===========================================================================
48 MSCFModel::MSCFModel(const MSVehicleType* vtype, double accel,
49  double decel, double emergencyDecel, double apparentDecel, double headwayTime) :
50  myType(vtype),
51  myAccel(accel),
52  myDecel(decel),
53  myEmergencyDecel(emergencyDecel),
54  myApparentDecel(apparentDecel),
55  myHeadwayTime(headwayTime) {
56 }
57 
58 
60 
61 
63 
64 
65 double
66 MSCFModel::brakeGap(const double speed, const double decel, const double headwayTime) {
68  return brakeGapEuler(speed, decel, headwayTime);
69  } else {
70  // ballistic
71  if (speed <= 0) {
72  return 0.;
73  } else {
74  return speed * (headwayTime + 0.5 * speed / decel);
75  }
76  }
77 }
78 
79 
80 double
81 MSCFModel::brakeGapEuler(const double speed, const double decel, const double headwayTime) {
82  /* one possibility to speed this up is to calculate speedReduction * steps * (steps+1) / 2
83  for small values of steps (up to 10 maybe) and store them in an array */
84  const double speedReduction = ACCEL2SPEED(decel);
85  const int steps = int(speed / speedReduction);
86  return SPEED2DIST(steps * speed - speedReduction * steps * (steps + 1) / 2) + speed * headwayTime;
87 }
88 
89 
90 double
91 MSCFModel::freeSpeed(const double currentSpeed, const double decel, const double dist, const double targetSpeed, const bool onInsertion) {
92  // XXX: (Leo) This seems to be exclusively called with decel = myDecel (max deceleration) and is not overridden
93  // by any specific CFModel. That may cause undesirable hard braking (at junctions where the vehicle
94  // changes to a road with a lower speed limit).
95 
97  // adapt speed to succeeding lane, no reaction time is involved
98  // when breaking for y steps the following distance g is covered
99  // (drive with v in the final step)
100  // g = (y^2 + y) * 0.5 * b + y * v
101  // y = ((((sqrt((b + 2.0*v)*(b + 2.0*v) + 8.0*b*g)) - b)*0.5 - v)/b)
102  const double v = SPEED2DIST(targetSpeed);
103  if (dist < v) {
104  return targetSpeed;
105  }
106  const double b = ACCEL2DIST(decel);
107  const double y = MAX2(0.0, ((sqrt((b + 2.0 * v) * (b + 2.0 * v) + 8.0 * b * dist) - b) * 0.5 - v) / b);
108  const double yFull = floor(y);
109  const double exactGap = (yFull * yFull + yFull) * 0.5 * b + yFull * v + (y > yFull ? v : 0.0);
110  const double fullSpeedGain = (yFull + (onInsertion ? 1. : 0.)) * ACCEL2SPEED(decel);
111  return DIST2SPEED(MAX2(0.0, dist - exactGap) / (yFull + 1)) + fullSpeedGain + targetSpeed;
112  } else {
113  // ballistic update (Leo)
114  // calculate maximum next speed vN that is adjustable to vT=targetSpeed after a distance d=dist
115  // and given a maximal deceleration b=decel, denote the current speed by v0.
116  // the distance covered by a trajectory that attains vN in the next timestep and decelerates afterwards
117  // with b is given as
118  // d = 0.5*dt*(v0+vN) + (t-dt)*vN - 0.5*b*(t-dt)^2, (1)
119  // where time t of arrival at d with speed vT is
120  // t = dt + (vN-vT)/b. (2)
121  // We insert (2) into (1) to obtain
122  // d = 0.5*dt*(v0+vN) + vN*(vN-vT)/b - 0.5*b*((vN-vT)/b)^2
123  // 0 = (dt*b*v0 - vT*vT - 2*b*d) + dt*b*vN + vN*vN
124  // and solve for vN
125 
126  assert(currentSpeed >= 0);
127  assert(targetSpeed >= 0);
128 
129  const double dt = onInsertion ? 0 : TS; // handles case that vehicle is inserted just now (at the end of move)
130  const double v0 = currentSpeed;
131  const double vT = targetSpeed;
132  const double b = decel;
133  const double d = dist - NUMERICAL_EPS; // prevent returning a value > targetSpeed due to rounding errors
134 
135  // Solvability for positive vN (if d is small relative to v0):
136  // 1) If 0.5*(v0+vT)*dt > d, we set vN=vT.
137  // (In case vT<v0, this implies that on the interpolated trajectory there are points beyond d where
138  // the interpolated velocity is larger than vT, but at least on the temporal discretization grid, vT is not exceeded)
139  // 2) We ignore the (possible) constraint vN >= v0 - b*dt, which could lead to a problem if v0 - t*b > vT.
140  // (moveHelper() is responsible for assuring that the next velocity is chosen in accordance with maximal decelerations)
141 
142  if (0.5 * (v0 + vT)*dt >= d) {
143  return vT; // (#)
144  }
145 
146  const double q = ((dt * v0 - 2 * d) * b - vT * vT); // (q < 0 is fulfilled because of (#))
147  const double p = 0.5 * b * dt;
148  return -p + sqrt(p * p - q);
149  }
150 }
151 
152 double
153 MSCFModel::moveHelper(MSVehicle* const veh, double vPos) const {
154  const double oldV = veh->getSpeed(); // save old v for optional acceleration computation
155  const double vSafe = MIN2(vPos, veh->processNextStop(vPos)); // process stops
156  // we need the acceleration for emission computation;
157  // in this case, we neglect dawdling, nonetheless, using
158  // vSafe does not incorporate speed reduction due to interaction
159  // on lane changing
160  double vMin, vNext;
161  const double vMax = MIN3(veh->getMaxSpeedOnLane(), maxNextSpeed(oldV, veh), vSafe);
163  // we cannot rely on never braking harder than maxDecel because TraCI or strange cf models may decide to do so
164  // vMin = MIN2(getSpeedAfterMaxDecel(oldV), vMax);
165  vMin = MIN2(minNextSpeed(oldV, veh), vMax);
166  vNext = veh->getLaneChangeModel().patchSpeed(vMin, vMax, vMax, *this);
167  } else {
168  // for ballistic update, negative vnext must be allowed to
169  // indicate a stop within the coming timestep (i.e., to attain negative values)
170  vMin = MIN2(minNextSpeed(oldV, veh), vMax);
171  vNext = veh->getLaneChangeModel().patchSpeed(vMin, vMax, vMax, *this);
172  // (Leo) moveHelper() is responsible for assuring that the next
173  // velocity is chosen in accordance with maximal decelerations.
174  // At this point vNext may also be negative indicating a stop within next step.
175  // Moreover, because maximumSafeStopSpeed() does not consider deceleration bounds
176  // vNext can be a large negative value at this point. We cap vNext here.
177  vNext = MAX2(vNext, vMin);
178  }
179 
180  return vNext;
181 }
182 
183 
184 double
185 MSCFModel::interactionGap(const MSVehicle* const veh, double vL) const {
186  // Resolve the vsafe equation to gap. Assume predecessor has
187  // speed != 0 and that vsafe will be the current speed plus acceleration,
188  // i.e that with this gap there will be no interaction.
189  const double vNext = MIN2(maxNextSpeed(veh->getSpeed(), veh), veh->getLane()->getVehicleMaxSpeed(veh));
190  const double gap = (vNext - vL) *
191  ((veh->getSpeed() + vL) / (2.*myDecel) + myHeadwayTime) +
192  vL * myHeadwayTime;
193 
194  // Don't allow timeHeadWay < deltaT situations.
195  return MAX2(gap, SPEED2DIST(vNext));
196 }
197 
198 
199 double
200 MSCFModel::maxNextSpeed(double speed, const MSVehicle* const /*veh*/) const {
201  return MIN2(speed + (double) ACCEL2SPEED(getMaxAccel()), myType->getMaxSpeed());
202 }
203 
204 
205 double
206 MSCFModel::minNextSpeed(double speed, const MSVehicle* const /*veh*/) const {
208 // return MAX2(speed - ACCEL2SPEED(getMaxDecel()), 0.);
209  return MAX2(speed - ACCEL2SPEED(myEmergencyDecel), 0.);
210  } else {
211  // NOTE: ballistic update allows for negative speeds to indicate a stop within the next timestep
212 // return speed - ACCEL2SPEED(getMaxDecel());
213  return speed - ACCEL2SPEED(myEmergencyDecel);
214  }
215 }
216 
217 
218 double
219 MSCFModel::freeSpeed(const MSVehicle* const /* veh */, double speed, double seen, double maxSpeed, const bool onInsertion) const {
220  double vSafe = freeSpeed(speed, myDecel, seen, maxSpeed, onInsertion);
221  return vSafe;
222 }
223 
224 
225 double
226 MSCFModel::insertionFollowSpeed(const MSVehicle* const /* v */, double speed, double gap2pred, double predSpeed, double predMaxDecel) const {
228  return maximumSafeFollowSpeed(gap2pred, speed, predSpeed, predMaxDecel);
229  } else {
230  // NOTE: Even for ballistic update, the current speed is irrelevant at insertion, therefore passing 0. (Leo)
231  return maximumSafeFollowSpeed(gap2pred, 0., predSpeed, predMaxDecel, true);
232  }
233 }
234 
235 
236 double
237 MSCFModel::insertionStopSpeed(const MSVehicle* const veh, double speed, double gap) const {
239  return stopSpeed(veh, speed, gap);
240  } else {
241  return MIN2(maximumSafeStopSpeed(gap, 0., true, 0.), myType->getMaxSpeed());
242  }
243 }
244 
245 
246 double
247 MSCFModel::followSpeedTransient(double duration, const MSVehicle* const /*veh*/, double /*speed*/, double gap2pred, double predSpeed, double predMaxDecel) const {
248  // minimium distance covered by the leader if braking
249  double leaderMinDist = gap2pred + distAfterTime(duration, predSpeed, predMaxDecel);
250  // if ego would not brake it could drive with speed leaderMinDist / duration
251  // due to potentential ego braking it can safely drive faster
253  // number of potential braking steps
254  int a = (int)ceil(duration / TS - TS);
255  // can we brake for the whole time?
256  const double bg = brakeGap(a * myDecel, myDecel, 0);
257  if (bg <= leaderMinDist) {
258  // braking continuously for duration
259  // distance reduction due to braking
260  double b = TS * getMaxDecel() * 0.5 * (a * a - a);
261  if (gDebugFlag2) std::cout << " followSpeedTransient"
262  << " duration=" << duration
263  << " gap=" << gap2pred
264  << " leaderMinDist=" << leaderMinDist
265  << " decel=" << getMaxDecel()
266  << " a=" << a
267  << " bg=" << bg
268  << " b=" << b
269  << " x=" << (b + leaderMinDist) / duration
270  << "\n";
271  return (b + leaderMinDist) / duration;
272  } else {
273  // @todo improve efficiency
274  double bg = 0;
275  double speed = 0;
276  while (bg < leaderMinDist) {
277  speed += ACCEL2SPEED(myDecel);
278  bg += SPEED2DIST(speed);
279  }
280  speed -= DIST2SPEED(bg - leaderMinDist);
281  return speed;
282  }
283  } else {
284  // can we brake for the whole time?
285  const double fullBrakingSeconds = sqrt(leaderMinDist * 2 / myDecel);
286  if (fullBrakingSeconds >= duration) {
287  // braking continuously for duration
288  // average speed after braking for duration is x2 = x - 0.5 * duration * myDecel
289  // x2 * duration <= leaderMinDist must hold
290  return leaderMinDist / duration + duration * getMaxDecel() / 2;
291  } else {
292  return fullBrakingSeconds * myDecel;
293  }
294  }
295 }
296 
297 double
298 MSCFModel::distAfterTime(double t, double speed, double decel) {
299  assert(decel > 0);
300  if (speed <= decel * t) {
301  // braking to a full stop
302  return brakeGap(speed, decel, 0);
303  }
305  // @todo improve efficiency
306  double result = 0;
307  while (t > 0) {
308  speed -= ACCEL2SPEED(decel);
309  result += MAX2(0.0, SPEED2DIST(speed));
310  t -= TS;
311  }
312  return result;
313  } else {
314  const double speed2 = speed - t * decel;
315  return 0.5 * (speed + speed2) * t;
316  }
317 }
318 
319 SUMOTime
320 MSCFModel::getMinimalArrivalTime(double dist, double currentSpeed, double arrivalSpeed) const {
321  const double accel = (arrivalSpeed >= currentSpeed) ? getMaxAccel() : -getMaxDecel();
322  const double accelTime = (arrivalSpeed - currentSpeed) / accel;
323  const double accelWay = accelTime * (arrivalSpeed + currentSpeed) * 0.5;
324  const double nonAccelWay = MAX2(0., dist - accelWay);
325  // will either drive as fast as possible and decelerate as late as possible
326  // or accelerate as fast as possible and then hold that speed
327  const double nonAccelSpeed = MAX3(currentSpeed, arrivalSpeed, SUMO_const_haltingSpeed);
328  return TIME2STEPS(accelTime + nonAccelWay / nonAccelSpeed);
329 }
330 
331 
332 double
333 MSCFModel::estimateArrivalTime(double dist, double speed, double maxSpeed, double accel) const {
334  assert(speed >= 0.);
335  assert(dist >= 0.);
336 
337  if (dist == 0.) {
338  return 0.;
339  }
340 
341  if ((accel < 0. && -0.5 * speed * speed / accel < dist) || (accel <= 0. && speed == 0.)) {
342  // distance will never be covered with these values
343  return INVALID_DOUBLE;
344  }
345 
346  if (accel == 0.) {
347  return dist / speed;
348  }
349 
350  double p = speed / accel;
351 
352  if (accel < 0.) {
353  // we already know, that the distance will be covered despite breaking
354  return (-p - sqrt(p * p + 2 * dist / accel));
355  }
356 
357  // Here, accel > 0
358  // t1 is the time to use the given acceleration
359  double t1 = (maxSpeed - speed) / accel;
360  // distance covered until t1
361  double d1 = speed * t1 + 0.5 * accel * t1 * t1;
362  if (d1 >= dist) {
363  // dist is covered before changing the speed
364  return (-p + sqrt(p * p + 2 * dist / accel));
365  } else {
366  return (-p + sqrt(p * p + 2 * d1 / accel)) + (dist - d1) / maxSpeed;
367  }
368 
369 }
370 
371 
372 
373 double
374 MSCFModel::getMinimalArrivalSpeed(double dist, double currentSpeed) const {
375  // ballistic update
376  return estimateSpeedAfterDistance(dist - currentSpeed * getHeadwayTime(), currentSpeed, -getMaxDecel());
377 }
378 
379 
380 double
381 MSCFModel::getMinimalArrivalSpeedEuler(double dist, double currentSpeed) const {
382  double arrivalSpeedBraking;
383  // Because we use a continuous formula for computing the possible slow-down
384  // we need to handle the mismatch with the discrete dynamics
385  if (dist < currentSpeed) {
386  arrivalSpeedBraking = INVALID_SPEED; // no time left for braking after this step
387  // (inserted max() to get rid of arrivalSpeed dependency within method) (Leo)
388  } else if (2 * (dist - currentSpeed * getHeadwayTime()) * -getMaxDecel() + currentSpeed * currentSpeed >= 0) {
389  arrivalSpeedBraking = estimateSpeedAfterDistance(dist - currentSpeed * getHeadwayTime(), currentSpeed, -getMaxDecel());
390  } else {
391  arrivalSpeedBraking = getMaxDecel();
392  }
393  return arrivalSpeedBraking;
394 }
395 
396 
397 
398 
399 double
400 MSCFModel::gapExtrapolation(const double duration, const double currentGap, double v1, double v2, double a1, double a2, const double maxV1, const double maxV2) {
401 
402  double newGap = currentGap;
403 
405  for (unsigned int steps = 1; steps * TS <= duration; ++steps) {
406  v1 = MIN2(MAX2(v1 + a1, 0.), maxV1);
407  v2 = MIN2(MAX2(v2 + a2, 0.), maxV2);
408  newGap += TS * (v1 - v2);
409  }
410  } else {
411  // determine times t1, t2 for which vehicles can break until stop (within duration)
412  // and t3, t4 for which they reach their maximal speed on their current lanes.
413  double t1 = 0, t2 = 0, t3 = 0, t4 = 0;
414 
415  // t1: ego veh stops
416  if (a1 < 0 && v1 > 0) {
417  const double leaderStopTime = - v1 / a1;
418  t1 = MIN2(leaderStopTime, duration);
419  } else if (a1 >= 0) {
420  t1 = duration;
421  }
422  // t2: veh2 stops
423  if (a2 < 0 && v2 > 0) {
424  const double followerStopTime = -v2 / a2;
425  t2 = MIN2(followerStopTime, duration);
426  } else if (a2 >= 0) {
427  t2 = duration;
428  }
429  // t3: ego veh reaches vMax
430  if (a1 > 0 && v1 < maxV1) {
431  const double leaderMaxSpeedTime = (maxV1 - v1) / a1;
432  t3 = MIN2(leaderMaxSpeedTime, duration);
433  } else if (a1 <= 0) {
434  t3 = duration;
435  }
436  // t4: veh2 reaches vMax
437  if (a2 > 0 && v2 < maxV2) {
438  const double followerMaxSpeedTime = (maxV2 - v2) / a2;
439  t4 = MIN2(followerMaxSpeedTime, duration);
440  } else if (a2 <= 0) {
441  t4 = duration;
442  }
443 
444  // NOTE: this assumes that the accelerations a1 and a2 are constant over the next
445  // followerBreakTime seconds (if no vehicle stops before or reaches vMax)
446  std::list<double> l;
447  l.push_back(t1);
448  l.push_back(t2);
449  l.push_back(t3);
450  l.push_back(t4);
451  l.sort();
452  std::list<double>::const_iterator i;
453  double tLast = 0.;
454  for (i = l.begin(); i != l.end(); ++i) {
455  if (*i != tLast) {
456  double dt = MIN2(*i, duration) - tLast; // time between *i and tLast
457  double dv = v1 - v2; // current velocity difference
458  double da = a1 - a2; // current acceleration difference
459  newGap += dv * dt + da * dt * dt / 2.; // update gap
460  v1 += dt * a1;
461  v2 += dt * a2;
462  }
463  if (*i == t1 || *i == t3) {
464  // ego veh reached velocity bound
465  a1 = 0.;
466  }
467 
468  if (*i == t2 || *i == t4) {
469  // veh2 reached velocity bound
470  a2 = 0.;
471  }
472 
473  tLast = MIN2(*i, duration);
474  if (tLast == duration) {
475  break;
476  }
477  }
478 
479  if (duration != tLast) {
480  // (both vehicles have zero acceleration)
481  assert(a1 == 0. && a2 == 0.);
482  double dt = duration - tLast; // remaining time until duration
483  double dv = v1 - v2; // current velocity difference
484  newGap += dv * dt; // update gap
485  }
486  }
487 
488  return newGap;
489 }
490 
491 
492 
493 double
494 MSCFModel::passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed) {
495 
496  assert(passedPos <= currentPos && passedPos >= lastPos && currentPos > lastPos);
497  assert(currentSpeed >= 0);
498 
499  if (passedPos > currentPos || passedPos < lastPos) {
500  std::stringstream ss;
501  // Debug (Leo)
503  // NOTE: error is guarded to maintain original test output for euler update (Leo).
504  ss << "passingTime(): given argument passedPos = " << passedPos << " doesn't lie within [lastPos, currentPos] = [" << lastPos << ", " << currentPos << "]\nExtrapolating...";
505  std::cout << ss.str() << "\n";
506  WRITE_ERROR(ss.str());
507  }
508  const double lastCoveredDist = currentPos - lastPos;
509  const double extrapolated = passedPos > currentPos ? TS * (passedPos - lastPos) / lastCoveredDist : TS * (currentPos - passedPos) / lastCoveredDist;
510  return extrapolated;
511  } else if (currentSpeed < 0) {
512  WRITE_ERROR("passingTime(): given argument 'currentSpeed' is negative. This case is not handled yet.");
513  return -1;
514  }
515 
516  const double distanceOldToPassed = passedPos - lastPos; // assert: >=0
517 
519  // euler update (constantly moving with currentSpeed during [0,TS])
520  const double t = distanceOldToPassed / currentSpeed;
521  return MIN2(TS, MAX2(0., t)); //rounding errors could give results out of the admissible result range
522 
523  } else {
524  // ballistic update (constant acceleration a during [0,TS], except in case of a stop)
525 
526  // determine acceleration
527  double a;
528  if (currentSpeed > 0) {
529  // the acceleration was constant within the last time step
530  a = SPEED2ACCEL(currentSpeed - lastSpeed);
531  } else {
532  // the currentSpeed is zero (the last was not because lastPos<currentPos).
533  assert(currentSpeed == 0 && lastSpeed != 0);
534  // In general the stop has taken place within the last time step.
535  // The acceleration (a<0) is obtained from
536  // deltaPos = - lastSpeed^2/(2*a)
537  a = lastSpeed * lastSpeed / (2 * (lastPos - currentPos));
538 
539  assert(a < 0);
540  }
541 
542  // determine passing time t
543  // we solve distanceOldToPassed = lastSpeed*t + a*t^2/2
544  if (fabs(a) < NUMERICAL_EPS) {
545  // treat as constant speed within [0, TS]
546  const double t = 2 * distanceOldToPassed / (lastSpeed + currentSpeed);
547  return MIN2(TS, MAX2(0., t)); //rounding errors could give results out of the admissible result range
548  } else if (a > 0) {
549  // positive acceleration => only one positive solution
550  const double va = lastSpeed / a;
551  const double t = -va + sqrt(va * va + 2 * distanceOldToPassed / a);
552  assert(t < 1 && t >= 0);
553  return t;
554  } else {
555  // negative acceleration => two positive solutions (pick the smaller one.)
556  const double va = lastSpeed / a;
557  const double t = -va - sqrt(va * va + 2 * distanceOldToPassed / a);
558  assert(t < 1 && t >= 0);
559  return t;
560  }
561  }
562 }
563 
564 
565 double
566 MSCFModel::speedAfterTime(const double t, const double v0, const double dist) {
567  assert(dist >= 0);
568  assert(t >= 0 && t <= TS);
570  // euler: constant speed within [0,TS]
571  return DIST2SPEED(dist);
572  } else {
573  // ballistic: piecewise constant acceleration in [0,TS] (may become 0 for a stop within TS)
574  // We reconstruct acceleration at time t=0. Note that the covered distance in case
575  // of a stop exactly at t=TS is TS*v0/2.
576  if (dist < TS * v0 / 2) {
577  // stop must have occured within [0,TS], use dist = -v0^2/(2a) (stopping dist),
578  // i.e., a = -v0^2/(2*dist)
579  const double accel = - v0 * v0 / (2 * dist);
580  // The speed at time t is then
581  return v0 + accel * t;
582  } else {
583  // no stop occured within [0,TS], thus (from dist = v0*TS + accel*TS^2/2)
584  const double accel = 2 * (dist / TS - v0) / TS;
585  // The speed at time t is then
586  return v0 + accel * t;
587  }
588  }
589 }
590 
591 
592 
593 
594 double
595 MSCFModel::estimateSpeedAfterDistance(const double dist, const double v, const double accel) const {
596  // dist=v*t + 0.5*accel*t^2, solve for t and use v1 = v + accel*t
597  return MAX2(0., MIN2(myType->getMaxSpeed(),
598  (double)sqrt(2 * dist * accel + v * v)));
599 }
600 
601 
602 
603 double
604 MSCFModel::maximumSafeStopSpeed(double g /*gap*/, double v /*currentSpeed*/, bool onInsertion, double headway) const {
606  return maximumSafeStopSpeedEuler(g);
607  } else {
608  return maximumSafeStopSpeedBallistic(g, v, onInsertion, headway);
609  }
610 }
611 
612 
613 double
615  gap -= NUMERICAL_EPS; // lots of code relies on some slack XXX: it shouldn't...
616  if (gap <= 0) {
617  return 0;
618  } else if (gap <= ACCEL2SPEED(myDecel)) {
619  // workaround for #2310
620  return MIN2(ACCEL2SPEED(myDecel), DIST2SPEED(gap));
621  }
622  const double g = gap;
623  const double b = ACCEL2SPEED(myDecel);
624  const double t = myHeadwayTime;
625  const double s = TS;
626 
627 
628  // h = the distance that would be covered if it were possible to stop
629  // exactly after gap and decelerate with b every simulation step
630  // h = 0.5 * n * (n-1) * b * s + n * b * t (solve for n)
631  //n = ((1.0/2.0) - ((t + (pow(((s*s) + (4.0*((s*((2.0*h/b) - t)) + (t*t)))), (1.0/2.0))*sign/2.0))/s));
632  const double n = floor(.5 - ((t + (sqrt(((s * s) + (4.0 * ((s * (2.0 * g / b - t)) + (t * t))))) * -0.5)) / s));
633  const double h = 0.5 * n * (n - 1) * b * s + n * b * t;
634  assert(h <= g + NUMERICAL_EPS);
635  // compute the additional speed that must be used during deceleration to fix
636  // the discrepancy between g and h
637  const double r = (g - h) / (n * s + t);
638  const double x = n * b + r;
639  assert(x >= 0);
640  return x;
641 }
642 
643 
644 double
645 MSCFModel::maximumSafeStopSpeedBallistic(double g /*gap*/, double v /*currentSpeed*/, bool onInsertion, double headway) const {
646  // decrease gap slightly (to avoid passing end of lane by values of magnitude ~1e-12, when exact stop is required)
647  g = MAX2(0., g - NUMERICAL_EPS);
648  headway = headway >= 0 ? headway : myHeadwayTime;
649 
650  // (Leo) Note that in contrast to the Euler update, for the ballistic update
651  // the distance covered in the coming step depends on the current velocity, in general.
652  // one exception is the situation when the vehicle is just being inserted.
653  // In that case, it will not cover any distance until the next timestep by convention.
654 
655  // We treat the latter case first:
656  if (onInsertion) {
657  // The distance covered with constant insertion speed v0 until time tau is given as
658  // G1 = tau*v0
659  // The distance covered between time tau and the stopping moment at time tau+v0/b is
660  // G2 = v0^2/(2b),
661  // where b is an assumed constant deceleration (= myDecel)
662  // We solve g = G1 + G2 for v0:
663  const double btau = myDecel * headway;
664  const double v0 = -btau + sqrt(btau * btau + 2 * myDecel * g);
665  return v0;
666  }
667 
668  // In the usual case during the driving task, the vehicle goes by
669  // a current speed v0=v, and we seek to determine a safe acceleration a (possibly <0)
670  // such that starting to break after accelerating with a for the time tau
671  // still allows us to stop in time.
672 
673  const double tau = headway;
674  const double v0 = MAX2(0., v);
675  // We first consider the case that a stop has to take place within time tau
676  if (v0 * tau >= 2 * g) {
677  if (g == 0.) {
678  if (v0 > 0.) {
679  // indicate to brake as hard as possible
680  return -INVALID_SPEED;
681  } else {
682  // stay stopped
683  return 0.;
684  }
685  }
686  // In general we solve g = v0^2/(-2a), where the the rhs is the distance
687  // covered until stop when breaking with a<0
688  const double a = -v0 * v0 / (2 * g);
689  return v0 + a * TS;
690  }
691 
692  // The last case corresponds to a situation, where the vehicle may go with a positive
693  // speed v1 = v0 + tau*a after time tau.
694  // The distance covered until time tau is given as
695  // G1 = tau*(v0+v1)/2
696  // The distance covered between time tau and the stopping moment at time tau+v1/b is
697  // G2 = v1^2/(2b),
698  // where b is an assumed constant deceleration (= myDecel)
699  // We solve g = G1 + G2 for v1>0:
700  // <=> 0 = v1^2 + b*tau*v1 + b*tau*v0 - 2bg
701  // => v1 = -b*tau/2 + sqrt( (b*tau)^2/4 + b(2g - tau*v0) )
702 
703  const double btau2 = myDecel * tau / 2;
704  const double v1 = -btau2 + sqrt(btau2 * btau2 + myDecel * (2 * g - tau * v0));
705  const double a = (v1 - v0) / tau;
706  return v0 + a * TS;
707 }
708 
709 
711 double
712 MSCFModel::maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion) const {
713  // the speed is safe if allows the ego vehicle to come to a stop behind the leader even if
714  // the leaders starts braking hard until stopped
715  // unfortunately it is not sufficient to compare stopping distances if the follower can brake harder than the leader
716  // (the trajectories might intersect before both vehicles are stopped even if the follower has a shorter stopping distance than the leader)
717  // To make things safe, we ensure that the leaders brake distance is computed with an deceleration that is at least as high as the follower's.
718  // @todo: this is a conservative estimate for safe speed which could be increased
719 
720 // // For negative gaps, we return the lowest meaningful value by convention
721 // // XXX: check whether this is desireable (changes test results, therefore I exclude it for now (Leo), refs. #2575)
722 // if(gap<0){
723 // if(MSGlobals::gSemiImplicitEulerUpdate){
724 // return 0.;
725 // } else {
726 // return -INVALID_SPEED;
727 // }
728 // }
729 
730  // The following commented code is a variant to assure brief stopping behind a stopped leading vehicle:
731  // if leader is stopped, calculate stopSpeed without time-headway to prevent creeping stop
732  // NOTE: this can lead to the strange phenomenon (for the Krauss-model at least) that if the leader comes to a stop,
733  // the follower accelerates for a short period of time. Refs #2310 (Leo)
734 // const double headway = predSpeed > 0. ? myHeadwayTime : 0.;
735 
736  const double headway = myHeadwayTime;
737  const double x = maximumSafeStopSpeed(gap + brakeGap(predSpeed, MAX2(myDecel, predMaxDecel), 0), egoSpeed, onInsertion, headway);
738  assert(x >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
739  assert(!ISNAN(x));
740  return x;
741 }
742 
743 
744 /****************************************************************************/
static double speedAfterTime(const double t, const double oldSpeed, const double dist)
Calculates the speed after a time t [0,TS] given the initial speed and the distance traveled in an i...
Definition: MSCFModel.cpp:566
#define DIST2SPEED(x)
Definition: SUMOTime.h:57
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:83
const MSVehicleType * myType
The type to which this model definition belongs to.
Definition: MSCFModel.h:521
#define SPEED2DIST(x)
Definition: SUMOTime.h:55
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:61
virtual double moveHelper(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences.
Definition: MSCFModel.cpp:153
virtual double interactionGap(const MSVehicle *const veh, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
Definition: MSCFModel.cpp:185
double maximumSafeStopSpeed(double gap, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap.
Definition: MSCFModel.cpp:604
virtual double getHeadwayTime() const
Get the driver&#39;s desired headway [s].
Definition: MSCFModel.h:247
T MAX2(T a, T b)
Definition: StdDefs.h:74
double getMaxSpeed() const
Get vehicle&#39;s maximum speed [m/s].
#define TIME2STEPS(x)
Definition: SUMOTime.h:66
double getMinimalArrivalSpeed(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance.
Definition: MSCFModel.cpp:374
#define TS
Definition: SUMOTime.h:52
#define SPEED2ACCEL(x)
Definition: SUMOTime.h:63
T MAX3(T a, T b, T c)
Definition: StdDefs.h:88
The car-following model and parameter.
Definition: MSVehicleType.h:73
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:3144
SUMOTime getMinimalArrivalTime(double dist, double currentSpeed, double arrivalSpeed) const
Computes the minimal time needed to cover a distance given the desired speed at arrival.
Definition: MSCFModel.cpp:320
static double distAfterTime(double t, double speed, double decel)
calculates the distance travelled after braking for time t
Definition: MSCFModel.cpp:298
virtual double patchSpeed(const double min, const double wanted, const double max, const MSCFModel &cfModel)=0
Called to adapt the speed in order to allow a lane change.
virtual double followSpeedTransient(double duration, const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel) const
Computes the vehicle&#39;s follow speed that avoids a collision for the given amount of time...
Definition: MSCFModel.cpp:247
#define ACCEL2DIST(x)
Definition: SUMOTime.h:59
static double brakeGapEuler(const double speed, const double decel, const double headwayTime)
Definition: MSCFModel.cpp:81
double getMaxDecel() const
Get the vehicle type&#39;s maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:212
T MIN2(T a, T b)
Definition: StdDefs.h:68
virtual double freeSpeed(const MSVehicle *const veh, double speed, double seen, double maxSpeed, const bool onInsertion=false) const
Computes the vehicle&#39;s safe speed without a leader.
Definition: MSCFModel.cpp:219
double maximumSafeStopSpeedBallistic(double gap, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap when using the ballistic positional update...
Definition: MSCFModel.cpp:645
double maximumSafeStopSpeedEuler(double gap) const
Returns the maximum next velocity for stopping within gap when using the semi-implicit Euler update...
Definition: MSCFModel.cpp:614
T ISNAN(T a)
Definition: StdDefs.h:109
virtual double insertionFollowSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel) const
Computes the vehicle&#39;s safe speed (no dawdling) This method is used during the insertion stage...
Definition: MSCFModel.cpp:226
double myDecel
The vehicle&#39;s maximum deceleration [m/s^2].
Definition: MSCFModel.h:527
static double gapExtrapolation(const double duration, const double currentGap, double v1, double v2, double a1=0, double a2=0, const double maxV1=std::numeric_limits< double >::max(), const double maxV2=std::numeric_limits< double >::max())
return the resulting gap if, starting with gap currentGap, two vehicles continue with constant accele...
Definition: MSCFModel.cpp:400
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
virtual ~MSCFModel()
Destructor.
Definition: MSCFModel.cpp:59
static double passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed)
Calculates the time at which the position passedPosition has been passed In case of a ballistic updat...
Definition: MSCFModel.cpp:494
double getMaxSpeedOnLane() const
Returns the maximal speed for the vehicle on its current lane (including speed factor and deviation...
Definition: MSVehicle.h:509
double getMaxAccel() const
Get the vehicle type&#39;s maximum acceleration [m/s^2].
Definition: MSCFModel.h:204
double processNextStop(double currentVelocity)
Processes stops, returns the velocity needed to reach the stop.
Definition: MSVehicle.cpp:1284
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
Definition: MSCFModel.cpp:200
virtual double minNextSpeed(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed given the current speed (depends on the numerical update scheme and its ste...
Definition: MSCFModel.cpp:206
double myEmergencyDecel
The vehicle&#39;s maximum emergency deceleration [m/s^2].
Definition: MSCFModel.h:529
double estimateSpeedAfterDistance(const double dist, const double v, const double accel) const
Definition: MSCFModel.cpp:595
#define INVALID_SPEED
Definition: MSCFModel.h:40
double getVehicleMaxSpeed(const SUMOVehicle *const veh) const
Returns the lane&#39;s maximum speed, given a vehicle&#39;s speed limit adaptation.
Definition: MSLane.h:462
virtual double stopSpeed(const MSVehicle *const veh, const double speed, double gap) const =0
Computes the vehicle&#39;s safe speed for approaching a non-moving obstacle (no dawdling) ...
MSCFModel(const MSVehicleType *vtype, double accel, double decel, double emergencyDecel, double apparentDecel, double headwayTime)
Constructor.
Definition: MSCFModel.cpp:48
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
virtual double insertionStopSpeed(const MSVehicle *const veh, double speed, double gap) const
Computes the vehicle&#39;s safe speed for approaching an obstacle at insertion without constraints due to...
Definition: MSCFModel.cpp:237
bool gDebugFlag2
Definition: StdDefs.cpp:34
static bool gSemiImplicitEulerUpdate
Definition: MSGlobals.h:63
T MIN3(T a, T b, T c)
Definition: StdDefs.h:81
long long int SUMOTime
Definition: TraCIDefs.h:52
#define NUMERICAL_EPS
Definition: config.h:152
const double INVALID_DOUBLE
Definition: StdDefs.h:60
double myHeadwayTime
The driver&#39;s desired time headway (aka reaction time tau) [s].
Definition: MSCFModel.h:534
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:499
double maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion=false) const
Returns the maximum safe velocity for following the given leader.
Definition: MSCFModel.cpp:712
double estimateArrivalTime(double dist, double speed, double maxSpeed, double accel) const
Computes the time needed to travel a distance dist given an initial speed and constant acceleration...
Definition: MSCFModel.cpp:333
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver&#39;s reaction time tau (i...
Definition: MSCFModel.h:290
double getMinimalArrivalSpeedEuler(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance for Euler update...
Definition: MSCFModel.cpp:381
double getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:443