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