1 package org.opentrafficsim.road.gtu.lane.tactical.util; 2 3 import org.djunits.unit.AccelerationUnit; 4 import org.djunits.unit.SpeedUnit; 5 import org.djunits.value.vdouble.scalar.Acceleration; 6 import org.djunits.value.vdouble.scalar.Length; 7 import org.djunits.value.vdouble.scalar.Speed; 8 import org.opentrafficsim.base.parameters.ParameterException; 9 import org.opentrafficsim.base.parameters.Parameters; 10 import org.opentrafficsim.core.gtu.GTUException; 11 import org.opentrafficsim.core.gtu.Try; 12 import org.opentrafficsim.road.gtu.lane.perception.PerceptionIterable; 13 import org.opentrafficsim.road.gtu.lane.perception.PerceptionIterableSet; 14 import org.opentrafficsim.road.gtu.lane.perception.headway.AbstractHeadway; 15 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway; 16 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU; 17 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel; 18 import org.opentrafficsim.road.network.speed.SpeedLimitInfo; 19 20 import nl.tudelft.simulation.language.Throw; 21 22 /** 23 * Static methods regarding car-following for composition in tactical planners. 24 * <p> 25 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 26 * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>. 27 * <p> 28 * @version $Revision$, $LastChangedDate$, by $Author$, initial version May 23, 2016 <br> 29 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 30 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a> 31 */ 32 public final class CarFollowingUtil 33 { 34 35 /** 36 * Do not instantiate. 37 */ 38 private CarFollowingUtil() 39 { 40 // 41 } 42 43 /** 44 * Follow a set of headway GTUs. 45 * @param carFollowingModel car-following model 46 * @param parameters parameters 47 * @param speed current speed 48 * @param speedLimitInfo speed limit info 49 * @param distance distance 50 * @param leaderSpeed speed of the leader 51 * @return acceleration for following the leader 52 * @throws ParameterException if a parameter is not given or out of bounds 53 */ 54 public static Acceleration followSingleLeader(final CarFollowingModel carFollowingModel, final Parameters parameters, 55 final Speed speed, final SpeedLimitInfo speedLimitInfo, final Length distance, final Speed leaderSpeed) 56 throws ParameterException 57 { 58 return carFollowingModel.followingAcceleration(parameters, speed, speedLimitInfo, createLeader(distance, leaderSpeed)); 59 } 60 61 /** 62 * Follow a set of headway GTUs. 63 * @param carFollowingModel car-following model 64 * @param parameters parameters 65 * @param speed current speed 66 * @param speedLimitInfo speed limit info 67 * @param leader leader 68 * @return acceleration for following the leader 69 * @throws ParameterException if a parameter is not given or out of bounds 70 */ 71 public static Acceleration followSingleLeader(final CarFollowingModel carFollowingModel, final Parameters parameters, 72 final Speed speed, final SpeedLimitInfo speedLimitInfo, final HeadwayGTU leader) throws ParameterException 73 { 74 return carFollowingModel.followingAcceleration(parameters, speed, speedLimitInfo, new PerceptionIterableSet<>(leader)); 75 } 76 77 /** 78 * Stop within given distance. 79 * @param carFollowingModel car-following model 80 * @param parameters parameters 81 * @param speed current speed 82 * @param speedLimitInfo speed limit info 83 * @param distance distance to stop over 84 * @return acceleration to stop over distance 85 * @throws ParameterException if a parameter is not given or out of bounds 86 */ 87 public static Acceleration stop(final CarFollowingModel carFollowingModel, final Parameters parameters, final Speed speed, 88 final SpeedLimitInfo speedLimitInfo, final Length distance) throws ParameterException 89 { 90 return carFollowingModel.followingAcceleration(parameters, speed, speedLimitInfo, createLeader(distance, Speed.ZERO)); 91 } 92 93 /** 94 * Return constant acceleration in order to stop in specified distance. The car-following model is used to determine the 95 * stopping distance (i.e. distance remaining at stand still, e.g. 1-3m). 96 * @param carFollowingModel car-following model 97 * @param parameters parameters 98 * @param speed current speed 99 * @param distance distance to stop over 100 * @return constant acceleration in order to stop in specified distance 101 * @throws ParameterException on missing parameter 102 */ 103 public static Acceleration constantAccelerationStop(final CarFollowingModel carFollowingModel, final Parameters parameters, 104 final Speed speed, final Length distance) throws ParameterException 105 { 106 Length s0 = carFollowingModel.desiredHeadway(parameters, Speed.ZERO); 107 return new Acceleration(-0.5 * speed.si * speed.si / (distance.si - s0.si), AccelerationUnit.SI); 108 } 109 110 /** 111 * Calculate free acceleration. 112 * @param carFollowingModel car-following model 113 * @param parameters parameters 114 * @param speed current speed 115 * @param speedLimitInfo speed limit info 116 * @return acceleration free acceleration 117 * @throws ParameterException if a parameter is not given or out of bounds 118 */ 119 public static Acceleration freeAcceleration(final CarFollowingModel carFollowingModel, final Parameters parameters, 120 final Speed speed, final SpeedLimitInfo speedLimitInfo) throws ParameterException 121 { 122 PerceptionIterableSet<Headway> leaders = new PerceptionIterableSet<>(); 123 return carFollowingModel.followingAcceleration(parameters, speed, speedLimitInfo, leaders); 124 } 125 126 /** 127 * Returns an acceleration based on the car-following model in order to adjust the speed to a given value at some location 128 * ahead. This is done by placing a virtual vehicle somewhere near the location. Both the location and speed of this virtual 129 * vehicle are dynamically adjusted to resemble a car-following situation. To explain, first consider the situation where a 130 * virtual vehicle is placed at the target speed and such that the equilibrium headway is in line with the location: 131 * 132 * <pre> 133 * 134 * ___ location of target speed --)| ___ 135 * |___|(--------------s--------------) (--h--)|___| ))) vTar 136 * </pre> 137 * 138 * Here, {@code s} is the distance to the target speed, and {@code h} is the desired headway if the vehicle would drive at 139 * the target speed {@code vTar}.<br> 140 * <br> 141 * In this way car-following models will first underestimate the required deceleration, as the virtual vehicle is actually 142 * stationary and does not move with {@code vTar} at all. Because of this underestimation, strong deceleration is required 143 * later. This behavior is not in line with the sensitivity parameters of the car-following model.<br> 144 * <br> 145 * To correct for the fact that the virtual vehicle is actually not moving, the speed difference should be larger, i.e. the 146 * speed of the virtual vehicle {@code vTar'} should be lower. We require: 147 * <ul> 148 * <li>if {@code v = vTar} then {@code vTar' = vTar}, otherwise there is an incentive to accelerate or decelerate for no 149 * good reason</li> 150 * <li>if {@code vTar ~ 0} then {@code vTar' ~ 0}, as car-following models are suitable for stopping and need no additional 151 * incentive to decelerate in such cases</li> 152 * <li>if {@code 0 < vTar < v} then {@code vTar' < vTar}, introducing additional deceleration to compensate for the fact 153 * that the virtual vehicle does not move 154 * </ul> 155 * These requirements are met by {@code vTar' = vTar * (vTar/v) = vTar^2/v}.<br> 156 * <br> 157 * Furthermore, if {@code v < vTar} we get {@code vTar' > vTar} leading to additional acceleration. Acceleration is then 158 * appropriate, and possibly limited by a free term in the car-following model.<br> 159 * <br> 160 * The virtual vehicle is thus placed with speed {@code vTar'} at a distance {@code s + h'} where {@code h'} is the desired 161 * headway if the vehicle would drive at speed {@code vTar'}. Both {@code vTar'} and {@code h'} depend on the current speed 162 * of the vehicle, so the virtual vehicle in this case actually moves, but not with {@code vTar}.<br> 163 * <br> 164 * This approach has been tested with the IDM+ to deliver decelerations in line with the parameters. On a plane with initial 165 * speed ranging from 0 to 33.33m/s and a target speed in 300m also ranging from 0 to 33.33m/s, strongest deceleration is 166 * equal to the car-following model stopping from 33.33m/s to a stand-still vehicle in 300m (+ stopping distance of 3m). 167 * Throughout the plane the maximum deceleration of each scenario is close to this value, unless the initial speed is so 168 * low, and the target speed is so high, that such levels of deceleration are never required.<br> 169 * <br> 170 * @param carFollowingModel car-following model to use 171 * @param parameters parameters 172 * @param speed current speed 173 * @param speedLimitInfo info regarding the desired speed for car-following 174 * @param distance distance to the location of the target speed 175 * @param targetSpeed target speed 176 * @return acceleration acceleration based on the car-following model in order to adjust the speed 177 * @throws ParameterException if parameter exception occurs 178 * @throws NullPointerException if any input is null 179 * @throws IllegalArgumentException if the distance or target speed is not at least 0 180 */ 181 public static Acceleration approachTargetSpeed(final CarFollowingModel carFollowingModel, final Parameters parameters, 182 final Speed speed, final SpeedLimitInfo speedLimitInfo, final Length distance, final Speed targetSpeed) 183 throws ParameterException 184 { 185 Throw.whenNull(parameters, "Parameters may not be null."); 186 Throw.whenNull(speed, "Speed may not be null."); 187 Throw.whenNull(speedLimitInfo, "Speed limit info may not be null."); 188 Throw.whenNull(distance, "Distance may not be null"); 189 Throw.whenNull(targetSpeed, "Target speed may not be null"); 190 Throw.when(distance.si < 0, IllegalArgumentException.class, "Distance must be at least 0."); 191 Throw.when(targetSpeed.si < 0, IllegalArgumentException.class, "Target speed must be at least 0."); 192 // adjust speed of virtual vehicle to add deceleration incentive as the virtual vehicle does not move 193 Speed virtualSpeed; 194 if (speed.si > 0) 195 { 196 virtualSpeed = new Speed(targetSpeed.si * targetSpeed.si / speed.si, SpeedUnit.SI); 197 } 198 else 199 { 200 virtualSpeed = new Speed(Double.MAX_VALUE, SpeedUnit.SI); 201 } 202 // set distance in line with equilibrium headway at virtual speed 203 Length virtualDistance = distance.plus(carFollowingModel.desiredHeadway(parameters, virtualSpeed)); 204 // calculate acceleration towards virtual vehicle with car-following model 205 return carFollowingModel.followingAcceleration(parameters, speed, speedLimitInfo, 206 createLeader(virtualDistance, virtualSpeed)); 207 } 208 209 /** 210 * Create a single leader set. 211 * @param headway Length; distance to the leader 212 * @param speed Speed; leader speed 213 * @return Set; set with a single leader 214 */ 215 private static PerceptionIterable<Headway> createLeader(final Length headway, final Speed speed) 216 { 217 PerceptionIterable<Headway> leaders = 218 Try.assign(() -> new PerceptionIterableSet<>(new CarFollowingHeadway(headway, speed)), 219 "Exception during headway creation."); 220 return leaders; 221 } 222 223 /** 224 * Simple headway implementation for minimum car-following information. 225 * <p> 226 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. 227 * <br> 228 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>. 229 * <p> 230 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 26 feb. 2018 <br> 231 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 232 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a> 233 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a> 234 */ 235 public static class CarFollowingHeadway extends AbstractHeadway 236 { 237 /** */ 238 private static final long serialVersionUID = 20180226L; 239 240 /** Speed of the leader. */ 241 private final Speed speed; 242 243 /** 244 * Constructor. 245 * @param headway Length; distance to the leader 246 * @param speed Speed; leader speed 247 * @throws GTUException on exception 248 */ 249 public CarFollowingHeadway(final Length headway, final Speed speed) throws GTUException 250 { 251 super(headway); 252 this.speed = speed; 253 } 254 255 /** {@inheritDoc} */ 256 @Override 257 public String getId() 258 { 259 return null; 260 } 261 262 /** {@inheritDoc} */ 263 @Override 264 public Length getLength() 265 { 266 return null; 267 } 268 269 /** {@inheritDoc} */ 270 @Override 271 public Speed getSpeed() 272 { 273 return this.speed; 274 } 275 276 /** {@inheritDoc} */ 277 @Override 278 public ObjectType getObjectType() 279 { 280 return null; 281 } 282 283 /** {@inheritDoc} */ 284 @Override 285 public Acceleration getAcceleration() 286 { 287 return null; 288 } 289 } 290 291 }