1 package org.opentrafficsim.road.gtu.lane.perception.categories;
2
3 import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.POSITIVE;
4 import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.POSITIVEZERO;
5
6 import java.util.HashMap;
7 import java.util.Map;
8 import java.util.SortedSet;
9 import java.util.TreeSet;
10
11 import org.djunits.value.vdouble.scalar.Acceleration;
12 import org.djunits.value.vdouble.scalar.Duration;
13 import org.djunits.value.vdouble.scalar.Length;
14 import org.djunits.value.vdouble.scalar.Speed;
15 import org.djunits.value.vdouble.scalar.Time;
16 import org.opentrafficsim.base.TimeStampedObject;
17 import org.opentrafficsim.core.gtu.GTUException;
18 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
19 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
20 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDouble;
21 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDuration;
22 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
23 import org.opentrafficsim.core.gtu.perception.EgoPerception;
24 import org.opentrafficsim.core.gtu.perception.PerceptionException;
25 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
26 import org.opentrafficsim.core.network.LateralDirectionality;
27 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
28 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
29 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
30
31 import nl.tudelft.simulation.jstats.distributions.DistNormal;
32 import nl.tudelft.simulation.language.Throw;
33
34
35
36
37
38
39
40
41
42
43
44
45 public class DelayedNeighborsPerception extends AbstractDelayedNeighborsPerception
46 {
47
48
49 public static final ParameterTypeDuration TA =
50 new ParameterTypeDuration("ta", "anticipation time in future", Duration.ZERO, POSITIVEZERO);
51
52
53 public static final ParameterTypeDuration TAUE =
54 new ParameterTypeDuration("tau_e", "error correlation time", Duration.createSI(20), POSITIVE);
55
56
57 public static final ParameterTypeDouble SERROR =
58 new ParameterTypeDouble("s_error", "distance error factor", 0.1, POSITIVEZERO);
59
60
61 public static final ParameterTypeDouble VERROR =
62 new ParameterTypeDouble("v_error", "speed error factor", 0.1, POSITIVEZERO);
63
64
65 public static final ParameterTypeDouble AERROR =
66 new ParameterTypeDouble("a_error", "acceleration error factor", 0.2, POSITIVEZERO);
67
68
69 private static final double MARGIN = 1e-6;
70
71
72 private static final long serialVersionUID = 20170217L;
73
74
75 private final Anticipation anticipation;
76
77
78 private Time rearrangeTime;
79
80
81 private final Map<RelativeLane, SortedSet<HeadwayGTU>> followers = new HashMap<>();
82
83
84 private final Map<RelativeLane, SortedSet<HeadwayGTU>> leaders = new HashMap<>();
85
86
87 private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstFollowers = new HashMap<>();
88
89
90 private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstLeaders = new HashMap<>();
91
92
93 private final Map<LateralDirectionality, Boolean> gtuAlongside = new HashMap<>();
94
95
96 private HashMap<String, ErrorValue> errors = new HashMap<>();
97
98
99 private final DistNormal norm;
100
101
102
103
104
105 public DelayedNeighborsPerception(final LanePerception perception, final Anticipation anticipation)
106 {
107 super(perception);
108 Throw.whenNull(anticipation, "Anticipation may not be null.");
109 this.anticipation = anticipation;
110 try
111 {
112 this.norm = new DistNormal(perception.getGtu().getSimulator().getReplication().getStream("perception"));
113 }
114 catch (GTUException exception)
115 {
116 throw new RuntimeException("GTU not initialized.", exception);
117 }
118 }
119
120
121
122
123 private void rearrangeNeighbors()
124 {
125 Time time;
126 Duration ta;
127 Duration taue;
128 Length length;
129 Length traveledDistance;
130 double distanceError;
131 double speedError;
132 double accelerationError;
133 Speed egoSpeed;
134 Duration dt;
135 try
136 {
137 time = getPerception().getGtu().getSimulator().getSimulatorTime().getTime();
138 if (time.equals(this.rearrangeTime))
139 {
140 return;
141 }
142 BehavioralCharacteristics bc = getPerception().getGtu().getBehavioralCharacteristics();
143 ta = bc.getParameter(TA);
144 taue = bc.getParameter(TAUE);
145 distanceError = bc.getParameter(SERROR);
146 speedError = bc.getParameter(VERROR);
147 accelerationError = bc.getParameter(AERROR);
148 length = getPerception().getGtu().getLength();
149 egoSpeed = getPerception().getPerceptionCategory(EgoPerception.class).getSpeed();
150 dt = bc.getParameter(ParameterTypes.DT);
151 try
152 {
153 traveledDistance = getPerception().getGtu().getOdometer().minus(getInfo(ODOMETER).getObject());
154 }
155 catch (PerceptionException exception)
156 {
157 throw new RuntimeException("Odometer not percieved.", exception);
158 }
159 if (!ta.eq0())
160 {
161 Acceleration acceleration = getPerception().getPerceptionCategory(EgoPerception.class).getAcceleration();
162 traveledDistance = traveledDistance.plus(this.anticipation.egoAnticipation(egoSpeed, acceleration, ta));
163 }
164 this.rearrangeTime = time;
165 }
166 catch (GTUException exception)
167 {
168 throw new RuntimeException("GTU not initialized while rearranging neighbors.", exception);
169 }
170 catch (ParameterException exception)
171 {
172 throw new RuntimeException("Could not obtain parameter.", exception);
173 }
174 catch (OperationalPlanException exception)
175 {
176 throw new RuntimeException("No ego perception.", exception);
177 }
178 this.firstFollowers.clear();
179 this.firstLeaders.clear();
180 this.gtuAlongside.clear();
181 this.followers.clear();
182 this.leaders.clear();
183 SortedSet<RelativeLane> crossSection = getDelayedCrossSection();
184 for (RelativeLane lane : crossSection)
185 {
186
187 try
188 {
189
190 if (lane.getNumLanes() == 1)
191 {
192
193 boolean gtuAlongSide = getInfo(NeighborsInfoType.getBooleanType(GTUALONGSIDE), lane).getObject();
194
195
196 SortedSet<HeadwayGTU> firstFollowersSet = new TreeSet<>();
197 this.firstFollowers.put(lane.getLateralDirectionality(), firstFollowersSet);
198 TimeStampedObject<SortedSet<HeadwayGTU>> delayedFirstFollowers =
199 getInfo(NeighborsInfoType.getSortedSetType(FIRSTFOLLOWERS), lane);
200 Duration d = time.minus(delayedFirstFollowers.getTimestamp()).plus(ta);
201 for (HeadwayGTU gtu : delayedFirstFollowers.getObject())
202 {
203 NeighborTriplet info = this.anticipation.anticipate(erroneousTriplet(gtu.getDistance().neg(),
204 gtu.getSpeed(), gtu.getAcceleration(), getError(gtu.getId(), taue, dt), distanceError,
205 speedError, accelerationError, egoSpeed), d, traveledDistance);
206 if (info.getHeadway().le0())
207 {
208 firstFollowersSet.add(gtu.moved(info.getHeadway().neg(), info.getSpeed(), info.getAcceleration()));
209 }
210 else
211 {
212 gtuAlongSide = true;
213 }
214 }
215
216
217 SortedSet<HeadwayGTU> firstLeaderssSet = new TreeSet<>();
218 this.firstLeaders.put(lane.getLateralDirectionality(), firstLeaderssSet);
219 TimeStampedObject<SortedSet<HeadwayGTU>> delayedFirstLeaders =
220 getInfo(NeighborsInfoType.getSortedSetType(FIRSTLEADERS), lane);
221 d = time.minus(delayedFirstLeaders.getTimestamp()).plus(ta);
222 for (HeadwayGTU gtu : delayedFirstLeaders.getObject())
223 {
224 NeighborTriplet info = this.anticipation.anticipate(erroneousTriplet(gtu.getDistance(), gtu.getSpeed(),
225 gtu.getAcceleration(), getError(gtu.getId(), taue, dt), distanceError, speedError,
226 accelerationError, egoSpeed), d, traveledDistance);
227 if (info.getHeadway().ge0())
228 {
229 firstLeaderssSet.add(gtu.moved(info.getHeadway(), info.getSpeed(), info.getAcceleration()));
230 }
231 else
232 {
233 gtuAlongSide = true;
234 }
235 }
236
237
238 this.gtuAlongside.put(lane.getLateralDirectionality(), gtuAlongSide);
239 }
240
241
242 SortedSet<HeadwayGTU> followersSet = new TreeSet<>();
243 this.followers.put(lane, followersSet);
244 SortedSet<HeadwayGTU> leadersSet = new TreeSet<>();
245 this.leaders.put(lane, leadersSet);
246
247
248 TimeStampedObject<SortedSet<HeadwayGTU>> delayedFollowers =
249 getInfo(NeighborsInfoType.getSortedSetType(FOLLOWERS), lane);
250 Duration d = time.minus(delayedFollowers.getTimestamp()).plus(ta);
251 for (HeadwayGTU gtu : delayedFollowers.getObject())
252 {
253 NeighborTriplet info = this.anticipation.anticipate(
254 erroneousTriplet(gtu.getDistance().neg(), gtu.getSpeed(), gtu.getAcceleration(),
255 getError(gtu.getId(), taue, dt), distanceError, speedError, accelerationError, egoSpeed),
256 d, traveledDistance);
257 if (info.getHeadway().le(length) || lane.isCurrent())
258 {
259 followersSet.add(gtu.moved(info.getHeadway().neg(), info.getSpeed(), info.getAcceleration()));
260 }
261 else
262 {
263 leadersSet.add(gtu.moved(info.getHeadway().minus(length).minus(gtu.getLength()), info.getSpeed(),
264 info.getAcceleration()));
265 }
266 }
267
268
269 TimeStampedObject<SortedSet<HeadwayGTU>> delayedLeaders =
270 getInfo(NeighborsInfoType.getSortedSetType(LEADERS), lane);
271 d = time.minus(delayedLeaders.getTimestamp()).plus(ta);
272 for (HeadwayGTU gtu : delayedLeaders.getObject())
273 {
274
275 NeighborTriplet info = this.anticipation.anticipate(
276 erroneousTriplet(gtu.getDistance(), gtu.getSpeed(), gtu.getAcceleration(),
277 getError(gtu.getId(), taue, dt), distanceError, speedError, accelerationError, egoSpeed),
278 d, traveledDistance);
279 if (info.getHeadway().ge(gtu.getLength().neg()) || lane.isCurrent())
280 {
281 leadersSet.add(gtu.moved(info.getHeadway(), info.getSpeed(), info.getAcceleration()));
282 }
283 else
284 {
285 followersSet.add(gtu.moved(info.getHeadway().plus(length).plus(gtu.getLength()).neg(), info.getSpeed(),
286 info.getAcceleration()));
287 }
288 }
289 }
290 catch (@SuppressWarnings("unused") PerceptionException exception)
291 {
292
293 }
294
295 }
296
297 }
298
299
300
301
302
303
304
305
306 private double getError(final String gtuId, final Duration tau, final Duration dt)
307 {
308 Time now;
309 try
310 {
311 now = getTimestamp();
312 }
313 catch (GTUException exception)
314 {
315 throw new RuntimeException("Could not get time stamp.", exception);
316 }
317
318 double err;
319 ErrorValue errorValue;
320 if (!this.errors.containsKey(gtuId))
321 {
322 err = this.norm.draw();
323 errorValue = new ErrorValue();
324 this.errors.put(gtuId, errorValue);
325 }
326 else
327 {
328 errorValue = this.errors.get(gtuId);
329 if (errorValue.getTime().eq(now))
330 {
331 return errorValue.getError();
332 }
333 double dtErr = now.si - errorValue.getTime().si;
334 if (dtErr <= dt.si + MARGIN)
335 {
336 err = Math.exp(-dtErr / tau.si) * errorValue.getError() + Math.sqrt((2 * dtErr) / tau.si) * this.norm.draw();
337 }
338 else
339 {
340
341 err = this.norm.draw();
342 }
343 }
344 errorValue.set(now, err);
345 return err;
346
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361 @SuppressWarnings("checkstyle:parameternumber")
362 private NeighborTriplet erroneousTriplet(final Length distance, final Speed speed, final Acceleration acceleration,
363 final double error, final double distanceError, final double speedError, final double accelerationError,
364 final Speed egoSpeed)
365 {
366 Length s = Length.createSI(distance.si * (1 + ((distance.ge0() ? error : -error) * distanceError)));
367 Speed v = Speed.createSI(speed.si + (error * speedError * distance.si));
368 if (v.lt0())
369 {
370 v = Speed.ZERO;
371 }
372 Acceleration a = Acceleration.createSI(acceleration.si * (1 + error * accelerationError));
373 return new NeighborTriplet(s, v, a);
374 }
375
376
377 @Override
378 public SortedSet<HeadwayGTU> getFirstLeaders(final LateralDirectionality lat)
379 throws ParameterException, NullPointerException, IllegalArgumentException
380 {
381 rearrangeNeighbors();
382 return this.firstLeaders.get(lat);
383 }
384
385
386 @Override
387 public SortedSet<HeadwayGTU> getFirstFollowers(final LateralDirectionality lat)
388 throws ParameterException, NullPointerException, IllegalArgumentException
389 {
390 rearrangeNeighbors();
391 return this.firstFollowers.get(lat);
392 }
393
394
395 @Override
396 public boolean isGtuAlongside(final LateralDirectionality lat)
397 throws ParameterException, NullPointerException, IllegalArgumentException
398 {
399 if (isGtuAlongsideOverride(lat))
400 {
401 return true;
402 }
403 rearrangeNeighbors();
404 if (this.gtuAlongside.containsKey(lat))
405 {
406 return this.gtuAlongside.get(lat);
407 }
408
409
410 return true;
411 }
412
413
414 @Override
415 public SortedSet<HeadwayGTU> getLeaders(final RelativeLane lane)
416 {
417 rearrangeNeighbors();
418 return this.leaders.get(lane);
419 }
420
421
422 @Override
423 public SortedSet<HeadwayGTU> getFollowers(final RelativeLane lane)
424 {
425 rearrangeNeighbors();
426 return this.followers.get(lane);
427 }
428
429
430
431
432
433
434
435
436
437
438
439
440 private class ErrorValue
441 {
442
443
444 private Time time;
445
446
447 private double error;
448
449
450
451
452 ErrorValue()
453 {
454 }
455
456
457
458
459 public Time getTime()
460 {
461 return this.time;
462 }
463
464
465
466
467 public double getError()
468 {
469 return this.error;
470 }
471
472
473
474
475
476 public void set(final Time t, final double err)
477 {
478 this.time = t;
479 this.error = err;
480 }
481
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496 public enum Anticipation
497 {
498
499
500 NONE
501 {
502 @Override
503 public NeighborTriplet anticipate(final NeighborTriplet neighborTriplet, final Duration duration,
504 final Length traveledDistance)
505 {
506 return neighborTriplet;
507 }
508
509 @Override
510 public Length egoAnticipation(final Speed speed, final Acceleration acceleration, final Duration duration)
511 {
512 return Length.ZERO;
513 }
514 },
515
516
517 CONSTANT_SPEED
518 {
519 @Override
520 public NeighborTriplet anticipate(final NeighborTriplet neighborTriplet, final Duration duration,
521 final Length traveledDistance)
522 {
523 return new NeighborTriplet(neighborTriplet.getHeadway().plus(neighborTriplet.getSpeed().multiplyBy(duration))
524 .minus(traveledDistance), neighborTriplet.getSpeed(), neighborTriplet.getAcceleration());
525 }
526
527 @Override
528 public Length egoAnticipation(final Speed speed, final Acceleration acceleration, final Duration duration)
529 {
530 return speed.multiplyBy(duration);
531 }
532 },
533
534
535 CONSTANT_ACCELERATION
536 {
537 @Override
538 public NeighborTriplet anticipate(final NeighborTriplet neighborTriplet, final Duration duration,
539 final Length traveledDistance)
540 {
541 if (neighborTriplet.getSpeed().si < -neighborTriplet.getAcceleration().si * duration.si)
542 {
543
544 double t = neighborTriplet.getSpeed().si / -neighborTriplet.getAcceleration().si;
545 double dx = neighborTriplet.getSpeed().si * t + .5 * neighborTriplet.getAcceleration().si * t * t;
546 return new NeighborTriplet(Length.createSI(neighborTriplet.getHeadway().si + dx - traveledDistance.si),
547 Speed.ZERO, Acceleration.ZERO);
548 }
549 double dx = neighborTriplet.getSpeed().si * duration.si
550 + .5 * neighborTriplet.getAcceleration().si * duration.si * duration.si;
551 double dv = neighborTriplet.getAcceleration().si * duration.si;
552 return new NeighborTriplet(Length.createSI(neighborTriplet.getHeadway().si + dx - traveledDistance.si),
553 Speed.createSI(neighborTriplet.getSpeed().si + dv), neighborTriplet.getAcceleration());
554 }
555
556 @Override
557 public Length egoAnticipation(final Speed speed, final Acceleration acceleration, final Duration duration)
558 {
559 return speed.multiplyBy(duration);
560 }
561 };
562
563
564
565
566
567
568
569
570 public abstract NeighborTriplet anticipate(NeighborTriplet neighborTriplet, Duration duration, Length traveledDistance);
571
572
573
574
575
576
577
578
579 public abstract Length egoAnticipation(Speed speed, Acceleration acceleration, Duration duration);
580
581 }
582
583
584
585
586
587
588
589
590
591
592
593
594
595 private static class NeighborTriplet
596 {
597
598
599 private final Length headway;
600
601
602 private final Speed speed;
603
604
605 private final Acceleration acceleration;
606
607
608
609
610
611
612 NeighborTriplet(final Length headway, final Speed speed, final Acceleration acceleration)
613 {
614 this.headway = headway;
615 this.speed = speed;
616 this.acceleration = acceleration;
617 }
618
619
620
621
622 public Length getHeadway()
623 {
624 return this.headway;
625 }
626
627
628
629
630 public Speed getSpeed()
631 {
632 return this.speed;
633 }
634
635
636
637
638 public Acceleration getAcceleration()
639 {
640 return this.acceleration;
641 }
642
643 }
644 }