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