View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical.lmrs;
2   
3   import org.djunits.unit.DimensionlessUnit;
4   import org.djunits.value.vdouble.scalar.Acceleration;
5   import org.djunits.value.vdouble.scalar.Dimensionless;
6   import org.djunits.value.vdouble.scalar.Speed;
7   import org.djutils.exceptions.Try;
8   import org.opentrafficsim.base.parameters.ParameterException;
9   import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
10  import org.opentrafficsim.base.parameters.ParameterTypeSpeed;
11  import org.opentrafficsim.base.parameters.ParameterTypes;
12  import org.opentrafficsim.base.parameters.Parameters;
13  import org.opentrafficsim.core.gtu.perception.EgoPerception;
14  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
15  import org.opentrafficsim.core.network.LateralDirectionality;
16  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
17  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
18  import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
19  import org.opentrafficsim.road.gtu.lane.perception.categories.TrafficPerception;
20  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
21  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
22  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.LmrsParameters;
23  import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.VoluntaryIncentive;
24  
25  /**
26   * Determines lane change desire for speed. The anticipation speed in the current and adjacent lanes are compared. The larger
27   * the difference, the larger the lane change desire. For negative differences, negative desire results. Anticipation speed
28   * involves the most critical vehicle considered to be in a lane. Vehicles are more critical if their speed is lower, and if
29   * they are closer. The set of vehicles considered to be on a lane includes drivers on adjacent lanes of the considered lane,
30   * with a lane change desire towards the considered lane above a certain threshold. If such vehicles have low speeds (i.e.
31   * vehicle accelerating to merge), this may result in a courtesy lane change, or in not changing lane out of courtesy from the
32   * 2nd lane of the mainline. Vehicles on the current lane of the driver, are not considered on adjacent lanes. This would
33   * maintain a large speed difference between the lanes where all drivers do not change lane as they consider leading vehicles to
34   * be on the adjacent lane, lowering the anticipation speed on the adjacent lane. The desire for speed is reduced as
35   * acceleration is larger, preventing over-assertive lane changes as acceleration out of congestion in the adjacent lane has
36   * progressed more.<br>
37   * <br>
38   * <b>Note:</b> This incentive includes speed, and a form of courtesy. It should therefore not be combined with incentives
39   * solely for speed, or solely for courtesy.
40   * <p>
41   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
42   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
43   * </p>
44   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
45   */
46  public class IncentiveSpeedWithCourtesy implements VoluntaryIncentive
47  {
48  
49      /** Acceleration parameter type. */
50      protected static final ParameterTypeAcceleration A = ParameterTypes.A;
51  
52      /** Anticipation speed difference parameter type. */
53      protected static final ParameterTypeSpeed VGAIN = LmrsParameters.VGAIN;
54  
55      /** Speed threshold below which traffic is considered congested. */
56      protected static final ParameterTypeSpeed VCONG = ParameterTypes.VCONG;
57  
58      @Override
59      public final Desire determineDesire(final Parameters parameters, final LanePerception perception,
60              final CarFollowingModel carFollowingModel, final Desire mandatoryDesire, final Desire voluntaryDesire)
61              throws ParameterException, OperationalPlanException
62      {
63  
64          // zero if no lane change is possible
65          InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
66          TrafficPerception traffic = perception.getPerceptionCategory(TrafficPerception.class);
67          EgoPerception ego = perception.getPerceptionCategory(EgoPerception.class);
68          double leftDist = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).si;
69          double rightDist = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si;
70  
71          // gather some info
72          Speed vCur = traffic.getSpeed(RelativeLane.CURRENT);
73          Speed vGain = parameters.getParameter(VGAIN);
74  
75          // calculate aGain (default 1; lower as acceleration is higher than 0)
76          Dimensionless aGain;
77          /*
78           * Instead of instantaneous car-following acceleration, use current acceleration; only then is the acceleration factor
79           * consistent with possible lane change incentives pertaining to speed (which used to be only vehicles in the original
80           * LMRS, but can be any number of reasons here. E.g. traffic lights, conflicts, etc.)
81           */
82          Acceleration aCur = ego.getAcceleration();
83  
84          /*
85           * The idea to let aCur simply be the current acceleration is wrong; aCur -should- only describe the car-following
86           * relation, as this describes a sense of sticking to a lane as the leader is getting away.
87           */
88          aCur = Try.assign(() -> perception.getGtu().getCarFollowingAcceleration(), "Could not obtain the GTU.");
89          if (aCur.si > 0)
90          {
91              Acceleration a = parameters.getParameter(A);
92              aGain = a.minus(aCur).divide(a);
93          }
94          else
95          {
96              aGain = new Dimensionless(1, DimensionlessUnit.SI);
97          }
98  
99          // left desire
100         double dLeft;
101         if (leftDist > 0.0 && infra.getCrossSection().contains(RelativeLane.LEFT))
102         {
103             Speed vLeft = traffic.getSpeed(RelativeLane.LEFT);
104             dLeft = aGain.si * (vLeft.si - vCur.si) / vGain.si;
105         }
106         else
107         {
108             dLeft = 0.0;
109         }
110 
111         // right desire
112         double dRight;
113         if (rightDist > 0.0 && infra.getCrossSection().contains(RelativeLane.RIGHT))
114         {
115             Speed vRight = traffic.getSpeed(RelativeLane.RIGHT);
116             if (vCur.si >= parameters.getParameter(VCONG).si)
117             {
118                 dRight = aGain.si * Math.min(vRight.si - vCur.si, 0) / vGain.si;
119             }
120             else
121             {
122                 dRight = aGain.si * (vRight.si - vCur.si) / vGain.si;
123             }
124         }
125         else
126         {
127             dRight = 0.0;
128         }
129 
130         // return desire
131         return new Desire(dLeft, dRight);
132     }
133 
134     @Override
135     public final String toString()
136     {
137         return "IncentiveSpeedWithCourtesy";
138     }
139 
140 }