View Javadoc
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-2019 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-2019 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 }