LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_ACC.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.2 % 86 81
Test Date: 2026-06-15 15:46:12 Functions: 85.7 % 14 12

            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_ACC.cpp
      15              : /// @author  Kallirroi Porfyri
      16              : /// @date    Feb 2018
      17              : ///
      18              : // ACC car-following model based on [1], [2].
      19              : // [1] Milanes, V., and S. E. Shladover. Handling Cut-In Vehicles in Strings
      20              : //    of Cooperative Adaptive Cruise Control Vehicles. Journal of Intelligent
      21              : //     Transportation Systems, Vol. 20, No. 2, 2015, pp. 178-191.
      22              : // [2] Xiao, L., M. Wang and B. van Arem. Realistic Car-Following Models for
      23              : //    Microscopic Simulation of Adaptive and Cooperative Adaptive Cruise
      24              : //     Control Vehicles. Transportation Research Record: Journal of the
      25              : //     Transportation Research Board, No. 2623, 2017. (DOI: 10.3141/2623-01).
      26              : //[3]  Xiao, L., Wang, M., Schakel, W., & van Arem, B. (2018). Unravelling
      27              : //    effects of cooperative adaptive cruise control deactivation on
      28              : //    traffic flow characteristics at merging bottlenecks. Transportation
      29              : //    Research Part C: Emerging Technologies, 96, 380–397.
      30              : //    <https://doi.org/10.1016/j.trc.2018.10.008>
      31              : /****************************************************************************/
      32              : #include <config.h>
      33              : 
      34              : #include <stdio.h>
      35              : #include <iostream>
      36              : 
      37              : #include "MSCFModel_ACC.h"
      38              : #include <microsim/MSVehicle.h>
      39              : #include <microsim/MSLane.h>
      40              : #include <utils/common/RandHelper.h>
      41              : #include <utils/common/SUMOTime.h>
      42              : #include <utils/xml/SUMOSAXAttributes.h>
      43              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      44              : #include <math.h>
      45              : #include <microsim/MSNet.h>
      46              : 
      47              : // ===========================================================================
      48              : // debug flags
      49              : // ===========================================================================
      50              : //#define DEBUG_ACC
      51              : //#define DEBUG_COND (true)
      52              : //#define DEBUG_COND (veh->isSelected())
      53              : 
      54              : 
      55              : // ===========================================================================
      56              : // defaults
      57              : // ===========================================================================
      58              : #define DEFAULT_SC_GAIN -0.4
      59              : #define DEFAULT_GCC_GAIN_SPEED 0.8
      60              : #define DEFAULT_GCC_GAIN_SPACE 0.04
      61              : #define DEFAULT_GC_GAIN_SPEED 0.07
      62              : #define DEFAULT_GC_GAIN_SPACE 0.23
      63              : #define DEFAULT_CA_GAIN_SPACE 0.8
      64              : #define DEFAULT_CA_GAIN_SPEED 0.23
      65              : 
      66              : // ===========================================================================
      67              : // thresholds
      68              : // ===========================================================================
      69              : #define GAP_THRESHOLD_SPEEDCTRL 120
      70              : #define GAP_THRESHOLD_GAPCTRL 100
      71              : // override followSpeed when deemed unsafe by the given margin (the value was selected to reduce the number of necessary interventions)
      72              : #define DEFAULT_EMERGENCY_OVERRIDE_THRESHOLD 2.0
      73              : 
      74              : /// @todo: add attributes for myCollisionAvoidanceGainSpeed and myCollisionAvoidanceGainSpace
      75              : 
      76              : // ===========================================================================
      77              : // method definitions
      78              : // ===========================================================================
      79          818 : MSCFModel_ACC::MSCFModel_ACC(const MSVehicleType* vtype) :
      80              :     MSCFModel(vtype),
      81          818 :     mySpeedControlGain(vtype->getParameter().getCFParam(SUMO_ATTR_SC_GAIN, DEFAULT_SC_GAIN)),
      82          818 :     myGapClosingControlGainSpeed(vtype->getParameter().getCFParam(SUMO_ATTR_GCC_GAIN_SPEED, DEFAULT_GCC_GAIN_SPEED)),
      83          818 :     myGapClosingControlGainSpace(vtype->getParameter().getCFParam(SUMO_ATTR_GCC_GAIN_SPACE, DEFAULT_GCC_GAIN_SPACE)),
      84          818 :     myGapControlGainSpeed(vtype->getParameter().getCFParam(SUMO_ATTR_GC_GAIN_SPEED, DEFAULT_GC_GAIN_SPEED)),
      85          818 :     myGapControlGainSpace(vtype->getParameter().getCFParam(SUMO_ATTR_GC_GAIN_SPACE, DEFAULT_GC_GAIN_SPACE)),
      86          818 :     myCollisionAvoidanceGainSpeed(vtype->getParameter().getCFParam(SUMO_ATTR_CA_GAIN_SPEED, DEFAULT_CA_GAIN_SPEED)),
      87          818 :     myCollisionAvoidanceGainSpace(vtype->getParameter().getCFParam(SUMO_ATTR_CA_GAIN_SPACE, DEFAULT_CA_GAIN_SPACE)),
      88          818 :     myApplyDriverstate(vtype->getParameter().getCFParam(SUMO_ATTR_APPLYDRIVERSTATE, 0)),
      89         1636 :     myEmergencyThreshold(vtype->getParameter().getCFParam(SUMO_ATTR_CA_OVERRIDE, DEFAULT_EMERGENCY_OVERRIDE_THRESHOLD)) {
      90              :     // ACC does not drive very precise and often violates minGap
      91          818 :     myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.1);
      92          818 : }
      93              : 
      94         1185 : MSCFModel_ACC::~MSCFModel_ACC() {}
      95              : 
      96              : 
      97              : void
      98           10 : MSCFModel_ACC::ACCVehicleVariables::saveState(OutputDevice& out, const MSCFModel& /*cfm*/) const {
      99           10 :     out.openTag(SUMO_TAG_CFM_VARIABLES);
     100           10 :     out.writeAttr(SUMO_ATTR_ID, "ACC");
     101           10 :     std::ostringstream internals;
     102           10 :     internals << ACC_ControlMode << " ";
     103           10 :     internals << lastUpdateTime;
     104           10 :     out.writeAttr(SUMO_ATTR_STATE, internals.str());
     105           10 :     out.closeTag();
     106           10 : }
     107              : 
     108              : 
     109              : void
     110           10 : MSCFModel_ACC::ACCVehicleVariables::loadState(const SUMOSAXAttributes& attrs) {
     111           10 :     bool ok = true;
     112           10 :     const std::string cfmID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     113           10 :     if (cfmID != "ACC") {
     114            0 :         throw ProcessError(TLF("incompatible carFollowModel '%' when loading state for ACC", cfmID));
     115              :     }
     116           10 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     117           10 :     bis >> ACC_ControlMode;
     118           10 :     bis >> lastUpdateTime;
     119           20 : }
     120              : 
     121              : double
     122     31868372 : MSCFModel_ACC::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred, const CalcReason /*usage*/) const {
     123     31868372 :     if (myApplyDriverstate) {
     124        52060 :         applyHeadwayAndSpeedDifferencePerceptionErrors(veh, speed, gap2pred, predSpeed, predMaxDecel, pred);
     125              :     }
     126     31868372 :     const double desSpeed = MIN2(veh->getLane()->getSpeedLimit(), veh->getMaxSpeed());
     127     31868372 :     const double vACC = _v(veh, gap2pred, speed, predSpeed, desSpeed, true);
     128     31868372 :     const double vSafe = maximumSafeFollowSpeed(gap2pred, speed, predSpeed, predMaxDecel);
     129     31868372 :     if (vSafe + myEmergencyThreshold < vACC) {
     130              :         //ACCVehicleVariables* vars = (ACCVehicleVariables*)veh->getCarFollowVariables();
     131              :         //std::cout << SIMTIME << " veh=" << veh->getID() << " v=" << speed << " vL=" << predSpeed << " gap=" << gap2pred << " vACC=" << vACC << " vSafe=" << vSafe << " cm=" << vars->ACC_ControlMode << "\n";
     132       352638 :         return vSafe + myEmergencyThreshold;
     133              :     }
     134              :     return vACC;
     135              : }
     136              : 
     137              : 
     138              : double
     139     11596357 : MSCFModel_ACC::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
     140     11596357 :     if (myApplyDriverstate) {
     141         2728 :         applyHeadwayPerceptionError(veh, speed, gap);
     142              :     }
     143              :     // NOTE: This allows return of smaller values than minNextSpeed().
     144              :     // Only relevant for the ballistic update: We give the argument headway=TS, to assure that
     145              :     // the stopping position is approached with a uniform deceleration also for tau!=TS.
     146     11596357 :     return MIN2(maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs()), maxNextSpeed(speed, veh));
     147              : }
     148              : 
     149              : 
     150              : double
     151     27519730 : MSCFModel_ACC::getSecureGap(const MSVehicle* const /*veh*/, const MSVehicle* const /*pred*/, const double speed, const double leaderSpeed, const double /* leaderMaxDecel */) const {
     152              :     // Accel in gap mode should vanish:
     153              :     //      0 = myGapControlGainSpeed * (leaderSpeed - speed) + myGapControlGainSpace * (g - myHeadwayTime * speed);
     154              :     // <=>  myGapControlGainSpace * g = - myGapControlGainSpeed * (leaderSpeed - speed) + myGapControlGainSpace * myHeadwayTime * speed;
     155              :     // <=>  g = - myGapControlGainSpeed * (leaderSpeed - speed) / myGapControlGainSpace + myHeadwayTime * speed;
     156     27519730 :     return myGapControlGainSpeed * (speed - leaderSpeed) / myGapControlGainSpace + myHeadwayTime * speed;
     157              : }
     158              : 
     159              : 
     160              : double
     161       123364 : MSCFModel_ACC::insertionFollowSpeed(const MSVehicle* const v, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const /*pred*/) const {
     162              : //#ifdef DEBUG_ACC
     163              : //        std::cout << "MSCFModel_ACC::insertionFollowSpeed(), speed="<<speed<< std::endl;
     164              : //#endif
     165              :     // iterate to find a stationary value for
     166              :     //    speed = followSpeed(v, speed, gap2pred, predSpeed, predMaxDecel, nullptr, CalcReason::FUTURE)
     167              :     const int max_iter = 50;
     168              :     int n_iter = 0;
     169              :     const double tol = 0.1;
     170              :     const double damping = 0.1;
     171              : 
     172              :     double res = speed;
     173      3844287 :     while (n_iter < max_iter) {
     174              :         // proposed acceleration
     175      3809103 :         const double a = SPEED2ACCEL(followSpeed(v, res, gap2pred, predSpeed, predMaxDecel, nullptr, CalcReason::FUTURE) - res);
     176      3809103 :         res = res + damping * a;
     177              : //#ifdef DEBUG_ACC
     178              : //        std::cout << "   n_iter=" << n_iter << ", a=" << a << ", res=" << res << std::endl;
     179              : //#endif
     180      3809103 :         if (fabs(a) < tol) {
     181              :             break;
     182              :         } else {
     183      3720923 :             n_iter++;
     184              :         }
     185              :     }
     186       123364 :     return res;
     187              : }
     188              : 
     189              : 
     190              : /// @todo update interactionGap logic
     191              : double
     192            0 : MSCFModel_ACC::interactionGap(const MSVehicle* const /*veh */, double /* vL */) const {
     193              :     /*maximum radar range is ACC is enabled*/
     194            0 :     return 250;
     195              : }
     196              : 
     197     14027197 : double MSCFModel_ACC::accelSpeedControl(double vErr) const {
     198              :     // Speed control law
     199     14027197 :     return mySpeedControlGain * vErr;
     200              : }
     201              : 
     202              : double
     203     17893646 : MSCFModel_ACC::accelGapControl(const MSVehicle* const /* veh */, const double gap2pred, const double speed, const double predSpeed, double vErr) const {
     204              :     // Gap control law
     205              :     double gclAccel = 0.0;
     206     17893646 :     const double deltaVel = predSpeed - speed;
     207              : 
     208              :     // see dynamic gap margin definition from (Xiao et. al, 2018)[3], equation 5 reformulated as min/max to avoid discontinuities
     209     17893646 :     const double d0 = MAX2(0., MIN2(75. / speed - 5., 2.));
     210              :     // this is equation 4, gap2pred is the difference in vehicle positions minus the length
     211     17893646 :     const double spacingErr = gap2pred - myHeadwayTime * speed - d0;
     212              : 
     213              : 
     214     17893646 :     if (fabs(spacingErr) < 0.2 && fabs(vErr) < 0.1) {
     215              :         // gap mode
     216        19429 :         gclAccel = myGapControlGainSpeed * deltaVel + myGapControlGainSpace * spacingErr;
     217              : #ifdef DEBUG_ACC
     218              :         if (DEBUG_COND) {
     219              :             std::cout << "        applying gap control:  spacingErr=" << spacingErr << " speedErr=" << vErr << std::endl;
     220              :         }
     221              : #endif
     222     17874217 :     } else if (spacingErr < 0)  {
     223              :         // collision avoidance mode
     224      3623431 :         gclAccel = myCollisionAvoidanceGainSpeed * deltaVel + myCollisionAvoidanceGainSpace * spacingErr;
     225              : #ifdef DEBUG_ACC
     226              :         if (DEBUG_COND) {
     227              :             std::cout << "        applying collision avoidance:  spacingErr=" << spacingErr << " speedErr=" << vErr << std::endl;
     228              :         }
     229              : #endif
     230              :     } else {
     231              :         // gap closing mode
     232     14250786 :         gclAccel = myGapClosingControlGainSpeed * deltaVel + myGapClosingControlGainSpace * spacingErr;
     233              : #ifdef DEBUG_ACC
     234              :         if (DEBUG_COND) {
     235              :             std::cout << "        applying gap closing:  spacingErr=" << spacingErr << " speedErr=" << vErr << std::endl;
     236              :         }
     237              : #endif
     238              :     }
     239     17893646 :     return gclAccel;
     240              : }
     241              : 
     242              : 
     243              : double
     244     31920843 : MSCFModel_ACC::_v(const MSVehicle* const veh, const double gap2pred, const double speed,
     245              :                   const double predSpeed, const double desSpeed, const bool /* respectMinGap */) const {
     246              : 
     247              :     double accelACC = 0;
     248              :     double gapLimit_SC = GAP_THRESHOLD_SPEEDCTRL; // lower gap limit in meters to enable speed control law
     249              :     double gapLimit_GC = GAP_THRESHOLD_GAPCTRL; // upper gap limit in meters to enable gap control law
     250              : 
     251              : #ifdef DEBUG_ACC
     252              :     if (DEBUG_COND) {
     253              :         std::cout << SIMTIME << " MSCFModel_ACC::_v() for veh '" << veh->getID() << "'\n"
     254              :                   << "        gap=" << gap2pred << " speed="  << speed << " predSpeed=" << predSpeed
     255              :                   << " desSpeed=" << desSpeed << " tau=" << myHeadwayTime << std::endl;
     256              :     }
     257              : #endif
     258              : 
     259              : 
     260              :     /* Velocity error */
     261     31920843 :     double vErr = speed - desSpeed;
     262              :     int setControlMode = 0;
     263              :     ACCVehicleVariables* vars = (ACCVehicleVariables*) veh->getCarFollowVariables();
     264     31920843 :     if (vars->lastUpdateTime != MSNet::getInstance()->getCurrentTimeStep()) {
     265      4270715 :         vars->lastUpdateTime = MSNet::getInstance()->getCurrentTimeStep();
     266              :         setControlMode = 1;
     267              :     }
     268     31920843 :     if (gap2pred > gapLimit_SC) {
     269              : 
     270              : #ifdef DEBUG_ACC
     271              :         if (DEBUG_COND) {
     272              :             std::cout << "        applying speedControl" << std::endl;
     273              :         }
     274              : #endif
     275              :         // Find acceleration - Speed control law
     276     14026812 :         accelACC = accelSpeedControl(vErr);
     277              :         // Set cl to vehicle parameters
     278     14026812 :         if (setControlMode) {
     279        22648 :             vars->ACC_ControlMode = 0;
     280              :         }
     281     17894031 :     } else if (gap2pred < gapLimit_GC) {
     282              :         // Find acceleration - Gap control law
     283     17456636 :         accelACC = accelGapControl(veh, gap2pred, speed, predSpeed, vErr);
     284              :         // Set cl to vehicle parameters
     285     17456636 :         if (setControlMode) {
     286      4247442 :             vars->ACC_ControlMode = 1;
     287              :         }
     288              :     } else {
     289              :         // Follow previous applied law
     290       437395 :         int cm = vars->ACC_ControlMode;
     291       437395 :         if (!cm) {
     292              : 
     293              : #ifdef DEBUG_ACC
     294              :             if (DEBUG_COND) {
     295              :                 std::cout << "        applying speedControl" << std::endl;
     296              :             }
     297              : #endif
     298          385 :             accelACC = accelSpeedControl(vErr);
     299              :         } else {
     300       437010 :             accelACC = accelGapControl(veh, gap2pred, speed, predSpeed, vErr);
     301              :         }
     302              : 
     303              :     }
     304              : 
     305     31920843 :     double newSpeed = speed + ACCEL2SPEED(accelACC);
     306              : 
     307              : #ifdef DEBUG_ACC
     308              :     if (DEBUG_COND) {
     309              :         std::cout << "        result: accel=" << accelACC << " newSpeed="  << newSpeed << std::endl;
     310              :     }
     311              : #endif
     312              : 
     313     31920843 :     return MAX2(0., newSpeed);
     314              : }
     315              : 
     316              : 
     317              : MSCFModel*
     318            0 : MSCFModel_ACC::duplicate(const MSVehicleType* vtype) const {
     319            0 :     return new MSCFModel_ACC(vtype);
     320              : }
        

Generated by: LCOV version 2.0-1