View Javadoc
1   package org.opentrafficsim.road.gtu.tactical.following;
2   
3   import org.djunits.unit.SpeedUnit;
4   import org.djunits.value.vdouble.scalar.Acceleration;
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.djunits.value.vdouble.scalar.Speed;
7   import org.opentrafficsim.base.parameters.ParameterException;
8   import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
9   import org.opentrafficsim.base.parameters.ParameterTypeDouble;
10  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
11  import org.opentrafficsim.base.parameters.ParameterTypeLength;
12  import org.opentrafficsim.base.parameters.ParameterTypes;
13  import org.opentrafficsim.base.parameters.Parameters;
14  import org.opentrafficsim.base.parameters.constraint.ConstraintInterface;
15  import org.opentrafficsim.core.gtu.Stateless;
16  import org.opentrafficsim.road.gtu.perception.PerceptionIterable;
17  import org.opentrafficsim.road.gtu.perception.object.PerceivedObject;
18  import org.opentrafficsim.road.network.speed.SpeedLimits;
19  
20  /**
21   * Implementation of the IDM. See <a
22   * href=https://en.wikipedia.org/wiki/Intelligent_driver_model>https://en.wikipedia.org/wiki/Intelligent_driver_model</a>
23   * <p>
24   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
25   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
26   * </p>
27   * @author Alexander Verbraeck
28   * @author Peter Knoppers
29   * @author Wouter Schakel
30   */
31  // @docs/06-behavior/parameters.md
32  public abstract class AbstractIdm extends AbstractCarFollowingModel
33  {
34  
35      /** Acceleration parameter type. */
36      // @docs/06-behavior/parameters.md
37      protected static final ParameterTypeAcceleration A = ParameterTypes.A;
38  
39      /** Comfortable deceleration parameter type. */
40      protected static final ParameterTypeAcceleration B = ParameterTypes.B;
41  
42      /** Desired headway parameter type. */
43      protected static final ParameterTypeDuration T = ParameterTypes.T;
44  
45      /** Stopping distance parameter type. */
46      protected static final ParameterTypeLength S0 = ParameterTypes.S0;
47  
48      /** Adjustment deceleration parameter type. */
49      protected static final ParameterTypeAcceleration B0 = ParameterTypes.B0;
50  
51      /** Lane speed limit adherence factor parameter type. */
52      protected static final ParameterTypeDouble FSPEED = ParameterTypes.FSPEED;
53  
54      /** GTU type speed limit adherence factor parameter type. */
55      protected static final ParameterTypeDouble FSPEED_GTU = ParameterTypes.FSPEED_GTU;
56  
57      /** Speed to which FSPEED is applied if there is no speed limit. */
58      private static final Speed NO_SPEED_LIMIT_SPEED = new Speed(130.0, SpeedUnit.KM_PER_HOUR);
59  
60      /** Acceleration flattening. */
61      // @docs/06-behavior/parameters.md
62      public static final ParameterTypeDouble DELTA = new ParameterTypeDouble("delta",
63              "Acceleration flattening exponent towards desired speed", 4.0, ConstraintInterface.POSITIVE);
64  
65      /** Default IDM desired headway model. */
66      public static final IdmDesiredHeadwayModel HEADWAY = IdmDesiredHeadwayModel.SINGLETON;
67  
68      /** Default IDM desired speed model. */
69      public static final IdmDesiredSpeedModel DESIRED_SPEED = IdmDesiredSpeedModel.SINGLETON;
70  
71      /**
72       * Constructor with modular models for desired headway and desired speed.
73       * @param desiredHeadwayModel desired headway model
74       * @param desiredSpeedModel desired speed model
75       */
76      public AbstractIdm(final DesiredHeadwayModel desiredHeadwayModel, final DesiredSpeedModel desiredSpeedModel)
77      {
78          super(desiredHeadwayModel, desiredSpeedModel);
79      }
80  
81      /**
82       * Determination of car-following acceleration, possibly based on multiple leaders. This implementation calculates the IDM
83       * free term, which is returned if there are no leaders. If there are leaders <code>combineInteractionTerm()</code> is
84       * invoked to combine the free term with some implementation specific interaction term. The IDM free term is limited by a
85       * deceleration of <code>B0</code> for cases where the current speed is above the desired speed. This method can be
86       * overridden if the free term needs to be redefined.
87       * @param parameters Parameters.
88       * @param speed Current speed.
89       * @param desiredSpeed Desired speed.
90       * @param desiredHeadway Desired headway.
91       * @param leaders Set of leader headways (guaranteed positive) and speeds, ordered by headway (closest first).
92       * @throws ParameterException If parameter exception occurs.
93       * @return Car-following acceleration.
94       */
95      @Override
96      @SuppressWarnings("checkstyle:designforextension")
97      protected Acceleration followingAcceleration(final Parameters parameters, final Speed speed, final Speed desiredSpeed,
98              final Length desiredHeadway, final PerceptionIterable<? extends PerceivedObject> leaders) throws ParameterException
99      {
100         Acceleration a = parameters.getParameter(A);
101         Acceleration b0 = parameters.getParameter(B0);
102         double delta = parameters.getParameter(DELTA);
103         double aFree = a.si * (1 - Math.pow(speed.si / desiredSpeed.si, delta));
104         // limit deceleration in free term (occurs if speed > desired speed)
105         aFree = aFree > -b0.si ? aFree : -b0.si;
106         // return free term if there are no leaders
107         if (leaders.isEmpty())
108         {
109             return Acceleration.ofSI(aFree);
110         }
111         // return combined acceleration
112         return combineInteractionTerm(Acceleration.ofSI(aFree), parameters, speed, desiredSpeed, desiredHeadway, leaders);
113     }
114 
115     /**
116      * Combines an interaction term with the free term. There should be at least 1 leader for this method.
117      * @param aFree Free term of acceleration.
118      * @param parameters Parameters.
119      * @param speed Current speed.
120      * @param desiredSpeed Desired speed.
121      * @param desiredHeadway Desired headway.
122      * @param leaders Set of leader headways (guaranteed positive) and speeds, ordered by headway (closest first).
123      * @return Combination of terms into a single acceleration.
124      * @throws ParameterException In case of parameter exception.
125      */
126     protected abstract Acceleration combineInteractionTerm(Acceleration aFree, Parameters parameters, Speed speed,
127             Speed desiredSpeed, Length desiredHeadway, PerceptionIterable<? extends PerceivedObject> leaders)
128             throws ParameterException;
129 
130     /**
131      * Determines the dynamic desired headway, which is non-negative.
132      * @param parameters Parameters.
133      * @param speed Current speed.
134      * @param desiredHeadway Desired headway.
135      * @param leaderSpeed Speed of the leading vehicle.
136      * @return Dynamic desired headway.
137      * @throws ParameterException In case of parameter exception.
138      */
139     protected final Length dynamicDesiredHeadway(final Parameters parameters, final Speed speed, final Length desiredHeadway,
140             final Speed leaderSpeed) throws ParameterException
141     {
142         double sStar = desiredHeadway.si + dynamicHeadwayTerm(parameters, speed, leaderSpeed).si;
143         /*
144          * Due to a power of 2 in the IDM, negative values of sStar are not allowed. A negative sStar means that the leader is
145          * faster to such an extent, that the equilibrium headway (s0+vT) is completely compensated by the dynamic part in
146          * sStar. This might occur if a much faster leader changes lane closely in front. The compensation is limited to the
147          * equilibrium headway minus the stopping distance (i.e. sStar > s0), which means the driver wants to follow with
148          * acceleration. Note that usually the free term determines acceleration in such cases.
149          */
150         Length s0 = parameters.getParameter(S0);
151         /*
152          * Limit used to be 0, but the IDM is very sensitive there. With a decelerating leader, an ok acceleration in one time
153          * step, may results in acceleration < -10 in the next.
154          */
155         return Length.ofSI(sStar >= s0.si ? sStar : s0.si);
156     }
157 
158     /**
159      * Determines the dynamic headway term. May be used on individual leaders for multi-anticipative following.
160      * @param parameters Parameters.
161      * @param speed Current speed.
162      * @param leaderSpeed Speed of the leading vehicle.
163      * @return Dynamic headway term.
164      * @throws ParameterException In case of parameter exception.
165      */
166     protected final Length dynamicHeadwayTerm(final Parameters parameters, final Speed speed, final Speed leaderSpeed)
167             throws ParameterException
168     {
169         Acceleration a = parameters.getParameter(A);
170         Acceleration b = parameters.getParameter(B);
171         return Length.ofSI(speed.si * (speed.si - leaderSpeed.si) / (2 * Math.sqrt(a.si * b.si)));
172     }
173 
174     /**
175      * IDM desired headway model.
176      */
177     public static class IdmDesiredHeadwayModel implements DesiredHeadwayModel, Stateless<IdmDesiredHeadwayModel>
178     {
179         /** Singleton instance. */
180         public static final IdmDesiredHeadwayModel SINGLETON = new IdmDesiredHeadwayModel();
181 
182         /**
183          * Constructor.
184          */
185         public IdmDesiredHeadwayModel()
186         {
187             //
188         }
189 
190         @Override
191         public IdmDesiredHeadwayModel get()
192         {
193             return SINGLETON;
194         }
195 
196         @Override
197         public Length desiredHeadway(final Parameters parameters, final Speed speed) throws ParameterException
198         {
199             return Length.ofSI(parameters.getParameter(S0).si + speed.si * parameters.getParameter(T).si);
200         }
201     }
202 
203     /**
204      * IDM desired speed model. This model returns the minimum of fSpeed'*laneSpeedLimit and fSpeedGtu'*gtuTypeSpeedLimit if
205      * both exist, or one of them if one exists. If both do not exist this model returns fSpeed*130km/h. For both fSpeed' and
206      * fSpeedGtu', if the speed limit is enforced the value is the minimum of fSpeed/fSpeedGtu (respectively) and 1.0.
207      */
208     public static class IdmDesiredSpeedModel implements DesiredSpeedModel, Stateless<IdmDesiredSpeedModel>
209     {
210         /** Singleton instance. */
211         public static final IdmDesiredSpeedModel SINGLETON = new IdmDesiredSpeedModel();
212 
213         /**
214          * Constructor.
215          */
216         public IdmDesiredSpeedModel()
217         {
218             //
219         }
220 
221         @Override
222         public IdmDesiredSpeedModel get()
223         {
224             return SINGLETON;
225         }
226 
227         @Override
228         public Speed desiredSpeed(final Parameters parameters, final SpeedLimits speedLimits, final Speed maxVehicleSpeed)
229                 throws ParameterException
230         {
231             Speed speed = null;
232             if (speedLimits.laneSpeedLimit() != null)
233             {
234                 double laneFactor = parameters.getParameter(FSPEED);
235                 if (speedLimits.laneSpeedLimit().enforced() && laneFactor > 1.0)
236                 {
237                     laneFactor = 1.0;
238                 }
239                 speed = speedLimits.laneSpeedLimit().speed().times(laneFactor);
240             }
241             if (speedLimits.gtuTypeSpeedLimit() != null)
242             {
243                 double gtuTypeFactor = parameters.getParameter(FSPEED_GTU);
244                 if (speedLimits.gtuTypeSpeedLimit().enforced() && gtuTypeFactor > 1.0)
245                 {
246                     gtuTypeFactor = 1.0;
247                 }
248                 if (speed == null)
249                 {
250                     speed = speedLimits.gtuTypeSpeedLimit().speed().times(gtuTypeFactor);
251                 }
252                 else
253                 {
254                     speed = Speed.min(speed, speedLimits.gtuTypeSpeedLimit().speed().times(gtuTypeFactor));
255                 }
256             }
257             else if (speed != null)
258             {
259                 return Speed.min(maxVehicleSpeed, speed);
260             }
261             return Speed.min(maxVehicleSpeed, NO_SPEED_LIMIT_SPEED.times(parameters.getParameter(FSPEED)));
262         }
263     }
264 
265 }