View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.util;
2   
3   import java.io.Serializable;
4   
5   import org.djunits.unit.DurationUnit;
6   import org.djunits.unit.LengthUnit;
7   import org.djunits.value.vdouble.scalar.Acceleration;
8   import org.djunits.value.vdouble.scalar.Duration;
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.djunits.value.vdouble.scalar.Speed;
11  import org.opentrafficsim.base.parameters.ParameterException;
12  import org.opentrafficsim.base.parameters.Parameters;
13  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
14  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
15  
16  /**
17   * Utility class that stores duration and end-speed for a given anticipated movement.
18   * <p>
19   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
21   * <p>
22   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 7, 2016 <br>
23   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
24   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
25   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
26   */
27  public final class AnticipationInfo implements Serializable
28  {
29  
30      /** */
31      private static final long serialVersionUID = 20160811L;
32  
33      /** Duration of movement. */
34      private final Duration duration;
35  
36      /** End speed of movement. */
37      private final Speed endSpeed;
38  
39      /**
40       * @param duration duration of movement
41       * @param endSpeed end speed of movement
42       */
43      public AnticipationInfo(final Duration duration, final Speed endSpeed)
44      {
45          this.duration = duration;
46          this.endSpeed = endSpeed;
47      }
48  
49      /**
50       * @return duration.
51       */
52      public Duration getDuration()
53      {
54          return this.duration;
55      }
56  
57      /**
58       * @return endSpeed.
59       */
60      public Speed getEndSpeed()
61      {
62          return this.endSpeed;
63      }
64  
65      /**
66       * Returns info of the anticipation assuming constant acceleration.
67       * @param distance distance to cover
68       * @param initialSpeed initial speed
69       * @param acceleration (assumed) acceleration
70       * @return duration to cover given distance with given initial speed and acceleration
71       */
72      public static AnticipationInfo anticipateMovement(final Length distance, final Speed initialSpeed,
73              final Acceleration acceleration)
74      {
75          return anticipateMovementSpeedLimited(distance, initialSpeed, acceleration, Speed.POSITIVE_INFINITY);
76      }
77  
78      /**
79       * Returns info of the anticipation assuming constant acceleration, without exceeding maximum speed.
80       * @param distance distance to cover
81       * @param initialSpeed initial speed
82       * @param acceleration (assumed) acceleration
83       * @param maxSpeed maximum speed
84       * @return duration to cover given distance with given initial speed and acceleration, without exceeding maximum speed
85       */
86      public static AnticipationInfo anticipateMovementSpeedLimited(final Length distance, final Speed initialSpeed,
87              final Acceleration acceleration, final Speed maxSpeed)
88      {
89          if (distance.lt0())
90          {
91              return new AnticipationInfo(Duration.ZERO, initialSpeed);
92          }
93          // solve constant speed movement
94          if (acceleration.eq(Acceleration.ZERO))
95          {
96              if (initialSpeed.gt0())
97              {
98                  return new AnticipationInfo(distance.divideBy(initialSpeed), initialSpeed);
99              }
100             // stand-still, so infinite
101             return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
102         }
103         // solve parabolic movement
104         double tmp = initialSpeed.si * initialSpeed.si + 2.0 * acceleration.si * distance.si;
105         if (tmp < 0)
106         {
107             // will never cover distance due to deceleration
108             return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
109         }
110         // parabolic solution
111         Duration d = new Duration((Math.sqrt(tmp) - initialSpeed.si) / acceleration.si, DurationUnit.SI);
112         // check max speed
113         Speed endSpeed = initialSpeed.plus(acceleration.multiplyBy(d));
114         if (endSpeed.le(maxSpeed))
115         {
116             return new AnticipationInfo(d, endSpeed);
117         }
118         // maximum speed exceeded, calculate in two steps
119         Duration d1 = maxSpeed.minus(initialSpeed).divideBy(acceleration);
120         Length x2 = new Length(distance.si - initialSpeed.si * d1.si - .5 * acceleration.si * d1.si * d1.si, LengthUnit.SI);
121         return new AnticipationInfo(d1.plus(x2.divideBy(maxSpeed)), maxSpeed);
122     }
123 
124     /**
125      * Returns info of the anticipation using free acceleration from car-following model.
126      * @param distance distance to cover
127      * @param initialSpeed initial speed
128      * @param parameters parameters of the anticipated GTU
129      * @param carFollowingModel car-following model of the anticipated GTU
130      * @param speedLimitInfo speed limit info of the anticipated GTU
131      * @param timeStep time step to use
132      * @return info regarding anticipation of movement
133      * @throws ParameterException if parameter is not defined
134      */
135     public static AnticipationInfo anticipateMovementFreeAcceleration(final Length distance, final Speed initialSpeed,
136             final Parameters parameters, final CarFollowingModel carFollowingModel,
137             final SpeedLimitInfo speedLimitInfo, final Duration timeStep) throws ParameterException
138     {
139         if (distance.lt0())
140         {
141             return new AnticipationInfo(Duration.ZERO, initialSpeed);
142         }
143         Duration out = Duration.ZERO;
144         if (distance.lt0())
145         {
146             return new AnticipationInfo(out, initialSpeed);
147         }
148         Length xCumul = Length.ZERO;
149         Speed speed = initialSpeed;
150         while (xCumul.lt(distance))
151         {
152             Acceleration a =
153                     CarFollowingUtil.freeAcceleration(carFollowingModel, parameters, speed, speedLimitInfo);
154             Length add = new Length(speed.si * timeStep.si + .5 * a.si * timeStep.si * timeStep.si, LengthUnit.SI);
155             Length remain = distance.minus(xCumul);
156             if (add.lt(remain))
157             {
158                 xCumul = xCumul.plus(add);
159                 speed = speed.plus(a.multiplyBy(timeStep));
160                 out = out.plus(timeStep);
161             }
162             else
163             {
164                 Duration timeInStep;
165                 double tmp = Math.sqrt(2 * a.si * remain.si + speed.si * speed.si) - speed.si;
166                 if (tmp < 0.000001)
167                 {
168                     // (near) constant speed
169                     timeInStep = remain.divideBy(speed);
170                 }
171                 else
172                 {
173                     timeInStep = new Duration(tmp / a.si, DurationUnit.SI);
174                     speed = speed.plus(a.multiplyBy(timeInStep));
175                 }
176                 out = out.plus(timeInStep);
177                 return new AnticipationInfo(out, speed);
178             }
179         }
180         // should not happen
181         throw new RuntimeException("Distance for anticipation of conflict movement is surpassed.");
182     }
183 
184     /** {@inheritDoc} */
185     @Override
186     public String toString()
187     {
188         return "AnticipationInfo [duration = " + this.duration + ", endSpeed = " + this.endSpeed + "]";
189     }
190 
191 }