LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_Wiedemann.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 68 73 93.2 %
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) 2011-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_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             : 
      37             : //#define DEBUG_V
      38             : 
      39             : // ===========================================================================
      40             : // static members
      41             : // ===========================================================================
      42             : 
      43             : // magic constant proposed by Wiedemann (based on real world measurements)
      44             : const double MSCFModel_Wiedemann::D_MAX = 150;
      45             : 
      46             : #define B_MIN_MULT 0
      47             : #define B_MIN_ADD  -1
      48             : #define PRED_DECEL_MULT 0.5
      49             : #define PRED_DECEL_MULT_EMERGENCY 0.55
      50             : 
      51             : // ===========================================================================
      52             : // method definitions
      53             : // ===========================================================================
      54         276 : MSCFModel_Wiedemann::MSCFModel_Wiedemann(const MSVehicleType* vtype) :
      55             :     MSCFModel(vtype),
      56         276 :     mySecurity(vtype->getParameter().getCFParam(SUMO_ATTR_CF_WIEDEMANN_SECURITY, 0.5)),
      57         276 :     myEstimation(vtype->getParameter().getCFParam(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION, 0.5)),
      58         276 :     myAX(vtype->getLength() + 1. + 2. * mySecurity),
      59         276 :     myCX(25. *(1. + mySecurity + myEstimation)),
      60         276 :     myMinAccel(0.2 * myAccel),
      61         276 :     myMaxApproachingDecel((myDecel + myEmergencyDecel) / 2) {
      62             :     // Wiedemann does not drive very precise and may violate minGap on occasion
      63         276 :     myCollisionMinGapFactor = vtype->getParameter().getCFParam(SUMO_ATTR_COLLISION_MINGAP_FACTOR, 0.1);
      64         276 : }
      65             : 
      66             : 
      67         552 : MSCFModel_Wiedemann::~MSCFModel_Wiedemann() {}
      68             : 
      69             : 
      70             : double
      71     3373938 : MSCFModel_Wiedemann::finalizeSpeed(MSVehicle* const veh, double vPos) const {
      72     3373938 :     const double vNext = MSCFModel::finalizeSpeed(veh, vPos);
      73             :     VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
      74     3373938 :     vars->accelSign = vNext > veh->getSpeed() ? 1. : -1.;
      75     3373938 :     return vNext;
      76             : }
      77             : 
      78             : 
      79             : double
      80    22088154 : MSCFModel_Wiedemann::followSpeed(const MSVehicle* const veh, double /* speed */, double gap2pred, double predSpeed, double /*predMaxDecel*/, const MSVehicle* const pred, const CalcReason /*usage*/) const {
      81    22088154 :     return _v(veh, predSpeed, gap2pred, pred != nullptr ? pred->getAcceleration() : 0);
      82             : }
      83             : 
      84             : 
      85             : double
      86     9484401 : MSCFModel_Wiedemann::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
      87             :     /* Wiedemann does not handle approaching junctions or stops very well:
      88             :      * regime approaching() fails when dv = 0 (i.e. a vehicle inserted with speed 0 does not accelerate to reach a stop)
      89             :      * for dv ~ 0 the standard decision tree will switch to following() which
      90             :      * does a lousy job of closing in on a stop / junction
      91             :      * hence we borrow from Krauss here
      92             :      */
      93     9484401 :     return MIN2(maximumSafeStopSpeed(gap, decel, speed, false, veh->getActionStepLengthSecs()), maxNextSpeed(speed, veh));
      94             : }
      95             : 
      96             : 
      97             : double
      98           0 : MSCFModel_Wiedemann::interactionGap(const MSVehicle* const, double vL) const {
      99             :     UNUSED_PARAMETER(vL);
     100           0 :     return D_MAX;
     101             : }
     102             : 
     103             : 
     104             : MSCFModel*
     105           0 : MSCFModel_Wiedemann::duplicate(const MSVehicleType* vtype) const {
     106           0 :     return new MSCFModel_Wiedemann(vtype);
     107             : }
     108             : 
     109             : 
     110             : double
     111    19567071 : MSCFModel_Wiedemann::getSecureGap(const MSVehicle* const veh, const MSVehicle* const pred, const double speed, const double leaderSpeed, const double leaderMaxDecel) const {
     112    19567071 :     const double bx = (1 + 7 * mySecurity) * sqrt(speed);
     113    19567071 :     const double abx = myAX + bx - myType->getLength(); // abx is the brutto gap
     114    19567071 :     return MAX2(abx, MSCFModel::getSecureGap(veh, pred, speed, leaderSpeed, leaderMaxDecel));
     115             : }
     116             : 
     117             : 
     118             : double
     119    22088154 : MSCFModel_Wiedemann::_v(const MSVehicle* veh, double predSpeed, double gap, double predAccel) const {
     120             :     const VehicleVariables* vars = (VehicleVariables*)veh->getCarFollowVariables();
     121    22088154 :     const double dx = gap + myType->getLength(); // wiedemann uses brutto gap
     122    22088154 :     const double v = veh->getSpeed();
     123    22088154 :     const double vpref = veh->getMaxSpeed();
     124    22088154 :     const double dv = v - predSpeed;
     125             :     // desired minimum following distance at low speed difference
     126    22088154 :     const double bx = (1 + 7 * mySecurity) * sqrt(v); // Harding propose a factor of  *.8 here
     127    22088154 :     const double abx = myAX + bx; // Harding propose a factor of  *.8 here
     128    22088154 :     const double ex = 2 - myEstimation; // + RandHelper::randNorm(0.5, 0.15)
     129    22088154 :     const double sdx = myAX + ex * bx; /// the distance at which we drift out of following
     130    22088154 :     const double sdv_root = (dx - myAX) / myCX;
     131    22088154 :     const double sdv = sdv_root * sdv_root;
     132    22088154 :     const double cldv = sdv * ex * ex;
     133    22088154 :     const double opdv = cldv * (-1 - 2 * RandHelper::randNorm(0.5, 0.15, veh->getRNG()));
     134             :     // D_MAX is too low to brake safely when driving at speeds above 36m/s
     135    22088154 :     const double dmax = MAX2(D_MAX, brakeGap(v, myDecel, 0));
     136             :     // select the regime, get new acceleration, compute new speed based
     137             :     double accel;
     138             :     int branch = 0;
     139    22088154 :     if (dx <= abx) {
     140      341312 :         accel = emergency(dv, dx, predAccel, v, gap, abx, bx);
     141             :         branch = 1;
     142    21746842 :     } else if (dx < sdx) {
     143     2213523 :         if (dv > cldv) {
     144      598474 :             accel = approaching(dv, dx, abx, predAccel);
     145             :             branch = 2;
     146     1615049 :         } else if (dv > opdv) {
     147      867230 :             accel = following(vars->accelSign);
     148             :             branch = 3;
     149             :         } else {
     150      747819 :             accel = fullspeed(v, vpref, dx, abx);
     151             :             branch = 4;
     152             :         }
     153             :     } else {
     154    19533319 :         if (dv > sdv && dx < dmax) { //@note other versions have an disjunction instead of conjunction
     155      680434 :             accel = approaching(dv, dx, abx, predAccel);
     156      680434 :             branch = 5;
     157             :         } else {
     158    18852885 :             accel = fullspeed(v, vpref, dx, abx);
     159             :             branch = 6;
     160             :         }
     161             :     }
     162             :     // since we have hard constraints on accel we may as well use them here
     163             : #ifdef DEBUG_V
     164             :     const double rawAccel = accel;
     165             : #endif
     166    22088154 :     accel = MAX2(MIN2(accel, myAccel), -myEmergencyDecel);
     167    22088154 :     const double vNew = MAX2(0., v + ACCEL2SPEED(accel)); // don't allow negative speeds
     168             : #ifdef DEBUG_V
     169             :     if (veh->isSelected() && !MSGlobals::gComputeLC) {
     170             :         std::cout << SIMTIME << " Wiedemann::_v veh=" << veh->getID()
     171             :                   << " v=" << v << " pV=" << predSpeed << " pA=" << predAccel << " gap=" << gap
     172             :                   << " dv=" << dv << " dx=" << dx << " ax=" << myAX << " bx=" << bx << " abx=" << abx
     173             :                   << " sdx=" << sdx << " sdv=" << sdv << " cldv=" << cldv << " opdv=" << opdv
     174             :                   << " branch=" << branch << " rawAccel=" << rawAccel
     175             :                   << " accel=" << accel << " vNew=" << vNew << "\n";
     176             :     }
     177             : #else
     178             :     UNUSED_PARAMETER(branch);
     179             : #endif
     180    22088154 :     return vNew;
     181             : }
     182             : 
     183             : 
     184             : double
     185    19600704 : MSCFModel_Wiedemann::fullspeed(double v, double vpref, double dx, double abx) const {
     186             :     // maximum acceleration is reduced with increasing speed
     187    19600704 :     double bmax = 0.2 + 0.8 * myAccel * (7 - sqrt(v));
     188             :     // if veh just drifted out of a 'following' process the acceleration is reduced
     189    19600704 :     double accel = dx <= 2 * abx ? MIN2(myMinAccel, bmax * (dx - abx) / abx) : bmax;
     190    19600704 :     if (v > vpref) {
     191           0 :         accel = - accel;
     192             :     }
     193    19600704 :     return accel;
     194             : }
     195             : 
     196             : 
     197             : double
     198      867230 : MSCFModel_Wiedemann::following(double sign) const {
     199      867230 :     return myMinAccel * sign;
     200             : }
     201             : 
     202             : 
     203             : double
     204     1278908 : MSCFModel_Wiedemann::approaching(double dv, double dx, double abx, double predAccel) const {
     205             :     // there is singularity in the formula. we do the sanity check outside
     206             :     assert(abx < dx);
     207             :     // @note: the original model does not have a limit on maximum deceleration here.
     208             :     // We add this to avoid cascading emergency deceleration
     209             :     // also, the multiplier on predAccel is always 1 in the original model
     210     1278908 :     return MAX2(0.5 * dv * dv / (abx - dx) + predAccel * PRED_DECEL_MULT, -myMaxApproachingDecel);
     211             : }
     212             : 
     213             : 
     214             : double
     215      341312 : MSCFModel_Wiedemann::emergency(double dv, double dx, double predAccel, double v, double gap, double abx, double bx) const {
     216             :     // wiedemann assumes that dx will always be larger than myAX (sumo may
     217             :     // violate this assumption when crashing (-:
     218             :     //
     219             :     // predAccel is called b_(n-1) in the literature and it's multipleir is always 1
     220             : 
     221      341312 :     if (dx > myAX) {
     222      255628 :         const double bmin = B_MIN_ADD + B_MIN_MULT * v;
     223      255628 :         const double accel = (0.5 * dv * dv / (myAX - dx)
     224      255628 :                               + predAccel * PRED_DECEL_MULT_EMERGENCY
     225      255628 :                               + bmin * (abx - gap) / bx);
     226      255628 :         return accel;
     227             :     } else {
     228       85684 :         return -myEmergencyDecel;
     229             :     }
     230             : 
     231             :     // emergency according to C.Werner
     232             :     //return -myEmergencyDecel;
     233             : }

Generated by: LCOV version 1.14