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://github.com/peter-knoppers">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 the maximum acceleration of a stationary vehicle (normal value is 1.56 m/s/s)
72       * @param b the maximum deemed-safe deceleration (this is a positive value). Normal value is 2.09 m/s/s.
73       * @param s0 the minimum stationary headway (normal value is 3 m)
74       * @param tSafe the minimum time-headway (normal value is 1.2 s)
75       * @param delta the speed limit adherence (1.0; mean free speed equals the speed limit; 1.1: mean free speed equals 110% of
76       *            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 the speed limit
90       * @param followerMaximumSpeed the maximum speed that the follower can drive
91       * @return 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      @Override
99      public final Acceleration computeAcceleration(final Speed followerSpeed, final Speed followerMaximumSpeed,
100             final Speed leaderSpeed, final Length headway, final Speed speedLimit)
101     {
102         return computeAcceleration(followerSpeed, followerMaximumSpeed, leaderSpeed, headway, speedLimit, DEFAULT_STEP_SIZE);
103     }
104 
105     @Override
106     public final Acceleration computeAcceleration(final Speed followerSpeed, final Speed followerMaximumSpeed,
107             final Speed leaderSpeed, final Length headway, final Speed speedLimit, final Duration stepSize)
108     {
109         // TODO maxDistance
110         // dV is the approach speed
111         Speed dV = followerSpeed.minus(leaderSpeed);
112         double sStar = this.s0.si + followerSpeed.si * this.tSafe.si
113                 + dV.si * followerSpeed.si / (2.0 * Math.sqrt(this.a.si * this.b.si));
114         if (sStar < 0.0 && headway.si < 0.0)
115         {
116             return new Acceleration(Double.NEGATIVE_INFINITY, AccelerationUnit.SI);
117         }
118         sStar = sStar >= 0.0 ? sStar : 0.0;
119         double s = headway.si > 0.0 ? headway.si : 1E-99;
120         Acceleration aInteraction = new Acceleration(this.a.si * (sStar / s) * (sStar / s), AccelerationUnit.SI);
121         Acceleration aFree =
122                 new Acceleration(this.a.si * (1.0 - Math.pow(followerSpeed.si / vDes(speedLimit, followerMaximumSpeed).si, 4)),
123                         AccelerationUnit.SI);
124         // limit deceleration for free term (= aFree)
125         if (aFree.si < -0.5)
126         {
127             aFree = new Acceleration(-0.5, AccelerationUnit.SI);
128         }
129         Acceleration newAcceleration = aFree.minus(aInteraction);
130         if (newAcceleration.si * stepSize.si + followerSpeed.si < 0)
131         {
132             newAcceleration = new Acceleration(-followerSpeed.si / stepSize.si, AccelerationUnit.SI);
133         }
134         return newAcceleration;
135     }
136 
137     @Override
138     public final Duration getStepSize()
139     {
140         return DEFAULT_STEP_SIZE;
141     }
142 
143     @Override
144     public final Acceleration getMaximumSafeDeceleration()
145     {
146         return this.b;
147     }
148 
149     @Override
150     public final String getName()
151     {
152         return "IDM";
153     }
154 
155     @Override
156     public final String getLongName()
157     {
158         return String.format("%s (a=%.1fm/s\u00b2, b=%.1fm/s\u00b2, s0=%.1fm, tSafe=%.1fs, delta=%.2f)", getName(),
159                 this.a.getSI(), this.b.getSI(), this.s0.getSI(), this.tSafe.getSI(), this.delta);
160     }
161 
162     @Override
163     public final void setA(final Acceleration a)
164     {
165         this.a = a;
166     }
167 
168     @Override
169     public final void setT(final Duration t)
170     {
171         this.tSafe = t;
172     }
173 
174     @Override
175     public final void setFspeed(final double fSpeed)
176     {
177         this.delta = fSpeed;
178     }
179 
180     // The following is inherited from CarFollowingModel
181 
182     @Override
183     public final Speed desiredSpeed(final Parameters parameters, final SpeedLimitInfo speedInfo) throws ParameterException
184     {
185         throw new UnsupportedOperationException("Old car-following model does not support desired speed.");
186     }
187 
188     @Override
189     public final Length desiredHeadway(final Parameters parameters, final Speed speed) throws ParameterException
190     {
191         throw new UnsupportedOperationException("Old car-following model does not support desired headway.");
192     }
193 
194     @Override
195     public final Acceleration followingAcceleration(final Parameters parameters, final Speed speed,
196             final SpeedLimitInfo speedInfo, final PerceptionIterable<? extends Headway> leaders) throws ParameterException
197     {
198         Length headway;
199         Speed leaderSpeed;
200         if (leaders.isEmpty())
201         {
202             headway = new Length(Double.MAX_VALUE, LengthUnit.SI);
203             leaderSpeed = speed;
204         }
205         else
206         {
207             Headway leader = leaders.first();
208             headway = leader.getDistance();
209             leaderSpeed = leader.getSpeed();
210         }
211         return this.computeAcceleration(speed, speedInfo.getSpeedInfo(SpeedLimitTypes.MAX_VEHICLE_SPEED), leaderSpeed, headway,
212                 speedInfo.getSpeedInfo(SpeedLimitTypes.FIXED_SIGN));
213     }
214 
215     @Override
216     public final String toString()
217     {
218         return "IDMOld [s0=" + this.s0 + ", a=" + this.a + ", b=" + this.b + ", tSafe=" + this.tSafe + ", stepSize="
219                 + DEFAULT_STEP_SIZE + ", delta=" + this.delta + "]";
220     }
221 
222 }