1 package org.opentrafficsim.road.gtu.lane.tactical.util;
2
3 import java.io.Serializable;
4
5 import org.djunits.unit.DurationUnit;
6 import org.djunits.unit.LengthUnit;
7 import org.djunits.value.vdouble.scalar.Acceleration;
8 import org.djunits.value.vdouble.scalar.Duration;
9 import org.djunits.value.vdouble.scalar.Length;
10 import org.djunits.value.vdouble.scalar.Speed;
11 import org.opentrafficsim.base.parameters.ParameterException;
12 import org.opentrafficsim.base.parameters.Parameters;
13 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
14 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
15
16
17
18
19
20
21
22
23
24
25
26
27
28 public final record AnticipationInfo(Duration duration, Speed endSpeed) implements Serializable
29 {
30
31
32 private static final long serialVersionUID = 20160811L;
33
34
35
36
37
38
39
40
41 public static AnticipationInfo anticipateMovement(final Length distance, final Speed initialSpeed,
42 final Acceleration acceleration)
43 {
44 return anticipateMovementSpeedLimited(distance, initialSpeed, acceleration, Speed.POSITIVE_INFINITY);
45 }
46
47
48
49
50
51
52
53
54
55 public static AnticipationInfo anticipateMovementSpeedLimited(final Length distance, final Speed initialSpeed,
56 final Acceleration acceleration, final Speed maxSpeed)
57 {
58 if (distance.lt0())
59 {
60 return new AnticipationInfo(Duration.ZERO, initialSpeed);
61 }
62
63 if (acceleration.eq(Acceleration.ZERO))
64 {
65 if (initialSpeed.gt0())
66 {
67 return new AnticipationInfo(distance.divide(initialSpeed), initialSpeed);
68 }
69
70 return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
71 }
72
73 double tmp = initialSpeed.si * initialSpeed.si + 2.0 * acceleration.si * distance.si;
74 if (tmp < 0)
75 {
76
77 return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
78 }
79
80 Duration d = new Duration((Math.sqrt(tmp) - initialSpeed.si) / acceleration.si, DurationUnit.SI);
81
82 Speed endSpeed = initialSpeed.plus(acceleration.times(d));
83 if (endSpeed.le(maxSpeed))
84 {
85 return new AnticipationInfo(d, endSpeed);
86 }
87
88 Duration d1 = maxSpeed.minus(initialSpeed).divide(acceleration);
89 Length x2 = new Length(distance.si - initialSpeed.si * d1.si - .5 * acceleration.si * d1.si * d1.si, LengthUnit.SI);
90 return new AnticipationInfo(d1.plus(x2.divide(maxSpeed)), maxSpeed);
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104 public static AnticipationInfo anticipateMovementFreeAcceleration(final Length distance, final Speed initialSpeed,
105 final Parameters parameters, final CarFollowingModel carFollowingModel, final SpeedLimitInfo speedLimitInfo,
106 final Duration timeStep) throws ParameterException
107 {
108 if (distance.lt0())
109 {
110 return new AnticipationInfo(Duration.ZERO, initialSpeed);
111 }
112 Duration out = Duration.ZERO;
113 if (distance.lt0())
114 {
115 return new AnticipationInfo(out, initialSpeed);
116 }
117 Length xCumul = Length.ZERO;
118 Speed speed = initialSpeed;
119 while (xCumul.lt(distance))
120 {
121 Acceleration a = CarFollowingUtil.freeAcceleration(carFollowingModel, parameters, speed, speedLimitInfo);
122 Length add = new Length(speed.si * timeStep.si + .5 * a.si * timeStep.si * timeStep.si, LengthUnit.SI);
123 Length remain = distance.minus(xCumul);
124 if (add.lt(remain))
125 {
126 xCumul = xCumul.plus(add);
127 speed = speed.plus(a.times(timeStep));
128 out = out.plus(timeStep);
129 }
130 else
131 {
132 Duration timeInStep;
133 double tmp = Math.sqrt(2 * a.si * remain.si + speed.si * speed.si) - speed.si;
134 if (tmp < 0.000001)
135 {
136
137 timeInStep = remain.divide(speed);
138 }
139 else
140 {
141 timeInStep = new Duration(tmp / a.si, DurationUnit.SI);
142 speed = speed.plus(a.times(timeInStep));
143 }
144 out = out.plus(timeInStep);
145 return new AnticipationInfo(out, speed);
146 }
147 }
148
149 throw new RuntimeException("Distance for anticipation of conflict movement is surpassed.");
150 }
151
152 }