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   * The Intelligent Driver Model by Treiber, Hennecke and Helbing.
22   * <p>
23   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
25   * </p>
26   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
27   */
28  public class IdmOld extends AbstractGtuFollowingModelMobil implements Serializable
29  {
30      /** */
31      private static final long serialVersionUID = 20141119L;
32  
33      /** Preferred net longitudinal distance when stopped [m]. */
34      private final Length s0;
35  
36      /** Maximum longitudinal acceleration [m/s^2]. */
37      private Acceleration a;
38  
39      /** Longitudinal deceleration [m/s^2]. (Should be a positive value even though it is a <b>de</b>celeration.) */
40      private final Acceleration b;
41  
42      /** Safe time headway. */
43      private Duration tSafe;
44  
45      /**
46       * Default step size used by IDM (not defined in the paper, but 0.5s is a reasonable trade-off between computational speed
47       * and accuracy).
48       */
49      private static final Duration DEFAULT_STEP_SIZE = new Duration(0.5, DurationUnit.SECOND);
50  
51      /**
52       * Mean speed limit adherence (1.0: mean free speed equals the speed limit; 1.1: mean speed limit equals 110% of the speed
53       * limit, etc.).
54       */
55      private double delta;
56  
57      /**
58       * Construct a new IDM car following model with reasonable values (reasonable for passenger cars).
59       */
60      public IdmOld()
61      {
62          this.a = new Acceleration(1.56, AccelerationUnit.METER_PER_SECOND_2);
63          this.b = new Acceleration(2.09, AccelerationUnit.METER_PER_SECOND_2);
64          this.s0 = new Length(3, LengthUnit.METER);
65          this.tSafe = new Duration(1.2, DurationUnit.SECOND);
66          this.delta = 1.0;
67      }
68  
69      /**
70       * Construct a new IDM car following model.
71       * @param a Acceleration; the maximum acceleration of a stationary vehicle (normal value is 1.56 m/s/s)
72       * @param b Acceleration; the maximum deemed-safe deceleration (this is a positive value). Normal value is 2.09 m/s/s.
73       * @param s0 Length; the minimum stationary headway (normal value is 3 m)
74       * @param tSafe Duration; the minimum time-headway (normal value is 1.2 s)
75       * @param delta double; the speed limit adherence (1.0; mean free speed equals the speed limit; 1.1: mean free speed equals
76       *            110% of the speed limit; etc.)
77       */
78      public IdmOld(final Acceleration a, final Acceleration b, final Length s0, final Duration tSafe, final double delta)
79      {
80          this.a = a;
81          this.b = b;
82          this.s0 = s0;
83          this.tSafe = tSafe;
84          this.delta = delta;
85      }
86  
87      /**
88       * Desired speed (taking into account the urge to drive a little faster or slower than the posted speed limit).
89       * @param speedLimit Speed; the speed limit
90       * @param followerMaximumSpeed Speed; the maximum speed that the follower can drive
91       * @return DoubleScalarRel&lt;SpeedUnit&gt;; the desired speed
92       */
93      private Speed vDes(final Speed speedLimit, final Speed followerMaximumSpeed)
94      {
95          return new Speed(Math.min(this.delta * speedLimit.getSI(), followerMaximumSpeed.getSI()), SpeedUnit.SI);
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     public final Acceleration computeAcceleration(final Speed followerSpeed, final Speed followerMaximumSpeed,
101             final Speed leaderSpeed, final Length headway, final Speed speedLimit)
102     {
103         return computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, headway, speedLimit, DEFAULT_STEP_SIZE);
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, final Duration stepSize)
110     {
111         // TODO maxDistance
112         // dV is the approach speed
113         Speed dV = followerSpeed.minus(leaderSpeed);
114         double sStar = this.s0.si + followerSpeed.si * this.tSafe.si
115                 + dV.si * followerSpeed.si / (2.0 * Math.sqrt(this.a.si * this.b.si));
116         if (sStar < 0.0 && headway.si < 0.0)
117         {
118             return new Acceleration(Double.NEGATIVE_INFINITY, AccelerationUnit.SI);
119         }
120         sStar = sStar >= 0.0 ? sStar : 0.0;
121         double s = headway.si > 0.0 ? headway.si : 1E-99;
122         Acceleration aInteraction = new Acceleration(this.a.si * (sStar / s) * (sStar / s), AccelerationUnit.SI);
123         Acceleration aFree =
124                 new Acceleration(this.a.si * (1.0 - Math.pow(followerSpeed.si / vDes(speedLimit, followerMaximumSpeed).si, 4)),
125                         AccelerationUnit.SI);
126         // limit deceleration for free term (= aFree)
127         if (aFree.si < -0.5)
128         {
129             aFree = new Acceleration(-0.5, AccelerationUnit.SI);
130         }
131         Acceleration newAcceleration = aFree.minus(aInteraction);
132         if (newAcceleration.si * stepSize.si + followerSpeed.si < 0)
133         {
134             newAcceleration = new Acceleration(-followerSpeed.si / stepSize.si, AccelerationUnit.SI);
135         }
136         return newAcceleration;
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public final Duration getStepSize()
142     {
143         return DEFAULT_STEP_SIZE;
144     }
145 
146     /** {@inheritDoc} */
147     @Override
148     public final Acceleration getMaximumSafeDeceleration()
149     {
150         return this.b;
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public final String getName()
156     {
157         return "IDM";
158     }
159 
160     /** {@inheritDoc} */
161     @Override
162     public final String getLongName()
163     {
164         return String.format("%s (a=%.1fm/s\u00b2, b=%.1fm/s\u00b2, s0=%.1fm, tSafe=%.1fs, delta=%.2f)", getName(),
165                 this.a.getSI(), this.b.getSI(), this.s0.getSI(), this.tSafe.getSI(), this.delta);
166     }
167 
168     /** {@inheritDoc} */
169     @Override
170     public final void setA(final Acceleration a)
171     {
172         this.a = a;
173     }
174 
175     /** {@inheritDoc} */
176     @Override
177     public final void setT(final Duration t)
178     {
179         this.tSafe = t;
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     public final void setFspeed(final double fSpeed)
185     {
186         this.delta = fSpeed;
187     }
188 
189     // The following is inherited from CarFollowingModel
190 
191     /** {@inheritDoc} */
192     @Override
193     public final Speed desiredSpeed(final Parameters parameters, final SpeedLimitInfo speedInfo) throws ParameterException
194     {
195         throw new UnsupportedOperationException("Old car-following model does not support desired speed.");
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public final Length desiredHeadway(final Parameters parameters, final Speed speed) throws ParameterException
201     {
202         throw new UnsupportedOperationException("Old car-following model does not support desired headway.");
203     }
204 
205     /** {@inheritDoc} */
206     @Override
207     public final Acceleration followingAcceleration(final Parameters parameters, final Speed speed,
208             final SpeedLimitInfo speedInfo, final PerceptionIterable<? extends Headway> leaders) throws ParameterException
209     {
210         Length headway;
211         Speed leaderSpeed;
212         if (leaders.isEmpty())
213         {
214             headway = new Length(Double.MAX_VALUE, LengthUnit.SI);
215             leaderSpeed = speed;
216         }
217         else
218         {
219             Headway leader = leaders.first();
220             headway = leader.getDistance();
221             leaderSpeed = leader.getSpeed();
222         }
223         return this.computeAcceleration(speed, speedInfo.getSpeedInfo(SpeedLimitTypes.MAX_VEHICLE_SPEED), leaderSpeed, headway,
224                 speedInfo.getSpeedInfo(SpeedLimitTypes.FIXED_SIGN));
225     }
226 
227     /** {@inheritDoc} */
228     @Override
229     public final String toString()
230     {
231         return "IDMOld [s0=" + this.s0 + ", a=" + this.a + ", b=" + this.b + ", tSafe=" + this.tSafe + ", stepSize="
232                 + DEFAULT_STEP_SIZE + ", delta=" + this.delta + "]";
233     }
234 
235 }