-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
MSDevice_SSM.h
701 lines (581 loc) · 34.5 KB
/
MSDevice_SSM.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
/****************************************************************************/
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
// Copyright (C) 2013-2018 German Aerospace Center (DLR) and others.
// This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v20.html
// SPDX-License-Identifier: EPL-2.0
/****************************************************************************/
/// @file MSDevice_SSM.h
/// @author Daniel Krajzewicz
/// @author Jakob Erdmann
/// @author Leonhard Luecken
/// @date 11.06.2013
/// @version $Id$
///
// An SSM-device logs encounters / conflicts of the carrying vehicle with other surrounding vehicles.
// XXX: Preliminary implementation. Use with care. Especially rerouting vehicles could be problematic.
/****************************************************************************/
#ifndef MSDevice_SSM_h
#define MSDevice_SSM_h
// ===========================================================================
// included modules
// ===========================================================================
#include <config.h>
#include <queue>
#include "MSDevice.h"
#include <utils/common/SUMOTime.h>
#include <utils/iodevices/OutputDevice_File.h>
#include <utils/geom/Position.h>
// ===========================================================================
// class declarations
// ===========================================================================
class SUMOVehicle;
// ===========================================================================
// class definitions
// ===========================================================================
/**
* @class MSDevice_SSM
* @brief A device which collects info on the vehicle trip (mainly on departure and arrival)
*
* Each device collects departure time, lane and speed and the same for arrival.
*
* @see MSDevice
*/
class MSCrossSection;
class MSDevice_SSM : public MSDevice {
private:
/// All currently existing SSM devices
static std::set<MSDevice_SSM*>* instances;
public:
/// @brief Different types of encounters corresponding to relative positions of the vehicles.
/// The name describes the type from the ego perspective
enum EncounterType {
// Other vehicle is closer than range, but not on a lane conflicting with the ego's route ahead
ENCOUNTER_TYPE_NOCONFLICT_AHEAD = 0, //!< ENCOUNTER_TYPE_NOCONFLICT_AHEAD
// Ego and foe vehicles' edges form a part of a consecutive sequence of edges
// This type may be specified further by ENCOUNTER_TYPE_FOLLOWING_LEADER or ENCOUNTER_TYPE_FOLLOWING_FOLLOWER
ENCOUNTER_TYPE_FOLLOWING = 1, //!< ENCOUNTER_TYPE_FOLLOWING
// Ego vehicle is on an edge that has a sequence of successors connected to the other vehicle's edge
ENCOUNTER_TYPE_FOLLOWING_FOLLOWER = 2, //!< ENCOUNTER_TYPE_FOLLOWING_FOLLOWER
// Other vehicle is on an edge that has a sequence of successors connected to the ego vehicle's current edge
ENCOUNTER_TYPE_FOLLOWING_LEADER = 3, //!< ENCOUNTER_TYPE_FOLLOWING_LEADER
// Other vehicle is on an edge that has a sequence of successors connected to the ego vehicle's current edge
ENCOUNTER_TYPE_ON_ADJACENT_LANES = 4, //!< ENCOUNTER_TYPE_ON_ADJACENT_LANES
// Ego and foe share an upcoming edge of their routes while the merging point for the routes is still ahead
// This type may be specified further by ENCOUNTER_TYPE_MERGING_LEADER or ENCOUNTER_TYPE_MERGING_FOLLOWER
ENCOUNTER_TYPE_MERGING = 5, //!< ENCOUNTER_TYPE_MERGING
// Other vehicle is on an edge that has a sequence of successors connected to an edge on the ego vehicle's route
// and the estimated arrival vehicle at the merge point is earlier for the ego than for the foe
ENCOUNTER_TYPE_MERGING_LEADER = 6, //!< ENCOUNTER_TYPE_MERGING_LEADER
// Other vehicle is on an edge that has a sequence of successors connected to an edge on the ego vehicle's route
// and the estimated arrival vehicle at the merge point is earlier for the foe than for the ego
ENCOUNTER_TYPE_MERGING_FOLLOWER = 7,//!< ENCOUNTER_TYPE_MERGING_FOLLOWER
// Vehicles' bestlanes lead to the same edge but to adjacent lanes
ENCOUNTER_TYPE_MERGING_ADJACENT = 8,//!< ENCOUNTER_TYPE_MERGING_ADJACENT
// Ego's and foe's routes have crossing edges
// This type may be specified further by ENCOUNTER_TYPE_CROSSING_LEADER or ENCOUNTER_TYPE_CROSSING_FOLLOWER
ENCOUNTER_TYPE_CROSSING = 9, //!< ENCOUNTER_TYPE_CROSSING
// Other vehicle is on an edge that has a sequence of successors leading to an internal edge that crosses the ego vehicle's edge at a junction
// and the estimated arrival vehicle at the merge point is earlier for the ego than for the foe
ENCOUNTER_TYPE_CROSSING_LEADER = 10, //!< ENCOUNTER_TYPE_CROSSING_LEADER
// Other vehicle is on an edge that has a sequence of successors leading to an internal edge that crosses the ego vehicle's edge at a junction
// and the estimated arrival vehicle at the merge point is earlier for the foe than for the ego
ENCOUNTER_TYPE_CROSSING_FOLLOWER = 11, //!< ENCOUNTER_TYPE_CROSSING_FOLLOWER
// The encounter is a possible crossing conflict, and the ego vehicle has entered the conflict area
ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA = 12, //!< ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA
// The encounter is a possible crossing conflict, and the foe vehicle has entered the conflict area
ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA = 13, //!< ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA
// The encounter has been a possible crossing conflict, but the ego vehicle has left the conflict area
ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA = 14, //!< ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA
// The encounter has been a possible crossing conflict, but the foe vehicle has left the conflict area
ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA = 15, //!< ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA
// The encounter has been a possible crossing conflict, and both vehicles have entered the conflict area (one must have already left, otherwise this must be a collision)
ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA = 16, //!< ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA
// The encounter has been a possible crossing conflict, but both vehicle have left the conflict area
ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA = 17, //!< ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA
// FOLLOWING_PASSED and MERGING_PASSED are reserved to achieve that these encounter types may be tracked longer (see updatePassedEncounter)
// The encounter has been a following situation, but is not active any more
ENCOUNTER_TYPE_FOLLOWING_PASSED = 18, //!< ENCOUNTER_TYPE_FOLLOWING_PASSED
// The encounter has been a merging situation, but is not active any more
ENCOUNTER_TYPE_MERGING_PASSED = 19, //!< ENCOUNTER_TYPE_FOLLOWING_PASSED
// Collision (currently unused, might be differentiated further)
ENCOUNTER_TYPE_COLLISION = 111 //!< ENCOUNTER_TYPE_COLLISION
};
private:
/// @brief An encounter is an episode involving two vehicles,
/// which are closer to each other than some specified distance.
class Encounter {
private:
/// @brief A trajectory encloses a series of positions x and speeds v for one vehicle
/// (the times are stored only once in the enclosing encounter)
struct Trajectory {
// positions
PositionVector x;
// momentary speeds
PositionVector v;
};
/// @brief ConflictPointInfo stores some information on a specific conflict point
/// (used to store information on ssm-extremal values)
struct ConflictPointInfo {
/// @brief time point of the conflict
double time;
/// @brief Predicted location of the conflict:
/// In case of MERGING and CROSSING: entry point to conflict area for follower
/// In case of FOLLOWING: position of leader's back
Position pos;
/// @brief Type of the conflict
EncounterType type;
/// @brief value of the corresponding SSM
double value;
ConflictPointInfo(double time, Position x, EncounterType type, double ssmValue) :
time(time), pos(x), type(type), value(ssmValue) {};
};
public:
/// @brief Constructor
Encounter(const MSVehicle* _ego, const MSVehicle* const _foe, double _begin, double extraTime);
/// @brief Destructor
~Encounter();
/// @brief add a new data point and update encounter type
void add(double time, EncounterType type, Position egoX, Position egoV, Position foeX, Position foeV,
Position conflictPoint, double egoDistToConflict, double foeDistToConflict, double ttc, double drac, std::pair<double, double> pet);
/// @brief Returns the number of trajectory points stored
std::size_t size() const {
return timeSpan.size();
}
/// @brief resets remainingExtraTime to the given value
void resetExtraTime(double value);
/// @brief decreases myRemaingExtraTime by given amount in seconds
void countDownExtraTime(double amount);
/// @brief returns the remaining extra time
double getRemainingExtraTime() const;
/// @brief Compares encounters regarding to their start time
struct compare {
typedef bool value_type;
bool operator()(Encounter* e1, Encounter* e2) {
return e1->begin <= e2->begin;
};
};
public:
const MSVehicle* ego;
const MSVehicle* foe;
const std::string egoID;
const std::string foeID;
double begin, end;
EncounterType currentType;
/// @brief Remaining extra time (decreases after an encounter ended)
double remainingExtraTime;
/// @brief Times when the ego vehicle entered/left the conflict area. Currently only applies for crossing situations. Used for PET calculation. (May be defined for merge conflicts in the future)
double egoConflictEntryTime, egoConflictExitTime;
/// @brief Times when the foe vehicle entered/left the conflict area. Currently only applies for crossing situations. Used for PET calculation. (May be defined for merge conflicts in the future)
double foeConflictEntryTime, foeConflictExitTime;
/// @brief time points corresponding to the trajectories
std::vector<double> timeSpan;
/// @brief Evolution of the encounter classification (@see EncounterType)
std::vector<int> typeSpan;
/// @brief Trajectory of the ego vehicle
Trajectory egoTrajectory;
/// @brief Trajectory of the foe vehicle
Trajectory foeTrajectory;
/// Evolution of the ego vehicle's distance to the conflict point
std::vector<double> egoDistsToConflict;
/// Evolution of the foe vehicle's distance to the conflict point
std::vector<double> foeDistsToConflict;
/// @brief Predicted location of the conflict:
/// In case of MERGING and CROSSING: entry point to conflict area for follower
/// In case of FOLLOWING: position of leader's back
PositionVector conflictPointSpan;
/// @brief All values for TTC
std::vector<double> TTCspan;
/// @brief All values for DRAC
std::vector<double> DRACspan;
// /// @brief Cross sections at which a PET shall be calculated for the corresponding vehicle
// std::vector<std::pair<std::pair<const MSLane*, double>, double> > egoPETCrossSections;
// std::vector<std::pair<std::pair<const MSLane*, double>, double> > foePETCrossSections;
/// @name Extremal values for the SSMs
/// @{
ConflictPointInfo minTTC;
ConflictPointInfo maxDRAC;
ConflictPointInfo PET;
/// @}
/// @brief this flag is set by updateEncounter() or directly in processEncounters(), where encounters are closed if it is true.
bool closingRequested;
private:
/// @brief Invalidated Constructor.
Encounter(const Encounter&);
/// @brief Invalidated assignment operator.
Encounter& operator=(const Encounter&);
///
};
/// @brief Structure to collect some info on the encounter needed during ssm calculation by various functions.
struct EncounterApproachInfo {
EncounterApproachInfo(Encounter* e);
Encounter* encounter;
EncounterType type;
Position conflictPoint;
double egoConflictEntryDist;
double foeConflictEntryDist;
double egoConflictExitDist;
double foeConflictExitDist;
double egoEstimatedConflictEntryTime;
double foeEstimatedConflictEntryTime;
double egoEstimatedConflictExitTime;
double foeEstimatedConflictExitTime;
double egoConflictAreaLength;
double foeConflictAreaLength;
bool egoLeftConflict;
bool foeLeftConflict;
double ttc;
double drac;
std::pair<double, double> pet;
std::pair<const MSLane*, double> egoConflictEntryCrossSection;
std::pair<const MSLane*, double> foeConflictEntryCrossSection;
};
/// A new FoeInfo is created during findSurroundingVehicles() to memorize, where the potential conflict
/// corresponding to the encounter might occur. Each FoeInfo ends up in a call to updateEncounter() and
/// is deleted there.
struct FoeInfo {
const MSLane* egoConflictLane;
double egoDistToConflictLane;
};
// TODO: consider introducing a class foeCollector, which holds the foe info content
// plus a vehicle container to be used in findSurrounding vehicles.
// findSurroundingVehicles() would then deliver a vector of such foeCollectors
// (one for each possible egoConflictLane) instead of a map vehicle->foeInfo
// This could be helpful to resolve the resolution for several different
// projected conflicts with the same foe.
typedef std::priority_queue<Encounter*, std::vector<Encounter*>, Encounter::compare> EncounterQueue;
typedef std::vector<Encounter*> EncounterVector;
typedef std::map<const MSVehicle*, FoeInfo*> FoeInfoMap;
public:
/** @brief Inserts MSDevice_SSM-options
* @param[filled] oc The options container to add the options to
*/
static void insertOptions(OptionsCont& oc);
/** @brief Build devices for the given vehicle, if needed
*
* The options are read and evaluated whether a example-device shall be built
* for the given vehicle.
*
* The built device is stored in the given vector.
*
* @param[in] v The vehicle for which a device may be built
* @param[filled] into The vector to store the built device in
*/
static void buildVehicleDevices(SUMOVehicle& v, std::vector<MSDevice*>& into);
/** @brief returns all currently existing SSM devices
*/
static const std::set<MSDevice_SSM*>& getInstances();
/** @brief This is called once per time step in MSNet::writeOutput() and
* collects the surrounding vehicles, updates information on encounters
* and flushes the encounters qualified as conflicts (@see thresholds)
* to the output file.
*/
void updateAndWriteOutput();
private:
void update();
void writeOutConflict(Encounter* e);
/// @brief convert SUMO-positions to geo coordinates (in place)
static void toGeo(Position& x);
/// @brief convert SUMO-positions to geo coordinates (in place)
static void toGeo(PositionVector& x);
public:
/** @brief Clean up remaining devices instances
*/
static void cleanup();
public:
/// @brief Destructor.
~MSDevice_SSM();
/** @brief Returns all vehicles, which are within the given range of the given vehicle.
* @note all vehicles behind and in front are collected,
* including vehicles on confluent edges. For instance, if the range is 20 m. and
* a junction lies 10 m. ahead, an upstream scan of 20 m. is performed
* for all incoming edges.
*
* @param veh The ego vehicle, that forms the origin for the scan
* @param range The range to be scanned.
* @param[in/out] foeCollector container for all collected vehicles
* @return All vehicles within range from veh
*/
static void findSurroundingVehicles(const MSVehicle& veh, double range, FoeInfoMap& foeCollector);
/** @brief Collects all vehicles within range 'range' upstream of the position 'pos' on the edge 'edge' into foeCollector
*/
static void getUpstreamVehicles(const MSEdge* edge, double pos, double range, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector, std::set<const MSJunction*>& seenJunctions);
/** @brief Collects all vehicles on the junction into foeCollector
*/
static void getVehiclesOnJunction(const MSJunction*, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector);
/// @name Methods called on vehicle movement / state change, overwriting MSDevice
/// @{
/** @brief Checks for waiting steps when the vehicle moves
*
* @param[in] veh Vehicle that notifies.
* @param[in] oldPos Position before move.
* @param[in] newPos Position after move with newSpeed.
* @param[in] newSpeed Moving speed.
*
* @return Always true to keep the device as it cannot be thrown away
*/
bool notifyMove(SUMOVehicle& veh, double oldPos,
double newPos, double newSpeed);
/** @brief Called whenever the holder enteres a lane
*
* @param[in] veh The entering vehicle.
* @param[in] reason Reason for leaving the lane
* @param[in] enteredLane The lane entered.
* @return Always true to keep the device as it cannot be thrown away
* @see MSMoveReminder::notifyEnter
* @see MSMoveReminder::Notification
*/
bool notifyEnter(SUMOVehicle& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane = 0);
/** @brief Called whenever the holder leaves a lane
*
* @param[in] veh The leaving vehicle.
* @param[in] lastPos Position on the lane when leaving.
* @param[in] reason Reason for leaving the lane
* @param[in] enteredLane The lane entered.
* @return True if it did not leave the net.
*/
bool notifyLeave(SUMOVehicle& veh, double lastPos,
MSMoveReminder::Notification reason, const MSLane* enteredLane = 0);
/// @}
/// @brief return the name for this type of device
const std::string deviceName() const {
return "ssm";
}
/** @brief Finalizes output. Called on vehicle removal
*
* @param[in] os The stream to write the information into
* @exception IOError not yet implemented
* @see MSDevice::generateOutput
*/
void generateOutput() const;
private:
/** @brief Constructor
*
* @param[in] holder The vehicle that holds this device
* @param[in] id The ID of the device
* @param measures Vector of Surrogate Safety Measure IDs
* @param thresholds Vector of corresponding thresholds
* @param trajectories Flag indicating whether complete trajectories should be saved for an encounter (if false only extremal values are logged)
* @param range Detection range. For vehicles closer than this distance from the ego vehicle, SSMs are traced
* @param extraTime Extra time in seconds to be logged after a conflict is over
* @param useGeoCoords Whether coordinates should be written out in the original coordinate reference system or as sumo's x,y values
*/
MSDevice_SSM(SUMOVehicle& holder, const std::string& id, std::string outputFilename, std::map<std::string, double> thresholds,
bool trajectories, double range, double extraTime, bool useGeoCoords);
/** @brief Finds encounters for which the foe vehicle has disappeared from range.
* remainingExtraTime is decreased until it reaches zero, which triggers closing the encounter.
* If an ended encounter is qualified as a conflict, it is transferred to myPastConflicts
* All vehicles for which an encounter instance already exists (vehicle is already tracked)
* are removed from 'foes' during processing.
* @param[in] foes Foe vehicles that have been found by findSurroundingVehicles()
* @param[in] forceClose whether encounters for which the foe is not in range shall be closed immediately, disregarding the remaining extra time (is requested by resetEncounters()).
*/
void processEncounters(FoeInfoMap& foes, bool forceClose = false);
/** @brief Closes encounters, whose duration exceeds the maximal encounter length. If it is classified as conflict, the encounter is saved.
* In any case, a new active encounter is created holding the trailing part (of length myOverlapTime) of the original.
*/
void storeEncountersExceedingMaxLength();
/** @brief Makes new encounters for all given vehicles (these should be the ones entering the device's range in the current timestep)
*/
void createEncounters(FoeInfoMap& foes);
/** @brief Stores measures, that are not associated to a specific encounter as headways and brake rates
* @todo Manage as episodes (BR -> braking episode, SGAP/TGAP -> car-following episode) with invariant leader, and filtering applying the
* corresponding thresholds.
*/
void computeGlobalMeasures();
/** @brief Closes all current Encounters and moves conflicts to myPastConflicts, @see processEncounters
*/
void resetEncounters();
/** @brief Writes out all past conflicts that have begun earlier than the oldest active encounter
* @param[in] all Whether all conflicts should be flushed or only those for which no active encounters with earlier begin can exist
*/
void flushConflicts(bool all = false);
/** @brief Write out all non-encounter specific measures as headways and braking rates.
* @todo Adapt accordingly if episode structure is implemented, @see computeGlobalMeasures()
*/
void flushGlobalMeasures();
/** @brief Updates the encounter (adds a new trajectory point) and deletes the foeInfo.
*/
void updateEncounter(Encounter* e, FoeInfo* foeInfo);
/** @brief Updates an encounter, which was classified as ENCOUNTER_TYPE_NOCONFLICT_AHEAD
* this may be the case because the foe is out of the detection range but the encounter
* is still in extra time (in this case foeInfo==0), or because the foe does not head for a lane conflicting with
* the route of the ego vehicle.
* It is also used for an ongoing crossing conflict, where only the covered distances are traced
* until the situation is over. (A crossing conflict is ongoing, if one vehicle entered the conflict area)
* Writes the type of encounter which is determined for the current state into eInfo. And if appropriate some
* information concerning vehicles positions in relation to a crossed crossing point (for PET calculation).
*/
void updatePassedEncounter(Encounter* e, FoeInfo* foeInfo, EncounterApproachInfo& eInfo);
/** @brief Classifies the current type of the encounter provided some information on the opponents
* @param[in] foeInfo Info on distance to conflict point for the device holder.
* @param[in/out] eInfo Info structure for the current state of the encounter (provides a pointer to the encounter).
* @return Returns an encounter type and writes a value to the relevant distances (egoEncounterDist, foeEncounterDist members of eInfo),
* i.e. the distances to the entry points to the potential conflict.
* @note: The encounter distance has a different meaning for different types of encounters:
* 1) For rear-end conflicts (lead/follow situations) the follower's encounter distance is the distance to the actual back position of the leader. The leaders's distance is undefined.
* 2) For merging encounters the encounter distance is the distance until the begin of the common target edge/lane.
* 3) For crossing encounters the encounter distance is the distance until crossing point of the conflicting lanes.
*/
EncounterType classifyEncounter(const FoeInfo* foeInfo, EncounterApproachInfo& eInfo) const;
/** @brief Calculates the (x,y)-coordinate for the eventually predicted conflict point and stores the result in
* eInfo.conflictPoint. In case of MERGING and CROSSING, this is the entry point to conflict area for follower
* In case of FOLLOWING it is the position of leader's back.
* @param[in/out] eInfo Info structure for the current state of the encounter.
*/
static void determineConflictPoint(EncounterApproachInfo& eInfo);
/** @brief Estimates the time until conflict for the vehicles based on the distance to the conflict entry points.
* For acceleration profiles, we assume that the acceleration is <= 0 (that is, braking is extrapolated,
* while for acceleration it is assumed that the vehicle will continue with its current speed)
* @param[in/out] eInfo Info structure for the current state of the encounter.
* @note The '[in]'-part for eInfo are its members e->ego, e->foe (to access the vehicle parameters), egoConflictEntryDist, foeConflictEntryDist, i.e., distances to the conflict entry points.
* The '[out]'-part for eInfo are its members type (type information may be refined) egoConflictEntryTime, foeConflictEntryTime (estimated times until the conflict entry point is reached)
* and egoConflictExitTime, foeConflictExitTime (estimated time until the conflict exit point is reached).
* Further the type of the encounter as determined by classifyEncounter(), is refined for the cases CROSSING and MERGING here.
*/
static void estimateConflictTimes(EncounterApproachInfo& eInfo);
/** @brief Checks whether ego or foe have entered or left the conflict area in the last step and eventually writes
* the corresponding entry or exit times to eInfo.encounter. For ongoing crossing conflicts, it also manages
* the evolution of the conflict type.
* @param[in/out] eInfo Info structure for the current state of the encounter.
* @note The times are to be used for SSM computation in computeSSMs(), e.g. in determinePET()
*/
static void checkConflictEntryAndExit(EncounterApproachInfo& eInfo);
/** @brief Computes the conflict lane for the foe
*
* @param foe Foe vehicle
* @param egoConflictLane Lane, on which the ego would enter the possible conflict
* @param routeToConflict, Series of edges, that were traced back from egoConflictLane during findSurrounding Vehicles, when collecting the foe vehicle
* @param[out] distToConflictLane, distance to conflictlane entry link (may be negative if foe is already on the conflict lane)
* @return Lane, on which the foe would enter the possible conflict, if foe is not on conflict course, Null-pointer is returned.
*/
const MSLane* findFoeConflictLane(const MSVehicle* foe, const MSLane* egoConflictLane, double& distToConflictLane) const;
/** @brief Finalizes the encounter and calculates SSM values.
*/
void closeEncounter(Encounter* e);
/** @brief Tests if the SSM values exceed the threshold for qualification as conflict.
*/
bool qualifiesAsConflict(Encounter* e);
/** @brief Compute current values of the logged SSMs (myMeasures) for the given encounter 'e'
* and update 'e' accordingly (add point to SSM time-series, update maximal/minimal value)
* This is called just after adding the current vehicle positions and velocity vectors to the encounter.
*/
void computeSSMs(EncounterApproachInfo& e) const;
/** @brief Discriminates between different encounter types and correspondingly determines the PET for those cases
* and writes the result to eInfo.pet (after both vehicles have left the conflict area)
*/
void determinePET(EncounterApproachInfo& eInfo) const;
/** @brief Discriminates between different encounter types and correspondingly determines TTC and DRAC for those cases
* and writes the result to eInfo.ttc and eInfo.drac
*/
void determineTTCandDRAC(EncounterApproachInfo& eInfo) const;
/** @brief Computes the time to collision (in seconds) for two vehicles with a given initial gap under the assumption
* that both maintain their current speeds. Returns INVALID if no collision would occur under this assumption.
*/
double computeTTC(double gap, double followerSpeed, double leaderSpeed) const;
/** @brief Computes the DRAC (deceleration to avoid a collision) for a lead/follow situation as defined,
* e.g., in Guido et al. (2011, Safety performance measures: a comparison between microsimulation and observational data)
* for two vehicles with a given gap.
* Returns 0.0 if no deceleration is required by the follower to avoid a crash, INVALID if collision is detected.
*/
static double computeDRAC(double gap, double followerSpeed, double leaderSpeed);
/** @brief Computes the DRAC a crossing situation, determining the minimal constant deceleration needed
* for one of the vehicles to reach the conflict area after the other has left.
* for estimated leaving times, current deceleration is extrapolated, and acceleration is neglected.
* Returns 0.0 if no deceleration is required by the follower to avoid a crash, INVALID if collision is detected.
* @param[in] eInfo infos on the encounter. Used variables:
* dEntry1,dEntry2 The distances to the conflict area entry
* dExit1,dExit2 The distances to the conflict area exit
* v1,v2 The current speeds
* tEntry1,tEntry2 The estimated conflict entry times (including extrapolation of current acceleration)
* tExit1,tExit2 The estimated conflict exit times (including extrapolation of current acceleration)
*/
static double computeDRAC(const EncounterApproachInfo& eInfo);
/** @brief make a string of a double vector and treat a special value as invalid ("NA")
*
* @param v vector to be converted to string
* @param NA value to be treated as NA
* @param sep separator for values in string
* @return String concatenation of the vector entries
*/
static std::string makeStringWithNAs(std::vector<double> v, double NA, std::string sep = " ");
static std::string makeStringWithNAs(std::vector<double> v, std::vector<double> NAs, std::string sep = " ");
/// @name parameter load helpers (introduced for readability of buildVehicleDevices())
/// @{
static std::string getOutputFilename(const SUMOVehicle& v, std::string deviceID);
static double getDetectionRange(const SUMOVehicle& v);
static double getExtraTime(const SUMOVehicle& v);
static bool useGeoCoords(const SUMOVehicle& v);
static bool requestsTrajectories(const SUMOVehicle& v);
static bool getMeasuresAndThresholds(const SUMOVehicle& v, std::string deviceID,
std::map<std::string, double>& thresholds);
///@}
private:
/// @name Device parameters
/// @{
/// @brief thresholds for the ssms, i.e., critical values above or below which a value indicates that a conflict
/// has occurred. These are used in qualifiesAsConflict() and decide whether an encounter is saved.
std::map<std::string, double> myThresholds;
/// @brief This determines whether the whole trajectories of the vehicles (position, speed, ssms) shall be saved in the ssm-output
/// or only the most critical value shall be reported.
bool mySaveTrajectories;
/// Detection range. For vehicles closer than this distance from the ego vehicle, SSMs are traced
double myRange;
/// Extra time in seconds to be logged after a conflict is over
double myExtraTime;
/// Whether to use the original coordinate system for output
bool myUseGeoCoords;
/// Flags for switching on / off comutation of different SSMs, derived from myMeasures
bool myComputeTTC, myComputeDRAC, myComputePET, myComputeBR, myComputeSGAP, myComputeTGAP;
MSVehicle* myHolderMS;
/// @}
/// @name Internal storage for encounters/conflicts
/// @{
/// @brief Currently observed encounters/conflicts
EncounterVector myActiveEncounters;
/// @brief begin time of the oldest active encounter
double myOldestActiveEncounterBegin;
/// @brief Past encounters that where qualified as conflicts and are not yet flushed to the output file
EncounterQueue myPastConflicts;
/// @}
/// @name Internal storage for global measures
/// @{
std::vector<double> myGlobalMeasuresTimeSpan;
/// @brief All values for brake rate
std::vector<double> myBRspan;
/// @brief All values for space gap
std::vector<double> mySGAPspan;
/// @brief All values for time gap
std::vector<double> myTGAPspan;
/// @brief Extremal values for the global measures (as <<<time, Position>, value>, [leaderID]>-pairs)
/// @{
std::pair<std::pair<double, Position>, double> myMaxBR;
std::pair<std::pair<std::pair<double, Position>, double>, std::string> myMinSGAP;
std::pair<std::pair<std::pair<double, Position>, double>, std::string> myMinTGAP;
/// @}
/// @}
/// Output device
OutputDevice* myOutputFile;
/// @brief remember which files were created already (don't duplicate xml root-elements)
static std::set<std::string> createdOutputFiles;
/// @brief bitset storing info whether warning has already been issued about unset parameter (warn only once!)
static int issuedParameterWarnFlags;
enum SSMParameterWarning {
SSM_WARN_MEASURES = 1,
SSM_WARN_THRESHOLDS = 1 << 1,
SSM_WARN_TRAJECTORIES = 1 << 2,
SSM_WARN_RANGE = 1 << 3,
SSM_WARN_EXTRATIME = 1 << 4,
SSM_WARN_FILE = 1 << 5,
SSM_WARN_GEO = 1 << 6
};
private:
/// @brief Invalidated copy constructor.
MSDevice_SSM(const MSDevice_SSM&);
/// @brief Invalidated assignment operator.
MSDevice_SSM& operator=(const MSDevice_SSM&);
};
#endif
/****************************************************************************/