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.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 }