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