LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_Wiedemann.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 93.3 % 89 83
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) 2011-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_Wiedemann.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    June 2011
      19              : ///
      20              : // The psycho-physical model of Wiedemann
      21              : // references:
      22              : // Andre Stebens - Traffic simulation with the Wiedemann model
      23              : // Werner - Integration von Fahrzeugfolge- und Fahrstreifenwechselmodellen in die Nachtfahrsimulation LucidDrive
      24              : // Olstam, Tapani - Comparison of Car-following models
      25              : // Higgs, B. et.al - Analysis of theWiedemann car following model over different speeds using naturalistic data.
      26              : // Ahmed, H.U.; Huang, Y.; Lu, P. - A Review of Car-Following Models and Modeling Tools forHuman and Autonomous-Ready Driving Behaviors in Micro-Simulation
      27              : 
      28              : /****************************************************************************/
      29              : #include <config.h>
      30              : 
      31              : #include <cmath>
      32              : #include "MSCFModel_Wiedemann.h"
      33              : #include <microsim/MSVehicle.h>
      34              : #include <microsim/MSLane.h>
      35              : #include <utils/common/RandHelper.h>
      36              : #include <utils/xml/SUMOSAXAttributes.h>
      37              : 
      38              : //#define DEBUG_V
      39              : 
      40              : // ===========================================================================
      41              : // static members
      42              : // ===========================================================================
      43              : 
      44              : // magic constant proposed by Wiedemann (based on real world measurements)
      45              : const double MSCFModel_Wiedemann::D_MAX = 150;
      46              : 
      47              : #define B_MIN_MULT 0
      48              : #define B_MIN_ADD  -1
      49              : #define PRED_DECEL_MULT 0.5
      50              : #define PRED_DECEL_MULT_EMERGENCY 0.55
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55          291 : MSCFModel_Wiedemann::MSCFModel_Wiedemann(const MSVehicleType* vtype) :
      56              :     MSCFModel(vtype),
      57          291 :     mySecurity(vtype->getParameter().getCFParam(SUMO_ATTR_CF_WIEDEMANN_SECURITY, 0.5)),
      58          291 :     myEstimation(vtype->getParameter().getCFParam(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION, 0.5)),
      59          291 :     myAX(vtype->getLength() + 1. + 2. * mySecurity),
      60          291 :     myCX(25. *(1. + mySecurity + myEstimation)),
      61          291 :     myMinAccel(0.2 * myAccel),
      62          291 :     myMaxApproachingDecel((myDecel + myEmergencyDecel) / 2) {
      63              :     // Wiedemann does not drive very precise and may violate minGap on occasion
      64          291 :     myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.1);
      65          291 : }
      66              : 
      67              : 
      68          582 : MSCFModel_Wiedemann::~MSCFModel_Wiedemann() {}
      69              : 
      70              : 
      71              : void
      72           10 : MSCFModel_Wiedemann::VehicleVariables::saveState(OutputDevice& out, const MSCFModel& /*cfm*/) const {
      73           10 :     out.openTag(SUMO_TAG_CFM_VARIABLES);
      74           10 :     out.writeAttr(SUMO_ATTR_ID, "Wiedemann");
      75           10 :     std::ostringstream internals;
      76           10 :     internals << accelSign;
      77           10 :     out.writeAttr(SUMO_ATTR_STATE, internals.str());
      78           10 :     out.closeTag();
      79           10 : }
      80              : 
      81              : 
      82              : void
      83           10 : MSCFModel_Wiedemann::VehicleVariables::loadState(const SUMOSAXAttributes& attrs) {
      84           10 :     bool ok = true;
      85           10 :     const std::string cfmID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
      86           10 :     if (cfmID != "Wiedemann") {
      87            0 :         throw ProcessError(TLF("incompatible carFollowModel '%' when loading state for Wiedemann", cfmID));
      88              :     }
      89           10 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
      90           10 :     bis >> accelSign;
      91           20 : }
      92              : 
      93              : 
      94              : double
      95      3367019 : MSCFModel_Wiedemann::finalizeSpeed(MSVehicle* const veh, double vPos) const {
      96      3367019 :     const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
      97              :     VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
      98      3367019 :     vars->accelSign = vNext > veh->getSpeed() ? 1. : -1.;
      99      3367019 :     return vNext;
     100              : }
     101              : 
     102              : 
     103              : double
     104     22026540 : MSCFModel_Wiedemann::followSpeed(const MSVehicle* const veh, double /* speed */, double gap2pred, double predSpeed, double /*predMaxDecel*/, const MSVehicle* const pred, const CalcReason /*usage*/) const {
     105     22026540 :     return _v(veh, predSpeed, gap2pred, pred != nullptr ? pred->getAcceleration() : 0);
     106              : }
     107              : 
     108              : 
     109              : double
     110      9457194 : MSCFModel_Wiedemann::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
     111              :     /* Wiedemann does not handle approaching junctions or stops very well:
     112              :      * regime approaching() fails when dv = 0 (i.e. a vehicle inserted with speed 0 does not accelerate to reach a stop)
     113              :      * for dv ~ 0 the standard decision tree will switch to following() which
     114              :      * does a lousy job of closing in on a stop / junction
     115              :      * hence we borrow from Krauss here
     116              :      */
     117      9457194 :     return MIN2(maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs()), maxNextSpeed(speed, veh));
     118              : }
     119              : 
     120              : 
     121              : double
     122            0 : MSCFModel_Wiedemann::interactionGap(const MSVehicle* const, double vL) const {
     123              :     UNUSED_PARAMETER(vL);
     124            0 :     return D_MAX;
     125              : }
     126              : 
     127              : 
     128              : MSCFModel*
     129            0 : MSCFModel_Wiedemann::duplicate(const MSVehicleType* vtype) const {
     130            0 :     return new MSCFModel_Wiedemann(vtype);
     131              : }
     132              : 
     133              : 
     134              : double
     135     19407231 : MSCFModel_Wiedemann::getSecureGap(const MSVehicle* const veh, const MSVehicle* const pred, const double speed, const double leaderSpeed, const double leaderMaxDecel) const {
     136     19407231 :     const double bx = (1 + 7 * mySecurity) * sqrt(speed);
     137     19407231 :     const double abx = myAX + bx - myType->getLength(); // abx is the brutto gap
     138     19407231 :     return MAX2(abx, MSCFModel::getSecureGap(veh, pred, speed, leaderSpeed, leaderMaxDecel));
     139              : }
     140              : 
     141              : 
     142              : double
     143     22026540 : MSCFModel_Wiedemann::_v(const MSVehicle* veh, double predSpeed, double gap, double predAccel) const {
     144              :     const VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
     145     22026540 :     const double dx = gap + myType->getLength(); // wiedemann uses brutto gap
     146     22026540 :     const double v = veh->getSpeed();
     147     22026540 :     const double vpref = veh->getMaxSpeed();
     148     22026540 :     const double dv = v - predSpeed;
     149              :     // desired minimum following distance at low speed difference
     150     22026540 :     const double bx = (1 + 7 * mySecurity) * sqrt(v); // Harding propose a factor of  *.8 here
     151     22026540 :     const double abx = myAX + bx; // Harding propose a factor of  *.8 here
     152     22026540 :     const double ex = 2 - myEstimation; // + RandHelper::randNorm(0.5, 0.15)
     153     22026540 :     const double sdx = myAX + ex * bx; /// the distance at which we drift out of following
     154     22026540 :     const double sdv_root = (dx - myAX) / myCX;
     155     22026540 :     const double sdv = sdv_root * sdv_root;
     156     22026540 :     const double cldv = sdv * ex * ex;
     157     22026540 :     const double opdv = cldv * (-1 - 2 * RandHelper::randNorm(0.5, 0.15, veh->getRNG()));
     158              :     // D_MAX is too low to brake safely when driving at speeds above 36m/s
     159     22026540 :     const double dmax = MAX2(D_MAX, brakeGap(v, myDecel, 0));
     160              :     // select the regime, get new acceleration, compute new speed based
     161              :     double accel;
     162              :     int branch = 0;
     163     22026540 :     if (dx <= abx) {
     164       332921 :         accel = emergency(dv, dx, predAccel, v, gap, abx, bx);
     165              :         branch = 1;
     166     21693619 :     } else if (dx < sdx) {
     167      2189302 :         if (dv > cldv) {
     168       595007 :             accel = approaching(dv, dx, abx, predAccel);
     169              :             branch = 2;
     170      1594295 :         } else if (dv > opdv) {
     171       851191 :             accel = following(vars->accelSign);
     172              :             branch = 3;
     173              :         } else {
     174       743104 :             accel = fullspeed(v, vpref, dx, abx);
     175              :             branch = 4;
     176              :         }
     177              :     } else {
     178     19504317 :         if (dv > sdv && dx < dmax) { //@note other versions have an disjunction instead of conjunction
     179       682884 :             accel = approaching(dv, dx, abx, predAccel);
     180       682884 :             branch = 5;
     181              :         } else {
     182     18821433 :             accel = fullspeed(v, vpref, dx, abx);
     183              :             branch = 6;
     184              :         }
     185              :     }
     186              :     // since we have hard constraints on accel we may as well use them here
     187              : #ifdef DEBUG_V
     188              :     const double rawAccel = accel;
     189              : #endif
     190     22026540 :     accel = MAX2(MIN2(accel, myAccel), -myEmergencyDecel);
     191     22026540 :     const double vNew = MAX2(0., v + ACCEL2SPEED(accel)); // don't allow negative speeds
     192              : #ifdef DEBUG_V
     193              :     if (veh->isSelected() && !MSGlobals::gComputeLC) {
     194              :         std::cout << SIMTIME << " Wiedemann::_v veh=" << veh->getID()
     195              :                   << " v=" << v << " pV=" << predSpeed << " pA=" << predAccel << " gap=" << gap
     196              :                   << " dv=" << dv << " dx=" << dx << " ax=" << myAX << " bx=" << bx << " abx=" << abx
     197              :                   << " sdx=" << sdx << " sdv=" << sdv << " cldv=" << cldv << " opdv=" << opdv
     198              :                   << " branch=" << branch << " rawAccel=" << rawAccel
     199              :                   << " accel=" << accel << " vNew=" << vNew << "\n";
     200              :     }
     201              : #else
     202              :     UNUSED_PARAMETER(branch);
     203              : #endif
     204     22026540 :     return vNew;
     205              : }
     206              : 
     207              : 
     208              : double
     209     19564537 : MSCFModel_Wiedemann::fullspeed(double v, double vpref, double dx, double abx) const {
     210              :     // maximum acceleration is reduced with increasing speed
     211     19564537 :     double bmax = 0.2 + 0.8 * myAccel * (7 - sqrt(v));
     212              :     // if veh just drifted out of a 'following' process the acceleration is reduced
     213     19564537 :     double accel = dx <= 2 * abx ? MIN2(myMinAccel, bmax * (dx - abx) / abx) : bmax;
     214     19564537 :     if (v > vpref) {
     215            0 :         accel = - accel;
     216              :     }
     217     19564537 :     return accel;
     218              : }
     219              : 
     220              : 
     221              : double
     222       851191 : MSCFModel_Wiedemann::following(double sign) const {
     223       851191 :     return myMinAccel * sign;
     224              : }
     225              : 
     226              : 
     227              : double
     228      1277891 : MSCFModel_Wiedemann::approaching(double dv, double dx, double abx, double predAccel) const {
     229              :     // there is singularity in the formula. we do the sanity check outside
     230              :     assert(abx < dx);
     231              :     // @note: the original model does not have a limit on maximum deceleration here.
     232              :     // We add this to avoid cascading emergency deceleration
     233              :     // also, the multiplier on predAccel is always 1 in the original model
     234      1277891 :     return MAX2(0.5 * dv * dv / (abx - dx) + predAccel * PRED_DECEL_MULT, -myMaxApproachingDecel);
     235              : }
     236              : 
     237              : 
     238              : double
     239       332921 : MSCFModel_Wiedemann::emergency(double dv, double dx, double predAccel, double v, double gap, double abx, double bx) const {
     240              :     // wiedemann assumes that dx will always be larger than myAX (sumo may
     241              :     // violate this assumption when crashing (-:
     242              :     //
     243              :     // predAccel is called b_(n-1) in the literature and it's multipleir is always 1
     244              : 
     245       332921 :     if (dx > myAX) {
     246       252136 :         const double bmin = B_MIN_ADD + B_MIN_MULT * v;
     247       252136 :         const double accel = (0.5 * dv * dv / (myAX - dx)
     248       252136 :                               + predAccel * PRED_DECEL_MULT_EMERGENCY
     249       252136 :                               + bmin * (abx - gap) / bx);
     250       252136 :         return accel;
     251              :     } else {
     252        80785 :         return -myEmergencyDecel;
     253              :     }
     254              : 
     255              :     // emergency according to C.Werner
     256              :     //return -myEmergencyDecel;
     257              : }
        

Generated by: LCOV version 2.0-1