LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_IDM.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.4 % 93 85
Test Date: 2026-06-15 15:46:12 Functions: 87.5 % 16 14

            Line data    Source code
       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              : /****************************************************************************/
      14              : /// @file    MSCFModel_IDM.cpp
      15              : /// @author  Tobias Mayer
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Michael Behrisch
      18              : /// @date    Thu, 03 Sep 2009
      19              : ///
      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>
      26              : #include <utils/xml/SUMOSAXAttributes.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              : // ===========================================================================
      38         8567 : MSCFModel_IDM::MSCFModel_IDM(const MSVehicleType* vtype, bool idmm) :
      39              :     MSCFModel(vtype),
      40         8567 :     myIDMM(idmm),
      41         8292 :     myDelta(idmm ? 4.0 : vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_DELTA, 4.)),
      42         8567 :     myAdaptationFactor(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR, 1.8) : 1.0),
      43         8567 :     myAdaptationTime(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_TIME, 600.0) : 0.0),
      44         8567 :     myIterations(MAX2(1, int(TS / vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_STEPPING, .25) + .5))),
      45         8567 :     myTwoSqrtAccelDecel(double(2 * sqrt(myAccel * myDecel))) {
      46              :     // IDM does not drive very precise and may violate minGap on occasion
      47         8567 :     myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.1);
      48         8567 :     if (TS / myIterations > 0.25) {
      49           24 :         WRITE_WARNINGF("Stepping duration of % for % model in vType % is unsafe", (TS / myIterations), myIDMM ? "IDMM" : "IDM", vtype->getID());
      50              :     }
      51         8567 : }
      52              : 
      53        16938 : MSCFModel_IDM::~MSCFModel_IDM() {}
      54              : 
      55              : 
      56              : void
      57           10 : MSCFModel_IDM::VehicleVariables::saveState(OutputDevice& out, const MSCFModel& /*cfm*/) const {
      58           10 :     out.openTag(SUMO_TAG_CFM_VARIABLES);
      59           10 :     out.writeAttr(SUMO_ATTR_ID, "IDMM");
      60           10 :     std::ostringstream internals;
      61           10 :     internals << levelOfService;
      62           10 :     out.writeAttr(SUMO_ATTR_STATE, internals.str());
      63           10 :     out.closeTag();
      64           10 : }
      65              : 
      66              : 
      67              : void
      68           10 : MSCFModel_IDM::VehicleVariables::loadState(const SUMOSAXAttributes& attrs) {
      69           10 :     bool ok = true;
      70           10 :     const std::string cfmID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
      71           10 :     if (cfmID != "IDMM") {
      72            0 :         throw ProcessError(TLF("incompatible carFollowModel '%' when loading state for IDMM", cfmID));
      73              :     }
      74           10 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
      75           10 :     bis >> levelOfService;
      76           20 : }
      77              : 
      78              : 
      79              : double
      80     69849931 : MSCFModel_IDM::minNextSpeed(double speed, const MSVehicle* const /*veh*/) const {
      81              :     // permit exceeding myDecel when approaching stops
      82    139694178 :     const double decel = MAX2(myDecel, MIN2(myEmergencyDecel, 1.5));
      83     69849931 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
      84     67112578 :         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      2737353 :         return speed - ACCEL2SPEED(decel);
      88              :     }
      89              : }
      90              : 
      91              : 
      92              : 
      93              : double
      94     34599076 : MSCFModel_IDM::finalizeSpeed(MSVehicle* const veh, double vPos) const {
      95     34599076 :     const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
      96     34599076 :     if (myAdaptationFactor != 1.) {
      97              :         VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
      98      3651866 :         vars->levelOfService += (vNext / veh->getLane()->getVehicleMaxSpeed(veh) - vars->levelOfService) / myAdaptationTime * TS;
      99              :     }
     100     34599076 :     return vNext;
     101              : }
     102              : 
     103              : 
     104              : double
     105     61120240 : MSCFModel_IDM::freeSpeed(const MSVehicle* const veh, double speed, double seen, double maxSpeed, const bool /*onInsertion*/, const CalcReason /*usage*/) const {
     106     61120240 :     if (maxSpeed < 0.) {
     107              :         // can occur for ballistic update (in context of driving at red light)
     108              :         return maxSpeed;
     109              :     }
     110     61120240 :     const double secGap = getSecureGap(veh, nullptr, maxSpeed, 0, myDecel);
     111              :     double vSafe;
     112     61120240 :     if (speed <= maxSpeed) {
     113              :         // accelerate
     114     60269532 :         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      1701416 :         vSafe = _v(veh, MAX2(seen, secGap), speed, 0, veh->getLane()->getVehicleMaxSpeed(veh), false);
     120              :     }
     121     61120240 :     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              : 
     130              : double
     131    233004057 : MSCFModel_IDM::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred, const CalcReason /*usage*/) const {
     132    233004057 :     applyHeadwayAndSpeedDifferencePerceptionErrors(veh, speed, gap2pred, predSpeed, predMaxDecel, pred);
     133    233004057 :     return _v(veh, gap2pred, speed, predSpeed, veh->getLane()->getVehicleMaxSpeed(veh));
     134              : }
     135              : 
     136              : 
     137              : double
     138      1817588 : MSCFModel_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      1817588 :     double s = MAX2(0., speed * myHeadwayTime + speed * (speed - predSpeed) / myTwoSqrtAccelDecel);
     141      1817588 :     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      1318735 :         const double speed2 = followSpeed(v, speed, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
     152      1318735 :         const double speed3 = followSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
     153      1318735 :         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      1120839 :             return insertionFollowSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred);
     160              :         }
     161              :     }
     162              : }
     163              : 
     164              : 
     165              : double
     166          442 : MSCFModel_IDM::insertionStopSpeed(const MSVehicle* const veh, double speed, double gap) const {
     167              :     // we want to insert the vehicle in an equilibrium state
     168          442 :     double result = MSCFModel::insertionStopSpeed(veh, speed, gap);
     169              :     int i = 0;
     170          780 :     while (result - speed < -ACCEL2SPEED(myDecel) && ++i < 10) {
     171              :         speed = result;
     172          338 :         result = MSCFModel::insertionStopSpeed(veh, speed, gap);
     173              :     }
     174          442 :     return result;
     175              : }
     176              : 
     177              : 
     178              : double
     179     78219659 : MSCFModel_IDM::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
     180     78219659 :     applyHeadwayPerceptionError(veh, speed, gap);
     181     78219659 :     if (gap < 0.01) {
     182              :         return 0;
     183              :     }
     184     77477188 :     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     77477188 :     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        35582 :         result = maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs());
     190              :     }
     191              :     // avoid overshooting the stop location
     192     77477188 :     if (gap >= 0) {
     193     77477188 :         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              : 
     203              : /// @todo update interactionGap logic to IDM
     204              : double
     205            0 : MSCFModel_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            0 :     const double acc = myAccel * (1. - pow(veh->getSpeed() / veh->getLane()->getVehicleMaxSpeed(veh), myDelta));
     210            0 :     const double vNext = veh->getSpeed() + acc;
     211            0 :     const double gap = (vNext - vL) * (veh->getSpeed() + vL) / (2 * myDecel) + vL;
     212              : 
     213              :     // Don't allow timeHeadWay < deltaT situations.
     214            0 :     return MAX2(gap, SPEED2DIST(vNext));
     215              : }
     216              : 
     217              : double
     218    387249446 : MSCFModel_IDM::getSecureGap(const MSVehicle* const /*veh*/, const MSVehicle* const /*pred*/, const double speed, const double leaderSpeed, const double /*leaderMaxDecel*/) const {
     219    387249446 :     const double delta_v = speed - leaderSpeed;
     220    387249446 :     return MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel);
     221              : }
     222              : 
     223              : 
     224              : double
     225    371601485 : MSCFModel_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    371601485 :     double headwayTime = myHeadwayTime;
     231    371601485 :     if (myAdaptationFactor != 1.) {
     232              :         const VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
     233     42579235 :         headwayTime *= myAdaptationFactor + vars->levelOfService * (1. - myAdaptationFactor);
     234              :     }
     235              :     double newSpeed = egoSpeed;
     236              :     double gap = gap2pred;
     237    371601485 :     if (respectMinGap) {
     238              :         // gap2pred comes with minGap already subtracted so we need to add it here again
     239    233004057 :         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   1711392976 :     for (int i = 0; i < myIterations; i++) {
     247   1339791491 :         const double delta_v = newSpeed - predSpeed;
     248   1339791491 :         double s = MAX2(0., newSpeed * headwayTime + newSpeed * delta_v / myTwoSqrtAccelDecel);
     249   1339791491 :         if (respectMinGap) {
     250    835736333 :             s += myType->getMinGap();
     251              :         }
     252              :         gap = MAX2(NUMERICAL_EPS, gap); // avoid singularity
     253   1339791491 :         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   1339791491 :         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   2160459427 :         gap -= MAX2(0., SPEED2DIST(newSpeed - predSpeed) / myIterations);
     267              :     }
     268    371601485 :     return MAX2(0., newSpeed);
     269              : }
     270              : 
     271              : 
     272              : MSCFModel*
     273            0 : MSCFModel_IDM::duplicate(const MSVehicleType* vtype) const {
     274            0 :     return new MSCFModel_IDM(vtype, myIDMM);
     275              : }
        

Generated by: LCOV version 2.0-1