View Javadoc
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   * Implementation of delayed neighbors perception which anticipates using constant speed.
36   * <p>
37   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
38   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
39   * <p>
40   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 17 feb. 2017 <br>
41   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
42   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
43   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
44   */
45  public class DelayedNeighborsPerception extends AbstractDelayedNeighborsPerception
46  {
47  
48      /** Parameter for anticipating beyond current time. */
49      public static final ParameterTypeDuration TA =
50              new ParameterTypeDuration("ta", "anticipation time in future", Duration.ZERO, POSITIVEZERO);
51  
52      /** Parameter for correlation in errors. */
53      public static final ParameterTypeDuration TAUE =
54              new ParameterTypeDuration("tau_e", "error correlation time", Duration.createSI(20), POSITIVE);
55  
56      /** Parameter for distance error factor. */
57      public static final ParameterTypeDouble SERROR =
58              new ParameterTypeDouble("s_error", "distance error factor", 0.1, POSITIVEZERO);
59  
60      /** Parameter for speed error factor. */
61      public static final ParameterTypeDouble VERROR =
62              new ParameterTypeDouble("v_error", "speed error factor", 0.1, POSITIVEZERO);
63  
64      /** Parameter for acceleration error factor. */
65      public static final ParameterTypeDouble AERROR =
66              new ParameterTypeDouble("a_error", "acceleration error factor", 0.2, POSITIVEZERO);
67  
68      /** Margin to check time step in Wiener process. */
69      private static final double MARGIN = 1e-6;
70  
71      /** */
72      private static final long serialVersionUID = 20170217L;
73  
74      /** Form of anticipation. */
75      private final Anticipation anticipation;
76  
77      /** Latest update time of neighbor rearrangement. */
78      private Time rearrangeTime;
79  
80      /** Set of followers per relative lane. */
81      private final Map<RelativeLane, SortedSet<HeadwayGTU>> followers = new HashMap<>();
82  
83      /** Set of leaders per relative lane. */
84      private final Map<RelativeLane, SortedSet<HeadwayGTU>> leaders = new HashMap<>();
85  
86      /** Set of first followers per lane upstream of merge per lateral direction, i.e. in the left or right lane. */
87      private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstFollowers = new HashMap<>();
88  
89      /** Set of first leaders per lane downstream of split per lateral direction, i.e. in the left or right lane. */
90      private final Map<LateralDirectionality, SortedSet<HeadwayGTU>> firstLeaders = new HashMap<>();
91  
92      /** Whether a GTU is alongside per lateral direction, i.e. in the left or right lane. */
93      private final Map<LateralDirectionality, Boolean> gtuAlongside = new HashMap<>();
94  
95      /** Map of errors by a Wiener process for each GTU. */
96      private HashMap<String, ErrorValue> errors = new HashMap<>();
97  
98      /** Random numbers for perception errors. */
99      private final DistNormal norm;
100 
101     /**
102      * @param perception perception
103      * @param anticipation anticipation
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      * Rearrange neighbors, i.e. a follower may be anticipated to be a leader, etc.
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                 // adjacent lanes
190                 if (lane.getNumLanes() == 1)
191                 {
192                     // alongside, initial (can be overwritten as true by anticipation of first leaders/followers)
193                     boolean gtuAlongSide = getInfo(NeighborsInfoType.getBooleanType(GTUALONGSIDE), lane).getObject();
194 
195                     // followers
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                     // leaders
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                     // store alongside
238                     this.gtuAlongside.put(lane.getLateralDirectionality(), gtuAlongSide);
239                 }
240 
241                 // initiate sets
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                 // followers
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                 // leaders
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                 // lane change performed, info on a lane not present
293             }
294 
295         }
296 
297     }
298 
299     /**
300      * Returns a standard Gaussian distributed random value generated with a Wiener process.
301      * @param gtuId gtu id of neighbor
302      * @param tau error correlation parameter
303      * @param dt model time step
304      * @return standard Gaussian distributed random value generated with a Wiener process
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                 // too long ago, exp may result in extreme values, draw new independent value
341                 err = this.norm.draw();
342             }
343         }
344         errorValue.set(now, err);
345         return err;
346 
347     }
348 
349     /**
350      * Creates the initial erroneous values for distance, speed and acceleration.
351      * @param distance actual distance
352      * @param speed actual speed
353      * @param acceleration actual acceleration
354      * @param error random error
355      * @param distanceError error factor on distance
356      * @param speedError error factor on speed
357      * @param accelerationError error factor on acceleration
358      * @param egoSpeed own speed
359      * @return erroneous triplet
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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         // If the lane was not perceived at the reaction time in the past, but there is a lane now, be on the safe side.
409         // Note that infrastructure perception is separate, i.e. might be with a different or no reaction time.
410         return true;
411     }
412 
413     /** {@inheritDoc} */
414     @Override
415     public SortedSet<HeadwayGTU> getLeaders(final RelativeLane lane)
416     {
417         rearrangeNeighbors();
418         return this.leaders.get(lane);
419     }
420 
421     /** {@inheritDoc} */
422     @Override
423     public SortedSet<HeadwayGTU> getFollowers(final RelativeLane lane)
424     {
425         rearrangeNeighbors();
426         return this.followers.get(lane);
427     }
428 
429     /**
430      * <p>
431      * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
432      * <br>
433      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
434      * <p>
435      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 4 mrt. 2017 <br>
436      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
437      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
438      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
439      */
440     private class ErrorValue
441     {
442 
443         /** Time. */
444         private Time time;
445 
446         /** Error. */
447         private double error;
448 
449         /**
450          * 
451          */
452         ErrorValue()
453         {
454         }
455 
456         /**
457          * @return time.
458          */
459         public Time getTime()
460         {
461             return this.time;
462         }
463 
464         /**
465          * @return error.
466          */
467         public double getError()
468         {
469             return this.error;
470         }
471 
472         /**
473          * @param t time
474          * @param err error
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      * Form of anticipation.
486      * <p>
487      * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
488      * <br>
489      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
490      * <p>
491      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 feb. 2017 <br>
492      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
493      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
494      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
495      */
496     public enum Anticipation
497     {
498 
499         /** Assume no anticipation. */
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         /** Assume constant speed. */
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         /** Assume constant acceleration. */
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                     // to stand still
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          * Anticipate movement.
565          * @param neighborTriplet headway, speed and acceleration
566          * @param duration duration
567          * @param traveledDistance distance the subject vehicle traveled during the anticipation time
568          * @return anticipated info
569          */
570         public abstract NeighborTriplet anticipate(NeighborTriplet neighborTriplet, Duration duration, Length traveledDistance);
571 
572         /**
573          * Anticipate own movement.
574          * @param speed current speed
575          * @param acceleration current acceleration
576          * @param duration anticipation time
577          * @return anticipated distance traveled
578          */
579         public abstract Length egoAnticipation(Speed speed, Acceleration acceleration, Duration duration);
580 
581     }
582 
583     /**
584      * Results from anticipation.
585      * <p>
586      * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
587      * <br>
588      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
589      * <p>
590      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 feb. 2017 <br>
591      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
592      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
593      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
594      */
595     private static class NeighborTriplet
596     {
597 
598         /** Headway. */
599         private final Length headway;
600 
601         /** Speed. */
602         private final Speed speed;
603 
604         /** Acceleration. */
605         private final Acceleration acceleration;
606 
607         /**
608          * @param headway headway
609          * @param speed speed
610          * @param acceleration acceleration
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          * @return headway.
621          */
622         public Length getHeadway()
623         {
624             return this.headway;
625         }
626 
627         /**
628          * @return speed.
629          */
630         public Speed getSpeed()
631         {
632             return this.speed;
633         }
634 
635         /**
636          * @return acceleration.
637          */
638         public Acceleration getAcceleration()
639         {
640             return this.acceleration;
641         }
642 
643     }
644 }