double MSCFModel_ACC::stopSpeed(const MSVehicle* const veh, const double speed, double gap) const { // NOTE: This allows return of smaller values than minNextSpeed(). // Only relevant for the ballistic update: We give the argument headway=TS, to assure that // the stopping position is approached with a uniform deceleration also for tau!=TS. return MIN2(maximumSafeStopSpeed(gap, speed, false, veh->getActionStepLengthSecs()), maxNextSpeed(speed, veh)); }
double MSCFModel::insertionStopSpeed(const MSVehicle* const veh, double speed, double gap) const { if (MSGlobals::gSemiImplicitEulerUpdate) { return stopSpeed(veh, speed, gap); } else { return MIN2(maximumSafeStopSpeed(gap, 0., true, 0.), myType->getMaxSpeed()); } }
/** Returns the SK-vsafe. */ double MSCFModel::maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion) const { // the speed is safe if allows the ego vehicle to come to a stop behind the leader even if // the leaders starts braking hard until stopped // unfortunately it is not sufficient to compare stopping distances if the follower can brake harder than the leader // (the trajectories might intersect before both vehicles are stopped even if the follower has a shorter stopping distance than the leader) // To make things safe, we ensure that the leaders brake distance is computed with an deceleration that is at least as high as the follower's. // @todo: this is a conservative estimate for safe speed which could be increased // // For negative gaps, we return the lowest meaningful value by convention // // XXX: check whether this is desireable (changes test results, therefore I exclude it for now (Leo), refs. #2575) // // It must be done. Otherwise, negative gaps at high speeds can create nonsense results from the call to maximumSafeStopSpeed() below // if(gap<0){ // if(MSGlobals::gSemiImplicitEulerUpdate){ // return 0.; // } else { // return -INVALID_SPEED; // } // } // The following commented code is a variant to assure brief stopping behind a stopped leading vehicle: // if leader is stopped, calculate stopSpeed without time-headway to prevent creeping stop // NOTE: this can lead to the strange phenomenon (for the Krauss-model at least) that if the leader comes to a stop, // the follower accelerates for a short period of time. Refs #2310 (Leo) // const double headway = predSpeed > 0. ? myHeadwayTime : 0.; const double headway = myHeadwayTime; double x = maximumSafeStopSpeed(gap + brakeGap(predSpeed, MAX2(myDecel, predMaxDecel), 0), egoSpeed, onInsertion, headway); if (myDecel != myEmergencyDecel && !onInsertion && !MSGlobals::gComputeLC) { double origSafeDecel = SPEED2ACCEL(egoSpeed - x); if (origSafeDecel > myDecel + NUMERICAL_EPS) { // Braking harder than myDecel was requested -> calculate required emergency deceleration. // Note that the resulting safeDecel can be smaller than the origSafeDecel, since the call to maximumSafeStopSpeed() above // can result in corrupted values (leading to intersecting trajectories) if, e.g. leader and follower are fast (leader still faster) and the gap is very small, // such that braking harder than myDecel is required. #ifdef DEBUG_EMERGENCYDECEL if (DEBUG_COND2) { std::cout << SIMTIME << " initial vsafe=" << x << " egoSpeed=" << egoSpeed << " (origSafeDecel=" << origSafeDecel << ")" << " predSpeed=" << predSpeed << " (predDecel=" << predMaxDecel << ")" << std::endl; } #endif double safeDecel = EMERGENCY_DECEL_AMPLIFIER * calculateEmergencyDeceleration(gap, egoSpeed, predSpeed, predMaxDecel); // Don't be riskier than the usual method (myDecel <= safeDecel may occur, because a headway>0 is used above) safeDecel = MAX2(safeDecel, myDecel); // don't brake harder than originally planned (possible due to euler/ballistic mismatch) safeDecel = MIN2(safeDecel, origSafeDecel); x = egoSpeed - ACCEL2SPEED(safeDecel); if (MSGlobals::gSemiImplicitEulerUpdate) { x = MAX2(x, 0.); } #ifdef DEBUG_EMERGENCYDECEL if (DEBUG_COND2) { std::cout << " -> corrected emergency deceleration: " << safeDecel << " newVSafe=" << x << std::endl; } #endif } } assert(x >= 0 || !MSGlobals::gSemiImplicitEulerUpdate); assert(!ISNAN(x)); return x; }