Eclipse SUMO - Simulation of Urban MObility
MSCFModel_EIDM.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
17
24// The Extended Intelligent Driver Model (EIDM) car-following model
25//
26// Publication: Salles, Dominik, S. Kaufmann and H. Reuss. “Extending the Intelligent Driver
27// Model in SUMO and Verifying the Drive Off Trajectories with Aerial
28// Measurements.” (2020).
29/****************************************************************************/
30
31
32// ===========================================================================
33// included modules
34// ===========================================================================
35#include <config.h>
36
37#include "MSCFModel_EIDM.h"
38#include <microsim/MSVehicle.h>
39#include <microsim/MSLane.h>
40#include <microsim/MSEdge.h>
41#include <microsim/MSLink.h>
44
45//#define DEBUG_V
46
47#define EST_REAC_THRESHOLD 3. // under this threshold estimation, error and reaction time variables don't get taken into account
48#define ClutchEngageSpeed 0.5 // When a vehicle is below this speed, we assume a "slow to start", that is because of clutch operation / powertrain inertia
49#define EIDM_POS_ACC_EPS 0.05 // some slack number to ensure smoother position, speed and acceleration update
50
51// ===========================================================================
52// method definitions
53// ===========================================================================
55 MSCFModel(vtype), myDelta(vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_DELTA, 4.)),
56 myTwoSqrtAccelDecel(double(2 * sqrt(myAccel * myDecel))),
57 myIterations(MAX2(1, int(TS / vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_STEPPING, .25) + .5))),
58 myTPersDrive(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE, 3)),
59 myTreaction(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_T_REACTION, 0.5)),
60 myTpreview(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD, 4)),
61 myTPersEstimate(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE, 10)),
62 myCcoolness(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_C_COOLNESS, 0.99)),
63 mySigmaleader(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_SIG_LEADER, 0.02)),
64 mySigmagap(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_SIG_GAP, 0.1)),
65 mySigmaerror(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_SIG_ERROR, 0.04)),
66 myJerkmax(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_JERK_MAX, 3.)),
67 myEpsilonacc(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_EPSILON_ACC, 1.)),
68 myTaccmax(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_T_ACC_MAX, 1.2)),
69 myMflatness(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_M_FLATNESS, 2.)),
70 myMbegin(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_M_BEGIN, 0.7)),
71 myUseVehDynamics(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS, 0) == 1)
72 //, myMaxVehPreview(vtype->getParameter().getCFParam(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW, 0))
73{
74 // IDM does not drive very precise and may violate minGap on occasion
76}
77
79
80double
81MSCFModel_EIDM::insertionFollowSpeed(const MSVehicle* const /*veh*/, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const /*pred*/) const {
83 return maximumSafeFollowSpeed(gap2pred, speed, predSpeed, predMaxDecel, true);
84 } else {
85 // Not Done/checked yet for the ballistic update model!!!!
86 // NOTE: Even for ballistic update, the current speed is irrelevant at insertion, therefore passing 0. (Leo)
87// return maximumSafeFollowSpeed(gap2pred, 0., predSpeed, predMaxDecel, true);
88 return maximumSafeFollowSpeed(gap2pred, speed, predSpeed, predMaxDecel, true);
89 }
90}
91
92
93double
94MSCFModel_EIDM::insertionStopSpeed(const MSVehicle* const /*veh*/, double speed, double gap) const {
96 return maximumSafeStopSpeed(gap, myDecel, speed, true, myHeadwayTime);
97 } else {
98 // Not Done/checked yet for the ballistic update model!!!!
99// return MIN2(maximumSafeStopSpeed(gap, myDecel, 0., true, 0.), myType->getMaxSpeed());
100 return MIN2(maximumSafeStopSpeed(gap, myDecel, speed, true, myHeadwayTime), myType->getMaxSpeed());
101 }
102}
103
104double
105MSCFModel_EIDM::maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion, const CalcReason /* usage */) const {
106 double x;
107 if (gap >= 0 || MSGlobals::gComputeLC) {
108 double a = 1.;
109 double b = myHeadwayTime * myTwoSqrtAccelDecel - predSpeed;
110 double c = -sqrt(1 + myDecel / (2 * myAccel)) * gap * myTwoSqrtAccelDecel;
111 // with myDecel/myAccel, the intended deceleration is myDecel
112 // with myDecel/(2*myAccel), the intended deceleration is myDecel/2
113 // with the IIDM, if gap=s, then the acceleration is zero and if gap<s, then the term v/vMax is not present
114
115 // double c = -sqrt(1 - pow(egoSpeed / MAX2(NUMERICAL_EPS, desSpeed), myDelta) + myDecel / (2 * myAccel)) * gap * myTwoSqrtAccelDecel; // c calculation when using the IDM!
116
117 // myDecel is positive, but is intended as negative value here, therefore + instead of -
118 // quadratic formula
119 x = (-b + sqrt(b * b - 4.*a * c)) / (2.*a);
120 } else {
121 x = egoSpeed - ACCEL2SPEED(myEmergencyDecel);
123 x = MAX2(x, 0.);
124 }
125 }
126
127 if (myDecel != myEmergencyDecel && !onInsertion && !MSGlobals::gComputeLC) {
128 double origSafeDecel = SPEED2ACCEL(egoSpeed - x);
129 if (origSafeDecel > myDecel + NUMERICAL_EPS) {
130 // Braking harder than myDecel was requested -> calculate required emergency deceleration.
131 // Note that the resulting safeDecel can be smaller than the origSafeDecel, since the call to maximumSafeStopSpeed() above
132 // can result in corrupted values (leading to intersecting trajectories) if, e.g. leader and follower are fast (leader still faster) and the gap is very small,
133 // such that braking harder than myDecel is required.
134
135 double safeDecel = EMERGENCY_DECEL_AMPLIFIER * calculateEmergencyDeceleration(gap, egoSpeed, predSpeed, predMaxDecel);
136#ifdef DEBUG_EMERGENCYDECEL
137 if (DEBUG_COND2) {
138 std::cout << SIMTIME << " initial vsafe=" << x
139 << " egoSpeed=" << egoSpeed << " (origSafeDecel=" << origSafeDecel << ")"
140 << " predSpeed=" << predSpeed << " (predDecel=" << predMaxDecel << ")"
141 << " safeDecel=" << safeDecel
142 << std::endl;
143 }
144#endif
145 // Don't be riskier than the usual method (myDecel <= safeDecel may occur, because a headway>0 is used above)
146 safeDecel = MAX2(safeDecel, myDecel);
147 // don't brake harder than originally planned (possible due to euler/ballistic mismatch)
148 safeDecel = MIN2(safeDecel, origSafeDecel);
149 x = egoSpeed - ACCEL2SPEED(safeDecel);
151 x = MAX2(x, 0.);
152 }
153
154#ifdef DEBUG_EMERGENCYDECEL
155 if (DEBUG_COND2) {
156 std::cout << " -> corrected emergency deceleration: " << safeDecel << std::endl;
157 }
158#endif
159
160 }
161 }
162 assert(x >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
163 assert(!ISNAN(x));
164 return x;
165}
166
167double
168MSCFModel_EIDM::maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion, double headway) const {
169 double vsafe;
171 const double g = gap - NUMERICAL_EPS;
172 if (g < 0) {
173 return 0;
174 }
175 double a = 1.;
176 double b = headway * myTwoSqrtAccelDecel - 0.;
177 double c = -sqrt(1 + decel / (2 * myAccel)) * g * myTwoSqrtAccelDecel;
178 // with decel/myAccel, the intended deceleration is decel
179 // with decel/(2*myAccel), the intended deceleration is decel/2
180 // with the IIDM, if gap=s, then the acceleration is zero and if gap<s, then the term currentSpeed/vMax is not present
181
182 // double c = -sqrt(1 - pow(currentSpeed / MAX2(NUMERICAL_EPS, desSpeed), myDelta) + decel / (2 * myAccel)) * g * myTwoSqrtAccelDecel; // c calculation when using the IDM!
183
184 // decel is positive, but is intended as negative value here, therefore + instead of -
185 // quadratic formula
186 vsafe = (-b + sqrt(b * b - 4.*a * c)) / (2.*a);
187 } else {
188 // Not Done/checked yet for the ballistic update model!!!!
189 vsafe = maximumSafeStopSpeedBallistic(gap, decel, currentSpeed, onInsertion, headway);
190 }
191
192 return vsafe;
193}
194
195double
196MSCFModel_EIDM::patchSpeedBeforeLCEIDM(const MSVehicle* /*veh*/, double vMin, double vMax, const VehicleVariables* vars) const {
197 // The default value of SUMO_ATTR_JM_SIGMA_MINOR is sigma, not sigmaerror (used in EIDM),
198 // so we do not use SUMO_ATTR_JM_SIGMA_MINOR as parameter here, because this could confuse users...
199 //const double sigma = (veh->passingMinor()
200 // ? veh->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_SIGMA_MINOR, myDawdle)
201 // : myDawdle);
202
203 // dawdling/drivingerror is now calculated here (in finalizeSpeed, not in stop-/follow-/freeSpeed anymore):
204 // Instead of just multiplying mySigmaerror with vars->myw_error, we add a factor depending on the criticality of the situation,
205 // measured with s*/gap. Because when the driver drives "freely" (nothing in front) he may dawdle more than in e.g. congested traffic!
206 double s = MAX2(0., vars->myv_est * myHeadwayTime + vars->myv_est * (vars->myv_est - vars->myv_est_l) / myTwoSqrtAccelDecel);
207 if (vars->myrespectMinGap) {
209 } else {
210 const double minGapStop_EPS = 0.05 + 0.20 * MAX2(0.25, myAccel);
211 s += minGapStop_EPS + EIDM_POS_ACC_EPS;
212 }
213 const double intensity = MIN2(myAccel, MAX2(vMax - 0.5 * myAccel, 0.0));
214 const double criticality = MIN2(MAX2(s / vars->mys_est - 0.5, -0.4), 0.0);
215
216 const double drivingerror = mySigmaerror * vars->myw_error * intensity * (2.75 * 2.75 * criticality * criticality + 1.0);
217
218 // else: the vehicle is very slow and we do not add driving error (= 0), because
219 // we should not prevent vehicles from driving just due to dawdling
220 // if someone is starting, he should definitely start
221
222 //const double vDawdle = MAX2(vMin, dawdle2(vMax, sigma, veh->getRNG()));
223 const double vDawdle = MAX2(vMin, vMax + ACCEL2SPEED(drivingerror));
224 return vDawdle;
225}
226
227double
228MSCFModel_EIDM::slowToStartTerm(MSVehicle* const veh, const double newSpeed, const double currentSpeed, const double vMax, VehicleVariables* vars) const {
229 // Drive Off Activation and Term
230
231 if (newSpeed == 0 || newSpeed <= currentSpeed) {
232 return newSpeed;
233 }
234
235 double remainingDelay = 0.0;
236 if (newSpeed != vMax) {
237 remainingDelay = STEPS2TIME(DELTA_T - (myStartupDelay - (veh->getTimeSinceStartup() - DELTA_T)));
238 }
239
240 double v_corr = currentSpeed;
241 for (int i = 0; i < myIterations; i++) {
242 // @ToDo: Check if all clauses are still needed or if we need to add more for all possible drive off cases?!
243 // When we reach this point, "newSpeed > currentSpeed" already holds
244 // Activation of the Drive Off term, when
245 if (currentSpeed < ClutchEngageSpeed && // The start speed is lower than ClutchEngageSpeed m/s
246 vars->t_off + 4. - NUMERICAL_EPS < (SIMTIME - remainingDelay - TS * (myIterations - i - 1.) / myIterations) && // the last activation is at least 4 seconds ago
247 vars->myap_update == 0 && // the last activation is at least 4 seconds ago AND an Action Point was reached
248 veh->getAcceleration() < MIN2(myAccel / 4, 0.2)) { // && respectMinGap) { // the driver hasn't started accelerating yet (<0.2)
249 vars->t_off = (SIMTIME - remainingDelay - TS * (myIterations - i - 1.) / myIterations); // activate the drive off term
250 }
251 // Calculation of the Drive Off term
252 if (vars->t_off + myTaccmax + NUMERICAL_EPS > (SIMTIME - remainingDelay - TS * (myIterations - i - 1.) / myIterations)) {
253 v_corr = v_corr + (newSpeed - currentSpeed) / myIterations * (tanh((((SIMTIME - remainingDelay - TS * (myIterations - i - 1.) / myIterations) - vars->t_off) * 2. / myTaccmax - myMbegin) * myMflatness) + 1.) / 2.;
254 } else {
255 v_corr = v_corr + (newSpeed - currentSpeed) / myIterations;
256 }
257 }
258 return v_corr;
259}
260
261double
262MSCFModel_EIDM::finalizeSpeed(MSVehicle* const veh, double vPos) const {
263 // finalizeSpeed is only called once every timestep!
264
266 // save old v for optional acceleration computation
267 const double oldV = veh->getSpeed();
268
269 // @ToDo: Maybe change whole calculation to calculate real freeSpeed/stopSpeed/followSpeed in every call and here calculate resulting speed with reaction Time and update?!
270 // @ToDo: Could check which call resulted in speed update with stop-vector containing all calculated accelerations!
271 // Check whether the speed update results from a stop calculation, if so, run _v-function again with the saved variables from stopSpeed
272 double _vPos = vPos;
273 if ((vPos <= SUMO_const_haltingSpeed && vPos <= oldV) || !(vPos > oldV + ACCEL2SPEED(vars->realacc) - NUMERICAL_EPS && vPos < oldV + ACCEL2SPEED(vars->realacc) + NUMERICAL_EPS)) {
274 for (auto it = vars->stop.cbegin(); it != vars->stop.cend(); ++it) {
275 if (vPos > oldV + ACCEL2SPEED(it->first) - NUMERICAL_EPS && vPos < oldV + ACCEL2SPEED(it->first) + NUMERICAL_EPS) {
276 _vPos = _v(veh, it->second, oldV, 0, vars->v0_int, false, 1, CalcReason::CURRENT);
277 }
278 }
279 }
280
281 // process stops (includes update of stopping state)
282 const double vStop = MIN2(_vPos, veh->processNextStop(_vPos));
283 // apply deceleration bounds
284 const double vMinEmergency = minNextSpeedEmergency(oldV, veh);
285 // _vPos contains the uppper bound on safe speed. allow emergency braking here
286 const double vMin = MIN2(minNextSpeed(oldV, veh), MAX2(_vPos, vMinEmergency));
287 // apply planned speed constraints and acceleration constraints
288 double vMax = MIN2(maxNextSpeed(oldV, veh), vStop);
289 vMax = MAX2(vMin, vMax);
290
291#ifdef DEBUG_V
292 if (veh->isSelected()) {
293 std::cout << SIMTIME
294 << " EIDM::finalizeSpeed "
295 << " veh=" << veh->getID()
296 << " oldV=" << oldV
297 << " vPos=" << vPos
298 << " _vPos=" << _vPos
299 << " vStop=" << vStop
300 << " vMinEmergency=" << vMinEmergency
301 << " vMin=" << vMin
302 << " vMax=" << vMax
303 << "\n";
304 }
305#endif
306
307 // apply further speed adaptations
308 double vNext = patchSpeedBeforeLCEIDM(veh, vMin, vMax, vars);
309
311
312 // The model does not directly use vNext from patchSpeed (like the original MSCFModel::finalizeSpeed function),
313 // but rather slowly adapts to vNext.
314 vNext = veh->getLaneChangeModel().patchSpeed(vMin, vNext, vMax, *this);
315
316 // Bound the positive change of the acceleration with myJerkmax
317 if (vNext > oldV && oldV > ClutchEngageSpeed * 2 && vars->t_off + myTaccmax + NUMERICAL_EPS < SIMTIME) {
318 // At junctions with minor priority acceleration will still jump because after finalizeSpeed "MAX2(vNext, vSafeMin)" is called, vSafeMin is higher and vNext from finalizeSpeed is then ignored!!!
319 // If we put this jmax-Part into _v-function (via old calc_gap implementation), then vehicle can't drive over junction because it thinks it won't make it in time before a foe may appear!
320 if (myJerkmax * TS + veh->getAcceleration() < 0.) { // If driver wants to accelerate, but is still decelerating, then we use a factor of 2!
321 vNext = MAX2(oldV + MIN2(vNext - oldV, (myJerkmax * 2 * TS + veh->getAcceleration()) * TS), 0.); // change in acceleration (jerk) is bounded by myJerkmax*2
322 } else {
323 vNext = MAX2(oldV + MIN2(vNext - oldV, (myJerkmax * TS + veh->getAcceleration()) * TS), 0.); // change in acceleration (jerk) is bounded by myJerkmax
324 }
325 } else if (vNext <= oldV && vNext < vMax - NUMERICAL_EPS && oldV > ClutchEngageSpeed * 2) {
326 // Slowing down the deceleration like this may be critical!!! Vehicle can also not come back from Emergency braking fast enough!
327 /*if (vNext - oldV < -myJerkmax * TS + veh->getAcceleration()) { // driver wants to brake harder than before, change in acceleration is then bounded by -myJerkmax
328 vNext = MAX2(oldV + (-myJerkmax * TS + veh->getAcceleration()) * TS, 0.);
329 } else if (vNext - oldV > myJerkmax * TS + veh->getAcceleration()) { // driver wants to brake less harder than before, change in acceleration is then bounded by +myJerkmax
330 vNext = MAX2(oldV + (myJerkmax * TS + veh->getAcceleration()) * TS, 0.);
331 } else {
332 vNext = vNext; // Do nothing, as the new vNext is in the range of +/- jerk!
333 }*/
334
335 // Workaround letting the vehicle not brake hard for Lane Change reasons (vNext), but only for safety Car following / stopping reasons (vMax)!
336 vNext = MAX2(oldV + MIN2(vMax - oldV, MAX2(vNext - oldV, (-myJerkmax * TS + veh->getAcceleration()) * TS)), 0.);
337 }
338
339 } else {
340 // Not Done/checked yet for the ballistic update model!!!!
341
342 // for ballistic update, negative vnext must be allowed to
343 // indicate a stop within the coming timestep (i.e., to attain negative values)
344 vNext = veh->getLaneChangeModel().patchSpeed(vMin, vMax, vMax, *this);
345 // (Leo) finalizeSpeed() is responsible for assuring that the next
346 // velocity is chosen in accordance with maximal decelerations.
347 // At this point vNext may also be negative indicating a stop within next step.
348 // Moreover, because maximumSafeStopSpeed() does not consider deceleration bounds
349 // vNext can be a large negative value at this point. We cap vNext here.
350 vNext = MAX2(vNext, vMin);
351 }
352
353 // Driving off correction term: First we check for StartupDelay, then calculate Speed with SlowToStartTerm
354 // Apply Startup delay (time) before driving off
355 SUMOTime addTime = vars->myap_update * DELTA_T;
356 if (myStartupDelay + addTime - (veh->getTimeSinceStartup() - DELTA_T) < DELTA_T) {
357 addTime = (SUMOTime)0;
358 }
359 double vDelay = applyStartupDelay(veh, vMin, vNext, addTime);
360 // Apply the slow to start term to the acceleration/speed when driving off
361 vNext = slowToStartTerm(veh, vDelay, oldV, vNext, vars);
362#ifdef DEBUG_V
363 if (veh->isSelected()) {
364 std::cout << SIMTIME
365 << " EIDM::finalizeSpeed (2) "
366 << " veh=" << veh->getID()
367 << " timeSinceStartup=" << veh->getTimeSinceStartup()
368 << " myap_update=" << vars->myap_update
369 << " addTime=" << addTime
370 << " vDelay=" << vDelay
371 << " oldV=" << oldV
372 << " vNext=" << vNext
373 << "\n";
374 }
375#endif
376
377 // Update the desired speed
378 internalspeedlimit(veh, oldV);
379
380 if (vNext > EST_REAC_THRESHOLD) { // update the Wiener-Prozess variables
381 vars->myw_gap = exp(-TS / myTPersEstimate) * vars->myw_gap + sqrt(2 * TS / myTPersEstimate) * RandHelper::randNorm(0, 0.5); // variance of 1 can create very high values and may be too high!
382 vars->myw_speed = exp(-TS / myTPersEstimate) * vars->myw_speed + sqrt(2 * TS / myTPersEstimate) * RandHelper::randNorm(0, 0.5); // variance of 1 can create very high values and may be too high!
383 vars->myw_error = exp(-TS / myTPersDrive) * vars->myw_error + sqrt(2 * TS / myTPersDrive) * RandHelper::randNorm(0, 1);
384 } // else all those w_... are zero by default
385
386 // Update the Action-point reaction time
387 if (vars->myap_update == 0) { // Update all saved acceleration variables for further calculcation between two action points
388 vars->lastacc = vars->minaccel;
389 vars->wouldacc = vars->minaccel;
390 vars->lastrealacc = vars->realacc;
391 vars->lastleaderacc = vars->realleaderacc;
392 }
393
394#ifdef DEBUG_V
395 if (veh->isSelected()) {
396 std::cout << SIMTIME
397 << " EIDM::finalizeSpeed (3) "
398 << " veh=" << veh->getID()
399 << " vars->myw_gap=" << vars->myw_gap
400 << " vars->myw_speed=" << vars->myw_speed
401 << " vars->myw_error=" << vars->myw_error
402 << " vars->lastacc=" << vars->lastacc
403 << " vars->lastrealacc=" << vars->lastrealacc
404 << " vars->lastleaderacc=" << vars->lastleaderacc
405 << "\n";
406 }
407#endif
408
409 // Set myap_update back to 0 when maximal reaction time is reached,
410 // else add 1 for the next time step
411 if (double(vars->myap_update) >= double(myTreaction / TS - 1 - NUMERICAL_EPS)) {
412 vars->myap_update = 0;
413 } else {
414 vars->myap_update = vars->myap_update + 1;
415 }
416
417 // Here the acceleration the vehicle would adapt to without a reaction time is compared to the last acceleration update at the last action point.
418 // If between two action points the vehicle would like to brake harder than -myEpsilonacc, then an action point is called for the next time step (myap_update = 0).
419 // This update is only used when wouldacc becomes myEpsilonacc lower than lastacc! When accelerating (wouldacc > lastacc), always the maximal reaction time is used!
420 // @ToDo: Check how to use a stable reaction time below EST_REAC_THRESHOLD m/s when braking without oscillating acceleration, then this boundary could be eliminated.
421 // @ToDo: Use this asynchron action point update also for accelerating (like introduced by Wagner/Hoogendorn/Treiber), not only for keeping the CF-model stable!
422 if ((vars->wouldacc - vars->lastacc) < -myEpsilonacc || vars->wouldacc < -getEmergencyDecel() || (oldV < EST_REAC_THRESHOLD && vNext < oldV)) {
423 // When this if-clause holds, then the driver should react immediately!
424 // 1. When the change in deceleration is lower than -myEpsilonacc
425 // 2. When the intended deceleration is lower than emergencyDecel
426 // 3. When the vehicle is slow and decelerating
427 vars->myap_update = 0;
428 }
429
430 // Set the "inner" variables of the car-following model back to the default values for the next time step
431 vars->minaccel = 100;
432 vars->realacc = 100;
433 vars->realleaderacc = 100;
434
435 vars->stop.clear();
436
437 return vNext;
438}
439
440
441double
442MSCFModel_EIDM::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double /*predMaxDecel*/, const MSVehicle* const /*pred*/, const CalcReason usage) const {
443// applyHeadwayAndSpeedDifferencePerceptionErrors(veh, speed, gap2pred, predSpeed, predMaxDecel, pred);
445
446 // This update-variable is used to check what called followSpeed (LC- or CF-model), see enum CalcReason for more information
447 // Here we don't directly use gComputeLC, which is also 0 and 1, because in freeSpeed we have another call (update = 2),
448 // which is needed to differentiate between the different cases/calculations/needed output/saved variables
449 int update = 1;
450 CalcReason _vUsage = usage;
452 _vUsage = CalcReason::LANE_CHANGE;
453 }
454 if (_vUsage == CalcReason::LANE_CHANGE || _vUsage == CalcReason::FUTURE) {
455 update = 0;
456 }
457
458#ifdef DEBUG_V
459 if (veh->isSelected()) {
460 std::cout << SIMTIME
461 << " EIDM::followSpeed "
462 << " veh=" << veh->getID()
463 << " speed=" << speed
464 << " gap2pred=" << gap2pred
465 << " predSpeed=" << predSpeed
466 << " vars->v0_int=" << vars->v0_int
467 << " update=" << update
468 << "\n";
469 }
470#endif
471
472 double result = _v(veh, gap2pred, speed, predSpeed, vars->v0_int, true, update, _vUsage);
473 return result;
474}
475
476
477double
478MSCFModel_EIDM::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double /*decel*/, const CalcReason usage) const {
479// applyHeadwayPerceptionError(veh, speed, gap);
480// if (gap < 0.01) {
481// return 0;
482// }
484
485 // This update-variable is used to check what called stopSpeed (LC- or CF-model), see enum CalcReason for more information
486 // Here we don't directly use gComputeLC, which is also 0 and 1, because in freeSpeed we have another call (update = 2),
487 // which is needed to differentiate between the different cases/calculations/needed output/saved variables
488 int update = 1;
489 CalcReason _vUsage = usage;
491 _vUsage = CalcReason::LANE_CHANGE;
492 }
493 if (_vUsage == CalcReason::LANE_CHANGE || _vUsage == CalcReason::FUTURE || usage == CalcReason::CURRENT_WAIT) {
494 update = 0;
495 }
496
497#ifdef DEBUG_V
498 if (veh->isSelected()) {
499 std::cout << SIMTIME
500 << " EIDM::stopSpeed "
501 << " veh=" << veh->getID()
502 << " speed=" << speed
503 << " gap=" << gap
504 << " vars->v0_int=" << vars->v0_int
505 << " update=" << update
506 << "\n";
507 }
508#endif
509
510 double result = _v(veh, gap, speed, 0, vars->v0_int, false, update, _vUsage);
511// From Sumo_IDM-implementation:
512// if (gap > 0 && speed < NUMERICAL_EPS && result < NUMERICAL_EPS) {
513// // ensure that stops can be reached:
514// result = maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs());
515// }
516 return result;
517}
518
519double
520MSCFModel_EIDM::freeSpeed(const double currentSpeed, const double decel, const double dist, const double targetSpeed, const bool onInsertion) {
521 // XXX: (Leo) This seems to be exclusively called with decel = myDecel (max deceleration) and is not overridden
522 // by any specific CFModel. That may cause undesirable hard braking (at junctions where the vehicle
523 // changes to a road with a lower speed limit).
524
526 // adapt speed to succeeding lane, no reaction time is involved
527 // when breaking for y steps the following distance g is covered
528 // (drive with v in the final step)
529 // g = (y^2 + y) * 0.5 * b + y * v
530 // y = ((((sqrt((b + 2.0*v)*(b + 2.0*v) + 8.0*b*g)) - b)*0.5 - v)/b)
531 const double v = SPEED2DIST(targetSpeed);
532 if (dist < v) {
533 return targetSpeed;
534 }
535 const double b = ACCEL2DIST(decel);
536 const double y = MAX2(0.0, ((sqrt((b + 2.0 * v) * (b + 2.0 * v) + 8.0 * b * dist) - b) * 0.5 - v) / b);
537 const double yFull = floor(y);
538 const double exactGap = (yFull * yFull + yFull) * 0.5 * b + yFull * v + (y > yFull ? v : 0.0);
539 const double fullSpeedGain = (yFull + (onInsertion ? 1. : 0.)) * ACCEL2SPEED(decel);
540 return DIST2SPEED(MAX2(0.0, dist - exactGap) / (yFull + 1)) + fullSpeedGain + targetSpeed;
541 } else {
542 // ballistic update (Leo)
543 // calculate maximum next speed vN that is adjustable to vT=targetSpeed after a distance d=dist
544 // and given a maximal deceleration b=decel, denote the current speed by v0.
545 // the distance covered by a trajectory that attains vN in the next timestep and decelerates afterwards
546 // with b is given as
547 // d = 0.5*dt*(v0+vN) + (t-dt)*vN - 0.5*b*(t-dt)^2, (1)
548 // where time t of arrival at d with speed vT is
549 // t = dt + (vN-vT)/b. (2)
550 // We insert (2) into (1) to obtain
551 // d = 0.5*dt*(v0+vN) + vN*(vN-vT)/b - 0.5*b*((vN-vT)/b)^2
552 // 0 = (dt*b*v0 - vT*vT - 2*b*d) + dt*b*vN + vN*vN
553 // and solve for vN
554
555 assert(currentSpeed >= 0);
556 assert(targetSpeed >= 0);
557
558 const double dt = onInsertion ? 0 : TS; // handles case that vehicle is inserted just now (at the end of move)
559 const double v0 = currentSpeed;
560 const double vT = targetSpeed;
561 const double b = decel;
562 const double d = dist - NUMERICAL_EPS; // prevent returning a value > targetSpeed due to rounding errors
563
564 // Solvability for positive vN (if d is small relative to v0):
565 // 1) If 0.5*(v0+vT)*dt > d, we set vN=vT.
566 // (In case vT<v0, this implies that on the interpolated trajectory there are points beyond d where
567 // the interpolated velocity is larger than vT, but at least on the temporal discretization grid, vT is not exceeded)
568 // 2) We ignore the (possible) constraint vN >= v0 - b*dt, which could lead to a problem if v0 - t*b > vT.
569 // (finalizeSpeed() is responsible for assuring that the next velocity is chosen in accordance with maximal decelerations)
570
571 if (0.5 * (v0 + vT)*dt >= d) {
572 return vT; // (#)
573 }
574
575 const double q = ((dt * v0 - 2 * d) * b - vT * vT); // (q < 0 is fulfilled because of (#))
576 const double p = 0.5 * b * dt;
577 return -p + sqrt(p * p - q);
578 }
579}
580
581double
582MSCFModel_EIDM::freeSpeed(const MSVehicle* const veh, double speed, double seen, double maxSpeed, const bool onInsertion, const CalcReason usage) const {
583
584 // @ToDo: Set new internal speed limit/desired speed <maxSpeed> here and change it over time in internalspeedlimit()!
585
586 if (maxSpeed < 0.) {
587 // can occur for ballistic update (in context of driving at red light)
588 return maxSpeed;
589 }
590
591 // This update-variable is used to check what called freeSpeed (LC- or CF-model), see enum CalcReason for more information
592 // Here we don't directly use gComputeLC, which is also 0 and 1, because we have another call (update = 2),
593 // which is needed to differentiate between the different cases/calculations/needed output/saved variables
594 int update = 1;
595 CalcReason _vUsage = usage;
597 _vUsage = CalcReason::LANE_CHANGE;
598 }
599 if (_vUsage == CalcReason::LANE_CHANGE || _vUsage == CalcReason::FUTURE) {
600 update = 0;
601 }
602
603#ifdef DEBUG_V
604 if (veh->isSelected()) {
605 std::cout << SIMTIME
606 << " EIDM::freeSpeed "
607 << " veh=" << veh->getID()
608 << " speed=" << speed
609 << " seen=" << seen
610 << " maxSpeed=" << maxSpeed
611 << " update=" << update
612 << " onInsertion=" << onInsertion
613 << "\n";
614 }
615#endif
616
618
619 double vSafe, remaining_time, targetDecel;
620 double secGap;
621 if (onInsertion) {
622 // Needed for the Insertion-Calculation to check, if insertion at this "speed" is possible to reach "maxSpeed" in the given distance "seen" (vehicle can max decelerate with myDecel!)!
623 // @ToDo: Could maybe be changed to maximumSafeFollowSpeed instead of freeSpeed-Krauss calculation!
624 vSafe = freeSpeed(speed, myDecel, seen, maxSpeed, onInsertion);
625 } else {
626 // driver needs to brake, because he is faster than the desired speed limit <maxSpeed> on the next lane or the next upcoming event (e.g. red light violation)
627 // The adaption/braking starts when the <seen> time-distance is lower than myTpreview+myTreaction
628 if (maxSpeed < speed && seen < speed * (myTpreview + myTreaction)) {
629
630 update = update == 0 ? 0 : 2;
631
632 remaining_time = MAX3((seen - speed * myTreaction) / speed, myTreaction / 2, TS); // The remaining time is at least a time step or the reaction time of the driver
633 targetDecel = (speed - maxSpeed) / remaining_time; // The needed constant deceleration to reach maxSpeed before reaching the next lane/event
634
635 // targetDecel is not set immediatly, if the vehicle is far enough away from the event (bounded by myJerkmax)
636 if (remaining_time > myTpreview - targetDecel / myJerkmax) {
637 targetDecel = (myTpreview - remaining_time) * myJerkmax;
638 }
639
640 // calculate distance which would result in the accel-value targetDecel at this <speed> and leaderspeed <0>
641 if (vars->myap_update == 0 || update == 0) { // at action point update
642 secGap = internalsecuregap(veh, speed, 0., targetDecel);
643 } else { // between two action points
644 secGap = internalsecuregap(veh, vars->myv_est + vars->lastrealacc * vars->myap_update * TS, 0., targetDecel);
645 }
646
647 vSafe = _v(veh, MAX2(seen, secGap), speed, 0., vars->v0_int, true, update, _vUsage);
648
649 // Add this for "old implementation" when vehicle doesn't HAVE to reach maxspeed at seen-distance!
650 // @ToDo: See #7644: <double v = MIN2(maxV, laneMaxV);> in MSVehicle::planMoveInternal! -> DONE!
651 // But still: Is it better, if the vehicle brakes early enough to reach the next lane with its speed limit?
652 // Instead of driving too fast for a while on the new lane, which can be more "human", but leads to other problems (junction model, traffic light braking...)
653 /* if (seen < speed*myTpreview || seen < veh->getLane()->getVehicleMaxSpeed(veh)*myTpreview / 2) {
654 remaining_time = speed < veh->getLane()->getVehicleMaxSpeed(veh) / 2 ? seen / (veh->getLane()->getVehicleMaxSpeed(veh) / 2) : seen / MAX2(speed, 0.01);
655 if (vars->v0_int > maxSpeed + NUMERICAL_EPS && vars->v0_old > vars->v0_int + NUMERICAL_EPS) {
656 maxSpeed = MAX2(maxSpeed, MIN2(vars->v0_int, vars->v0_old - (vars->v0_old - maxSpeed) / myTpreview * (myTpreview - remaining_time)));
657 vSafe = _v(veh, 500., speed, maxSpeed, maxSpeed, true, update, _vUsage);
658 } else if (vars->v0_int > maxSpeed + NUMERICAL_EPS) {
659 maxSpeed = MAX2(maxSpeed, vars->v0_int - (vars->v0_int - maxSpeed) / myTpreview * (myTpreview - remaining_time));
660 vSafe = _v(veh, 500., speed, maxSpeed, maxSpeed, true, update, _vUsage);
661 } else {
662 vSafe = _v(veh, 500., speed, maxSpeed, vars->v0_int, true, update, _vUsage);
663 }
664 */
665 } else { // when the <speed> is lower than <maxSpeed> or the next lane/event is not seen with myTpreview+myTreaction yet
666 vSafe = _v(veh, 500., speed, maxSpeed, vars->v0_int, true, update, _vUsage);
667 }
668 }
669
670 return vSafe;
671}
672
674double
675MSCFModel_EIDM::interactionGap(const MSVehicle* const veh, double vL) const {
676 // Resolve the IDM equation to gap. Assume predecessor has
677 // speed != 0 and that vsafe will be the current speed plus acceleration,
678 // i.e that with this gap there will be no interaction.
679 const double acc = myAccel * (1. - pow(veh->getSpeed() / veh->getLane()->getVehicleMaxSpeed(veh), myDelta));
680 const double vNext = veh->getSpeed() + acc;
681 const double gap = (vNext - vL) * (veh->getSpeed() + vL) / (2 * myDecel) + vL;
682
683 // Don't allow timeHeadWay < deltaT situations.
684 return MAX2(gap, SPEED2DIST(vNext));
685
686 // Only needed for old Lane Change Model????
687}
688
689double
690MSCFModel_EIDM::getSecureGap(const MSVehicle* const /*veh*/, const MSVehicle* const /*pred*/, const double speed, const double leaderSpeed, const double /*leaderMaxDecel*/) const {
691 // SecureGap depends on v0 and may be higher than just looking at s* (In case of the IDM)
692 //VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
693 const double delta_v = speed - leaderSpeed;
694 double s = MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel); // is calculated without MinGap because it is compared to a gap without MinGap!
695 // For the IDM: - pow(speed / veh->getLane()->getVehicleMaxSpeed(veh), myDelta)) must be added to (myDecel / myAccel + 1)!
696 // For the IIDM: Left out the case check for estSpeed > v0, assuming this is not needed here. The vehicle therefore may brake harder when newSpeed > v0 occurs!
697 // The secure gap is calculated using -myDecel as secure maximal acceleration (using myDecel/myAccel)!
698
699 double erg = sqrt((s * s) / (myDecel / myAccel + 1.0));
700 return MIN2(s, erg);
701}
702
703// Only needed when vehicle has to reach laneMaxV before entering the new lane, see #7644
704double
705MSCFModel_EIDM::internalsecuregap(const MSVehicle* const veh, const double speed, const double leaderSpeed, const double targetDecel) const {
706 // SecureGap depends on v0 and may be higher than just looking at s* (In case of the IDM)
707 // internalsecuregap uses a targetDecel instead of myDecel!
709 const double delta_v = speed - leaderSpeed;
710 double s = MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel); // is calculated without MinGap because it is compared to a gap without MinGap!
711 // For the IDM: - pow(speed / veh->getLane()->getVehicleMaxSpeed(veh), myDelta)) must be added to (myDecel / myAccel + 1)!
712 // the secure gap is calculated using -myDecel as secure maximal acceleration (using myDecel/myAccel)!
713
714 double erg;
715 if (speed <= vars->v0_int) {
716 erg = sqrt((s * s) / (MAX2(targetDecel / myAccel + 1.0, 1.0)));
717 } else { // speed > v0
718 double a_free = - myDecel * (1.0 - pow(vars->v0_int / speed, myAccel * myDelta / myDecel));
719 erg = sqrt((s * s) / (MAX2(targetDecel / myAccel + 1.0 + a_free / myAccel, 1.0)));
720 }
721
722 return erg;
723}
724
725void
726MSCFModel_EIDM::internalspeedlimit(MSVehicle* const veh, const double oldV) const {
727
729
730 double v_limcurr, v_limprev;
731 v_limcurr = vars->v0_int; // model internal desired speed limit
732 v_limprev = vars->v0_old; // previous desired speed limit for calculation reasons
733
734 const MSLane* lane = veh->getLane();
735 const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation();
736 int view = 1;
737 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
738 double seen = lane->getLength() - veh->getPositionOnLane();
739 double v0 = lane->getVehicleMaxSpeed(veh); // current desired lane speed
740
741 // @ToDo: nextTurn is only defined in sublane-model calculation?!
742 // @ToDo: So cannot use it yet, but the next turn or speed recommendation for the street curvature (e.g. vmax=sqrt(a_transverse*Radius), a_transverse=3-4m/s^2)
743 // @ToDo: should not come from here, but from MSVehicle/the street network
744 // const std::pair<double, LinkDirection> nextTurn = veh->getNextTurn();
745
746 // When driving on the last lane/link, the vehicle shouldn't adapt to the lane after anymore.
747 // Otherwise we check the <seen> time-distance and whether is lower than myTpreview
748 if (lane->isLinkEnd(link) != 1 && (seen < oldV * myTpreview || seen < v0 * myTpreview / 2)) {
749 double speedlim = 200;
750 while (true) { // loop over all upcoming edges/lanes/links until the <seen> time-distance is higher than myTpreview
751 if (lane->isLinkEnd(link) != 1 && (seen < oldV * myTpreview || seen < v0 * myTpreview / 2)) { // @ToDo: add && (*link)->havePriority()???
752 // @ToDo: When vehicles already brake because of a minor link, it may not be necessary to adapt the internal desired speed when turning...
753 // @ToDo: The vehicle brakes anyway and it may happen, that is brakes too hard because of the low internal desired speed and takes too long
754 // @ToDo: to accelerate again, because the internal desired speed must rise again?!
755 // @ToDo: It can't be done via (*link)->havePriority() (vehicle will not brake for other vehicles, so it needs to brake for curve radius),
756 // @ToDo: because then turning at traffic lights or somewhere else might be missing (traffic light links don't have priority definition?!)
757 LinkDirection dir = (*link)->getDirection();
758 switch (dir) {
760 break;
762 break;
764 speedlim = 4;
765 break;
767 speedlim = 4;
768 break;
770 speedlim = 8;
771 break;
773 speedlim = 6;
774 break;
776 speedlim = 12;
777 break;
779 speedlim = 12;
780 break;
781 }
782
783 if (v0 > speedlim * veh->getChosenSpeedFactor() + NUMERICAL_EPS) {
784 v0 = speedlim * veh->getChosenSpeedFactor();
785 }
786 } else {
787 break;
788 }
789 if ((*link)->getViaLane() == nullptr) {
790 ++view;
791 }
792 lane = (*link)->getViaLaneOrLane();
793 // @ToDo: Previously: (seen < oldV*myTpreview / 2 || seen < v0*myTpreview / 4)! Changed freeSpeed, so also changed v0-calculation here.
794 // @ToDo: Vehicle now decelerates to new Speedlimit before reaching new edge (not /2 anymore)!
795 // @ToDo: v0 for changing speed limits when seen < oldV*myTpreview, not seen < oldV*myTpreview/2 anymore!!!
796 if (v0 > lane->getVehicleMaxSpeed(veh)) {
797 v0 = lane->getVehicleMaxSpeed(veh);
798 }
799 seen += lane->getLength();
800 link = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
801 }
802
803 if (!(v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) || // if v_limprev!=v0, then the upcoming v0 is different, than the old desired v_limprev and therefore v0_int must change slowly to the new v0
804 (v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS && !(v_limprev < v_limcurr + NUMERICAL_EPS && v_limprev > v_limcurr - NUMERICAL_EPS))) { // When v_limprev==v0, but v_limprev!=v_limcurr, then we may have a special case and need to slowly change v_limcurr to v0
805
806 if ((v_limcurr < v_limprev + NUMERICAL_EPS && v_limcurr < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) || // important when v_limcurr < v0 < v_limprev --> v_limcurr was decreasing, but needs to suddenly increase again
807 (v_limcurr > v_limprev - NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS && v_limprev < v0 + NUMERICAL_EPS)) { // important when v_limcurr > v0 > v_limprev --> v_limcurr was increasing, but needs to suddenly decrease again
808 vars->v0_old = v_limcurr;
809 } else {
810 if (v_limcurr >= v0 - NUMERICAL_EPS) { // v_limcurr is too high and needs to decrease
811 v_limcurr = MAX2(v0, v_limcurr - (v_limprev - v0) * TS / myTpreview);
812 } else { // v_limcurr is too low and needs to increase
813 v_limcurr = MIN2(v0, v_limcurr - (v_limprev - v0) * TS / myTpreview);
814 }
815 }
816
817 // when v_limcurr reaches v0, then update v_limprev=v0
818 if (v_limcurr < v0 + NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS) {
819 vars->v0_old = v0;
820 vars->v0_int = v0;
821 } else { // else just update the internal desired speed with v_limcurr
822 vars->v0_int = v_limcurr;
823 }
824 }
825
826 } else if (!(v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) || // if v_limprev!=v0, then the upcoming v0 is different, than the old desired v_limprev and therefore v0_int must change slowly to the new v0
827 (v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS && !(v_limprev < v_limcurr + NUMERICAL_EPS && v_limprev > v_limcurr - NUMERICAL_EPS))) { // When v_limprev==v0, but v_limprev!=v_limcurr, then we may have a special case and need to slowly change v_limcurr to v0
828
829 if ((v_limcurr < v_limprev + NUMERICAL_EPS && v_limcurr < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) || // important when v_limcurr < v0 < v_limprev --> v_limcurr was decreasing, but needs to suddenly increase again
830 (v_limcurr > v_limprev - NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS && v_limprev < v0 + NUMERICAL_EPS)) { // important when v_limcurr > v0 > v_limprev --> v_limcurr was increasing, but needs to suddenly decrease again
831 vars->v0_old = v_limcurr;
832 } else {
833 if (v_limcurr >= v0 - NUMERICAL_EPS) { // v_limcurr is too high and needs to decrease
834 v_limcurr = MAX2(v0, v_limcurr - (v_limprev - v0) * TS / myTpreview);
835 } else { // v_limcurr is too low and needs to increase
836 v_limcurr = MIN2(v0, v_limcurr - (v_limprev - v0) * TS / myTpreview);
837 }
838 }
839
840 // when v_limcurr reaches v0, then update v_limprev=v0
841 if (v_limcurr < v0 + NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS) {
842 vars->v0_old = v0;
843 vars->v0_int = v0;
844 } else { // else just update the internal desired speed with v_limcurr
845 vars->v0_int = v_limcurr;
846 }
847 }
848}
849
850double
851MSCFModel_EIDM::_v(const MSVehicle* const veh, const double gap2pred, const double egoSpeed,
852 const double predSpeed, const double desSpeed, const bool respectMinGap, const int update, const CalcReason usage) const {
853
854 double v0 = MAX2(NUMERICAL_EPS, desSpeed);
856
857 // @ToDo: Where to put such an insertion function/update, which only needs to be calculated once at the first step?????!
858 // For the first iteration
859 if (vars->v0_old == 0) {
861 vars->v0_old = MAX2(NUMERICAL_EPS, veh->getLane()->getVehicleMaxSpeed(veh));
862 vars->v0_int = MAX2(NUMERICAL_EPS, veh->getLane()->getVehicleMaxSpeed(veh));
863 v0 = MAX2(NUMERICAL_EPS, veh->getLane()->getVehicleMaxSpeed(veh));
864 }
865
866 double wantedacc = 0., a_free;
867 double wouldacc = 0., woulds, woulda_free;
868
869 double estSpeed, estleaderSpeed, estGap;
870 double current_estSpeed, current_estGap, current_estleaderSpeed;
871 double current_gap;
872 double acc = 0.;
873 double a_leader = NUMERICAL_EPS; // Default without a leader, should not be 0!
874 double newSpeed = egoSpeed;
875 bool lastrespectMinGap = respectMinGap;
876 const double minGapStop_EPS = 0.05 + 0.20 * MAX2(0.25, myAccel);
877
878 // When doing the Follow-Calculation in adapttoLeader (MSVehicle.cpp) the mingap gets subtracted from the current gap (maybe this is needed for the Krauss-Model!).
879 // For the IDM this Mingap is needed or else the vehicle will stop at two times mingap behind the leader!
880 if (respectMinGap) {
881 current_gap = MAX2(NUMERICAL_EPS, gap2pred + MAX2(NUMERICAL_EPS, myType->getMinGap() - 0.25)); // 0.25m tolerance because of reaction time and estimated variables
882 } else {
883 // gap2pred may go to 0 when offset is reached (e.g. 1m Offset -> gap2pred=0, when vehicle stands at 0.95m, gap2pred is still 0 and does not become -0.05m (negative)!)
884 current_gap = MAX2(NUMERICAL_EPS, gap2pred + minGapStop_EPS);
885 }
886
887 double newGap = current_gap;
888
889 for (int i = 0; i < myIterations; i++) {
890
891 // Using Action-Point reaction time: update the variables, when myap_update is zero and update is 1
892 current_estSpeed = newSpeed;
893 if (respectMinGap) {
894 current_estleaderSpeed = MAX2(predSpeed - newGap * mySigmaleader * vars->myw_speed, 0.0); // estimated variable with Wiener Prozess
895 } else {
896 // @ToDo: Use this??? driver would always know, that junctions, traffic lights, etc. have v=0!
897 // @ToDo: With estimated variables predSpeed > 0 is possible! > 0 may result in oscillating
898 current_estleaderSpeed = predSpeed;
899 }
900 if (update == 2) { // For freeSpeed
901 current_estGap = newGap; // not-estimated variable
902 } else {
903 if (respectMinGap) {
904 current_estGap = newGap * exp(mySigmagap * vars->myw_gap); // estimated variable with Wiener Prozess
905 } else {
906 current_estGap = newGap * exp(mySigmagap * vars->myw_gap * MIN2(current_estSpeed / EST_REAC_THRESHOLD, 1.0)); // estimated variable with Wiener Prozess
907 }
908 }
909
910 if (vars->myap_update == 0 && usage == CalcReason::CURRENT) { // update variables with current observation
911 estSpeed = current_estSpeed;
912 estleaderSpeed = current_estleaderSpeed; // estimated variable with Wiener Prozess
913 estGap = current_estGap; // estimated variable with Wiener Prozess
914 } else if (usage == CalcReason::CURRENT) { // use stored variables (reaction time)
915 estSpeed = MAX2(vars->myv_est + vars->lastrealacc * (vars->myap_update * TS - TS * (myIterations - i - 1.) / myIterations), 0.0);
916 // estSpeed = vars->myv_est;
917 if (update == 2) { // For freeSpeed
918 estGap = newGap; // not-estimated variable
919 estleaderSpeed = MAX2(vars->myv_est_l + vars->lastleaderacc * (vars->myap_update * TS - TS * (myIterations - i - 1.) / myIterations) - vars->mys_est * mySigmaleader * vars->myw_speed, 0.0);
920 // estleaderSpeed = MAX2(vars->myv_est_l - vars->mys_est * mySigmaleader*vars->myw_speed, 0.0);
921 } else {
922 lastrespectMinGap = vars->myrespectMinGap;
923 if (lastrespectMinGap) {
924 estleaderSpeed = MAX2(vars->myv_est_l + vars->lastleaderacc * (vars->myap_update * TS - TS * (myIterations - i - 1.) / myIterations) - vars->mys_est * mySigmaleader * vars->myw_speed, 0.0);
925 // estleaderSpeed = MAX2(vars->myv_est_l - vars->mys_est * mySigmaleader*vars->myw_speed, 0.0);
926 estGap = vars->mys_est * exp(mySigmagap * vars->myw_gap) - ((vars->myv_est + estSpeed) / 2. - (vars->myv_est_l + estleaderSpeed) / 2.) * (vars->myap_update * TS - TS * (myIterations - i - 1.) / myIterations); // estimated variable with Wiener Prozess
927 } else {
928 // @ToDo: Use this??? driver would always know, that junctions, traffic lights, etc. have v=0!
929 // @ToDo: With estimated variables predSpeed > 0 is possible! > 0 may result in oscillating
930 estleaderSpeed = vars->myv_est_l;
931 estGap = vars->mys_est * exp(mySigmagap * vars->myw_gap * MIN2(current_estSpeed / EST_REAC_THRESHOLD, 1.0)) - ((vars->myv_est + estSpeed) / 2. - (vars->myv_est_l + estleaderSpeed) / 2.) * (vars->myap_update * TS - TS * (myIterations - i - 1.) / myIterations); // estimated variable with Wiener Prozess
932 }
933 }
934 } else { // use actual variables without reaction time
935 estSpeed = current_estSpeed;
936 estleaderSpeed = current_estleaderSpeed; // estimated variable with Wiener Prozess
937 estGap = current_estGap; // estimated variable with Wiener Prozess
938 }
939
940 // ToDo: The headway can change for IDMM based on the scenario, should something like that also be integrated here???
941 double headwayTime = myHeadwayTime;
942 MSVehicle* leader;
943
944 double s = MAX2(0., estSpeed * headwayTime + estSpeed * (estSpeed - estleaderSpeed) / myTwoSqrtAccelDecel);
945 if (lastrespectMinGap) {
947 } else {
948 s += minGapStop_EPS + EIDM_POS_ACC_EPS;
949 }
950
951 // Because of the reaction time and estimated variables, s* can become lower than gap when the vehicle needs to brake/is braking, that results in the vehicle accelerating again...
952 // Here: When the gap is very small, s* is influenced to then always be bigger than the gap. With this there are no oscillations in accel at small gaps!
953 if (lastrespectMinGap) {
954 // The allowed position error when coming to a stop behind a leader is higher with higher timesteps (approx. 0.5m at 1.0s timstep, 0.1m at 0.1s)
955 if (estGap < myType->getMinGap() + (TS * 10 + 1) * EIDM_POS_ACC_EPS && estSpeed < EST_REAC_THRESHOLD && s < estGap * sqrt(1 + 2 * EIDM_POS_ACC_EPS / myAccel)) {
956 s = estGap * sqrt(1 + 2 * EIDM_POS_ACC_EPS / myAccel);
957 }
958 } else {
959 if (estGap < minGapStop_EPS + 2 * EIDM_POS_ACC_EPS && s < estGap * sqrt(1 + EIDM_POS_ACC_EPS / myAccel)) {
960 // when the vehicle wants to stop (stopSpeed), it may take long to come to a full stop
961 // To lower this stop time, we restrict the deceleration to always be higher than 0.05m/s^2 when stopping
962 s = estGap * sqrt(1 + EIDM_POS_ACC_EPS / myAccel);
963 }
964 }
965
966 // IDM calculation:
967 // wantedacc = myAccel * (1. - pow(estSpeed / v0, myDelta) - (s * s) / (estGap * estGap));
968
969 // IIDM calculation -NOT- from the original Treiber/Kesting publication:
970 // With the saved variables from the last Action Point
971 /*double wantedacc;
972 double a_free = myAccel * (1. - pow(estSpeed / v0, myDelta));
973 if (s >= estGap) { // This is the IIDM
974 wantedacc = myAccel * (1. - (s * s) / (estGap * estGap));
975 } else {
976 wantedacc = a_free * (1. - pow(s / estGap, 2*myAccel / fabs(a_free)));
977 }*/ // Old calculation form without the distinction between v > v0 and v <= v0!!! Published it in the EIDM with this form, but may be worse than original IIDM!
978
979 // IIDM calculation from the original Treiber/Kesting publication:
980 // With the saved variables from the last Action Point
981 if (estSpeed <= v0) {
982 a_free = myAccel * (1. - pow(estSpeed / v0, myDelta));
983 if (s >= estGap) {
984 wantedacc = myAccel * (1. - (s * s) / (estGap * estGap));
985 } else {
986 wantedacc = a_free * (1. - pow(s / estGap, 2 * myAccel / a_free));
987 }
988 } else { // estSpeed > v0
989 a_free = - myDecel * (1. - pow(v0 / estSpeed, myAccel * myDelta / myDecel));
990 if (s >= estGap) {
991 wantedacc = a_free + myAccel * (1. - (s * s) / (estGap * estGap));
992 } else {
993 wantedacc = a_free;
994 }
995 }
996 wantedacc = SPEED2ACCEL(MAX2(0.0, estSpeed + ACCEL2SPEED(wantedacc)) - estSpeed);
997
998 // IIDM calculation from the original Treiber/Kesting publication:
999 // With the current variables (what would the acceleration be without reaction time)
1000 if (usage == CalcReason::CURRENT) {
1001 woulds = MAX2(0., current_estSpeed * headwayTime + current_estSpeed * (current_estSpeed - current_estleaderSpeed) / myTwoSqrtAccelDecel); // s_soll
1002 if (respectMinGap) {
1003 woulds += myType->getMinGap() + EIDM_POS_ACC_EPS; // when behind a vehicle use MinGap and when at a junction then not????
1004 } else {
1005 woulds += minGapStop_EPS + EIDM_POS_ACC_EPS;
1006 }
1007
1008 if (current_estSpeed <= v0) {
1009 woulda_free = myAccel * (1. - pow(current_estSpeed / v0, myDelta));
1010 if (woulds >= current_estGap) {
1011 wouldacc = myAccel * (1. - (woulds * woulds) / (current_estGap * current_estGap));
1012 } else {
1013 wouldacc = woulda_free * (1. - pow(woulds / current_estGap, 2 * myAccel / woulda_free));
1014 }
1015 } else { // current_estSpeed > v0
1016 woulda_free = - myDecel * (1. - pow(v0 / current_estSpeed, myAccel * myDelta / myDecel));
1017 if (woulds >= current_estGap) {
1018 wouldacc = woulda_free + myAccel * (1. - (woulds * woulds) / (current_estGap * current_estGap));
1019 } else {
1020 wouldacc = woulda_free;
1021 }
1022 }
1023 wouldacc = SPEED2ACCEL(MAX2(0.0, current_estSpeed + ACCEL2SPEED(wouldacc)) - current_estSpeed);
1024 }
1025
1026 // @ToDo: calc_gap is just estGap here, used to have an extra calc_gap calculation (like jmax), but doesn't work well here with the junction calculation:
1027 // @ToDo: The driver would slowly start accelerating when he thinks the junction is clear, but may still decelerate for a bit and not jump to acceleration.
1028 // @ToDo: This causes the driver not to drive over the junction because he thinks he won't make it in time before a foe may appear!
1029
1030 // IIDM calculation -NOT- from the original Treiber/Kesting publication:
1031 // Resulting acceleration also with the correct drive off term.
1032 double calc_gap = estGap;
1033 /*a_free = myAccel * (1. - pow(estSpeed / v0, myDelta));
1034 if (s >= calc_gap) { // This is the IIDM
1035 acc = myAccel * (1. - (s * s) / (calc_gap * calc_gap));
1036 } else {
1037 acc = a_free * (1. - pow(s / calc_gap, 2*myAccel / fabs(a_free)));
1038 } */ // Old calculation form without the distinction between v > v0 and v <= v0!!! Published it in the EIDM with this form, but may be worse than original IIDM!
1039
1040 // IDM calculation:
1041 // acc = myAccel * (1. - pow(estSpeed / v0, myDelta) - (s * s) / (calc_gap * calc_gap));
1042
1043 // IIDM calculation from the original Treiber/Kesting publication:
1044 // Resulting acceleration also with the correct drive off term.
1045 if (estSpeed <= v0) {
1046 a_free = myAccel * (1. - pow(estSpeed / v0, myDelta));
1047 if (s >= calc_gap) {
1048 acc = myAccel * (1. - (s * s) / (calc_gap * calc_gap));
1049 } else {
1050 acc = a_free * (1. - pow(s / calc_gap, 2 * myAccel / a_free));
1051 }
1052 } else { // estSpeed > v0
1053 a_free = - myDecel * (1. - pow(v0 / estSpeed, myAccel * myDelta / myDecel));
1054 if (s >= calc_gap) {
1055 acc = a_free + myAccel * (1. - (s * s) / (calc_gap * calc_gap));
1056 } else {
1057 acc = a_free;
1058 }
1059 }
1060
1061 double a_cah;
1062 // Coolness from Enhanced Intelligent Driver Model, when gap "jump" to a smaller gap accurs
1063 // @ToDo: Maybe without usage == CalcReason::CURRENT??? To let all calculations profit from Coolness??? (e.g. also lane change calculation)
1064 if (vars->minaccel > wantedacc - NUMERICAL_EPS && usage == CalcReason::CURRENT) {
1065
1066 leader = (MSVehicle*)veh->getLeader(estGap + 25).first;
1067 if (leader != nullptr && lastrespectMinGap && estleaderSpeed >= SPEED_EPS) {
1068 a_leader = MIN2(leader->getAcceleration(), myAccel);
1069 // Change a_leader to lower values when far away from leader or else far away leaders influence the ego-vehicle!
1070 if (estGap > s * 3 / 2) { // maybe estGap > 2*s???
1071 a_leader = a_leader * (s * 3 / 2) / estGap;
1072 }
1073 }
1074
1075 // speed of the leader shouldnt become zero, because then problems with the calculation occur
1076 if (estleaderSpeed < SPEED_EPS) {
1077 estleaderSpeed = SPEED_EPS;
1078 }
1079
1080 if (vars->t_off + myTaccmax + NUMERICAL_EPS < (SIMTIME - TS * (myIterations - i - 1.) / myIterations) && egoSpeed > SUMO_const_haltingSpeed) {
1081
1082 // Enhanced Intelligent Driver Model
1083 if (estleaderSpeed * (estSpeed - estleaderSpeed) <= -2 * estGap * a_leader) {
1084 a_cah = (estSpeed * estSpeed * a_leader) / (estleaderSpeed * estleaderSpeed - 2 * estGap * a_leader);
1085 } else {
1086 if (estSpeed - estleaderSpeed >= 0) {
1087 a_cah = a_leader - ((estSpeed - estleaderSpeed) * (estSpeed - estleaderSpeed)) / (2 * estGap);
1088 } else {
1089 a_cah = a_leader;
1090 }
1091 }
1092
1093 if (acc >= a_cah) {
1094 // do nothing, meaning acc = acc_IDM;
1095 } else {
1096 acc = (1 - myCcoolness) * acc + myCcoolness * (a_cah + myDecel * tanh((acc - a_cah) / myDecel));
1097 }
1098 }
1099 }
1100
1101 newSpeed = MAX2(0.0, current_estSpeed + ACCEL2SPEED(acc) / myIterations);
1102
1103 // Euler Update as future gap prediction, this will be the "real" gap with this timestep and speed calculation
1104 // Although this is the correct gap prediction, the calculation is unstable with this method
1105 //newGap = MAX2(NUMERICAL_EPS, current_gap - SPEED2DIST(newSpeed - predSpeed) * ((i + 1.) / myIterations));
1106
1107 // Ballistic Update as future gap prediction, this will be the "real" gap with this timestep and speed calculation
1108 // Although this is the correct gap prediction, the calculation is unstable with this method
1109 //newGap = MAX2(NUMERICAL_EPS, current_gap - SPEED2DIST(MAX2(0.0, current_estSpeed + 0.5 * ACCEL2SPEED(acc) ((i + 1.) / myIterations)) - predSpeed) * ((i + 1.) / myIterations));
1110
1111 // We cannot rely on sub-timesteps, because the here calculated "sub"-gap will not match the "full"-gap calculation of the Euler/Ballistic Update.
1112 // The "full"-gap is only calculated with the last measured newSpeed, while the "sub"-gap uses all "sub"-newSpeeds
1113 // Example: In the last iteration-step newSpeed becomes 0. Therefore in the Euler Update, the vehicle does not move for the whole timestep!
1114 // Example: But in the "sub"-gaps the vehicle may have moved. Therefore, stops can sometimes not be reached
1115 newGap = MAX2(NUMERICAL_EPS, newGap - MAX2(0., SPEED2DIST(newSpeed - predSpeed) / myIterations));
1116 // Ballistic:
1117 //newGap = MAX2(NUMERICAL_EPS, newGap - MAX2(0., SPEED2DIST(MAX2(0.0, current_estSpeed + 0.5 * ACCEL2SPEED(acc) / myIterations) - predSpeed) / myIterations));
1118
1119 // To always reach stops in high-timestep simulations, we adapt the speed to the actual distance that is covered:
1120 // This may only be needed for Euler Update...
1121 if (myIterations > 1 && newSpeed < EST_REAC_THRESHOLD * TS && !lastrespectMinGap) {
1122 newSpeed = MAX2(0.0, predSpeed + DIST2SPEED(current_gap - newGap) * myIterations / (i + 1.));
1123 }
1124 }
1125
1126 // The "real" acceleration after iterations
1127 acc = SPEED2ACCEL(MIN2(newSpeed, maxNextSpeed(egoSpeed, veh)) - veh->getSpeed());
1128
1129#ifdef DEBUG_V
1130 if (veh->isSelected()) {
1131 std::cout << SIMTIME
1132 << " EIDM::_v "
1133 << " veh=" << veh->getID()
1134 << " vars->minaccel=" << vars->minaccel
1135 << " vars->myap_update=" << vars->myap_update
1136 << " vars->myv_est_l=" << vars->myv_est_l
1137 << " vars->myv_est=" << vars->myv_est
1138 << " vars->mys_est=" << vars->mys_est
1139 << " vars->wouldacc=" << vars->wouldacc
1140 << " vars->realacc=" << vars->realacc
1141 << "\n";
1142 std::cout << SIMTIME
1143 << " EIDM::_v (2) "
1144 << " veh=" << veh->getID()
1145 << " newSpeed=" << newSpeed
1146 << " newGap=" << newGap
1147 << " predSpeed=" << predSpeed
1148 << " estSpeed=" << estSpeed
1149 << " estleaderSpeed=" << estleaderSpeed
1150 << " estGap=" << estGap
1151 << " wantedacc=" << wantedacc
1152 << " wouldacc=" << wouldacc
1153 << " acc=" << acc
1154 << "\n";
1155 }
1156#endif
1157
1158 // wantedacc is already calculated at this point. acc may still change (because of coolness and drive off), but the ratio should stay the same!
1159 // this means when vars->minaccel > wantedacc stands, so should vars->minaccel > acc!
1160 // When updating at an Action Point, store the observed variables for the next time steps until the next Action Point.
1161 if (vars->minaccel > wantedacc - NUMERICAL_EPS && vars->myap_update == 0 && usage == CalcReason::CURRENT) {
1162 vars->myv_est_l = predSpeed;
1163 vars->myv_est = egoSpeed;
1164 if (update == 2) { // For freeSpeed
1165 vars->mys_est = current_gap + myTreaction * egoSpeed;
1166 } else {
1167 vars->mys_est = current_gap;
1168 }
1169 vars->myrespectMinGap = respectMinGap;
1170 }
1171
1172 if (usage == CalcReason::CURRENT && vars->wouldacc > wouldacc) {
1173 vars->wouldacc = wouldacc;
1174 }
1175
1176 // It can happen that wantedacc ist higher than previous calculated wantedacc, BUT acc is lower than prev calculated values!
1177 // This often occurs because of "coolness"+Iteration and in this case "acc" is set to the previous (higher) calculated value!
1178 if (vars->realacc > acc && vars->minaccel <= wantedacc - NUMERICAL_EPS && usage == CalcReason::CURRENT) {
1179 acc = vars->realacc;
1180 newSpeed = MAX2(0.0, egoSpeed + ACCEL2SPEED(acc));
1181 }
1182
1183 // Capture the relevant variables, because it was determined, that this call will result in the acceleration update (vars->minaccel > wantedacc)
1184 if (vars->minaccel > wantedacc - NUMERICAL_EPS && usage == CalcReason::CURRENT) {
1185 vars->minaccel = wantedacc;
1186 if (vars->realacc > acc) {
1187 vars->realacc = acc;
1188 }
1189 vars->realleaderacc = a_leader;
1190 }
1191
1192 // Save the parameters for a potential update in finalizeSpeed, when _v was called in a stopSpeed-function!!!
1193 if (vars->minaccel > wantedacc - NUMERICAL_EPS && usage == CalcReason::CURRENT_WAIT && !respectMinGap) {
1194 vars->stop.push_back(std::make_pair(acc, gap2pred));
1195 }
1196
1197 return MAX2(0., newSpeed);
1198}
1199
1200
1201MSCFModel*
1203 return new MSCFModel_EIDM(vtype);
1204}
long long int SUMOTime
Definition: GUI.h:36
#define DEBUG_COND2(obj)
Definition: MESegment.cpp:52
#define EMERGENCY_DECEL_AMPLIFIER
Definition: MSCFModel.h:33
#define ClutchEngageSpeed
#define EIDM_POS_ACC_EPS
#define EST_REAC_THRESHOLD
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define SPEED2DIST(x)
Definition: SUMOTime.h:44
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:50
#define TS
Definition: SUMOTime.h:41
#define SIMTIME
Definition: SUMOTime.h:61
#define DIST2SPEED(x)
Definition: SUMOTime.h:46
#define ACCEL2DIST(x)
Definition: SUMOTime.h:48
#define SPEED2ACCEL(x)
Definition: SUMOTime.h:52
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
@ SUMO_ATTR_CF_EIDM_T_ACC_MAX
@ SUMO_ATTR_CF_EIDM_EPSILON_ACC
@ SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD
@ SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS
@ SUMO_ATTR_CF_EIDM_C_COOLNESS
@ SUMO_ATTR_CF_EIDM_SIG_ERROR
@ SUMO_ATTR_CF_IDM_DELTA
@ SUMO_ATTR_CF_EIDM_T_REACTION
@ SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE
@ SUMO_ATTR_CF_EIDM_SIG_GAP
@ SUMO_ATTR_CF_EIDM_JERK_MAX
@ SUMO_ATTR_CF_IDM_STEPPING
@ SUMO_ATTR_COLLISION_MINGAP_FACTOR
@ SUMO_ATTR_CF_EIDM_M_FLATNESS
@ SUMO_ATTR_CF_EIDM_M_BEGIN
@ SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE
@ SUMO_ATTR_CF_EIDM_SIG_LEADER
T MIN2(T a, T b)
Definition: StdDefs.h:71
T ISNAN(T a)
Definition: StdDefs.h:112
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
T MAX2(T a, T b)
Definition: StdDefs.h:77
T MAX3(T a, T b, T c)
Definition: StdDefs.h:91
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. It uses information on LC-related desired ...
virtual bool isSelected() const
whether this vehicle is selected in the GUI
double getChosenSpeedFactor() const
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
std::vector< std::pair< double, double > > stop
const double myTPersEstimate
double patchSpeedBeforeLCEIDM(const MSVehicle *veh, double vMin, double vMax, const VehicleVariables *vars) const
Applies dawdling / driving error.
const double myTPersDrive
~MSCFModel_EIDM()
Destructor.
const double myDelta
const double myCcoolness
const double myTaccmax
const double mySigmaleader
const double myEpsilonacc
double slowToStartTerm(MSVehicle *const veh, const double newSpeed, const double currentSpeed, const double vMax, VehicleVariables *vars) const
double maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Returns the maximum safe velocity for following the given leader.
double maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap.
double insertionFollowSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0) const
Computes the vehicle's safe speed (no dawdling) This method is used during the insertion stage....
double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences.
const double myTreaction
const double myMbegin
const double myTwoSqrtAccelDecel
double stopSpeed(const MSVehicle *const veh, const double speed, double gap, double decel, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed for approaching a non-moving obstacle.
MSCFModel_EIDM(const MSVehicleType *vtype)
Constructor.
double insertionStopSpeed(const MSVehicle *const veh, double speed, double gap) const
Computes the vehicle's safe speed for approaching an obstacle at insertion without constraints due to...
double freeSpeed(const MSVehicle *const veh, double speed, double seen, double maxSpeed, const bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed without a leader.
double internalsecuregap(const MSVehicle *const veh, const double speed, const double leaderSpeed, const double targetDecel) const
const double mySigmagap
double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed.
void internalspeedlimit(MSVehicle *const veh, const double oldV) const
double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
const double myMflatness
const double myJerkmax
MSCFModel * duplicate(const MSVehicleType *vtype) const
Duplicates the car-following model.
double interactionGap(const MSVehicle *const, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
const double mySigmaerror
const double myTpreview
const int myIterations
double _v(const MSVehicle *const veh, const double gap2pred, const double mySpeed, const double predSpeed, const double desSpeed, const bool respectMinGap, const int update, const CalcReason usage) const
The car-following model abstraction.
Definition: MSCFModel.h:55
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
Definition: MSCFModel.cpp:270
virtual double minNextSpeedEmergency(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed after emergency braking, given the current speed (depends on the numerical ...
Definition: MSCFModel.cpp:287
virtual double applyStartupDelay(const MSVehicle *veh, const double vMin, const double vMax, const SUMOTime addTime=0) const
apply speed adaptation on startup
Definition: MSCFModel.cpp:235
double getEmergencyDecel() const
Get the vehicle type's maximal phisically possible deceleration [m/s^2].
Definition: MSCFModel.h:270
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:276
SUMOTime myStartupDelay
The startup delay after halting [s].
Definition: MSCFModel.h:698
double myEmergencyDecel
The vehicle's maximum emergency deceleration [m/s^2].
Definition: MSCFModel.h:688
CalcReason
What the return value of stop/follow/free-Speed is used for.
Definition: MSCFModel.h:77
double myCollisionMinGapFactor
The factor of minGap that must be maintained to avoid a collision event.
Definition: MSCFModel.h:692
double calculateEmergencyDeceleration(double gap, double egoSpeed, double predSpeed, double predMaxDecel) const
Returns the minimal deceleration for following the given leader safely.
Definition: MSCFModel.cpp:977
double myDecel
The vehicle's maximum deceleration [m/s^2].
Definition: MSCFModel.h:686
double myAccel
The vehicle's maximum acceleration [m/s^2].
Definition: MSCFModel.h:683
const MSVehicleType * myType
The type to which this model definition belongs to.
Definition: MSCFModel.h:680
double maximumSafeStopSpeedBallistic(double gap, double decel, 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:830
double myHeadwayTime
The driver's desired time headway (aka reaction time tau) [s].
Definition: MSCFModel.h:695
static bool gSemiImplicitEulerUpdate
Definition: MSGlobals.h:53
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition: MSGlobals.h:136
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition: MSLane.cpp:2379
double getLength() const
Returns the lane's length.
Definition: MSLane.h:575
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition: MSLane.h:802
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition: MSLane.h:547
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
SUMOTime getTimeSinceStartup() const
Returns the SUMOTime spent driving since startup (speed was larger than 0.1m/s)
Definition: MSVehicle.h:673
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5367
double getAcceleration() const
Returns the vehicle's acceleration in m/s (this is computed as the last step's mean acceleration in c...
Definition: MSVehicle.h:510
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
Definition: MSVehicle.cpp:5848
std::pair< const MSVehicle *const, double > getLeader(double dist=0) const
Returns the leader of the vehicle looking for a fixed distance.
Definition: MSVehicle.cpp:6088
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:577
double getSpeed() const
Returns the vehicle's current speed.
Definition: MSVehicle.h:486
double processNextStop(double currentVelocity)
Processes stops, returns the velocity needed to reach the stop.
Definition: MSVehicle.cpp:1593
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition: MSVehicle.h:377
MSCFModel::VehicleVariables * getCarFollowVariables() const
Returns the vehicle's car following model variables.
Definition: MSVehicle.h:987
The car-following model and parameter.
Definition: MSVehicleType.h:63
double getMaxSpeed() const
Get vehicle's (technical) maximum speed [m/s].
double getMinGap() const
Get the free space in front of vehicles of this class.
const SUMOVTypeParameter & getParameter() const
const std::string & getID() const
Returns the id.
Definition: Named.h:74
static double randNorm(double mean, double variance, SumoRNG *rng=nullptr)
Access to a random number from a normal distribution.
Definition: RandHelper.cpp:137
double getCFParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.