Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSCFModel_IDM.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-2026 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/****************************************************************************/
20// The Intelligent Driver Model (IDM) car-following model
21/****************************************************************************/
22#include <config.h>
23
24#include "MSCFModel_IDM.h"
25#include <microsim/MSVehicle.h>
27
28//#define DEBUG_V
29//#define DEBUG_INSERTION_SPEED
30
31#define DEBUG_COND (veh->isSelected())
32//#define DEBUG_COND true
33
34
35// ===========================================================================
36// method definitions
37// ===========================================================================
39 MSCFModel(vtype),
40 myIDMM(idmm),
41 myDelta(idmm ? 4.0 : vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_DELTA, 4.)),
42 myAdaptationFactor(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR, 1.8) : 1.0),
43 myAdaptationTime(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_TIME, 600.0) : 0.0),
44 myIterations(MAX2(1, int(TS / vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_STEPPING, .25) + .5))),
45 myTwoSqrtAccelDecel(double(2 * sqrt(myAccel * myDecel))) {
46 // IDM does not drive very precise and may violate minGap on occasion
48 if (TS / myIterations > 0.25) {
49 WRITE_WARNINGF("Stepping duration of % for % model in vType % is unsafe", (TS / myIterations), myIDMM ? "IDMM" : "IDM", vtype->getID());
50 }
51}
52
54
55
56void
59 out.writeAttr(SUMO_ATTR_ID, "IDMM");
60 std::ostringstream internals;
61 internals << levelOfService;
62 out.writeAttr(SUMO_ATTR_STATE, internals.str());
63 out.closeTag();
64}
65
66
67void
69 bool ok = true;
70 const std::string cfmID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
71 if (cfmID != "IDMM") {
72 throw ProcessError(TLF("incompatible carFollowModel '%' when loading state for IDMM", cfmID));
73 }
74 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
75 bis >> levelOfService;
76}
77
78
79double
80MSCFModel_IDM::minNextSpeed(double speed, const MSVehicle* const /*veh*/) const {
81 // permit exceeding myDecel when approaching stops
82 const double decel = MAX2(myDecel, MIN2(myEmergencyDecel, 1.5));
84 return MAX2(speed - ACCEL2SPEED(decel), 0.);
85 } else {
86 // NOTE: ballistic update allows for negative speeds to indicate a stop within the next timestep
87 return speed - ACCEL2SPEED(decel);
88 }
89}
90
91
92
93double
94MSCFModel_IDM::finalizeSpeed(MSVehicle* const veh, double vPos) const {
95 const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
96 if (myAdaptationFactor != 1.) {
98 vars->levelOfService += (vNext / veh->getLane()->getVehicleMaxSpeed(veh) - vars->levelOfService) / myAdaptationTime * TS;
99 }
100 return vNext;
101}
102
103
104double
105MSCFModel_IDM::freeSpeed(const MSVehicle* const veh, double speed, double seen, double maxSpeed, const bool /*onInsertion*/, const CalcReason /*usage*/) const {
106 if (maxSpeed < 0.) {
107 // can occur for ballistic update (in context of driving at red light)
108 return maxSpeed;
109 }
110 const double secGap = getSecureGap(veh, nullptr, maxSpeed, 0, myDecel);
111 double vSafe;
112 if (speed <= maxSpeed) {
113 // accelerate
114 vSafe = _v(veh, 1e6, speed, maxSpeed, veh->getLane()->getVehicleMaxSpeed(veh), false);
115 } else {
116 // decelerate
117 // @note relax gap to avoid emergency braking
118 // @note since the transition point does not move we set the leader speed to 0
119 vSafe = _v(veh, MAX2(seen, secGap), speed, 0, veh->getLane()->getVehicleMaxSpeed(veh), false);
120 }
121 if (seen < secGap) {
122 // avoid overshoot when close to change in speed limit
123 vSafe = MIN2(vSafe, maxSpeed);
124 }
125 //std::cout << SIMTIME << " speed=" << speed << " maxSpeed=" << maxSpeed << " seen=" << seen << " secGap=" << secGap << " vSafe=" << vSafe << "\n";
126 return vSafe;
127}
128
129
130double
131MSCFModel_IDM::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred, const CalcReason /*usage*/) const {
132 applyHeadwayAndSpeedDifferencePerceptionErrors(veh, speed, gap2pred, predSpeed, predMaxDecel, pred);
133 return _v(veh, gap2pred, speed, predSpeed, veh->getLane()->getVehicleMaxSpeed(veh));
134}
135
136
137double
138MSCFModel_IDM::insertionFollowSpeed(const MSVehicle* const v, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred) const {
139 // see definition of s in _v()
140 double s = MAX2(0., speed * myHeadwayTime + speed * (speed - predSpeed) / myTwoSqrtAccelDecel);
141 if (gap2pred >= s) {
142 // followSpeed always stays below speed because s*s / (gap2pred * gap2pred) > 0. This would prevent insertion with maximum speed at all distances
143 return speed;
144 } else {
145 // we cannot call follow speed directly because it assumes that 'speed'
146 // is the current speed rather than the desired insertion speed.
147 // If the safe speed is much lower than the desired speed, the
148 // followSpeed function would still return a new speed that involves
149 // reasonable braking rather than the actual safe speed (and cause
150 // emergency braking in a subsequent step)
151 const double speed2 = followSpeed(v, speed, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
152 const double speed3 = followSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
153 if (speed2 - speed3 < ACCEL2SPEED(1)) {
154 return speed2;
155 } else {
156#ifdef DEBUG_INSERTION_SPEED
157 std::cout << SIMTIME << " veh=" << v->getID() << " speed=" << speed << " gap2pred=" << gap2pred << " predSpeed=" << predSpeed << " predMaxDecel=" << predMaxDecel << " pred=" << Named::getIDSecure(pred) << " s=" << s << " speed2=" << speed2 << " speed3=" << speed3 << "\n";
158#endif
159 return insertionFollowSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred);
160 }
161 }
162}
163
164
165double
166MSCFModel_IDM::insertionStopSpeed(const MSVehicle* const veh, double speed, double gap) const {
167 // we want to insert the vehicle in an equilibrium state
168 double result = MSCFModel::insertionStopSpeed(veh, speed, gap);
169 int i = 0;
170 while (result - speed < -ACCEL2SPEED(myDecel) && ++i < 10) {
171 speed = result;
172 result = MSCFModel::insertionStopSpeed(veh, speed, gap);
173 }
174 return result;
175}
176
177
178double
179MSCFModel_IDM::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
180 applyHeadwayPerceptionError(veh, speed, gap);
181 if (gap < 0.01) {
182 return 0;
183 }
184 double result = _v(veh, gap, speed, 0, veh->getLane()->getVehicleMaxSpeed(veh), false);
185 //std::cout << SIMTIME << " stopSpeed speed=" << speed << " gap=" << gap << " decel=" << decel << " result=" << result << "\n";
186 if (gap > 0 && speed < NUMERICAL_EPS && result < NUMERICAL_EPS) {
187 // ensure that stops can be reached:
188 //std::cout << " switching to krauss: " << veh->getID() << " gap=" << gap << " speed=" << speed << " res1=" << result << " res2=" << maximumSafeStopSpeed(gap, speed, false, veh->getActionStepLengthSecs())<< "\n";
189 result = maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs());
190 }
191 // avoid overshooting the stop location
192 if (gap >= 0) {
193 result = MIN2(result, DIST2SPEED(gap));
194 //if (result * TS > gap) {
195 // std::cout << "Maximum stop speed exceeded for gap=" << gap << " result=" << result << " veh=" << veh->getID() << " speed=" << speed << " t=" << SIMTIME << "\n";
196 //}
197 }
198
199 return result;
200}
201
202
204double
205MSCFModel_IDM::interactionGap(const MSVehicle* const veh, double vL) const {
206 // Resolve the IDM equation to gap. Assume predecessor has
207 // speed != 0 and that vsafe will be the current speed plus acceleration,
208 // i.e that with this gap there will be no interaction.
209 const double acc = myAccel * (1. - pow(veh->getSpeed() / veh->getLane()->getVehicleMaxSpeed(veh), myDelta));
210 const double vNext = veh->getSpeed() + acc;
211 const double gap = (vNext - vL) * (veh->getSpeed() + vL) / (2 * myDecel) + vL;
212
213 // Don't allow timeHeadWay < deltaT situations.
214 return MAX2(gap, SPEED2DIST(vNext));
215}
216
217double
218MSCFModel_IDM::getSecureGap(const MSVehicle* const /*veh*/, const MSVehicle* const /*pred*/, const double speed, const double leaderSpeed, const double /*leaderMaxDecel*/) const {
219 const double delta_v = speed - leaderSpeed;
220 return MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel);
221}
222
223
224double
225MSCFModel_IDM::_v(const MSVehicle* const veh, const double gap2pred, const double egoSpeed,
226 const double predSpeed, const double desSpeed, const bool respectMinGap) const {
227// this is more or less based on http://www.vwi.tu-dresden.de/~treiber/MicroApplet/IDM.html
228// and http://arxiv.org/abs/cond-mat/0304337
229// we assume however constant speed for the leader
230 double headwayTime = myHeadwayTime;
231 if (myAdaptationFactor != 1.) {
233 headwayTime *= myAdaptationFactor + vars->levelOfService * (1. - myAdaptationFactor);
234 }
235 double newSpeed = egoSpeed;
236 double gap = gap2pred;
237 if (respectMinGap) {
238 // gap2pred comes with minGap already subtracted so we need to add it here again
239 gap += myType->getMinGap();
240 }
241#ifdef DEBUG_V
242 if (DEBUG_COND) {
243 std::cout << SIMTIME << " veh=" << veh->getID() << " gap2pred=" << gap2pred << " egoSpeed=" << egoSpeed << " predSpeed=" << predSpeed << " desSpeed=" << desSpeed << " rMG=" << respectMinGap << " hw=" << headwayTime << "\n";
244 }
245#endif
246 for (int i = 0; i < myIterations; i++) {
247 const double delta_v = newSpeed - predSpeed;
248 double s = MAX2(0., newSpeed * headwayTime + newSpeed * delta_v / myTwoSqrtAccelDecel);
249 if (respectMinGap) {
250 s += myType->getMinGap();
251 }
252 gap = MAX2(NUMERICAL_EPS, gap); // avoid singularity
253 const double acc = myAccel * (1. - pow(newSpeed / MAX2(NUMERICAL_EPS, desSpeed), myDelta) - (s * s) / (gap * gap));
254#ifdef DEBUG_V
255 if (DEBUG_COND) {
256 std::cout << " i=" << i << " gap=" << gap << " t=" << myHeadwayTime << " t2=" << headwayTime << " s=" << s << " pow=" << pow(newSpeed / desSpeed, myDelta) << " gapDecel=" << (s * s) / (gap * gap) << " a=" << acc;
257 }
258#endif
259 newSpeed = MAX2(0.0, newSpeed + ACCEL2SPEED(acc) / myIterations);
260#ifdef DEBUG_V
261 if (DEBUG_COND) {
262 std::cout << " v2=" << newSpeed << " gLC=" << MSGlobals::gComputeLC << "\n";
263 }
264#endif
265 //TODO use more realistic position update which takes accelerated motion into account
266 gap -= MAX2(0., SPEED2DIST(newSpeed - predSpeed) / myIterations);
267 }
268 return MAX2(0., newSpeed);
269}
270
271
274 return new MSCFModel_IDM(vtype, myIDMM);
275}
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define TLF(string,...)
Definition MsgHandler.h:306
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define ACCEL2SPEED(x)
Definition SUMOTime.h:54
#define TS
Definition SUMOTime.h:45
#define SIMTIME
Definition SUMOTime.h:65
#define DIST2SPEED(x)
Definition SUMOTime.h:50
@ SUMO_TAG_CFM_VARIABLES
@ SUMO_ATTR_CF_IDMM_ADAPT_TIME
@ SUMO_ATTR_CF_IDM_DELTA
@ SUMO_ATTR_CF_IDM_STEPPING
@ SUMO_ATTR_CF_IDMM_ADAPT_FACTOR
@ SUMO_ATTR_COLLISION_MINGAP_FACTOR
@ SUMO_ATTR_ID
@ SUMO_ATTR_STATE
The state of a link.
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the vehicle variables from the given description.
void saveState(OutputDevice &out, const MSCFModel &cfm) const
Saves the vehicle variables.
double levelOfService
state variable for remembering speed deviation history (lambda)
const int myIterations
The number of iterations in speed calculations.
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 (no dawdling).
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...
double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences.
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 (no dawdling).
virtual 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.
~MSCFModel_IDM()
Destructor.
const bool myIDMM
whether the model is IDMM or IDM
double getSecureGap(const MSVehicle *const veh, const MSVehicle *const pred, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0).
MSCFModel_IDM(const MSVehicleType *vtype, bool idmm)
Constructor.
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....
const double myAdaptationTime
The IDMM adaptation time tau.
MSCFModel * duplicate(const MSVehicleType *vtype) const
Duplicates the car-following model.
const double myTwoSqrtAccelDecel
A computational shortcut.
const double myAdaptationFactor
The IDMM adaptation factor beta.
const double myDelta
The IDM delta exponent.
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 _v(const MSVehicle *const veh, const double gap2pred, const double mySpeed, const double predSpeed, const double desSpeed, const bool respectMinGap=true) const
double interactionGap(const MSVehicle *const, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
The car-following model abstraction.
Definition MSCFModel.h:59
virtual std::string getParameter(const MSVehicle *veh, const std::string &key) const
try to get the given parameter for this carFollowingModel
Definition MSCFModel.h:707
void applyHeadwayPerceptionError(const MSVehicle *const veh, double speed, double &gap) const
Overwrites gap by the perceived value obtained from the vehicle's driver state.
virtual double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences. Called at most once per simulation...
double myEmergencyDecel
The vehicle's maximum emergency deceleration [m/s^2].
Definition MSCFModel.h:764
void applyHeadwayAndSpeedDifferencePerceptionErrors(const MSVehicle *const veh, double speed, double &gap, double &predSpeed, double predMaxDecel, const MSVehicle *const pred) const
Overwrites gap2pred and predSpeed by the perceived values obtained from the vehicle's driver state,...
CalcReason
What the return value of stop/follow/free-Speed is used for.
Definition MSCFModel.h:95
@ FUTURE
the return value is used for calculating future speeds
Definition MSCFModel.h:99
double myCollisionMinGapFactor
The factor of minGap that must be maintained to avoid a collision event.
Definition MSCFModel.h:768
MSCFModel(const MSVehicleType *vtype)
Constructor.
Definition MSCFModel.cpp:55
double myDecel
The vehicle's maximum deceleration [m/s^2].
Definition MSCFModel.h:762
double maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1, bool relaxEmergency=true) const
Returns the maximum next velocity for stopping within gap.
double myAccel
The vehicle's maximum acceleration [m/s^2].
Definition MSCFModel.h:759
const MSVehicleType * myType
The type to which this model definition belongs to.
Definition MSCFModel.h:756
double myHeadwayTime
The driver's desired time headway (aka reaction time tau) [s].
Definition MSCFModel.h:771
virtual 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...
static bool gSemiImplicitEulerUpdate
Definition MSGlobals.h:53
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition MSGlobals.h:140
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:575
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
double getActionStepLengthSecs() const
Returns the vehicle's action step length in secs, i.e. the interval between two action points.
Definition MSVehicle.h:533
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
MSCFModel::VehicleVariables * getCarFollowVariables() const
Returns the vehicle's car following model variables.
Definition MSVehicle.h:994
The car-following model and parameter.
const std::string & getID() const
Returns the name of the vehicle type.
const SUMOVTypeParameter & getParameter() const
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Encapsulated SAX-Attributes.
virtual std::string getString(int id, bool *isPresent=nullptr) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
#define DEBUG_COND