LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_CC.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 3.7 % 618 23
Test Date: 2024-12-21 15:45:41 Functions: 7.3 % 41 3

            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_CC.cpp
      15              : /// @author  Michele Segata
      16              : /// @date    Wed, 18 Apr 2012
      17              : ///
      18              : // A series of automatic Cruise Controllers (CC, ACC, CACC)
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <algorithm>
      23              : #include <utils/common/RandHelper.h>
      24              : #include <utils/common/SUMOTime.h>
      25              : #include <utils/common/StringUtils.h>
      26              : #include <microsim/MSVehicle.h>
      27              : #include <microsim/MSVehicleControl.h>
      28              : #include <microsim/MSNet.h>
      29              : #include <microsim/MSEdge.h>
      30              : #include <microsim/MSStop.h>
      31              : #include <microsim/cfmodels/ParBuffer.h>
      32              : #include <libsumo/Vehicle.h>
      33              : #include <libsumo/TraCIDefs.h>
      34              : #include "MSCFModel_CC.h"
      35              : 
      36              : #ifndef sgn
      37              : #define sgn(x) ((x > 0) - (x < 0))
      38              : #endif
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // method definitions
      43              : // ===========================================================================
      44           71 : MSCFModel_CC::MSCFModel_CC(const MSVehicleType* vtype) : MSCFModel(vtype),
      45           71 :     myCcDecel(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_CCDECEL, 1.5)),
      46           71 :     myCcAccel(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_CCACCEL, 1.5)),
      47           71 :     myConstantSpacing(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_CONSTSPACING, 5.0)),
      48           71 :     myKp(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_KP, 1.0)),
      49           71 :     myLambda(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_LAMBDA, 0.1)),
      50           71 :     myC1(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_C1, 0.5)),
      51           71 :     myXi(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_XI, 1.0)),
      52           71 :     myOmegaN(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_OMEGAN, 0.2)),
      53           71 :     myTau(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_TAU, 0.5)),
      54           71 :     myLanesCount((int)vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_LANES_COUNT, -1)),
      55           71 :     myPloegH(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_PLOEG_H, 0.5)),
      56           71 :     myPloegKp(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_PLOEG_KP, 0.2)),
      57           71 :     myPloegKd(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_PLOEG_KD, 0.7)),
      58           71 :     myFlatbedKa(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_FLATBED_KA, 2.4)),
      59           71 :     myFlatbedKv(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_FLATBED_KV, 0.6)),
      60           71 :     myFlatbedKp(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_FLATBED_KP, 12.0)),
      61           71 :     myFlatbedH(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_FLATBED_H, 4.0)),
      62          142 :     myFlatbedD(vtype->getParameter().getCFParam(SUMO_ATTR_CF_CC_FLATBED_D, 5.0)) {
      63              : 
      64              :     //if the lanes count has not been specified in the attributes of the model, lane changing cannot properly work
      65           71 :     if (myLanesCount == -1) {
      66            0 :         throw ProcessError(TL("The number of lanes needs to be specified in the attributes of carFollowing-CC with the \"lanesCount\" attribute"));
      67              :     }
      68              : 
      69              :     //instantiate the driver model. For now, use Krauss as default, then needs to be parameterized
      70           71 :     myHumanDriver = new MSCFModel_Krauss(vtype);
      71              : 
      72           71 : }
      73              : 
      74          142 : MSCFModel_CC::~MSCFModel_CC() {}
      75              : 
      76              : MSCFModel::VehicleVariables*
      77            0 : MSCFModel_CC::createVehicleVariables() const {
      78            0 :     CC_VehicleVariables* vars = new CC_VehicleVariables();
      79            0 :     vars->ccKp = myKp;
      80            0 :     vars->accLambda = myLambda;
      81            0 :     vars->caccSpacing = myConstantSpacing;
      82            0 :     vars->caccC1 = myC1;
      83            0 :     vars->caccXi = myXi;
      84            0 :     vars->caccOmegaN = myOmegaN;
      85            0 :     vars->engineTau = myTau;
      86              :     //we cannot invoke recomputeParameters() because we have no pointer to the MSVehicle class
      87            0 :     vars->caccAlpha1 = 1 - vars->caccC1;
      88            0 :     vars->caccAlpha2 = vars->caccC1;
      89            0 :     vars->caccAlpha3 = -(2 * vars->caccXi - vars->caccC1 * (vars->caccXi + sqrt(vars->caccXi * vars->caccXi - 1))) * vars->caccOmegaN;
      90            0 :     vars->caccAlpha4 = -(vars->caccXi + sqrt(vars->caccXi * vars->caccXi - 1)) * vars->caccOmegaN * vars->caccC1;
      91            0 :     vars->caccAlpha5 = -vars->caccOmegaN * vars->caccOmegaN;
      92              : 
      93            0 :     vars->ploegH = myPloegH;
      94            0 :     vars->ploegKp = myPloegKp;
      95            0 :     vars->ploegKd = myPloegKd;
      96            0 :     vars->flatbedKa = myFlatbedKa;
      97            0 :     vars->flatbedKv = myFlatbedKv;
      98            0 :     vars->flatbedKp = myFlatbedKp;
      99            0 :     vars->flatbedD = myFlatbedD;
     100            0 :     vars->flatbedH = myFlatbedH;
     101              :     //by default use a first order lag model for the engine
     102            0 :     vars->engine = new FirstOrderLagModel();
     103            0 :     vars->engine->setParameter(FOLM_PAR_TAU, vars->engineTau);
     104            0 :     vars->engine->setParameter(FOLM_PAR_DT, TS);
     105            0 :     vars->engine->setMaximumAcceleration(myAccel);
     106            0 :     vars->engine->setMaximumDeceleration(myDecel);
     107            0 :     vars->engineModel = CC_ENGINE_MODEL_FOLM;
     108            0 :     return (VehicleVariables*)vars;
     109              : }
     110              : 
     111              : void
     112            0 : MSCFModel_CC::setLeader(MSVehicle* veh, MSVehicle* const leader, std::string leaderId) const {
     113              :     auto* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     114            0 :     vars->leaderVehicle = leader;
     115            0 :     vars->leaderVehicleId = leaderId;
     116            0 :     if (leader != nullptr) {
     117            0 :         vars->isLeader = false;
     118              :     } else
     119              :         // if we are removing our leader, then this vehicle must become a leader of itself until being member of another platoon
     120              :     {
     121            0 :         vars->isLeader = true;
     122              :     }
     123            0 : }
     124              : 
     125              : int
     126            0 : MSCFModel_CC::isPlatoonLaneChangeSafe(const MSVehicle* veh, bool left) const {
     127              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     128            0 :     if (!vars->isLeader) {
     129              :         // before asking the leader, be sure it is still in the simulation
     130            0 :         if (findVehicle(vars->leaderVehicleId)) {
     131            0 :             return isPlatoonLaneChangeSafe(vars->leaderVehicle, left);
     132              :         } else {
     133              :             return LCA_BLOCKED;
     134              :         }
     135              :     }
     136              :     int result = 0;
     137            0 :     std::pair<int, int> state = libsumo::Vehicle::getLaneChangeState(veh->getID(), left ? +1 : -1);
     138              :     // bit 1: query lateral direction (left:0, right:1)
     139              :     // bit 2: query longitudinal direction (followers:0, leaders:1)
     140              :     // bit 3: blocking (return all:0, return only blockers:1)
     141            0 :     auto followers = libsumo::Vehicle::getNeighbors(veh->getID(), left ? 0b100 : 0b101);
     142            0 :     auto leaders = libsumo::Vehicle::getNeighbors(veh->getID(), left ? 0b110 : 0b111);
     143            0 :     bool noNeighbors = followers.empty() && leaders.empty();
     144            0 :     if (!(state.second & LCA_BLOCKED) && noNeighbors) {
     145              :         // leader is not blocked. check all the members
     146            0 :         for (auto m = vars->members.begin(); m != vars->members.end(); m++) {
     147            0 :             const std::pair<int, int> mState = libsumo::Vehicle::getLaneChangeState(m->second, left ? +1 : -1);
     148            0 :             followers = libsumo::Vehicle::getNeighbors(m->second, left ? 0b100 : 0b101);
     149            0 :             leaders = libsumo::Vehicle::getNeighbors(m->second, left ? 0b110 : 0b111);
     150            0 :             noNeighbors = followers.empty() && leaders.empty();
     151            0 :             if (mState.second & LCA_BLOCKED || !noNeighbors) {
     152            0 :                 if (mState.second & LCA_BLOCKED) {
     153              :                     result = mState.second;
     154              :                 } else {
     155            0 :                     if (!followers.empty()) {
     156            0 :                         result |= left ? LCA_BLOCKED_BY_LEFT_FOLLOWER : LCA_BLOCKED_BY_RIGHT_FOLLOWER;
     157              :                     }
     158            0 :                     if (!leaders.empty()) {
     159            0 :                         result |= left ? LCA_BLOCKED_BY_LEFT_LEADER : LCA_BLOCKED_BY_RIGHT_LEADER;
     160              :                     }
     161              :                 }
     162            0 :                 break;
     163              :             }
     164              :         }
     165              :     } else {
     166            0 :         if (state.second & LCA_BLOCKED) {
     167              :             result = state.second;
     168              :         } else {
     169            0 :             if (!followers.empty()) {
     170            0 :                 result |= left ? LCA_BLOCKED_BY_LEFT_FOLLOWER : LCA_BLOCKED_BY_RIGHT_FOLLOWER;
     171              :             }
     172            0 :             if (!leaders.empty()) {
     173            0 :                 result |= left ? LCA_BLOCKED_BY_LEFT_LEADER : LCA_BLOCKED_BY_RIGHT_LEADER;
     174              :             }
     175              :         }
     176              :     }
     177              :     return result;
     178            0 : }
     179              : 
     180              : void
     181            0 : MSCFModel_CC::changeWholePlatoonLane(MSVehicle* const veh, int direction) const {
     182              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     183            0 :     libsumo::Vehicle::changeLane(veh->getID(), veh->getLaneIndex() + direction, 0);
     184            0 :     for (auto& member : vars->members) {
     185            0 :         libsumo::Vehicle::changeLane(member.second, veh->getLaneIndex() + direction, 0);
     186              :     }
     187            0 : }
     188              : 
     189              : void
     190            0 : MSCFModel_CC::performAutoLaneChange(MSVehicle* const veh) const {
     191              :     // check for left lane change
     192            0 :     std::pair<int, int> state = libsumo::Vehicle::getLaneChangeState(veh->getID(), +1);
     193              :     int traciState = state.first;
     194            0 :     if (traciState & LCA_LEFT && traciState & LCA_SPEEDGAIN) {
     195              :         // we can gain by moving left. check that all vehicles can move left
     196            0 :         if (isPlatoonLaneChangeSafe(veh, true) == 0) {
     197            0 :             changeWholePlatoonLane(veh, +1);
     198              :         }
     199              :     }
     200              :     // check for right lane change
     201            0 :     state = libsumo::Vehicle::getLaneChangeState(veh->getID(), -1);
     202              :     traciState = state.first;
     203            0 :     if (traciState & LCA_RIGHT && traciState & LCA_KEEPRIGHT) {
     204              :         // we should move back right. check that all vehicles can move right
     205            0 :         if (isPlatoonLaneChangeSafe(veh, false) == 0) {
     206            0 :             changeWholePlatoonLane(veh, -1);
     207              :         }
     208              :     }
     209            0 : }
     210              : 
     211              : void
     212            0 : MSCFModel_CC::performPlatoonLaneChange(MSVehicle* const veh) const {
     213              :     auto* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     214            0 :     int currentLane = veh->getLaneIndex();
     215            0 :     if (currentLane == vars->platoonFixedLane) {
     216              :         // platoon has already reached the desired lane
     217            0 :         vars->platoonFixedLane = -1;
     218            0 :         return;
     219              :     }
     220            0 :     bool left = currentLane < vars->platoonFixedLane;
     221            0 :     if (isPlatoonLaneChangeSafe(veh, left) == 0) {
     222            0 :         changeWholePlatoonLane(veh, left ? +1 : -1);
     223              :     }
     224              : }
     225              : 
     226              : double
     227            0 : MSCFModel_CC::getSecureGap(const MSVehicle* const veh, const MSVehicle* const pred, const double speed, const double leaderSpeed, const double leaderMaxDecel) const {
     228              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     229              : 
     230              :     const double tolerance = 0.8;
     231            0 :     switch (vars->activeController) {
     232            0 :         case Plexe::CACC:
     233              :         case Plexe::FAKED_CACC:
     234            0 :             return vars->caccSpacing * tolerance;
     235            0 :         case Plexe::ACC:
     236            0 :             return (vars->accHeadwayTime * speed + 2) * tolerance;
     237            0 :         case Plexe::PLOEG:
     238            0 :             return (vars->ploegH * speed + 2) * tolerance;
     239            0 :         case Plexe::CONSENSUS:
     240            0 :             return d_i_j(vars->vehicles, vars->h, 1, 0) * tolerance;
     241            0 :         case Plexe::FLATBED:
     242            0 :             return (vars->flatbedD - vars->flatbedH * (speed - leaderSpeed)) * tolerance;
     243            0 :         case Plexe::DRIVER:
     244            0 :             return myHumanDriver->getSecureGap(veh, pred, speed, leaderSpeed, leaderMaxDecel);
     245            0 :         default:
     246            0 :             throw InvalidArgument("Unsupported activeController" + toString(vars->activeController));
     247              :     }
     248              : }
     249              : 
     250              : int
     251            0 : MSCFModel_CC::commitToLaneChange(const MSVehicle* veh, bool left) const {
     252              :     auto vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     253            0 :     if (isLeader(veh)) {
     254            0 :         SUMOTime timestep = MSNet::getInstance()->getCurrentTimeStep();
     255            0 :         if (vars->laneChangeCommitTime == timestep) {
     256            0 :             if (vars->commitToLaneChange) {
     257              :                 return 0;
     258              :             } else {
     259            0 :                 return vars->noCommitReason;
     260              :             }
     261              :         } else {
     262            0 :             int blocked = isPlatoonLaneChangeSafe(veh, left);
     263            0 :             if (blocked == 0) {
     264            0 :                 vars->commitToLaneChange = true;
     265            0 :                 vars->laneChangeCommitTime = timestep;
     266              :             }
     267            0 :             return blocked;
     268              :         }
     269              :     } else {
     270              :         // before asking the leader, be sure it is still in the simulation
     271            0 :         if (findVehicle(vars->leaderVehicleId)) {
     272            0 :             return commitToLaneChange(vars->leaderVehicle, left);
     273              :         } else {
     274              :             return LCA_BLOCKED;
     275              :         }
     276              :     }
     277              : }
     278              : 
     279              : MSVehicle*
     280            0 : MSCFModel_CC::findVehicle(std::string id) const {
     281            0 :     return dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(id));
     282              : }
     283              : 
     284              : double
     285            0 : MSCFModel_CC::finalizeSpeed(MSVehicle* const veh, double vPos) const {
     286              :     double vNext;
     287              :     //acceleration computed by the controller
     288              :     double controllerAcceleration;
     289              :     //acceleration after engine actuation
     290              :     double engineAcceleration;
     291              : 
     292              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     293              : 
     294              :     //call processNextStop() to ensure vehicle removal in case of crash
     295            0 :     veh->processNextStop(vPos);
     296              : 
     297              :     //check whether the vehicle has collided and set the flag in case
     298            0 :     if (!vars->crashed) {
     299            0 :         for (const MSStop& s : veh->getStops()) {
     300            0 :             if (s.pars.collision) {
     301            0 :                 vars->crashed = true;
     302              :             }
     303              :         }
     304              :     }
     305              : 
     306            0 :     if (vars->activeController != Plexe::DRIVER && !vars->useFixedAcceleration) {
     307            0 :         veh->setChosenSpeedFactor(vars->ccDesiredSpeed / veh->getLane()->getSpeedLimit());
     308              :     }
     309              : 
     310            0 :     if (vars->platoonFixedLane >= 0) {
     311            0 :         performPlatoonLaneChange(veh);
     312              :     }
     313              : 
     314            0 :     if (vars->autoLaneChange) {
     315            0 :         performAutoLaneChange(veh);
     316              :     }
     317              : 
     318            0 :     if (vars->activeController != Plexe::DRIVER) {
     319            0 :         controllerAcceleration = SPEED2ACCEL(vPos - veh->getSpeed());
     320            0 :         controllerAcceleration = std::min(vars->uMax, std::max(vars->uMin, controllerAcceleration));
     321              :         //compute the actual acceleration applied by the engine
     322            0 :         engineAcceleration = vars->engine->getRealAcceleration(veh->getSpeed(), veh->getAcceleration(), controllerAcceleration, MSNet::getInstance()->getCurrentTimeStep());
     323            0 :         vNext = MAX2(double(0), veh->getSpeed() + ACCEL2SPEED(engineAcceleration));
     324            0 :         vars->controllerAcceleration = controllerAcceleration;
     325              :     } else {
     326            0 :         vNext = myHumanDriver->finalizeSpeed(veh, vPos);
     327              :     }
     328              : 
     329            0 :     return vNext;
     330              : }
     331              : 
     332              : 
     333              : double
     334            0 : MSCFModel_CC::followSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const pred, const CalcReason usage) const {
     335              : 
     336              :     UNUSED_PARAMETER(pred);
     337              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     338              : 
     339            0 :     if (vars->activeController != Plexe::DRIVER) {
     340            0 :         return _v(veh, gap2pred, speed, predSpeed);
     341              :     } else {
     342            0 :         return myHumanDriver->followSpeed(veh, speed, gap2pred, predSpeed, predMaxDecel, pred, usage);
     343              :     }
     344              : }
     345              : 
     346              : double
     347            0 : MSCFModel_CC::insertionFollowSpeed(const MSVehicle* const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle* const /*pred*/) const {
     348              :     UNUSED_PARAMETER(veh);
     349              :     UNUSED_PARAMETER(gap2pred);
     350              :     UNUSED_PARAMETER(predSpeed);
     351              :     UNUSED_PARAMETER(predMaxDecel);
     352              :     //by returning speed + 1, we tell sumo that "speed" is always a safe speed
     353            0 :     return speed + 1;
     354              : }
     355              : 
     356              : double
     357            0 : MSCFModel_CC::stopSpeed(const MSVehicle* const veh, double speed, double gap2pred, double decel, const CalcReason usage) const {
     358              : 
     359              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     360            0 :     if (vars->activeController != Plexe::DRIVER) {
     361              :         double relSpeed;
     362            0 :         getRadarMeasurements(veh, gap2pred, relSpeed);
     363            0 :         if (gap2pred == -1) {
     364            0 :             gap2pred = std::numeric_limits<double>().max();
     365              :         }
     366            0 :         return _v(veh, gap2pred, speed, speed + relSpeed);
     367              :     } else {
     368            0 :         return myHumanDriver->stopSpeed(veh, speed, gap2pred, decel, usage);
     369              :     }
     370              : }
     371              : 
     372            0 : double MSCFModel_CC::freeSpeed(const MSVehicle* const veh, double speed, double seen, double maxSpeed, const bool onInsertion, const CalcReason usage) const {
     373              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     374            0 :     if (vars->activeController != Plexe::DRIVER) {
     375              :         double gap2pred, relSpeed;
     376            0 :         getRadarMeasurements(veh, gap2pred, relSpeed);
     377            0 :         if (gap2pred == -1) {
     378            0 :             gap2pred = std::numeric_limits<double>().max();
     379              :         }
     380            0 :         return _v(veh, gap2pred, speed, speed + relSpeed);
     381              :     } else {
     382            0 :         return MSCFModel::freeSpeed(veh, speed, seen, maxSpeed, onInsertion, usage);
     383              :     }
     384              : }
     385              : 
     386              : double
     387            0 : MSCFModel_CC::interactionGap(const MSVehicle* const veh, double vL) const {
     388              : 
     389              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     390            0 :     if (vars->activeController != Plexe::DRIVER) {
     391              :         //maximum radar range is CC is enabled
     392              :         return 250;
     393              :     } else {
     394            0 :         return myHumanDriver->interactionGap(veh, vL);
     395              :     }
     396              : 
     397              : }
     398              : 
     399              : double
     400            0 : MSCFModel_CC::maxNextSpeed(double speed, const MSVehicle* const veh) const {
     401              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     402            0 :     if (vars->engineModel == CC_ENGINE_MODEL_FOLM) {
     403            0 :         return speed + (double) ACCEL2SPEED(getMaxAccel());
     404              :     } else {
     405            0 :         return speed + (double) ACCEL2SPEED(20);
     406              :     }
     407              : }
     408              : 
     409              : double
     410            0 : MSCFModel_CC::minNextSpeed(double speed, const MSVehicle* const veh) const {
     411              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     412            0 :     if (vars->engineModel == CC_ENGINE_MODEL_FOLM) {
     413            0 :         return MSCFModel::minNextSpeed(speed, veh);
     414              :     } else {
     415            0 :         return MAX2((double)0, speed - (double) ACCEL2SPEED(20));
     416              :     }
     417              : }
     418              : 
     419              : double
     420            0 : MSCFModel_CC::_v(const MSVehicle* const veh, double gap2pred, double egoSpeed, double predSpeed) const {
     421              : 
     422              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     423              : 
     424              :     //acceleration computed by the controller
     425            0 :     double controllerAcceleration = vars->fixedAcceleration;
     426              :     //speed computed by the model
     427              :     double speed;
     428              :     //acceleration computed by the Cruise Control
     429              :     double ccAcceleration;
     430              :     //acceleration computed by the Adaptive Cruise Control
     431              :     double accAcceleration;
     432              :     //acceleration computed by the Cooperative Adaptive Cruise Control
     433              :     double caccAcceleration;
     434              :     //variables needed by CACC
     435              :     double predAcceleration, leaderAcceleration, leaderSpeed;
     436              :     //dummy variables used for auto feeding
     437              :     Position pos;
     438              :     double time;
     439            0 :     const double currentTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() + DELTA_T);
     440              : 
     441            0 :     if (vars->crashed) {
     442              :         return 0;
     443              :     }
     444            0 :     if (vars->autoFeed) {
     445            0 :         if (!findVehicle(vars->leaderVehicleId) || !findVehicle(vars->frontVehicleId)) {
     446              :             // either the leader or the front vehicle have left the simulation. Disable auto feed
     447            0 :             vars->autoFeed = false;
     448            0 :             vars->leaderVehicle = nullptr;
     449            0 :             vars->frontVehicle = nullptr;
     450              :         }
     451              :     }
     452            0 :     if (vars->activeController == Plexe::DRIVER || !vars->useFixedAcceleration) {
     453            0 :         switch (vars->activeController) {
     454            0 :             case Plexe::ACC:
     455            0 :                 ccAcceleration = _cc(veh, egoSpeed, vars->ccDesiredSpeed);
     456            0 :                 accAcceleration = _acc(veh, egoSpeed, predSpeed, gap2pred, vars->accHeadwayTime);
     457            0 :                 if (gap2pred > 250 || ccAcceleration < accAcceleration) {
     458            0 :                     controllerAcceleration = ccAcceleration;
     459              :                 } else {
     460              :                     controllerAcceleration = accAcceleration;
     461              :                 }
     462              :                 break;
     463              : 
     464            0 :             case Plexe::CACC:
     465            0 :                 if (vars->autoFeed) {
     466            0 :                     getVehicleInformation(vars->leaderVehicle, vars->leaderSpeed, vars->leaderAcceleration, vars->leaderControllerAcceleration, pos, time);
     467            0 :                     getVehicleInformation(vars->frontVehicle, vars->frontSpeed, vars->frontAcceleration, vars->frontControllerAcceleration, pos, time);
     468              :                 }
     469              : 
     470            0 :                 if (vars->useControllerAcceleration) {
     471            0 :                     predAcceleration = vars->frontControllerAcceleration;
     472            0 :                     leaderAcceleration = vars->leaderControllerAcceleration;
     473              :                 } else {
     474            0 :                     predAcceleration = vars->frontAcceleration;
     475            0 :                     leaderAcceleration = vars->leaderAcceleration;
     476              :                 }
     477              :                 //overwrite pred speed using data obtained through wireless communication
     478            0 :                 predSpeed = vars->frontSpeed;
     479            0 :                 leaderSpeed = vars->leaderSpeed;
     480            0 :                 if (vars->usePrediction) {
     481            0 :                     predSpeed += (currentTime - vars->frontDataReadTime) * vars->frontAcceleration;
     482            0 :                     leaderSpeed += (currentTime - vars->leaderDataReadTime) * vars->leaderAcceleration;
     483              :                 }
     484              : 
     485            0 :                 if (vars->caccInitialized) {
     486            0 :                     controllerAcceleration = _cacc(veh, egoSpeed, predSpeed, predAcceleration, gap2pred, leaderSpeed, leaderAcceleration, vars->caccSpacing);
     487              :                 } else
     488              :                     //do not let CACC take decisions until at least one packet has been received
     489              :                 {
     490              :                     controllerAcceleration = 0;
     491              :                 }
     492              : 
     493              :                 break;
     494              : 
     495            0 :             case Plexe::FAKED_CACC:
     496              : 
     497            0 :                 if (vars->autoFeed) {
     498            0 :                     getVehicleInformation(vars->leaderVehicle, vars->fakeData.leaderSpeed, vars->fakeData.leaderAcceleration, vars->fakeData.leaderControllerAcceleration, pos, time);
     499            0 :                     getVehicleInformation(vars->frontVehicle, vars->fakeData.frontSpeed, vars->fakeData.frontAcceleration, vars->fakeData.frontControllerAcceleration, pos, time);
     500            0 :                     vars->fakeData.frontDistance = pos.distanceTo2D(veh->getPosition());
     501              :                 }
     502              : 
     503            0 :                 if (vars->useControllerAcceleration) {
     504            0 :                     predAcceleration = vars->fakeData.frontControllerAcceleration;
     505            0 :                     leaderAcceleration = vars->fakeData.leaderControllerAcceleration;
     506              :                 } else {
     507            0 :                     predAcceleration = vars->fakeData.frontAcceleration;
     508            0 :                     leaderAcceleration = vars->fakeData.leaderAcceleration;
     509              :                 }
     510            0 :                 ccAcceleration = _cc(veh, egoSpeed, vars->ccDesiredSpeed);
     511            0 :                 caccAcceleration = _cacc(veh, egoSpeed, vars->fakeData.frontSpeed, predAcceleration, vars->fakeData.frontDistance, vars->fakeData.leaderSpeed, leaderAcceleration, vars->caccSpacing);
     512              :                 //faked CACC can be used to get closer to a platoon for joining
     513              :                 //using the minimum acceleration ensures that we do not exceed
     514              :                 //the CC desired speed
     515            0 :                 controllerAcceleration = std::min(ccAcceleration, caccAcceleration);
     516              : 
     517            0 :                 break;
     518              : 
     519            0 :             case Plexe::PLOEG:
     520              : 
     521            0 :                 if (vars->autoFeed) {
     522            0 :                     getVehicleInformation(vars->frontVehicle, vars->frontSpeed, vars->frontAcceleration, vars->frontControllerAcceleration, pos, time);
     523              :                 }
     524              : 
     525            0 :                 if (vars->useControllerAcceleration) {
     526            0 :                     predAcceleration = vars->frontControllerAcceleration;
     527              :                 } else {
     528            0 :                     predAcceleration = vars->frontAcceleration;
     529              :                 }
     530              :                 //check if we received at least one packet
     531            0 :                 if (vars->frontInitialized)
     532              :                     //ploeg's controller computes \dot{u}_i, so we need to sum such value to the previously computed u_i
     533              :                 {
     534            0 :                     controllerAcceleration = vars->controllerAcceleration + _ploeg(veh, egoSpeed, predSpeed, predAcceleration, gap2pred);
     535              :                 } else {
     536              :                     controllerAcceleration = 0;
     537              :                 }
     538              : 
     539              :                 break;
     540              : 
     541            0 :             case Plexe::CONSENSUS:
     542            0 :                 controllerAcceleration = _consensus(veh, egoSpeed, veh->getPosition(), currentTime);
     543            0 :                 break;
     544              : 
     545            0 :             case Plexe::FLATBED:
     546              : 
     547            0 :                 if (vars->autoFeed) {
     548            0 :                     getVehicleInformation(vars->leaderVehicle, vars->leaderSpeed, vars->leaderAcceleration, vars->leaderControllerAcceleration, pos, time);
     549            0 :                     getVehicleInformation(vars->frontVehicle, vars->frontSpeed, vars->frontAcceleration, vars->frontControllerAcceleration, pos, time);
     550              :                 }
     551              : 
     552              :                 //overwrite pred speed using data obtained through wireless communication
     553            0 :                 predSpeed = vars->frontSpeed;
     554            0 :                 leaderSpeed = vars->leaderSpeed;
     555            0 :                 if (vars->usePrediction) {
     556            0 :                     predSpeed += (currentTime - vars->frontDataReadTime) * vars->frontAcceleration;
     557            0 :                     leaderSpeed += (currentTime - vars->leaderDataReadTime) * vars->leaderAcceleration;
     558              :                 }
     559              : 
     560            0 :                 if (vars->caccInitialized) {
     561            0 :                     controllerAcceleration = _flatbed(veh, veh->getAcceleration(), egoSpeed, predSpeed, gap2pred, leaderSpeed);
     562              :                 } else
     563              :                     //do not let CACC take decisions until at least one packet has been received
     564              :                 {
     565              :                     controllerAcceleration = 0;
     566              :                 }
     567              : 
     568              :                 break;
     569              : 
     570            0 :             case Plexe::DRIVER:
     571            0 :                 std::cerr << "Switching to normal driver behavior still not implemented in MSCFModel_CC\n";
     572              :                 assert(false);
     573              :                 break;
     574              : 
     575            0 :             default:
     576            0 :                 std::cerr << "Invalid controller selected in MSCFModel_CC\n";
     577              :                 assert(false);
     578              :                 break;
     579              : 
     580              :         }
     581              : 
     582              :     }
     583              : 
     584            0 :     speed = MAX2(double(0), egoSpeed + ACCEL2SPEED(controllerAcceleration));
     585              : 
     586              :     return speed;
     587              : }
     588              : 
     589              : double
     590            0 : MSCFModel_CC::_cc(const MSVehicle* veh, double egoSpeed, double desSpeed) const {
     591              : 
     592              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     593              :     //Eq. 5.5 of the Rajamani book, with Ki = 0 and bounds on max and min acceleration
     594            0 :     return std::min(myCcAccel, std::max(-myCcDecel, -vars->ccKp * (egoSpeed - desSpeed)));
     595              : 
     596              : }
     597              : 
     598              : double
     599            0 : MSCFModel_CC::_acc(const MSVehicle* veh, double egoSpeed, double predSpeed, double gap2pred, double headwayTime) const {
     600              : 
     601              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     602              :     //Eq. 6.18 of the Rajamani book
     603            0 :     return -1.0 / headwayTime * (egoSpeed - predSpeed + vars->accLambda * (-gap2pred + headwayTime * egoSpeed + 2));
     604              : 
     605              : }
     606              : 
     607              : double
     608            0 : MSCFModel_CC::_cacc(const MSVehicle* veh, double egoSpeed, double predSpeed, double predAcceleration, double gap2pred, double leaderSpeed, double leaderAcceleration, double spacing) const {
     609              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     610              :     //compute epsilon, i.e., the desired distance error
     611            0 :     double epsilon = -gap2pred + spacing; //NOTICE: error (if any) should already be included in gap2pred
     612              :     //compute epsilon_dot, i.e., the desired speed error
     613            0 :     double epsilon_dot = egoSpeed - predSpeed;
     614              :     //Eq. 7.39 of the Rajamani book
     615            0 :     return vars->caccAlpha1 * predAcceleration + vars->caccAlpha2 * leaderAcceleration +
     616            0 :            vars->caccAlpha3 * epsilon_dot + vars->caccAlpha4 * (egoSpeed - leaderSpeed) + vars->caccAlpha5 * epsilon;
     617              : }
     618              : 
     619              : 
     620              : double
     621            0 : MSCFModel_CC::_ploeg(const MSVehicle* veh, double egoSpeed, double predSpeed, double predAcceleration, double gap2pred) const {
     622              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     623            0 :     return (1 / vars->ploegH * (
     624            0 :                 -vars->controllerAcceleration +
     625            0 :                 vars->ploegKp * (gap2pred - (2 + vars->ploegH * egoSpeed)) +
     626            0 :                 vars->ploegKd * (predSpeed - egoSpeed - vars->ploegH * veh->getAcceleration()) +
     627              :                 predAcceleration
     628            0 :             )) * TS ;
     629              : }
     630              : 
     631              : double
     632            0 : MSCFModel_CC::d_i_j(const struct Plexe::VEHICLE_DATA* vehicles, const double h[MAX_N_CARS], int i, int j) const {
     633              : 
     634              :     int k, min_i, max_i;
     635              :     double d = 0;
     636              :     //compute indexes of the summation
     637            0 :     if (j < i) {
     638              :         min_i = j;
     639            0 :         max_i = i - 1;
     640              :     } else {
     641              :         min_i = i;
     642            0 :         max_i = j - 1;
     643              :     }
     644              :     //compute distance
     645            0 :     for (k = min_i; k <= max_i; k++) {
     646            0 :         d += h[k] * vehicles[0].speed + vehicles[k].length + 15;
     647              :     }
     648              : 
     649            0 :     if (j < i) {
     650              :         return d;
     651              :     } else {
     652            0 :         return -d;
     653              :     }
     654              : 
     655              : }
     656              : 
     657              : double
     658            0 : MSCFModel_CC::_consensus(const MSVehicle* veh, double egoSpeed, Position egoPosition, double time) const {
     659              :     //TODO: this controller, by using real GPS coordinates, does only work
     660              :     //when vehicles are traveling west-to-east on a straight line, basically
     661              :     //on the X axis. This needs to be fixed to consider direction as well
     662              :     CC_VehicleVariables* vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
     663            0 :     int index = vars->position;
     664            0 :     int nCars = vars->nCars;
     665            0 :     struct Plexe::VEHICLE_DATA* vehicles = vars->vehicles;
     666              : 
     667              :     //loop variable
     668              :     int j;
     669              :     //control input
     670              :     double u_i = 0;
     671              :     //actual distance term
     672              :     double actualDistance = 0;
     673              :     //desired distance term
     674              :     double desiredDistance = 0;
     675              :     //speed error term
     676              :     double speedError = 0;
     677              :     //degree of agent i
     678              :     double d_i = 0;
     679              : 
     680              :     //compensate my position: compute prediction of what will be my position at time of actuation
     681            0 :     Position egoVelocity = veh->getVelocityVector();
     682            0 :     egoPosition.set(egoPosition.x() + egoVelocity.x() * STEPS2TIME(DELTA_T),
     683            0 :                     egoPosition.y() + egoVelocity.y() * STEPS2TIME(DELTA_T));
     684            0 :     vehicles[index].speed = egoSpeed;
     685            0 :     vehicles[index].positionX = egoPosition.x();
     686            0 :     vehicles[index].positionY = egoPosition.y();
     687              : 
     688              :     //check that data from all vehicles have been received. the control
     689              :     //law might actually need a subset of all the data, but d_i_j needs
     690              :     //the lengths of all vehicles. uninitialized values might cause problems
     691            0 :     if (vars->nInitialized != vars->nCars - 1) {
     692              :         return 0;
     693              :     }
     694              : 
     695              :     //compute speed error.
     696            0 :     speedError = -vars->b[index] * (egoSpeed - vehicles[0].speed);
     697              : 
     698              :     //compute desired distance term
     699            0 :     for (j = 0; j < nCars; j++) {
     700            0 :         if (j == index) {
     701            0 :             continue;
     702              :         }
     703            0 :         d_i += vars->L[index][j];
     704            0 :         desiredDistance -= vars->K[index][j] * vars->L[index][j] * d_i_j(vehicles, vars->h, index, j);
     705              :     }
     706            0 :     desiredDistance = desiredDistance / d_i;
     707              : 
     708              :     //compute actual distance term
     709            0 :     for (j = 0; j < nCars; j++) {
     710            0 :         if (j == index) {
     711              :             continue;
     712              :         }
     713              :         //distance error for consensus with GPS equipped
     714              :         Position otherPosition;
     715            0 :         double dt = time - vehicles[j].time;
     716              :         //predict the position of the other vehicle
     717            0 :         otherPosition.setx(vehicles[j].positionX + dt * vehicles[j].speedX);
     718            0 :         otherPosition.sety(vehicles[j].positionY + dt * vehicles[j].speedY);
     719            0 :         double distance = egoPosition.distanceTo2D(otherPosition) * sgn(j - index);
     720            0 :         actualDistance -= vars->K[index][j] * vars->L[index][j] * distance;
     721              :     }
     722              : 
     723            0 :     actualDistance = actualDistance / (d_i);
     724              : 
     725              :     //original paper formula
     726            0 :     u_i = (speedError + desiredDistance + actualDistance) / 1000;
     727              : 
     728            0 :     return u_i;
     729              : }
     730              : 
     731              : double
     732            0 : MSCFModel_CC::_flatbed(const MSVehicle* veh, double egoAcceleration, double egoSpeed, double predSpeed,
     733              :                        double gap2pred, double leaderSpeed) const {
     734              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     735              :     return (
     736            0 :                -vars->flatbedKa * egoAcceleration +
     737            0 :                vars->flatbedKv * (predSpeed - egoSpeed) +
     738            0 :                vars->flatbedKp * (gap2pred - vars->flatbedD - vars->flatbedH * (egoSpeed - leaderSpeed))
     739            0 :            );
     740              : }
     741              : 
     742              : double
     743            0 : MSCFModel_CC::getCACCConstantSpacing(const MSVehicle* veh) const {
     744              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     745            0 :     return vars->caccSpacing;
     746              : }
     747              : 
     748              : void
     749            0 : MSCFModel_CC::getVehicleInformation(const MSVehicle* veh, double& speed, double& acceleration, double& controllerAcceleration, Position& position, double& time) const {
     750              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     751            0 :     speed = veh->getSpeed();
     752            0 :     acceleration = veh->getAcceleration();
     753            0 :     controllerAcceleration = vars->controllerAcceleration;
     754            0 :     position = veh->getPosition();
     755            0 :     time = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
     756            0 : }
     757              : 
     758            0 : void MSCFModel_CC::setParameter(MSVehicle* veh, const std::string& key, const std::string& value) const {
     759              :     // vehicle variables used to set the parameter
     760              :     CC_VehicleVariables* vars;
     761              : 
     762            0 :     ParBuffer buf(value);
     763              : 
     764              :     vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
     765              :     try {
     766            0 :         if (key.compare(PAR_LEADER_SPEED_AND_ACCELERATION) == 0) {
     767              :             double x, y, vx, vy;
     768            0 :             buf >> vars->leaderSpeed >> vars->leaderAcceleration >> x >> y >> vars->leaderDataReadTime
     769            0 :                 >> vars->leaderControllerAcceleration >> vx >> vy >> vars->leaderAngle;
     770            0 :             vars->leaderPosition = Position(x, y);
     771            0 :             vars->leaderVelocity = Position(vx, vy);
     772            0 :             vars->leaderInitialized = true;
     773            0 :             if (vars->frontInitialized) {
     774            0 :                 vars->caccInitialized = true;
     775              :             }
     776              :             return;
     777              :         }
     778            0 :         if (key.compare(PAR_PRECEDING_SPEED_AND_ACCELERATION) == 0) {
     779              :             double x, y, vx, vy;
     780            0 :             buf >> vars->frontSpeed >> vars->frontAcceleration >> x >> y >> vars->frontDataReadTime
     781            0 :                 >> vars->frontControllerAcceleration >> vx >> vy >> vars->frontAngle;
     782            0 :             vars->frontPosition = Position(x, y);
     783            0 :             vars->frontVelocity = Position(vx, vy);
     784            0 :             vars->frontInitialized = true;
     785            0 :             if (vars->leaderInitialized) {
     786            0 :                 vars->caccInitialized = true;
     787              :             }
     788              :             return;
     789              :         }
     790            0 :         if (key.compare(CC_PAR_VEHICLE_DATA) == 0) {
     791              :             struct Plexe::VEHICLE_DATA vehicle;
     792            0 :             buf >> vehicle.index >> vehicle.speed >> vehicle.acceleration >>
     793            0 :                 vehicle.positionX >> vehicle.positionY >> vehicle.time >>
     794            0 :                 vehicle.length >> vehicle.u >> vehicle.speedX >>
     795            0 :                 vehicle.speedY >> vehicle.angle;
     796              :             //if the index is larger than the number of cars, simply ignore the data
     797            0 :             if (vehicle.index >= vars->nCars || vehicle.index == -1) {
     798              :                 return;
     799              :             }
     800            0 :             vars->vehicles[vehicle.index] = vehicle;
     801            0 :             if (!vars->initialized[vehicle.index] && vehicle.index != vars->position) {
     802            0 :                 vars->nInitialized++;
     803              :             }
     804            0 :             vars->initialized[vehicle.index] = true;
     805            0 :             return;
     806              :         }
     807            0 :         if (key.compare(PAR_LEADER_FAKE_DATA) == 0) {
     808            0 :             buf >> vars->fakeData.leaderSpeed >> vars->fakeData.leaderAcceleration
     809            0 :                 >> vars->fakeData.leaderControllerAcceleration;
     810            0 :             if (buf.last_empty()) {
     811            0 :                 vars->useControllerAcceleration = false;
     812              :             }
     813            0 :             return;
     814              :         }
     815            0 :         if (key.compare(PAR_FRONT_FAKE_DATA) == 0) {
     816            0 :             buf >> vars->fakeData.frontSpeed >> vars->fakeData.frontAcceleration >> vars->fakeData.frontDistance
     817            0 :                 >> vars->fakeData.frontControllerAcceleration;
     818            0 :             if (buf.last_empty()) {
     819            0 :                 vars->useControllerAcceleration = false;
     820              :             }
     821            0 :             return;
     822              :         }
     823            0 :         if (key.compare(CC_PAR_VEHICLE_POSITION) == 0) {
     824            0 :             vars->position = StringUtils::toInt(value.c_str());
     825            0 :             return;
     826              :         }
     827            0 :         if (key.compare(CC_PAR_PLATOON_SIZE) == 0) {
     828            0 :             vars->nCars = StringUtils::toInt(value.c_str());
     829              :             // given that we have a static matrix, check that we're not
     830              :             // setting a number of cars larger than the size of that matrix
     831            0 :             if (vars->nCars > MAX_N_CARS) {
     832            0 :                 vars->nCars = MAX_N_CARS;
     833            0 :                 std::stringstream warn;
     834            0 :                 warn << "MSCFModel_CC: setting a number of cars of " << vars->nCars << " out of a maximum of " << MAX_N_CARS <<
     835              :                      ". The CONSENSUS controller will not work properly if chosen. If you are using a different controller " <<
     836            0 :                      "you can ignore this warning";
     837            0 :                 WRITE_WARNING(warn.str());
     838            0 :             }
     839            0 :             return;
     840              :         }
     841            0 :         if (key.compare(PAR_ADD_MEMBER) == 0) {
     842              :             std::string id;
     843              :             int position;
     844            0 :             buf >> id >> position;
     845            0 :             vars->members[position] = id;
     846              : 
     847            0 :             auto vehicle = findVehicle(id);
     848            0 :             if (!vehicle) {
     849            0 :                 throw libsumo::TraCIException("Adding " + id + " as member but " + id + " does not exists");
     850              :             }
     851            0 :             auto cfm = dynamic_cast<const MSCFModel_CC*>(&vehicle->getVehicleType().getCarFollowModel());
     852            0 :             if (!cfm) {
     853            0 :                 throw libsumo::TraCIException("Adding " + id + " as member but " + id + " is not using MSCFModel_CC");
     854              :             }
     855            0 :             cfm->setLeader(vehicle, veh, veh->getID());
     856            0 :             vars->isLeader = true;
     857              :             return;
     858              :         }
     859            0 :         if (key.compare(PAR_REMOVE_MEMBER) == 0) {
     860            0 :             for (auto item = vars->members.begin(); item != vars->members.end(); item++)
     861            0 :                 if (item->second.compare(value) == 0) {
     862            0 :                     auto vehicle = findVehicle(value);
     863            0 :                     if (!vehicle) {
     864            0 :                         throw libsumo::TraCIException("Removing " + value + " from members but " + value + " does not exist");
     865              :                     }
     866            0 :                     auto cfm = dynamic_cast<const MSCFModel_CC*>(&vehicle->getVehicleType().getCarFollowModel());
     867            0 :                     if (!cfm) {
     868            0 :                         throw libsumo::TraCIException("Removing " + value + " from members but " + value + " is not using MSCFModel_CC");
     869              :                     }
     870            0 :                     cfm->setLeader(vehicle, nullptr, "");
     871              :                     vars->members.erase(item);
     872              :                     break;
     873              :                 }
     874            0 :             return;
     875              :         }
     876            0 :         if (key.compare(PAR_ENABLE_AUTO_LANE_CHANGE) == 0) {
     877            0 :             vars->autoLaneChange = StringUtils::toInt(value.c_str()) == 1;
     878              :             // if the user enables automatic lane changing, any request for a fixed lane is deleted
     879            0 :             if (vars->autoLaneChange) {
     880            0 :                 vars->platoonFixedLane = -1;
     881              :             }
     882            0 :             return;
     883              :         }
     884            0 :         if (key.compare(PAR_PLATOON_FIXED_LANE) == 0) {
     885            0 :             vars->platoonFixedLane = StringUtils::toInt(value.c_str());
     886              :             // asking a leader to change the lane for the whole platoon automatically disables auto lane change
     887            0 :             if (vars->platoonFixedLane >= 0) {
     888            0 :                 vars->autoLaneChange = false;
     889              :             }
     890            0 :             return;
     891              :         }
     892            0 :         if (key.compare(CC_PAR_CACC_XI) == 0) {
     893            0 :             vars->caccXi = StringUtils::toDouble(value.c_str());
     894            0 :             recomputeParameters(veh);
     895              :             return;
     896              :         }
     897            0 :         if (key.compare(CC_PAR_CACC_OMEGA_N) == 0) {
     898            0 :             vars->caccOmegaN = StringUtils::toDouble(value.c_str());
     899            0 :             recomputeParameters(veh);
     900              :             return;
     901              :         }
     902            0 :         if (key.compare(CC_PAR_CACC_C1) == 0) {
     903            0 :             vars->caccC1 = StringUtils::toDouble(value.c_str());
     904            0 :             recomputeParameters(veh);
     905              :             return;
     906              :         }
     907            0 :         if (key.compare(CC_PAR_ENGINE_TAU) == 0) {
     908            0 :             vars->engineTau = StringUtils::toDouble(value.c_str());
     909            0 :             vars->engine->setParameter(FOLM_PAR_TAU, vars->engineTau);
     910            0 :             recomputeParameters(veh);
     911            0 :             vars->engine->setParameter(FOLM_PAR_TAU, vars->engineTau);
     912              :         }
     913            0 :         if (key.compare(CC_PAR_UMIN) == 0) {
     914            0 :             vars->uMin = StringUtils::toDouble(value.c_str());
     915            0 :             return;
     916              :         }
     917            0 :         if (key.compare(CC_PAR_UMAX) == 0) {
     918            0 :             vars->uMax = StringUtils::toDouble(value.c_str());
     919            0 :             return;
     920              :         }
     921            0 :         if (key.compare(CC_PAR_PLOEG_H) == 0) {
     922            0 :             vars->ploegH = StringUtils::toDouble(value.c_str());
     923            0 :             return;
     924              :         }
     925            0 :         if (key.compare(CC_PAR_PLOEG_KP) == 0) {
     926            0 :             vars->ploegKp = StringUtils::toDouble(value.c_str());
     927            0 :             return;
     928              :         }
     929            0 :         if (key.compare(CC_PAR_PLOEG_KD) == 0) {
     930            0 :             vars->ploegKd = StringUtils::toDouble(value.c_str());
     931            0 :             return;
     932              :         }
     933            0 :         if (key.compare(CC_PAR_FLATBED_KA) == 0) {
     934            0 :             vars->flatbedKa = StringUtils::toDouble(value.c_str());
     935            0 :             return;
     936              :         }
     937            0 :         if (key.compare(CC_PAR_FLATBED_KV) == 0) {
     938            0 :             vars->flatbedKv = StringUtils::toDouble(value.c_str());
     939            0 :             return;
     940              :         }
     941            0 :         if (key.compare(CC_PAR_FLATBED_KP) == 0) {
     942            0 :             vars->flatbedKp = StringUtils::toDouble(value.c_str());
     943            0 :             return;
     944              :         }
     945            0 :         if (key.compare(CC_PAR_FLATBED_H) == 0) {
     946            0 :             vars->flatbedH = StringUtils::toDouble(value.c_str());
     947            0 :             return;
     948              :         }
     949            0 :         if (key.compare(CC_PAR_FLATBED_D) == 0) {
     950            0 :             vars->flatbedD = StringUtils::toDouble(value.c_str());
     951            0 :             return;
     952              :         }
     953            0 :         if (key.compare(CC_PAR_VEHICLE_ENGINE_MODEL) == 0) {
     954            0 :             if (vars->engine) {
     955            0 :                 delete vars->engine;
     956              :             }
     957            0 :             int engineModel = StringUtils::toInt(value.c_str());
     958            0 :             switch (engineModel) {
     959            0 :                 case CC_ENGINE_MODEL_REALISTIC: {
     960            0 :                     vars->engine = new RealisticEngineModel();
     961            0 :                     vars->engine->setParameter(ENGINE_PAR_DT, TS);
     962            0 :                     veh->getInfluencer().setSpeedMode(0);
     963            0 :                     vars->engineModel = CC_ENGINE_MODEL_REALISTIC;
     964            0 :                     break;
     965              :                 }
     966            0 :                 case CC_ENGINE_MODEL_FOLM:
     967              :                 default: {
     968            0 :                     vars->engine = new FirstOrderLagModel();
     969            0 :                     vars->engine->setParameter(FOLM_PAR_DT, TS);
     970            0 :                     vars->engine->setParameter(FOLM_PAR_TAU, vars->engineTau);
     971            0 :                     vars->engineModel = CC_ENGINE_MODEL_FOLM;
     972            0 :                     break;
     973              :                 }
     974              :             }
     975            0 :             vars->engine->setMaximumAcceleration(myAccel);
     976            0 :             vars->engine->setMaximumDeceleration(myDecel);
     977              :             return;
     978              :         }
     979            0 :         if (key.compare(CC_PAR_VEHICLE_MODEL) == 0) {
     980            0 :             vars->engine->setParameter(ENGINE_PAR_VEHICLE, value);
     981            0 :             return;
     982              :         }
     983            0 :         if (key.compare(CC_PAR_VEHICLES_FILE) == 0) {
     984            0 :             vars->engine->setParameter(ENGINE_PAR_XMLFILE, value);
     985            0 :             return;
     986              :         }
     987            0 :         if (key.compare(PAR_CACC_SPACING) == 0) {
     988            0 :             vars->caccSpacing = StringUtils::toDouble(value.c_str());
     989            0 :             return;
     990              :         }
     991            0 :         if (key.compare(PAR_FIXED_ACCELERATION) == 0) {
     992            0 :             buf >> vars->useFixedAcceleration >> vars->fixedAcceleration;
     993              :             return;
     994              :         }
     995            0 :         if (key.compare(PAR_CC_DESIRED_SPEED) == 0) {
     996            0 :             vars->ccDesiredSpeed = StringUtils::toDouble(value.c_str());
     997            0 :             return;
     998              :         }
     999            0 :         if (key.compare(PAR_ACTIVE_CONTROLLER) == 0) {
    1000            0 :             vars->activeController = (enum Plexe::ACTIVE_CONTROLLER) StringUtils::toInt(value.c_str());
    1001            0 :             return;
    1002              :         }
    1003            0 :         if (key.compare(PAR_ACC_HEADWAY_TIME) == 0) {
    1004            0 :             vars->accHeadwayTime = StringUtils::toDouble(value.c_str());
    1005            0 :             return;
    1006              :         }
    1007            0 :         if (key.compare(PAR_USE_CONTROLLER_ACCELERATION) == 0) {
    1008            0 :             vars->useControllerAcceleration = StringUtils::toInt(value.c_str()) != 0;
    1009            0 :             return;
    1010              :         }
    1011            0 :         if (key.compare(PAR_USE_AUTO_FEEDING) == 0) {
    1012              :             int af;
    1013              :             std::string leaderId, frontId;
    1014            0 :             buf >> af;
    1015            0 :             vars->autoFeed = af == 1;
    1016            0 :             if (vars->autoFeed) {
    1017            0 :                 vars->usePrediction = false;
    1018            0 :                 buf >> leaderId;
    1019            0 :                 if (buf.last_empty()) {
    1020            0 :                     throw InvalidArgument("Trying to enable auto feeding without providing leader vehicle id");
    1021              :                 }
    1022            0 :                 vars->leaderVehicleId = leaderId;
    1023            0 :                 vars->leaderVehicle = findVehicle(leaderId);
    1024            0 :                 if (!vars->leaderVehicle) {
    1025            0 :                     throw libsumo::TraCIException("Vehicle '" + leaderId + "' is not known");
    1026              :                 }
    1027            0 :                 buf >> frontId;
    1028            0 :                 if (buf.last_empty()) {
    1029            0 :                     throw InvalidArgument("Trying to enable auto feeding without providing front vehicle id");
    1030              :                 }
    1031            0 :                 vars->frontVehicleId = frontId;
    1032            0 :                 vars->frontVehicle = findVehicle(frontId);
    1033            0 :                 if (!vars->frontVehicle) {
    1034            0 :                     throw libsumo::TraCIException("Vehicle '" + frontId + "' is not known");
    1035              :                 }
    1036            0 :                 vars->leaderInitialized = true;
    1037            0 :                 vars->frontInitialized = true;
    1038            0 :                 vars->caccInitialized = true;
    1039              :             }
    1040              :             return;
    1041              :         }
    1042            0 :         if (key.compare(PAR_USE_PREDICTION) == 0) {
    1043            0 :             vars->usePrediction = StringUtils::toInt(value.c_str()) == 1;
    1044            0 :             return;
    1045              :         }
    1046            0 :     } catch (NumberFormatException&) {
    1047            0 :         throw InvalidArgument("Invalid value '" + value + "' for parameter '" + key + "' for vehicle '" + veh->getID() + "'");
    1048            0 :     }
    1049              : 
    1050              : }
    1051              : 
    1052            0 : std::string MSCFModel_CC::getParameter(const MSVehicle* veh, const std::string& key) const {
    1053              :     // vehicle variables used to set the parameter
    1054              :     CC_VehicleVariables* vars;
    1055              :     ParBuffer buf;
    1056              : 
    1057              :     vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1058            0 :     if (key.compare(PAR_SPEED_AND_ACCELERATION) == 0) {
    1059            0 :         Position velocity = veh->getVelocityVector();
    1060            0 :         buf << veh->getSpeed() << veh->getAcceleration() <<
    1061            0 :             vars->controllerAcceleration << veh->getPosition().x() <<
    1062            0 :             veh->getPosition().y() <<
    1063            0 :             STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) <<
    1064            0 :             velocity.x() << velocity.y() << veh->getAngle();
    1065              :         return buf.str();
    1066              :     }
    1067            0 :     if (key.compare(PAR_CRASHED) == 0) {
    1068            0 :         return vars->crashed ? "1" : "0";
    1069              :     }
    1070            0 :     if (key.compare(PAR_RADAR_DATA) == 0) {
    1071              :         double distance, relSpeed;
    1072            0 :         getRadarMeasurements(veh, distance, relSpeed);
    1073            0 :         buf << distance << relSpeed;
    1074              :         return buf.str();
    1075              :     }
    1076            0 :     if (key.compare(PAR_LANES_COUNT) == 0) {
    1077            0 :         buf << veh->getLane()->getEdge().getLanes().size();
    1078              :         return buf.str();
    1079              :     }
    1080            0 :     if (key.compare(PAR_DISTANCE_TO_END) == 0) {
    1081              :         //route of the vehicle
    1082            0 :         ConstMSRoutePtr route = veh->getRoutePtr();
    1083              :         //last lane of the route of this vehicle
    1084            0 :         const MSLane* lastLane = route->getEdges().back()->getLanes()[0];
    1085              :         //distance to trip end
    1086            0 :         buf << route->getDistanceBetween(veh->getPositionOnLane(), lastLane->getLength(), veh->getLane(), lastLane);
    1087              :         return buf.str();
    1088              :     }
    1089            0 :     if (key.compare(PAR_DISTANCE_FROM_BEGIN) == 0) {
    1090              :         //route of the vehicle
    1091            0 :         ConstMSRoutePtr route = veh->getRoutePtr();
    1092              :         //first lane of the route of this vehicle
    1093            0 :         const MSLane* firstLane = route->getEdges().front()->getLanes()[0];
    1094              :         //distance to trip start
    1095            0 :         buf << route->getDistanceBetween(0., veh->getPositionOnLane(), firstLane, veh->getLane());
    1096              :         return buf.str();
    1097              :     }
    1098            0 :     if (key.compare(PAR_CC_DESIRED_SPEED) == 0) {
    1099            0 :         buf << (double)vars->ccDesiredSpeed;
    1100              :         return buf.str();
    1101              :     }
    1102            0 :     if (key.compare(PAR_ACTIVE_CONTROLLER) == 0) {
    1103            0 :         buf << (int)vars->activeController;
    1104              :         return buf.str();
    1105              :     }
    1106            0 :     if (key.compare(PAR_ACC_HEADWAY_TIME) == 0) {
    1107            0 :         buf << (double)vars->accHeadwayTime;
    1108              :         return buf.str();
    1109              :     }
    1110            0 :     if (key.compare(PAR_ACC_ACCELERATION) == 0) {
    1111            0 :         buf << getACCAcceleration(veh);
    1112              :         return buf.str();
    1113              :     }
    1114            0 :     if (key.compare(PAR_CACC_SPACING) == 0) {
    1115            0 :         buf << vars->caccSpacing;
    1116              :         return buf.str();
    1117              :     }
    1118            0 :     if (key.find(CC_PAR_VEHICLE_DATA) == 0) {
    1119            0 :         ParBuffer inBuf(key);
    1120              :         int index;
    1121            0 :         inBuf >> index;
    1122              :         struct Plexe::VEHICLE_DATA vehicle;
    1123            0 :         if (index >= vars->nCars || index < 0) {
    1124            0 :             vehicle.index = -1;
    1125              :         } else {
    1126            0 :             vehicle = vars->vehicles[index];
    1127              :         }
    1128            0 :         buf << vehicle.index << vehicle.speed << vehicle.acceleration <<
    1129            0 :             vehicle.positionX << vehicle.positionY << vehicle.time <<
    1130            0 :             vehicle.length << vehicle.u << vehicle.speedX <<
    1131            0 :             vehicle.speedY << vehicle.angle;
    1132              :         return buf.str();
    1133              :     }
    1134            0 :     if (key.compare(PAR_ENGINE_DATA) == 0) {
    1135              :         int gear;
    1136              :         double rpm;
    1137            0 :         RealisticEngineModel* engine = dynamic_cast<RealisticEngineModel*>(vars->engine);
    1138            0 :         if (engine) {
    1139            0 :             engine->getEngineData(veh->getSpeed(), gear, rpm);
    1140              :         } else {
    1141            0 :             gear = -1;
    1142            0 :             rpm = 0;
    1143              :         }
    1144            0 :         buf << (gear + 1) << rpm;
    1145              :         return buf.str();
    1146              :     }
    1147            0 :     return "";
    1148              : }
    1149              : 
    1150            0 : void MSCFModel_CC::recomputeParameters(const MSVehicle* veh) const {
    1151              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1152            0 :     vars->caccAlpha1 = 1 - vars->caccC1;
    1153            0 :     vars->caccAlpha2 = vars->caccC1;
    1154            0 :     vars->caccAlpha3 = -(2 * vars->caccXi - vars->caccC1 * (vars->caccXi + sqrt(vars->caccXi * vars->caccXi - 1))) * vars->caccOmegaN;
    1155            0 :     vars->caccAlpha4 = -(vars->caccXi + sqrt(vars->caccXi * vars->caccXi - 1)) * vars->caccOmegaN * vars->caccC1;
    1156            0 :     vars->caccAlpha5 = -vars->caccOmegaN * vars->caccOmegaN;
    1157            0 : }
    1158              : 
    1159            0 : void MSCFModel_CC::resetConsensus(const MSVehicle* veh) const {
    1160              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1161            0 :     for (int i = 0; i < MAX_N_CARS; i++) {
    1162            0 :         vars->initialized[i] = false;
    1163            0 :         vars->nInitialized = 0;
    1164              :     }
    1165            0 : }
    1166              : 
    1167            0 : void MSCFModel_CC::switchOnACC(const MSVehicle* veh, double ccDesiredSpeed)  const {
    1168              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1169            0 :     vars->ccDesiredSpeed = ccDesiredSpeed;
    1170            0 :     vars->activeController = Plexe::ACC;
    1171            0 : }
    1172              : 
    1173            0 : enum Plexe::ACTIVE_CONTROLLER MSCFModel_CC::getActiveController(const MSVehicle* veh) const {
    1174              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1175            0 :     return vars->activeController;
    1176              : }
    1177              : 
    1178            0 : void MSCFModel_CC::getRadarMeasurements(const MSVehicle* veh, double& distance, double& relativeSpeed) const {
    1179            0 :     std::pair<std::string, double> l = libsumo::Vehicle::getLeader(veh->getID(), 250);
    1180            0 :     if (l.second < 0) {
    1181            0 :         distance = -1;
    1182            0 :         relativeSpeed = 0;
    1183              :     } else {
    1184            0 :         distance = l.second;
    1185            0 :         SUMOVehicle* leader = findVehicle(l.first);
    1186            0 :         relativeSpeed = leader->getSpeed() - veh->getSpeed();
    1187              :     }
    1188            0 : }
    1189              : 
    1190            0 : double MSCFModel_CC::getACCAcceleration(const MSVehicle* veh) const {
    1191              :     CC_VehicleVariables* vars = (CC_VehicleVariables*) veh->getCarFollowVariables();
    1192              :     double distance, relSpeed;
    1193            0 :     getRadarMeasurements(veh, distance, relSpeed);
    1194            0 :     if (distance < 0) {
    1195              :         return 0;
    1196              :     } else {
    1197            0 :         return _acc(veh, veh->getSpeed(), relSpeed + veh->getSpeed(), distance, vars->accHeadwayTime);
    1198              :     }
    1199              : }
    1200              : 
    1201            0 : int MSCFModel_CC::getMyLanesCount() const {
    1202            0 :     return myLanesCount;
    1203              : }
    1204              : 
    1205              : MSCFModel*
    1206            0 : MSCFModel_CC::duplicate(const MSVehicleType* vtype) const {
    1207            0 :     return new MSCFModel_CC(vtype);
    1208              : }
    1209              : 
    1210              : bool
    1211            0 : MSCFModel_CC::isLeader(const MSVehicle* veh) const {
    1212              :     auto vars = (CC_VehicleVariables*)veh->getCarFollowVariables();
    1213            0 :     return vars->isLeader;
    1214              : }
        

Generated by: LCOV version 2.0-1