1 package org.opentrafficsim.road.gtu.tactical.util.lmrs;
2
3 import java.util.NoSuchElementException;
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.opentrafficsim.base.OtsRuntimeException;
9 import org.opentrafficsim.base.parameters.ParameterException;
10 import org.opentrafficsim.base.parameters.ParameterTypeBoolean;
11 import org.opentrafficsim.base.parameters.ParameterTypeDouble;
12 import org.opentrafficsim.base.parameters.ParameterTypes;
13 import org.opentrafficsim.base.parameters.constraint.ConstraintInterface;
14 import org.opentrafficsim.road.gtu.LaneBasedGtu;
15 import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
16 import org.opentrafficsim.road.gtu.perception.RelativeLane;
17 import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
18 import org.opentrafficsim.road.gtu.perception.object.PerceivedGtu;
19 import org.opentrafficsim.road.gtu.tactical.TacticalContextEgo;
20 import org.opentrafficsim.road.network.LanePosition;
21
22
23
24
25
26
27
28
29
30
31
32 public interface Tailgating
33 {
34
35
36 ParameterTypeDouble RHO = new ParameterTypeDouble("rho", "Social pressure", 0.0, ConstraintInterface.UNITINTERVAL);
37
38
39 ParameterTypeBoolean DEV_RHO = new ParameterTypeBoolean("dev_split", "Deviate laterally for social pressure.", false);
40
41
42 Tailgating NONE = new Tailgating()
43 {
44 @Override
45 public void tailgate(final TacticalContextEgo context)
46 {
47
48 }
49
50 @Override
51 public String toString()
52 {
53 return "NONE";
54 }
55 };
56
57
58 Tailgating RHO_ONLY = new Tailgating()
59 {
60 @Override
61 public void tailgate(final TacticalContextEgo context)
62 {
63 PerceptionCollectable<PerceivedGtu,
64 LaneBasedGtu> leaders = context.getPerception().getPerceptionCategoryOptional(NeighborsPerception.class)
65 .orElseThrow(() -> new NoSuchElementException("No neighbors perception category."))
66 .getLeaders(RelativeLane.CURRENT);
67 try
68 {
69 if (leaders == null || leaders.isEmpty())
70 {
71 context.getParameters().setClaimedParameter(RHO, 0.0, this);
72 Tailgating.deviate(context, 0.0);
73 return;
74 }
75 Length x0 = context.getParameters().getParameter(ParameterTypes.LOOKAHEAD);
76 Speed vGain = context.getParameters().getParameter(LmrsParameters.VGAIN);
77 PerceivedGtu leader = leaders.first();
78 Speed desiredSpeed = context.getDesiredSpeed();
79 double rho = Tailgating.socialPressure(desiredSpeed, leader.getSpeed(), vGain, leader.getDistance(), x0);
80 context.getParameters().setClaimedParameter(RHO, rho, this);
81 Tailgating.deviate(context, rho);
82 }
83 catch (ParameterException exception)
84 {
85 throw new OtsRuntimeException("Could not obtain or set parameter value.", exception);
86 }
87 }
88
89 @Override
90 public String toString()
91 {
92 return "RHO_ONLY";
93 }
94 };
95
96
97 Tailgating PRESSURE = new Tailgating()
98 {
99 @Override
100 public void tailgate(final TacticalContextEgo context)
101 {
102 PerceptionCollectable<PerceivedGtu,
103 LaneBasedGtu> leaders = context.getPerception().getPerceptionCategoryOptional(NeighborsPerception.class)
104 .orElseThrow(() -> new NoSuchElementException("No neighbors perception category."))
105 .getLeaders(RelativeLane.CURRENT);
106 try
107 {
108 if (leaders == null || leaders.isEmpty())
109 {
110 context.getParameters().setClaimedParameter(RHO, 0.0, this);
111 Tailgating.deviate(context, 0.0);
112 return;
113 }
114 Duration t = context.getParameters().getParameter(ParameterTypes.T);
115 Duration tMin = context.getParameters().getParameter(ParameterTypes.TMIN);
116 Duration tMax = context.getParameters().getParameter(ParameterTypes.TMAX);
117 Length x0 = context.getParameters().getParameter(ParameterTypes.LOOKAHEAD);
118 Speed vGain = context.getParameters().getParameter(LmrsParameters.VGAIN);
119 PerceivedGtu leader = leaders.first();
120 Speed desiredSpeed = context.getDesiredSpeed();
121 double rho = Tailgating.socialPressure(desiredSpeed, leader.getSpeed(), vGain, leader.getDistance(), x0);
122 context.getParameters().setClaimedParameter(RHO, rho, this);
123 double tNew = rho * tMin.si + (1.0 - rho) * tMax.si;
124 if (tNew < t.si)
125 {
126 context.getParameters().setClaimedParameter(ParameterTypes.T, Duration.ofSI(tNew), LmrsUtil.T_KEY);
127 }
128 Tailgating.deviate(context, rho);
129 }
130 catch (ParameterException exception)
131 {
132 throw new OtsRuntimeException("Could not obtain or set parameter value.", exception);
133 }
134 }
135
136 @Override
137 public String toString()
138 {
139 return "PRESSURE";
140 }
141 };
142
143
144
145
146
147
148
149
150
151
152 static double socialPressure(final Speed desiredSpeed, final Speed leaderSpeed, final Speed vGain, final Length headway,
153 final Length x0)
154 {
155 double dv = desiredSpeed.si - leaderSpeed.si;
156 if (dv < 0 || headway.gt(x0))
157 {
158 return 0.0;
159 }
160 return 1.0 - Math.exp(-(dv / vGain.si) * (1.0 - (headway.si / x0.si)));
161 }
162
163
164
165
166
167 void tailgate(TacticalContextEgo context);
168
169
170
171
172
173
174
175 static void deviate(final TacticalContextEgo context, final double rho) throws ParameterException
176 {
177 if (context.getParameters().getParameter(DEV_RHO))
178 {
179 LanePosition position = context.getPosition();
180
181 Length deviation = position.lane().getWidth(position.position()).minus(context.getWidth()).times(0.5 * rho);
182 context.addIntent(deviation, Length.ZERO);
183 }
184 }
185
186 }