View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception.categories.neighbors;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.SortedSet;
6   import java.util.TreeSet;
7   
8   import org.djunits.value.vdouble.scalar.Acceleration;
9   import org.djunits.value.vdouble.scalar.Duration;
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.djunits.value.vdouble.scalar.Speed;
12  import org.djunits.value.vdouble.scalar.Time;
13  import org.djutils.exceptions.Throw;
14  import org.opentrafficsim.base.TimeStampedObject;
15  import org.opentrafficsim.base.parameters.ParameterException;
16  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
17  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
18  import org.opentrafficsim.base.parameters.Parameters;
19  import org.opentrafficsim.base.parameters.constraint.ConstraintInterface;
20  import org.opentrafficsim.core.gtu.GTUException;
21  import org.opentrafficsim.core.gtu.perception.EgoPerception;
22  import org.opentrafficsim.core.gtu.perception.PerceptionException;
23  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
24  import org.opentrafficsim.core.network.LateralDirectionality;
25  import org.opentrafficsim.core.network.OTSNetwork;
26  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
27  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
28  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
29  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
30  import org.opentrafficsim.road.gtu.lane.perception.SortedSetPerceptionIterable;
31  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.Anticipation.NeighborTriplet;
32  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
33  
34  import nl.tudelft.simulation.jstats.distributions.DistNormal;
35  
36  /**
37   * Implementation of delayed neighbors perception which anticipates using constant speed.
38   * <p>
39   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
40   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
41   * <p>
42   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 feb. 2017 <br>
43   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
44   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
45   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
46   */
47  public class DelayedNeighborsPerception extends AbstractDelayedNeighborsPerception
48  {
49  
50      /** Parameter for anticipating beyond current time. */
51      public static final ParameterTypeDuration TA =
52              new ParameterTypeDuration("ta", "anticipation time in future", Duration.ZERO, ConstraintInterface.POSITIVEZERO);
53  
54      /** Parameter for correlation in errors. */
55      public static final ParameterTypeDuration TAUE =
56              new ParameterTypeDuration("tau_e", "error correlation time", Duration.createSI(20), ConstraintInterface.POSITIVE);
57  
58      /** Parameter for distance error factor. */
59      public static final ParameterTypeDouble SERROR =
60              new ParameterTypeDouble("s_error", "distance error factor", 0.1, ConstraintInterface.POSITIVEZERO);
61  
62      /** Parameter for speed error factor. */
63      public static final ParameterTypeDouble VERROR =
64              new ParameterTypeDouble("v_error", "speed error factor", 0.1, ConstraintInterface.POSITIVEZERO);
65  
66      /** Parameter for acceleration error factor. */
67      public static final ParameterTypeDouble AERROR =
68              new ParameterTypeDouble("a_error", "acceleration error factor", 0.2, ConstraintInterface.POSITIVEZERO);
69  
70      /** Margin to check time step in Wiener process. */
71      private static final double MARGIN = 1e-6;
72  
73      /** */
74      private static final long serialVersionUID = 20170217L;
75  
76      /** Form of anticipation. */
77      private final Anticipation anticipation;
78  
79      /** Latest update time of neighbor rearrangement. */
80      private Time rearrangeTime;
81  
82      /** Set of followers per relative lane. */
83      private final Map<RelativeLane, PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> followers = new HashMap<>();
84  
85      /** Set of leaders per relative lane. */
86      private final Map<RelativeLane, PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> leaders = new HashMap<>();
87  
88      /** Set of first followers per lane upstream of merge per lateral direction, i.e. in the left or right lane. */
89      private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstFollowers = new HashMap<>();
90  
91      /** Set of first leaders per lane downstream of split per lateral direction, i.e. in the left or right lane. */
92      private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstLeaders = new HashMap<>();
93  
94      /** Whether a GTU is alongside per lateral direction, i.e. in the left or right lane. */
95      private final Map<LateralDirectionality, Boolean> gtuAlongside = new HashMap<>();
96  
97      /** Map of errors by a Wiener process for each GTU. */
98      private HashMap<String, ErrorValue> errors = new HashMap<>();
99  
100     /** Random numbers for perception errors. */
101     private final DistNormal norm;
102 
103     /**
104      * @param perception LanePerception; perception
105      * @param anticipation Anticipation; anticipation
106      */
107     public DelayedNeighborsPerception(final LanePerception perception, final Anticipation anticipation)
108     {
109         super(perception);
110         Throw.whenNull(anticipation, "Anticipation may not be null.");
111         this.anticipation = anticipation;
112         try
113         {
114             this.norm = new DistNormal(perception.getGtu().getSimulator().getReplication().getStream("perception"));
115         }
116         catch (GTUException exception)
117         {
118             throw new RuntimeException("GTU not initialized.", exception);
119         }
120     }
121 
122     /**
123      * Rearrange neighbors, i.e. a follower may be anticipated to be a leader, etc.
124      */
125     private void rearrangeNeighbors()
126     {
127         Time time;
128         Duration ta;
129         Duration taue;
130         Length length;
131         Length traveledDistance;
132         double distanceError;
133         double speedError;
134         double accelerationError;
135         Speed egoSpeed;
136         Duration dt;
137         try
138         {
139             time = getPerception().getGtu().getSimulator().getSimulatorTime();
140             if (time.equals(this.rearrangeTime))
141             {
142                 return;
143             }
144             Parameters params = getPerception().getGtu().getParameters();
145             ta = params.getParameter(TA);
146             taue = params.getParameter(TAUE);
147             distanceError = params.getParameter(SERROR);
148             speedError = params.getParameter(VERROR);
149             accelerationError = params.getParameter(AERROR);
150             length = getPerception().getGtu().getLength();
151             EgoPerception ego = getPerception().getPerceptionCategory(EgoPerception.class);
152             egoSpeed = ego.getSpeed();
153             dt = params.getParameter(DT);
154             try
155             {
156                 traveledDistance = getPerception().getGtu().getOdometer().minus(getInfo(ODOMETER).getObject());
157             }
158             catch (PerceptionException exception)
159             {
160                 throw new RuntimeException("Odometer not percieved.", exception);
161             }
162             if (!ta.eq0())
163             {
164                 Acceleration acceleration = ego.getAcceleration();
165                 traveledDistance = traveledDistance.plus(this.anticipation.egoAnticipation(egoSpeed, acceleration, ta));
166             }
167             this.rearrangeTime = time;
168         }
169         catch (GTUException exception)
170         {
171             throw new RuntimeException("GTU not initialized while rearranging neighbors.", exception);
172         }
173         catch (ParameterException exception)
174         {
175             throw new RuntimeException("Could not obtain parameter.", exception);
176         }
177         catch (OperationalPlanException exception)
178         {
179             throw new RuntimeException("No ego perception.", exception);
180         }
181         this.firstFollowers.clear();
182         this.firstLeaders.clear();
183         this.gtuAlongside.clear();
184         this.followers.clear();
185         this.leaders.clear();
186         try
187         {
188             for (RelativeLane lane : getDelayedCrossSection())
189             {
190 
191                 // adjacent lanes
192                 if (lane.getNumLanes() == 1)
193                 {
194                     // alongside, initial (can be overwritten as true by anticipation of first leaders/followers)
195                     boolean gtuAlongSide = getInfo(NeighborsInfoType.getBooleanType(GTUALONGSIDE), lane).getObject();
196 
197                     // followers
198                     SortedSet<HeadwayGTU> firstFollowersSet = new TreeSet<>();
199                     this.firstFollowers.put(lane.getLateralDirectionality(), firstFollowersSet);
200                     TimeStampedObject<SortedSet<HeadwayGTU>> delayedFirstFollowers =
201                             getInfo(NeighborsInfoType.getSortedSetType(FIRSTFOLLOWERS), lane);
202                     Duration d = time.minus(delayedFirstFollowers.getTimestamp()).plus(ta);
203                     for (HeadwayGTU gtu : delayedFirstFollowers.getObject())
204                     {
205                         NeighborTriplet info = this.anticipation.anticipate(erroneousTriplet(gtu.getDistance().neg(),
206                                 gtu.getSpeed(), gtu.getAcceleration(), getError(gtu.getId(), taue, dt), distanceError,
207                                 speedError, accelerationError, egoSpeed), d, traveledDistance, false);
208                         if (info.getHeadway().le0())
209                         {
210                             firstFollowersSet.add(gtu.moved(info.getHeadway().neg(), info.getSpeed(), info.getAcceleration()));
211                         }
212                         else
213                         {
214                             gtuAlongSide = true;
215                         }
216                     }
217 
218                     // leaders
219                     SortedSet<HeadwayGTU> firstLeaderssSet = new TreeSet<>();
220                     this.firstLeaders.put(lane.getLateralDirectionality(), firstLeaderssSet);
221                     TimeStampedObject<SortedSet<HeadwayGTU>> delayedFirstLeaders =
222                             getInfo(NeighborsInfoType.getSortedSetType(FIRSTLEADERS), lane);
223                     d = time.minus(delayedFirstLeaders.getTimestamp()).plus(ta);
224                     for (HeadwayGTU gtu : delayedFirstLeaders.getObject())
225                     {
226                         NeighborTriplet info = this.anticipation.anticipate(erroneousTriplet(gtu.getDistance(), gtu.getSpeed(),
227                                 gtu.getAcceleration(), getError(gtu.getId(), taue, dt), distanceError, speedError,
228                                 accelerationError, egoSpeed), d, traveledDistance, true);
229                         if (info.getHeadway().ge0())
230                         {
231                             firstLeaderssSet.add(gtu.moved(info.getHeadway(), info.getSpeed(), info.getAcceleration()));
232                         }
233                         else
234                         {
235                             gtuAlongSide = true;
236                         }
237                     }
238 
239                     // store alongside
240                     this.gtuAlongside.put(lane.getLateralDirectionality(), gtuAlongSide);
241                 }
242 
243                 // initiate sets
244                 SortedSetPerceptionIterable<HeadwayGTU> followersSet = new SortedSetPerceptionIterable<>(
245                         (OTSNetwork) getPerception().getGtu().getReferencePosition().getLane().getParentLink().getNetwork());
246                 this.followers.put(lane, followersSet);
247                 SortedSetPerceptionIterable<HeadwayGTU> leadersSet = new SortedSetPerceptionIterable<>(
248                         (OTSNetwork) getPerception().getGtu().getReferencePosition().getLane().getParentLink().getNetwork());
249                 this.leaders.put(lane, leadersSet);
250 
251                 // followers
252                 TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> delayedFollowers =
253                         getInfo(NeighborsInfoType.getIterableType(FOLLOWERS), lane);
254                 Duration d = time.minus(delayedFollowers.getTimestamp()).plus(ta);
255 
256                 PerceptionCollectable<HeadwayGTU, LaneBasedGTU> perc = delayedFollowers.getObject();
257                 for (HeadwayGTU gtu : delayedFollowers.getObject())
258                 {
259                     NeighborTriplet info = this.anticipation.anticipate(
260                             erroneousTriplet(gtu.getDistance().neg(), gtu.getSpeed(), gtu.getAcceleration(),
261                                     getError(gtu.getId(), taue, dt), distanceError, speedError, accelerationError, egoSpeed),
262                             d, traveledDistance, false);
263                     if (info.getHeadway().le(length) || lane.isCurrent())
264                     {
265                         followersSet.add(gtu.moved(info.getHeadway().neg(), info.getSpeed(), info.getAcceleration()));
266                     }
267                     else
268                     {
269                         leadersSet.add(gtu.moved(info.getHeadway().minus(length).minus(gtu.getLength()), info.getSpeed(),
270                                 info.getAcceleration()));
271                     }
272                 }
273 
274                 // leaders
275                 TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> delayedLeaders =
276                         getInfo(NeighborsInfoType.getIterableType(LEADERS), lane);
277                 d = time.minus(delayedLeaders.getTimestamp()).plus(ta);
278                 for (HeadwayGTU gtu : delayedLeaders.getObject())
279                 {
280 
281                     NeighborTriplet info = this.anticipation.anticipate(
282                             erroneousTriplet(gtu.getDistance(), gtu.getSpeed(), gtu.getAcceleration(),
283                                     getError(gtu.getId(), taue, dt), distanceError, speedError, accelerationError, egoSpeed),
284                             d, traveledDistance, true);
285                     if (info.getHeadway().ge(gtu.getLength().neg()) || lane.isCurrent())
286                     {
287                         leadersSet.add(gtu.moved(info.getHeadway(), info.getSpeed(), info.getAcceleration()));
288                     }
289                     else
290                     {
291                         followersSet.add(gtu.moved(info.getHeadway().plus(length).plus(gtu.getLength()).neg(), info.getSpeed(),
292                                 info.getAcceleration()));
293                     }
294                 }
295 
296             }
297 
298         }
299         catch (PerceptionException | GTUException exception)
300         {
301             // lane change performed, info on a lane not present
302         }
303 
304         try
305         {
306             // add empty sets on all lanes in the current cross section that are not considered yet
307             for (RelativeLane lane : getPerception().getLaneStructure().getExtendedCrossSection())
308             {
309                 if (!this.followers.containsKey(lane))
310                 {
311                     this.followers.put(lane, new SortedSetPerceptionIterable<>((OTSNetwork) getPerception().getGtu()
312                             .getReferencePosition().getLane().getParentLink().getNetwork()));
313                 }
314                 if (!this.leaders.containsKey(lane))
315                 {
316                     this.leaders.put(lane, new SortedSetPerceptionIterable<>((OTSNetwork) getPerception().getGtu()
317                             .getReferencePosition().getLane().getParentLink().getNetwork()));
318                 }
319                 if (lane.isLeft() || lane.isRight())
320                 {
321                     if (!this.firstFollowers.containsKey(lane.getLateralDirectionality()))
322                     {
323                         this.firstFollowers.put(lane.getLateralDirectionality(), new TreeSet<>());
324                     }
325                     if (!this.firstLeaders.containsKey(lane.getLateralDirectionality()))
326                     {
327                         this.firstLeaders.put(lane.getLateralDirectionality(), new TreeSet<>());
328                     }
329                     if (!this.gtuAlongside.containsKey(lane.getLateralDirectionality()))
330                     {
331                         this.gtuAlongside.put(lane.getLateralDirectionality(), false);
332                     }
333                 }
334             }
335         }
336         catch (ParameterException | GTUException pe)
337         {
338             //
339         }
340 
341     }
342 
343     /**
344      * Returns a standard Gaussian distributed random value generated with a Wiener process.
345      * @param gtuId String; gtu id of neighbor
346      * @param tau Duration; error correlation parameter
347      * @param dt Duration; model time step
348      * @return standard Gaussian distributed random value generated with a Wiener process
349      */
350     private double getError(final String gtuId, final Duration tau, final Duration dt)
351     {
352         Time now;
353         try
354         {
355             now = getTimestamp();
356         }
357         catch (GTUException exception)
358         {
359             throw new RuntimeException("Could not get time stamp.", exception);
360         }
361 
362         double err;
363         ErrorValue errorValue;
364         if (!this.errors.containsKey(gtuId))
365         {
366             err = this.norm.draw();
367             errorValue = new ErrorValue();
368             this.errors.put(gtuId, errorValue);
369         }
370         else
371         {
372             errorValue = this.errors.get(gtuId);
373             if (errorValue.getTime().eq(now))
374             {
375                 return errorValue.getError();
376             }
377             double dtErr = now.si - errorValue.getTime().si;
378             if (dtErr <= dt.si + MARGIN)
379             {
380                 err = Math.exp(-dtErr / tau.si) * errorValue.getError() + Math.sqrt((2 * dtErr) / tau.si) * this.norm.draw();
381             }
382             else
383             {
384                 // too long ago, exp may result in extreme values, draw new independent value
385                 err = this.norm.draw();
386             }
387         }
388         errorValue.set(now, err);
389         return err;
390 
391     }
392 
393     /**
394      * Creates the initial erroneous values for distance, speed and acceleration.
395      * @param distance Length; actual distance
396      * @param speed Speed; actual speed
397      * @param acceleration Acceleration; actual acceleration
398      * @param error double; random error
399      * @param distanceError double; error factor on distance
400      * @param speedError double; error factor on speed
401      * @param accelerationError double; error factor on acceleration
402      * @param egoSpeed Speed; own speed
403      * @return erroneous triplet
404      */
405     @SuppressWarnings("checkstyle:parameternumber")
406     private NeighborTriplet erroneousTriplet(final Length distance, final Speed speed, final Acceleration acceleration,
407             final double error, final double distanceError, final double speedError, final double accelerationError,
408             final Speed egoSpeed)
409     {
410         Length s = Length.createSI(distance.si * (1 + ((distance.ge0() ? error : -error) * distanceError)));
411         Speed v = Speed.createSI(speed.si + (error * speedError * distance.si));
412         if (v.lt0())
413         {
414             v = Speed.ZERO;
415         }
416         Acceleration a = Acceleration.createSI(acceleration.si * (1 + error * accelerationError));
417         return new NeighborTriplet(s, v, a);
418     }
419 
420     /** {@inheritDoc} */
421     @Override
422     public final SortedSet<HeadwayGTU> getFirstLeaders(final LateralDirectionality lat)
423             throws ParameterException, NullPointerException, IllegalArgumentException
424     {
425         rearrangeNeighbors();
426         return this.firstLeaders.get(lat);
427     }
428 
429     /** {@inheritDoc} */
430     @Override
431     public final SortedSet<HeadwayGTU> getFirstFollowers(final LateralDirectionality lat)
432             throws ParameterException, NullPointerException, IllegalArgumentException
433     {
434         rearrangeNeighbors();
435         return this.firstFollowers.get(lat);
436     }
437 
438     /** {@inheritDoc} */
439     @Override
440     public final boolean isGtuAlongside(final LateralDirectionality lat)
441             throws ParameterException, NullPointerException, IllegalArgumentException
442     {
443         if (isGtuAlongsideOverride(lat))
444         {
445             return true;
446         }
447         rearrangeNeighbors();
448         if (this.gtuAlongside.containsKey(lat))
449         {
450             return this.gtuAlongside.get(lat);
451         }
452         // If the lane was not perceived at the reaction time in the past, but there is a lane now, be on the safe side.
453         // Note that infrastructure perception is separate, i.e. might be with a different or no reaction time.
454         return true;
455     }
456 
457     /** {@inheritDoc} */
458     @Override
459     public final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getLeaders(final RelativeLane lane)
460     {
461         rearrangeNeighbors();
462         return this.leaders.get(lane);
463     }
464 
465     /** {@inheritDoc} */
466     @Override
467     public final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getFollowers(final RelativeLane lane)
468     {
469         rearrangeNeighbors();
470         return this.followers.get(lane);
471     }
472 
473     /**
474      * <p>
475      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
476      * <br>
477      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
478      * <p>
479      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 4 mrt. 2017 <br>
480      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
481      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
482      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
483      */
484     private class ErrorValue
485     {
486 
487         /** Time. */
488         private Time time;
489 
490         /** Error. */
491         private double error;
492 
493         /**
494          * 
495          */
496         ErrorValue()
497         {
498         }
499 
500         /**
501          * @return time.
502          */
503         public Time getTime()
504         {
505             return this.time;
506         }
507 
508         /**
509          * @return error.
510          */
511         public double getError()
512         {
513             return this.error;
514         }
515 
516         /**
517          * @param t Time; time
518          * @param err double; error
519          */
520         public void set(final Time t, final double err)
521         {
522             this.time = t;
523             this.error = err;
524         }
525 
526         /** {@inheritDoc} */
527         @Override
528         public final String toString()
529         {
530             return "ErrorValue [time=" + this.time + ", error=" + this.error + "]";
531         }
532 
533     }
534 
535     /** {@inheritDoc} */
536     @Override
537     public final String toString()
538     {
539         return "DelayedNeighborsPerception [anticipation=" + this.anticipation + ", rearrangeTime=" + this.rearrangeTime
540                 + ", followers=" + this.followers + ", leaders=" + this.leaders + ", firstFollowers=" + this.firstFollowers
541                 + ", firstLeaders=" + this.firstLeaders + ", gtuAlongside=" + this.gtuAlongside + ", errors=" + this.errors
542                 + ", norm=" + this.norm + "]";
543     }
544 }