View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.following;
2   
3   import java.io.Serializable;
4   
5   import org.djunits.unit.AccelerationUnit;
6   import org.djunits.unit.DurationUnit;
7   import org.djunits.unit.LengthUnit;
8   import org.djunits.unit.SpeedUnit;
9   import org.djunits.value.vdouble.scalar.Acceleration;
10  import org.djunits.value.vdouble.scalar.Duration;
11  import org.djunits.value.vdouble.scalar.Length;
12  import org.djunits.value.vdouble.scalar.Speed;
13  import org.opentrafficsim.base.parameters.ParameterException;
14  import org.opentrafficsim.base.parameters.Parameters;
15  import org.opentrafficsim.road.gtu.lane.perception.PerceptionIterable;
16  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
17  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
18  import org.opentrafficsim.road.network.speed.SpeedLimitTypes;
19  
20  /**
21   * IDMPlus implements the <i>Integrated Lane Change Model with Relaxation and Synchronization</i> as published by Wouter J.
22   * Schakel, Bart van Arem, Member, IEEE, and Bart D. Netten. 2012. <br>
23   * There are two nasty type setting errors in equation 7 in this published version of the paper. Both times an equals sign
24   * (<cite>=</cite>) after <cite>a<sub>gain</sub></cite> should <b>not</b> be there.
25   * <p>
26   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * <p>
29   * @version $Revision: 1408 $, $LastChangedDate: 2015-09-24 15:17:25 +0200 (Thu, 24 Sep 2015) $, by $Author: pknoppers $,
30   *          initial version Jul 4, 2014 <br>
31   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
32   */
33  public class IDMPlusOld extends AbstractGTUFollowingModelMobil implements Serializable
34  {
35      /** */
36      private static final long serialVersionUID = 20140704L;
37  
38      /** Preferred net longitudinal distance when stopped [m]. */
39      private final Length s0;
40  
41      /** Longitudinal acceleration [m/s^2]. */
42      private Acceleration a;
43  
44      /** Longitudinal deceleration [m/s^2]. (Should be a positive value even though it is a <b>de</b>celeration.) */
45      private final Acceleration b;
46  
47      /** Safe time headway. */
48      private Duration tSafe;
49  
50      /**
51       * Mean speed limit adherence (1.0: mean free speed equals the speed limit; 1.1: mean free speed equals 110% of the speed
52       * limit, etc.).
53       */
54      private double delta;
55  
56      /**
57       * Default step size used by IDMPlus (not defined in the paper, but 0.5s is a reasonable trade-off between computational
58       * speed and accuracy).
59       */
60      private static final Duration DEFAULT_STEP_SIZE = new Duration(0.5, DurationUnit.SECOND);
61  
62      /**
63       * Construct a new IDM+ car following model with reasonable values (reasonable for passenger cars). <br>
64       * These values are from <b>Integrated Lane Change Model with Relaxation and Synchronization</b> by Wouter J. Schakel,
65       * Victor L. Knoop, and Bart van Arem, published in Transportation Research Record: Journal of the Transportation Research
66       * Board, No. 2316, Transportation Research Board of the National Academies, Washington, D.C., 2012, pp. 47–57.
67       */
68      public IDMPlusOld()
69      {
70          this.a = new Acceleration(1.56, AccelerationUnit.METER_PER_SECOND_2);
71          this.b = new Acceleration(2.09, AccelerationUnit.METER_PER_SECOND_2);
72          this.s0 = new Length(3, LengthUnit.METER);
73          this.tSafe = new Duration(1.2, DurationUnit.SECOND);
74          this.delta = 1d;
75      }
76  
77      /**
78       * Construct a new IDMPlus car following model.
79       * @param a Acceleration; the maximum acceleration of a stationary vehicle (normal value is 1 m/s/s)
80       * @param b Acceleration; the maximum deemed-safe deceleration (this is a positive value)
81       * @param s0 Length; the minimum stationary headway
82       * @param tSafe Duration; the minimum time-headway
83       * @param delta double; the speed limit adherence (1.0; mean free speed equals the speed limit; 1.1: mean free speed equals
84       *            110% of the speed limit; etc.)
85       */
86      public IDMPlusOld(final Acceleration a, final Acceleration b, final Length s0, final Duration tSafe, final double delta)
87      {
88          this.a = a;
89          this.b = b;
90          this.s0 = s0;
91          this.tSafe = tSafe;
92          this.delta = delta;
93      }
94  
95      /**
96       * Desired speed (taking into account the urge to drive a little faster or slower than the posted speed limit).
97       * @param speedLimit Speed; the speed limit
98       * @param followerMaximumSpeed Speed; the maximum speed that the follower can drive
99       * @return DoubleScalarRel&lt;SpeedUnit&gt;; the desired speed
100      */
101     private Speed vDes(final Speed speedLimit, final Speed followerMaximumSpeed)
102     {
103         return new Speed(Math.min(this.delta * speedLimit.getSI(), followerMaximumSpeed.getSI()), SpeedUnit.SI);
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public final Acceleration computeAcceleration(final Speed followerSpeed, final Speed followerMaximumSpeed,
109             final Speed leaderSpeed, final Length headway, final Speed speedLimit)
110     {
111         return computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, headway, speedLimit, DEFAULT_STEP_SIZE);
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public final Acceleration computeAcceleration(final Speed followerSpeed, final Speed followerMaximumSpeed,
117             final Speed leaderSpeed, final Length headway, final Speed speedLimit, final Duration stepSize)
118     {
119         // TODO maxDistance
120         double leftComponent = 1 - Math.pow(followerSpeed.getSI() / vDes(speedLimit, followerMaximumSpeed).getSI(), 4);
121         if (Double.isNaN(leftComponent))
122         {
123             leftComponent = 0;
124         }
125         // limit deceleration for free term (= leftComponent)
126         if (leftComponent * this.a.si < -0.5)
127         {
128             leftComponent = -0.5 / this.a.si;
129         }
130         Acceleration logWeightedAccelerationTimes2 =
131                 new Acceleration(Math.sqrt(this.a.getSI() * this.b.getSI()), AccelerationUnit.SI).multiplyBy(2);
132         // don't forget the times 2
133 
134         Speed dV = followerSpeed.minus(leaderSpeed);
135         Length sStar = this.s0.plus(followerSpeed.multiplyBy(this.tSafe))
136                 .plus(dV.multiplyBy(followerSpeed.divideBy(logWeightedAccelerationTimes2)));
137 
138         /*-
139         this.s0.plus(Calc.speedTimesTime(followerSpeed, this.tSafe)).plus(
140         Calc.speedTimesTime(dV, Calc.speedDividedByAcceleration(followerSpeed, logWeightedAccelerationTimes2)));
141          */
142         if (sStar.getSI() < 0)
143         {
144             // Negative value should be treated as 0? This is NOT in the LMRS paper
145             // Without this "fix" a higher speed of the leader may cause a lower acceleration (which is crazy)
146             sStar = new Length(0, LengthUnit.SI);
147         }
148 
149         double rightComponent = 1 - Math.pow(sStar.getSI() / headway.getSI(), 2);
150         Acceleration newAcceleration = new Acceleration(this.a).multiplyBy(Math.min(leftComponent, rightComponent));
151         if (newAcceleration.getSI() * stepSize.getSI() + followerSpeed.getSI() < 0)
152         {
153             newAcceleration = new Acceleration(-followerSpeed.getSI() / stepSize.getSI(), AccelerationUnit.SI);
154         }
155         return newAcceleration;
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public final Duration getStepSize()
161     {
162         return DEFAULT_STEP_SIZE;
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public final Acceleration getMaximumSafeDeceleration()
168     {
169         return this.b;
170     }
171 
172     /** {@inheritDoc} */
173     @Override
174     public final String getName()
175     {
176         return "IDM+";
177     }
178 
179     /** {@inheritDoc} */
180     @Override
181     public final String getLongName()
182     {
183         return String.format("%s (a=%.1fm/s\u00b2, b=%.1fm/s\u00b2, s0=%.1fm, tSafe=%.1fs, delta=%.2f)", getName(),
184                 this.a.getSI(), this.b.getSI(), this.s0.getSI(), this.tSafe.getSI(), this.delta);
185     }
186 
187     /** {@inheritDoc} */
188     @Override
189     public final void setA(final Acceleration a)
190     {
191         this.a = a;
192     }
193 
194     /** {@inheritDoc} */
195     @Override
196     public final void setT(final Duration t)
197     {
198         this.tSafe = t;
199     }
200 
201     /** {@inheritDoc} */
202     @Override
203     public final void setFspeed(final double fSpeed)
204     {
205         this.delta = fSpeed;
206     }
207 
208     // The following is inherited from CarFollowingModel
209 
210     /** {@inheritDoc} */
211     @Override
212     public final Speed desiredSpeed(final Parameters parameters, final SpeedLimitInfo speedInfo) throws ParameterException
213     {
214         throw new UnsupportedOperationException("Old car-following model does not support desired speed.");
215     }
216 
217     /** {@inheritDoc} */
218     @Override
219     public final Length desiredHeadway(final Parameters parameters, final Speed speed) throws ParameterException
220     {
221         throw new UnsupportedOperationException("Old car-following model does not support desired headway.");
222     }
223 
224     /** {@inheritDoc} */
225     @Override
226     public final Acceleration followingAcceleration(final Parameters parameters, final Speed speed,
227             final SpeedLimitInfo speedInfo, final PerceptionIterable<? extends Headway> leaders) throws ParameterException
228     {
229         Length headway;
230         Speed leaderSpeed;
231         if (leaders.isEmpty())
232         {
233             headway = new Length(Double.MAX_VALUE, LengthUnit.SI);
234             leaderSpeed = speed;
235         }
236         else
237         {
238             Headway leader = leaders.first();
239             headway = leader.getDistance();
240             leaderSpeed = leader.getSpeed();
241         }
242         return this.computeAcceleration(speed, speedInfo.getSpeedInfo(SpeedLimitTypes.MAX_VEHICLE_SPEED), leaderSpeed, headway,
243                 speedInfo.getSpeedInfo(SpeedLimitTypes.FIXED_SIGN));
244     }
245 
246     /** {@inheritDoc} */
247     @Override
248     public final String toString()
249     {
250         return "IDMPlusOld [s0=" + this.s0 + ", a=" + this.a + ", b=" + this.b + ", tSafe=" + this.tSafe + ", delta="
251                 + this.delta + ", stepSize=" + DEFAULT_STEP_SIZE + "]";
252     }
253 
254 }