1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MSCFModel_IDM.cpp
11 /// @author Tobias Mayer
12 /// @author Daniel Krajzewicz
13 /// @author Michael Behrisch
14 /// @date Thu, 03 Sep 2009
15 /// @version $Id$
16 ///
17 // The Intelligent Driver Model (IDM) car-following model
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include "MSCFModel_IDM.h"
27 #include <microsim/MSVehicle.h>
28
29 //#define DEBUG_V
30
31 // ===========================================================================
32 // method definitions
33 // ===========================================================================
MSCFModel_IDM(const MSVehicleType * vtype,bool idmm)34 MSCFModel_IDM::MSCFModel_IDM(const MSVehicleType* vtype, bool idmm) :
35 MSCFModel(vtype),
36 myIDMM(idmm),
37 myDelta(idmm ? 4.0 : vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_DELTA, 4.)),
38 myAdaptationFactor(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR, 1.8) : 1.0),
39 myAdaptationTime(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_TIME, 600.0) : 0.0),
40 myIterations(MAX2(1, int(TS / vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_STEPPING, .25) + .5))),
41 myTwoSqrtAccelDecel(double(2 * sqrt(myAccel * myDecel))) {
42 // IDM does not drive very precise and may violate minGap on occasion
43 myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.5);
44 }
45
~MSCFModel_IDM()46 MSCFModel_IDM::~MSCFModel_IDM() {}
47
48
49 double
finalizeSpeed(MSVehicle * const veh,double vPos) const50 MSCFModel_IDM::finalizeSpeed(MSVehicle* const veh, double vPos) const {
51 const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
52 if (myAdaptationFactor != 1.) {
53 VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
54 vars->levelOfService += (vNext / veh->getLane()->getVehicleMaxSpeed(veh) - vars->levelOfService) / myAdaptationTime * TS;
55 }
56 return vNext;
57 }
58
59
60 double
followSpeed(const MSVehicle * const veh,double speed,double gap2pred,double predSpeed,double,const MSVehicle * const) const61 MSCFModel_IDM::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double /*predMaxDecel*/, const MSVehicle* const /*pred*/) const {
62 #ifdef DEBUG_V
63 gDebugFlag1 = veh->isSelected();
64 #endif
65 return _v(veh, gap2pred, speed, predSpeed, veh->getLane()->getVehicleMaxSpeed(veh));
66 }
67
68
69 double
insertionFollowSpeed(const MSVehicle * const v,double speed,double gap2pred,double predSpeed,double predMaxDecel) const70 MSCFModel_IDM::insertionFollowSpeed(const MSVehicle* const v, double speed, double gap2pred, double predSpeed, double predMaxDecel) const {
71 const double vMax = v->getLane()->getVehicleMaxSpeed(v);
72 // see definition of s in _v()
73 double s = MAX2(0., vMax * myHeadwayTime + vMax * (vMax - predSpeed) / myTwoSqrtAccelDecel);
74 if (gap2pred >= s) {
75 // followSpeed always stays below vMax because s*s / (gap2pred * gap2pred) > 0. This would prevent insertion with maximum speed at all distances
76 return vMax;
77 } else {
78 return followSpeed(v, speed, gap2pred, predSpeed, predMaxDecel);
79 }
80 }
81
82
83 double
stopSpeed(const MSVehicle * const veh,const double speed,double gap) const84 MSCFModel_IDM::stopSpeed(const MSVehicle* const veh, const double speed, double gap) const {
85 if (gap < 0.01) {
86 return 0;
87 }
88 double result = _v(veh, gap, speed, 0, veh->getLane()->getVehicleMaxSpeed(veh));
89 if (gap > 0 && speed < NUMERICAL_EPS && result < NUMERICAL_EPS) {
90 // ensure that stops can be reached:
91 //std::cout << " switching to krauss: " << veh->getID() << " gap=" << gap << " speed=" << speed << " res1=" << result << " res2=" << maximumSafeStopSpeed(gap, speed, false, veh->getActionStepLengthSecs())<< "\n";
92 result = maximumSafeStopSpeed(gap, speed, false, veh->getActionStepLengthSecs());
93 }
94 //if (result * TS > gap) {
95 // std::cout << "Maximum stop speed exceeded for gap=" << gap << " result=" << result << " veh=" << veh->getID() << " speed=" << speed << " t=" << SIMTIME << "\n";
96 //}
97 return result;
98 }
99
100
101 /// @todo update interactionGap logic to IDM
102 double
interactionGap(const MSVehicle * const veh,double vL) const103 MSCFModel_IDM::interactionGap(const MSVehicle* const veh, double vL) const {
104 // Resolve the IDM equation to gap. Assume predecessor has
105 // speed != 0 and that vsafe will be the current speed plus acceleration,
106 // i.e that with this gap there will be no interaction.
107 const double acc = myAccel * (1. - pow(veh->getSpeed() / veh->getLane()->getVehicleMaxSpeed(veh), myDelta));
108 const double vNext = veh->getSpeed() + acc;
109 const double gap = (vNext - vL) * (veh->getSpeed() + vL) / (2 * myDecel) + vL;
110
111 // Don't allow timeHeadWay < deltaT situations.
112 return MAX2(gap, SPEED2DIST(vNext));
113 }
114
115 double
getSecureGap(const double speed,const double leaderSpeed,const double) const116 MSCFModel_IDM::getSecureGap(const double speed, const double leaderSpeed, const double /*leaderMaxDecel*/) const {
117 const double delta_v = speed - leaderSpeed;
118 return MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel);
119 }
120
121
122 double
_v(const MSVehicle * const veh,const double gap2pred,const double egoSpeed,const double predSpeed,const double desSpeed,const bool respectMinGap) const123 MSCFModel_IDM::_v(const MSVehicle* const veh, const double gap2pred, const double egoSpeed,
124 const double predSpeed, const double desSpeed, const bool respectMinGap) const {
125 // this is more or less based on http://www.vwi.tu-dresden.de/~treiber/MicroApplet/IDM.html
126 // and http://arxiv.org/abs/cond-mat/0304337
127 // we assume however constant speed for the leader
128 double headwayTime = myHeadwayTime;
129 if (myAdaptationFactor != 1.) {
130 const VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
131 headwayTime *= myAdaptationFactor + vars->levelOfService * (1. - myAdaptationFactor);
132 }
133 double newSpeed = egoSpeed;
134 double gap = gap2pred;
135 if (respectMinGap) {
136 // gap2pred comes with minGap already subtracted so we need to add it here again
137 gap += myType->getMinGap();
138 }
139 for (int i = 0; i < myIterations; i++) {
140 const double delta_v = newSpeed - predSpeed;
141 double s = MAX2(0., newSpeed * headwayTime + newSpeed * delta_v / myTwoSqrtAccelDecel);
142 if (respectMinGap) {
143 s += myType->getMinGap();
144 }
145 gap = MAX2(NUMERICAL_EPS, gap); // avoid singularity
146 const double acc = myAccel * (1. - pow(newSpeed / desSpeed, myDelta) - (s * s) / (gap * gap));
147 #ifdef DEBUG_V
148 if (gDebugFlag1) {
149 std::cout << " gap=" << gap << " t=" << myHeadwayTime << " t2=" << headwayTime << " s=" << s << " pow=" << pow(newSpeed / desSpeed, myDelta) << " gapDecel=" << (s * s) / (gap * gap) << " a=" << acc;
150 }
151 #endif
152 newSpeed += ACCEL2SPEED(acc) / myIterations;
153 #ifdef DEBUG_V
154 if (gDebugFlag1) {
155 std::cout << " v2=" << newSpeed << "\n";
156 }
157 #endif
158 //TODO use more realistic position update which takes accelerated motion into account
159 gap -= MAX2(0., SPEED2DIST(newSpeed - predSpeed) / myIterations);
160 }
161 return MAX2(0., newSpeed);
162 }
163
164
165 MSCFModel*
duplicate(const MSVehicleType * vtype) const166 MSCFModel_IDM::duplicate(const MSVehicleType* vtype) const {
167 return new MSCFModel_IDM(vtype, myIDMM);
168 }
169