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