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      /** {@inheritDoc} */
59      @Override
60      public final Desire determineDesire(final Parameters parameters, final LanePerception perception,
61              final CarFollowingModel carFollowingModel, final Desire mandatoryDesire, final Desire voluntaryDesire)
62              throws ParameterException, OperationalPlanException
63      {
64  
65          // zero if no lane change is possible
66          InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
67          TrafficPerception traffic = perception.getPerceptionCategory(TrafficPerception.class);
68          EgoPerception ego = perception.getPerceptionCategory(EgoPerception.class);
69          double leftDist = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).si;
70          double rightDist = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).si;
71  
72          // gather some info
73          Speed vCur = traffic.getSpeed(RelativeLane.CURRENT);
74          Speed vGain = parameters.getParameter(VGAIN);
75  
76          // calculate aGain (default 1; lower as acceleration is higher than 0)
77          Dimensionless aGain;
78          /*
79           * Instead of instantaneous car-following acceleration, use current acceleration; only then is the acceleration factor
80           * consistent with possible lane change incentives pertaining to speed (which used to be only vehicles in the original
81           * LMRS, but can be any number of reasons here. E.g. traffic lights, conflicts, etc.)
82           */
83          Acceleration aCur = ego.getAcceleration();
84  
85          /*
86           * The idea to let aCur simply be the current acceleration is wrong; aCur -should- only describe the car-following
87           * relation, as this describes a sense of sticking to a lane as the leader is getting away.
88           */
89          aCur = Try.assign(() -> perception.getGtu().getCarFollowingAcceleration(), "Could not obtain the GTU.");
90          if (aCur.si > 0)
91          {
92              Acceleration a = parameters.getParameter(A);
93              aGain = a.minus(aCur).divide(a);
94          }
95          else
96          {
97              aGain = new Dimensionless(1, DimensionlessUnit.SI);
98          }
99  
100         // left desire
101         double dLeft;
102         if (leftDist > 0.0 && infra.getCrossSection().contains(RelativeLane.LEFT))
103         {
104             Speed vLeft = traffic.getSpeed(RelativeLane.LEFT);
105             dLeft = aGain.si * (vLeft.si - vCur.si) / vGain.si;
106         }
107         else
108         {
109             dLeft = 0.0;
110         }
111 
112         // right desire
113         double dRight;
114         if (rightDist > 0.0 && infra.getCrossSection().contains(RelativeLane.RIGHT))
115         {
116             Speed vRight = traffic.getSpeed(RelativeLane.RIGHT);
117             if (vCur.si >= parameters.getParameter(VCONG).si)
118             {
119                 dRight = aGain.si * Math.min(vRight.si - vCur.si, 0) / vGain.si;
120             }
121             else
122             {
123                 dRight = aGain.si * (vRight.si - vCur.si) / vGain.si;
124             }
125         }
126         else
127         {
128             dRight = 0.0;
129         }
130 
131         // return desire
132         return new Desire(dLeft, dRight);
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public final String toString()
138     {
139         return "IncentiveSpeedWithCourtesy";
140     }
141 
142 }