View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;
2   
3   import static org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Tailgating.socialPressure;
4   
5   import org.djunits.value.vdouble.scalar.Duration;
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djunits.value.vdouble.scalar.Speed;
8   import org.djutils.exceptions.Try;
9   import org.opentrafficsim.base.parameters.ParameterException;
10  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
11  import org.opentrafficsim.base.parameters.ParameterTypes;
12  import org.opentrafficsim.base.parameters.Parameters;
13  import org.opentrafficsim.base.parameters.constraint.ConstraintInterface;
14  import org.opentrafficsim.core.gtu.perception.EgoPerception;
15  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
16  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
17  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
18  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
19  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
20  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGtu;
21  
22  /**
23   * Interface for LMRS tailgating behavior.
24   * <p>
25   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
27   * </p>
28   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
29   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
30   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
31   */
32  public interface Tailgating
33  {
34  
35      /** Social pressure applied to the leader. */
36      ParameterTypeDouble RHO = new ParameterTypeDouble("rho", "Social pressure", 0.0, ConstraintInterface.UNITINTERVAL);
37  
38      /** No tailgating. */
39      Tailgating NONE = new Tailgating()
40      {
41          @Override
42          public void tailgate(final LanePerception perception, final Parameters parameters)
43          {
44              //
45          }
46  
47          @Override
48          public String toString()
49          {
50              return "NONE";
51          }
52      };
53  
54      /** No tailgating, but social pressure exists. */
55      Tailgating RHO_ONLY = new Tailgating()
56      {
57          @Override
58          public void tailgate(final LanePerception perception, final Parameters parameters)
59          {
60              PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders =
61                      perception.getPerceptionCategoryOrNull(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT);
62              if (leaders == null || leaders.isEmpty())
63              {
64                  return;
65              }
66              try
67              {
68                  Speed speed = perception.getPerceptionCategoryOrNull(EgoPerception.class).getSpeed();
69                  Speed vCong = parameters.getParameter(ParameterTypes.VCONG);
70                  Length x0 = parameters.getParameter(ParameterTypes.LOOKAHEAD);
71                  Speed vGain = parameters.getParameter(LmrsParameters.VGAIN);
72                  HeadwayGtu leader = leaders.first();
73                  Speed desiredSpeed = Try.assign(() -> perception.getGtu().getDesiredSpeed(), "Could not obtain the GTU.");
74                  double rho = socialPressure(speed, vCong, desiredSpeed, leader.getSpeed(), vGain, leader.getDistance(), x0);
75                  parameters.setParameter(RHO, rho);
76              }
77              catch (ParameterException exception)
78              {
79                  throw new RuntimeException("Could not obtain or set parameter value.", exception);
80              }
81          }
82  
83          @Override
84          public String toString()
85          {
86              return "RHO_ONLY";
87          }
88      };
89  
90      /** Tailgating based on speed pressure. */
91      Tailgating PRESSURE = new Tailgating()
92      {
93          @Override
94          public void tailgate(final LanePerception perception, final Parameters parameters)
95          {
96              PerceptionCollectable<HeadwayGtu, LaneBasedGtu> leaders =
97                      perception.getPerceptionCategoryOrNull(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT);
98              if (leaders == null || leaders.isEmpty())
99              {
100                 return;
101             }
102             try
103             {
104                 Speed speed = perception.getPerceptionCategoryOrNull(EgoPerception.class).getSpeed();
105                 Speed vCong = parameters.getParameter(ParameterTypes.VCONG);
106                 Duration t = parameters.getParameter(ParameterTypes.T);
107                 Duration tMin = parameters.getParameter(ParameterTypes.TMIN);
108                 Duration tMax = parameters.getParameter(ParameterTypes.TMAX);
109                 Length x0 = parameters.getParameter(ParameterTypes.LOOKAHEAD);
110                 Speed vGain = parameters.getParameter(LmrsParameters.VGAIN);
111                 HeadwayGtu leader = leaders.first();
112                 Speed desiredSpeed = Try.assign(() -> perception.getGtu().getDesiredSpeed(), "Could not obtain the GTU.");
113                 double rho = socialPressure(speed, vCong, desiredSpeed, leader.getSpeed(), vGain, leader.getDistance(), x0);
114                 parameters.setParameter(RHO, rho);
115                 double tNew = rho * tMin.si + (1.0 - rho) * tMax.si;
116                 if (tNew < t.si)
117                 {
118                     parameters.setParameter(ParameterTypes.T, Duration.instantiateSI(tNew));
119                 }
120             }
121             catch (ParameterException exception)
122             {
123                 throw new RuntimeException("Could not obtain or set parameter value.", exception);
124             }
125         }
126 
127         @Override
128         public String toString()
129         {
130             return "PRESSURE";
131         }
132     };
133 
134     /**
135      * Returns a normalized social pressure, equal to (vDesired - vLead) / vGain.
136      * @param speed speed
137      * @param vCong speed indicating congestion
138      * @param desiredSpeed desired speed
139      * @param leaderSpeed leader speed
140      * @param vGain vGain parameter
141      * @param headway headway to the leader
142      * @param x0 anticipation distance
143      * @return normalized social pressure
144      */
145     static double socialPressure(final Speed speed, final Speed vCong, final Speed desiredSpeed, final Speed leaderSpeed,
146             final Speed vGain, final Length headway, final Length x0)
147     {
148         double dv = desiredSpeed.si - leaderSpeed.si;
149         if (dv < 0 || headway.gt(x0)) // larger headway may happen due to perception errors
150         {
151             return 0.0;
152         }
153         return 1.0 - Math.exp(-(dv / vGain.si) * (1.0 - (headway.si / x0.si)));
154     }
155 
156     /**
157      * Apply tailgating.
158      * @param perception perception
159      * @param parameters parameters
160      */
161     void tailgate(LanePerception perception, Parameters parameters);
162 
163 }