LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_IDM.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 68 75 90.7 %
Date: 2024-05-04 15:27:10 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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             : 
      27             : //#define DEBUG_V
      28             : //#define DEBUG_INSERTION_SPEED
      29             : 
      30             : #define DEBUG_COND (veh->isSelected())
      31             : //#define DEBUG_COND true
      32             : 
      33             : 
      34             : // ===========================================================================
      35             : // method definitions
      36             : // ===========================================================================
      37        7698 : MSCFModel_IDM::MSCFModel_IDM(const MSVehicleType* vtype, bool idmm) :
      38             :     MSCFModel(vtype),
      39        7698 :     myIDMM(idmm),
      40        7433 :     myDelta(idmm ? 4.0 : vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_DELTA, 4.)),
      41        7698 :     myAdaptationFactor(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR, 1.8) : 1.0),
      42        7698 :     myAdaptationTime(idmm ? vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDMM_ADAPT_TIME, 600.0) : 0.0),
      43        7698 :     myIterations(MAX2(1, int(TS / vtype->getParameter().getCFParam(SUMO_ATTR_CF_IDM_STEPPING, .25) + .5))),
      44        7698 :     myTwoSqrtAccelDecel(double(2 * sqrt(myAccel * myDecel))) {
      45             :     // IDM does not drive very precise and may violate minGap on occasion
      46        7698 :     myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.1);
      47        7698 : }
      48             : 
      49       15260 : MSCFModel_IDM::~MSCFModel_IDM() {}
      50             : 
      51             : 
      52             : double
      53    66243139 : MSCFModel_IDM::minNextSpeed(double speed, const MSVehicle* const /*veh*/) const {
      54             :     // permit exceeding myDecel when approaching stops
      55   132480594 :     const double decel = MAX2(myDecel, MIN2(myEmergencyDecel, 1.5));
      56    66243139 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
      57    64106147 :         return MAX2(speed - ACCEL2SPEED(decel), 0.);
      58             :     } else {
      59             :         // NOTE: ballistic update allows for negative speeds to indicate a stop within the next timestep
      60     2136992 :         return speed - ACCEL2SPEED(decel);
      61             :     }
      62             : }
      63             : 
      64             : 
      65             : 
      66             : double
      67    32913278 : MSCFModel_IDM::finalizeSpeed(MSVehicle* const veh, double vPos) const {
      68    32913278 :     const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
      69    32913278 :     if (myAdaptationFactor != 1.) {
      70             :         VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
      71     3668010 :         vars->levelOfService += (vNext / veh->getLane()->getVehicleMaxSpeed(veh) - vars->levelOfService) / myAdaptationTime * TS;
      72             :     }
      73    32913278 :     return vNext;
      74             : }
      75             : 
      76             : 
      77             : double
      78    57649270 : MSCFModel_IDM::freeSpeed(const MSVehicle* const veh, double speed, double seen, double maxSpeed, const bool /*onInsertion*/, const CalcReason /*usage*/) const {
      79    57649270 :     if (maxSpeed < 0.) {
      80             :         // can occur for ballistic update (in context of driving at red light)
      81             :         return maxSpeed;
      82             :     }
      83    57649270 :     const double secGap = getSecureGap(veh, nullptr, maxSpeed, 0, myDecel);
      84             :     double vSafe;
      85    57649270 :     if (speed <= maxSpeed) {
      86             :         // accelerate
      87    56835164 :         vSafe = _v(veh, 1e6, speed, maxSpeed, veh->getLane()->getVehicleMaxSpeed(veh), false);
      88             :     } else {
      89             :         // decelerate
      90             :         // @note relax gap to avoid emergency braking
      91             :         // @note since the transition point does not move we set the leader speed to 0
      92     1628212 :         vSafe = _v(veh, MAX2(seen, secGap), speed, 0, veh->getLane()->getVehicleMaxSpeed(veh), false);
      93             :     }
      94    57649270 :     if (seen < secGap) {
      95             :         // avoid overshoot when close to change in speed limit
      96             :         vSafe = MIN2(vSafe, maxSpeed);
      97             :     }
      98             :     //std::cout << SIMTIME << " speed=" << speed << " maxSpeed=" << maxSpeed << " seen=" << seen << " secGap=" << secGap << " vSafe=" << vSafe << "\n";
      99             :     return vSafe;
     100             : }
     101             : 
     102             : 
     103             : double
     104   210684354 : MSCFModel_IDM::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred, const CalcReason /*usage*/) const {
     105   210684354 :     applyHeadwayAndSpeedDifferencePerceptionErrors(veh, speed, gap2pred, predSpeed, predMaxDecel, pred);
     106   210684354 :     return _v(veh, gap2pred, speed, predSpeed, veh->getLane()->getVehicleMaxSpeed(veh));
     107             : }
     108             : 
     109             : 
     110             : double
     111      965491 : MSCFModel_IDM::insertionFollowSpeed(const MSVehicle* const v, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred) const {
     112             :     // see definition of s in _v()
     113      965491 :     double s = MAX2(0., speed * myHeadwayTime + speed * (speed - predSpeed) / myTwoSqrtAccelDecel);
     114      965491 :     if (gap2pred >= s) {
     115             :         // followSpeed always stays below speed because s*s / (gap2pred * gap2pred) > 0. This would prevent insertion with maximum speed at all distances
     116             :         return speed;
     117             :     } else {
     118             :         // we cannot call follow speed directly because it assumes that 'speed'
     119             :         // is the current speed rather than the desired insertion speed.
     120             :         // If the safe speed is much lower than the desired speed, the
     121             :         // followSpeed function would still return a new speed that involves
     122             :         // reasonable braking rather than the actual safe speed (and cause
     123             :         // emergency braking in a subsequent step)
     124      595370 :         const double speed2 = followSpeed(v, speed, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
     125      595370 :         const double speed3 = followSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred, CalcReason::FUTURE);
     126      595370 :         if (speed2 - speed3 < ACCEL2SPEED(1)) {
     127             :             return speed2;
     128             :         } else {
     129             : #ifdef DEBUG_INSERTION_SPEED
     130             :             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";
     131             : #endif
     132      448890 :             return insertionFollowSpeed(v, speed2, gap2pred, predSpeed, predMaxDecel, pred);
     133             :         }
     134             :     }
     135             : }
     136             : 
     137             : 
     138             : double
     139        4086 : MSCFModel_IDM::insertionStopSpeed(const MSVehicle* const veh, double speed, double gap) const {
     140             :     // we want to insert the vehicle in an equilibrium state
     141        4086 :     double result = MSCFModel::insertionStopSpeed(veh, speed, gap);
     142             :     int i = 0;
     143       13774 :     while (result - speed < -ACCEL2SPEED(myDecel) && ++i < 10) {
     144             :         speed = result;
     145        9688 :         result = MSCFModel::insertionStopSpeed(veh, speed, gap);
     146             :     }
     147        4086 :     return result;
     148             : }
     149             : 
     150             : 
     151             : double
     152    73100994 : MSCFModel_IDM::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
     153    73100994 :     applyHeadwayPerceptionError(veh, speed, gap);
     154    73100994 :     if (gap < 0.01) {
     155             :         return 0;
     156             :     }
     157    72569655 :     double result = _v(veh, gap, speed, 0, veh->getLane()->getVehicleMaxSpeed(veh), false);
     158             :     //std::cout << SIMTIME << " stopSpeed speed=" << speed << " gap=" << gap << " decel=" << decel << " result=" << result << "\n";
     159    72569655 :     if (gap > 0 && speed < NUMERICAL_EPS && result < NUMERICAL_EPS) {
     160             :         // ensure that stops can be reached:
     161             :         //std::cout << " switching to krauss: " << veh->getID() << " gap=" << gap << " speed=" << speed << " res1=" << result << " res2=" << maximumSafeStopSpeed(gap, speed, false, veh->getActionStepLengthSecs())<< "\n";
     162       17206 :         result = maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs());
     163             :     }
     164             :     // avoid overshooting the stop location
     165    72569655 :     if (gap >= 0) {
     166    72569655 :         result = MIN2(result, DIST2SPEED(gap));
     167             :         //if (result * TS > gap) {
     168             :         //    std::cout << "Maximum stop speed exceeded for gap=" << gap << " result=" << result << " veh=" << veh->getID() << " speed=" << speed << " t=" << SIMTIME << "\n";
     169             :         //}
     170             :     }
     171             : 
     172             :     return result;
     173             : }
     174             : 
     175             : 
     176             : /// @todo update interactionGap logic to IDM
     177             : double
     178           0 : MSCFModel_IDM::interactionGap(const MSVehicle* const veh, double vL) const {
     179             :     // Resolve the IDM equation to gap. Assume predecessor has
     180             :     // speed != 0 and that vsafe will be the current speed plus acceleration,
     181             :     // i.e that with this gap there will be no interaction.
     182           0 :     const double acc = myAccel * (1. - pow(veh->getSpeed() / veh->getLane()->getVehicleMaxSpeed(veh), myDelta));
     183           0 :     const double vNext = veh->getSpeed() + acc;
     184           0 :     const double gap = (vNext - vL) * (veh->getSpeed() + vL) / (2 * myDecel) + vL;
     185             : 
     186             :     // Don't allow timeHeadWay < deltaT situations.
     187           0 :     return MAX2(gap, SPEED2DIST(vNext));
     188             : }
     189             : 
     190             : double
     191   367920261 : MSCFModel_IDM::getSecureGap(const MSVehicle* const /*veh*/, const MSVehicle* const /*pred*/, const double speed, const double leaderSpeed, const double /*leaderMaxDecel*/) const {
     192   367920261 :     const double delta_v = speed - leaderSpeed;
     193   367920261 :     return MAX2(0.0, speed * myHeadwayTime + speed * delta_v / myTwoSqrtAccelDecel);
     194             : }
     195             : 
     196             : 
     197             : double
     198   340903279 : MSCFModel_IDM::_v(const MSVehicle* const veh, const double gap2pred, const double egoSpeed,
     199             :                   const double predSpeed, const double desSpeed, const bool respectMinGap) const {
     200             : // this is more or less based on http://www.vwi.tu-dresden.de/~treiber/MicroApplet/IDM.html
     201             : // and http://arxiv.org/abs/cond-mat/0304337
     202             : // we assume however constant speed for the leader
     203   340903279 :     double headwayTime = myHeadwayTime;
     204   340903279 :     if (myAdaptationFactor != 1.) {
     205             :         const VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
     206    42761535 :         headwayTime *= myAdaptationFactor + vars->levelOfService * (1. - myAdaptationFactor);
     207             :     }
     208             :     double newSpeed = egoSpeed;
     209             :     double gap = gap2pred;
     210   340903279 :     if (respectMinGap) {
     211             :         // gap2pred comes with minGap already subtracted so we need to add it here again
     212   210684354 :         gap += myType->getMinGap();
     213             :     }
     214             : #ifdef DEBUG_V
     215             :     if (DEBUG_COND) {
     216             :         std::cout << SIMTIME << " veh=" << veh->getID() << " gap2pred=" << gap2pred << " egoSpeed=" << egoSpeed << " predSpeed=" << predSpeed << " desSpeed=" << desSpeed << " rMG=" << respectMinGap << " hw=" << headwayTime << "\n";
     217             :     }
     218             : #endif
     219  1589949883 :     for (int i = 0; i < myIterations; i++) {
     220  1249046604 :         const double delta_v = newSpeed - predSpeed;
     221  1249046604 :         double s = MAX2(0., newSpeed * headwayTime + newSpeed * delta_v / myTwoSqrtAccelDecel);
     222  1249046604 :         if (respectMinGap) {
     223   770539543 :             s += myType->getMinGap();
     224             :         }
     225             :         gap = MAX2(NUMERICAL_EPS, gap); // avoid singularity
     226  1249046604 :         const double acc = myAccel * (1. - pow(newSpeed / MAX2(NUMERICAL_EPS, desSpeed), myDelta) - (s * s) / (gap * gap));
     227             : #ifdef DEBUG_V
     228             :         if (DEBUG_COND) {
     229             :             std::cout << "   i=" << i << " gap=" << gap << " t=" << myHeadwayTime << " t2=" << headwayTime << " s=" << s << " pow=" << pow(newSpeed / desSpeed, myDelta) << " gapDecel=" << (s * s) / (gap * gap) << " a=" << acc;
     230             :         }
     231             : #endif
     232  1249046604 :         newSpeed = MAX2(0.0, newSpeed + ACCEL2SPEED(acc) / myIterations);
     233             : #ifdef DEBUG_V
     234             :         if (DEBUG_COND) {
     235             :             std::cout << " v2=" << newSpeed << " gLC=" << MSGlobals::gComputeLC << "\n";
     236             :         }
     237             : #endif
     238             :         //TODO use more realistic position update which takes accelerated motion into account
     239  2007040266 :         gap -= MAX2(0., SPEED2DIST(newSpeed - predSpeed) / myIterations);
     240             :     }
     241   340903279 :     return MAX2(0., newSpeed);
     242             : }
     243             : 
     244             : 
     245             : MSCFModel*
     246           0 : MSCFModel_IDM::duplicate(const MSVehicleType* vtype) const {
     247           0 :     return new MSCFModel_IDM(vtype, myIDMM);
     248             : }

Generated by: LCOV version 1.14