Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSDevice_GLOSA.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2013-2024 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
19// A device for Green Light Optimal Speed Advisory
20/****************************************************************************/
21#include <config.h>
22
28#include <microsim/MSNet.h>
29#include <microsim/MSLane.h>
30#include <microsim/MSEdge.h>
31#include <microsim/MSLink.h>
32#include <microsim/MSVehicle.h>
33#include "MSDevice_GLOSA.h"
34
35//#define DEBUG_GLOSA
36//#define DEBUG_QUEUE
37#define DEBUG_COND (true)
38
39// ===========================================================================
40// method definitions
41// ===========================================================================
42// ---------------------------------------------------------------------------
43// static initialisation methods
44// ---------------------------------------------------------------------------
45void
47 oc.addOptionSubTopic("GLOSA Device");
48 insertDefaultAssignmentOptions("glosa", "GLOSA Device", oc);
49
50 oc.doRegister("device.glosa.range", new Option_Float(100.0));
51 oc.addDescription("device.glosa.range", "GLOSA Device", TL("The communication range to the traffic light"));
52
53 oc.doRegister("device.glosa.max-speedfactor", new Option_Float(1.1));
54 oc.addDescription("device.glosa.max-speedfactor", "GLOSA Device", TL("The maximum speed factor when approaching a green light"));
55
56 oc.doRegister("device.glosa.min-speed", new Option_Float(5.0));
57 oc.addDescription("device.glosa.min-speed", "GLOSA Device", TL("Minimum speed when coasting towards a red light"));
58
59 oc.doRegister("device.glosa.add-switchtime", new Option_Float(0.0));
60 oc.addDescription("device.glosa.add-switchtime", "GLOSA Device", TL("Additional time the vehicle shall need to reach the intersection after the signal turns green"));
61
62 oc.doRegister("device.glosa.use-queue", new Option_Bool(false));
63 oc.addDescription("device.glosa.use-queue", "GLOSA Device", TL("Use queue in front of the tls for GLOSA calculation"));
64
65 oc.doRegister("device.glosa.override-safety", new Option_Bool(false));
66 oc.addDescription("device.glosa.override-safety", "GLOSA Device", TL("Override safety features - ignore the current light state, always follow GLOSA's predicted state"));
67
68 oc.doRegister("device.glosa.ignore-cfmodel", new Option_Bool(false));
69 oc.addDescription("device.glosa.ignore-cfmodel", "GLOSA Device", TL("Vehicles follow a perfect speed calculation - ignore speed calculations from the CF model if not safety critical"));
70}
71
72
73void
74MSDevice_GLOSA::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
76 if (!MSGlobals::gUseMesoSim && equippedByDefaultAssignmentOptions(oc, "glosa", v, false)) {
77 MSDevice_GLOSA* device = new MSDevice_GLOSA(v, "glosa_" + v.getID(),
78 v.getFloatParam("device.glosa.min-speed", true),
79 v.getFloatParam("device.glosa.range", true),
80 v.getFloatParam("device.glosa.max-speedfactor", true),
81 v.getFloatParam("device.glosa.add-switchtime", true),
82 v.getBoolParam("device.glosa.use-queue", true),
83 v.getBoolParam("device.glosa.override-safety", true),
84 v.getBoolParam("device.glosa.ignore-cfmodel", true));
85 into.push_back(device);
86 }
87}
88
89void
91 // cleaning up global state (if any)
92}
93
94// ---------------------------------------------------------------------------
95// MSDevice_GLOSA-methods
96// ---------------------------------------------------------------------------
97MSDevice_GLOSA::MSDevice_GLOSA(SUMOVehicle& holder, const std::string& id, double minSpeed, double range, double maxSpeedFactor,
98 double addSwitchTime, bool useQueue, bool overrideSafety, bool ignoreCFModel) :
99 MSVehicleDevice(holder, id),
100 myVeh(dynamic_cast<MSVehicle&>(holder)),
101 myNextTLSLink(nullptr),
102 myDistance(0),
103 myMinSpeed(minSpeed),
104 myRange(range),
105 myMaxSpeedFactor(maxSpeedFactor),
106 myAddSwitchTime(addSwitchTime),
107 myOverrideSafety(overrideSafety),
108 myIgnoreCFModel(ignoreCFModel),
109 mySpeedAdviceActive(false),
110 myUseQueue(useQueue)
111
112{
114}
115
116
119
120
121bool
123 double newPos, double /*newSpeed*/) {
124 myDistance -= (newPos - oldPos);
125 if (myNextTLSLink != nullptr && myDistance <= myRange) {
126 const double vMax = myVeh.getLane()->getVehicleMaxSpeed(&myVeh);
127 double timeToJunction = earliest_arrival(myDistance, vMax);
128 int countOld = 0;
129 // calculate "first" next phase, all coming Phases are calculated via "getTimeToNextSwitch"
130 double timeToSwitch = getTimeToSwitch(myNextTLSLink, countOld);
131 bool currentPhaseGreen = false;
132 bool currentPhaseStop = false;
133 bool solved = false;
134 double nextSwitch = 0;
135 nextSwitch = timeToSwitch;
136 double QueueLength = 0;
137 double greenTime = 0;
138 double additionalJunctionTime = 0;
139 // It takes factor [seconds/per meter queue] to dissolve the queue at drive off
140 // experimental value from calibrated drone data
141 double factor = 0.21;
142 // Additional time (offset) for the leading vehicle to accelerate
143 // experimental value from calibrated drone data
144 double addition = 3;
145 // Vehicles are often not able to drive with their desired speed vMax.
146 // The further away from the junction, the more uncertain the arrival prediction becomes.
147 // For a vehicle trying to reach the begin/end of a green phase, this is critical.
148 // The vehicle should then rather opt for the next phase (trade travel time for traffic flow)
149 int switchOffset = 0;
150
151 if (myNextTLSLink->haveGreen()) { currentPhaseGreen = true; }
152 else if (myNextTLSLink->haveRed() || myNextTLSLink->haveYellow()) { currentPhaseStop = true; }
153 // else if any other phase, GLOSA does not interfere
154#if defined DEBUG_GLOSA || defined DEBUG_QUEUE
155 if (DEBUG_COND) {
156 std::cout << SIMTIME << " veh=" << myVeh.getID() << " d=" << myDistance << " ttJ=" << timeToJunction << " ttS=" << timeToSwitch << "\n";
157 }
158#endif
159 if (myUseQueue) {
160 // Detect queue length at tls
162#ifdef DEBUG_QUEUE
163 if (DEBUG_COND) {
164 std::cout << SIMTIME << " veh=" << myVeh.getID() << " Queuelength=" << QueueLength << "\n";
165 }
166#endif
167 if (currentPhaseGreen) {
168 // how long has it already been green in this phase
169 greenTime = timeGreen(myNextTLSLink);
170 additionalJunctionTime = (QueueLength * factor + addition) - greenTime;
171 if ((additionalJunctionTime > 0) && (additionalJunctionTime < nextSwitch)) {
172 // do note use queue system if queue is to long
173 timeToJunction += additionalJunctionTime;
174 } else {
175 // important for case: "speed can be increased to arrive at tls while green"
176 additionalJunctionTime = 0;
177 }
178#ifdef DEBUG_QUEUE
179 if (DEBUG_COND) {
180 std::cout << SIMTIME << " veh=" << myVeh.getID() << " Additonaljunctiontime=" << additionalJunctionTime << " Greentime=" << greenTime << " TimetoJunction(GreenQueue)=" << timeToJunction << "\n";
181 }
182#endif
183 }
184
185 if (currentPhaseStop) {
186 nextSwitch += QueueLength * factor + addition;
187#ifdef DEBUG_QUEUE
188 if (DEBUG_COND) {
189 std::cout << SIMTIME << " veh=" << myVeh.getID() << " Nextswitch(RedQueue)=" << nextSwitch << "\n";
190 }
191#endif
192 }
193 }
194
195 // Search for the next passable phase, maximum 10 Phases
196 for (int countwhile = 1; countwhile < 11; countwhile++) {
197 if (currentPhaseGreen) {
198 // reset nextSwitch because the queue matters only for the current Phase
199 if (countwhile == 2 && myUseQueue) {
200 nextSwitch -= QueueLength * factor + addition;
201 }
204 mySpeedAdviceActive = false;
205 }
206#ifdef DEBUG_GLOSA
207 if (DEBUG_COND) {
208 std::cout << SIMTIME << " veh=" << myVeh.getID() << " traffic light will be/is green" << "\n";
209 std::cout << SIMTIME << " veh=" << myVeh.getID()
210 << " timeToJunction=" << timeToJunction
211 << " nextSwitch=" << nextSwitch
212 << " myDistance=" << myDistance << "\n";
213 }
214#endif
215 // if we arrive at the tls after it switched to red (else do nothing)
216 if (timeToJunction > nextSwitch) {
217 // if speed can be increased to arrive at tls while green (else look for next phases)
219 const double vMax2 = vMax / myVeh.getChosenSpeedFactor() * myMaxSpeedFactor;
220 const double timetoJunction2 = earliest_arrival(myDistance, vMax2) + additionalJunctionTime;
221 // reaching the signal at yellow might be sufficient
223#ifdef DEBUG_GLOSA
224 if (DEBUG_COND) {
225 std::cout << SIMTIME << " veh=" << myVeh.getID()
226 << " vMax2=" << vMax2
227 << " timetoJunction2=" << timetoJunction2
228 << " yellowSlack=" << yellowSlack << "\n";
229 }
230#endif
231 // if increased speed is fast enough to arrive at tls while green (else look for next phases)
232 if (timetoJunction2 <= (nextSwitch + yellowSlack)) {
233 // increase speed factor up to a maximum if necessary and useful
234 // XXX could compute optimal speed factor here
236 mySpeedAdviceActive = true;
237 break; // solved
238 } else {
239 // speed can not be increased to arrive at tls while green
240 // next switch is calculated at the end of the for-loop
241 }
242 } else {
243 // speed increase is not enough to reach tls while green
244 // next switch is calculated at the end of the for-loop
245 }
246 } else {
247 // vehicle will arrive at tls while green
248 break; // solved
249 }
250 } else if (currentPhaseStop) {
251 // tls is red at the moment
252#ifdef DEBUG_GLOSA
253 if (DEBUG_COND) {
254 std::cout << SIMTIME << " veh=" << myVeh.getID() << " traffic light will be/is red" << "\n";
255 std::cout << SIMTIME << " veh=" << myVeh.getID()
256 << " timeToJunction=" << timeToJunction
257 << " nextSwitch=" << nextSwitch
258 << " myDistance=" << myDistance << "\n";
259 }
260#endif
261 if (countwhile == 2 && myUseQueue) {
262 // take queue into account if current green phase can not be passed and next red phase is used instead
263 nextSwitch += QueueLength * factor + addition;
264#ifdef DEBUG_QUEUE
265 if (DEBUG_COND) {
266 std::cout << SIMTIME << " veh=" << myVeh.getID() << " nextSwitch(redadditon): " << nextSwitch << "\n";
267 }
268#endif
269 }
270 adaptSpeed(myDistance, timeToJunction, nextSwitch + myAddSwitchTime, solved);
271 if (countwhile == 2 && myUseQueue) {
272 // reset queue because following phases should not calculate with current queue
273 nextSwitch -= QueueLength * factor + addition;
274 timeToJunction -= additionalJunctionTime;
275 }
276 if (solved) {
277 break; // solved
278 }
279 }
280 // calculate next Phase
281 nextSwitch += getTimeToNextSwitch(myNextTLSLink, currentPhaseGreen, currentPhaseStop, countOld);
282 // For vehicles far away from the junction we add an offset
283 if (nextSwitch > 80.) {
284 nextSwitch += (double)switchOffset;
285 switchOffset = 6;
286 nextSwitch -= (double)switchOffset;
287 } else if (nextSwitch > 60.) {
288 nextSwitch += (double)switchOffset;
289 switchOffset = 4;
290 nextSwitch -= (double)switchOffset;
291 } else if (nextSwitch > 40.) {
292 nextSwitch += (double)switchOffset;
293 switchOffset = 3;
294 nextSwitch -= (double)switchOffset;
295 } else if (nextSwitch > 20.) {
296 nextSwitch += (double)switchOffset;
297 switchOffset = 2;
298 nextSwitch -= (double)switchOffset;
299 }
300 }
301 }
302 return true; // keep the device
303}
304
305
306bool
308 const MSLink* prevLink = myNextTLSLink;
309 myNextTLSLink = nullptr;
310 const MSLane* lane = myVeh.getLane();
311 if (myVeh.getDeparture() < SIMSTEP) {
312 // no need to call at insertion
314 }
315 const std::vector<MSLane*>& bestLaneConts = myVeh.getBestLanesContinuation(lane);
316 double seen = lane->getLength() - myVeh.getPositionOnLane();
317 int view = 1;
318 std::vector<MSLink*>::const_iterator linkIt = MSLane::succLinkSec(myVeh, view, *lane, bestLaneConts);
319 while (!lane->isLinkEnd(linkIt)) {
320 if (!lane->getEdge().isInternal()) {
321 if ((*linkIt)->isTLSControlled()) {
322 myNextTLSLink = *linkIt;
323 myDistance = seen;
324 break;
325 }
326 }
327 lane = (*linkIt)->getViaLaneOrLane();
328 if (!lane->getEdge().isInternal()) {
329 view++;
330 }
331 seen += lane->getLength();
332 linkIt = MSLane::succLinkSec(myVeh, view, *lane, bestLaneConts);
333 }
334 if (prevLink != nullptr && myNextTLSLink == nullptr) {
335 // moved pass tls
337 mySpeedAdviceActive = false;
338 } else if (myNextTLSLink != nullptr && prevLink != myNextTLSLink) {
339 // approaching new tls
340 double tlsRange = 1e10;
341 const std::string val = myNextTLSLink->getTLLogic()->getParameter("device.glosa.range", "1e10");
342 try {
343 tlsRange = StringUtils::toDouble(val);
344 } catch (const NumberFormatException&) {
345 WRITE_WARNINGF(TL("Invalid value '%' for parameter 'device.glosa.range' of traffic light '%'"),
346 val, myNextTLSLink->getTLLogic()->getID());
347 }
348 myRange = MIN2(myVeh.getFloatParam("device.glosa.range", true), tlsRange);
349 }
350
351#ifdef DEBUG_GLOSA
352 if (DEBUG_COND) {
353 std::cout << SIMTIME << " veh=" << myVeh.getID() << " enter=" << myVeh.getLane()->getID() << " tls=" << (myNextTLSLink == nullptr ? "NULL" : myNextTLSLink->getTLLogic()->getID()) << " dist=" << myDistance << "\n";
354 }
355#endif
356 return true; // keep the device
357}
358
359
360double
361MSDevice_GLOSA::getTimeToSwitch(const MSLink* tlsLink, int& countOld) {
362 assert(tlsLink != nullptr);
363 const MSTrafficLightLogic* const tl = tlsLink->getTLLogic();
364 assert(tl != nullptr);
365 const auto& phases = tl->getPhases();
366 const int n = (int)phases.size();
367 const int cur = tl->getCurrentPhaseIndex();
368 SUMOTime result = tl->getNextSwitchTime() - SIMSTEP;
369
370 for (int i = 1; i < n; i++) {
371 const auto& phase = phases[(cur + i) % n];
372 const char ls = phase->getState()[tlsLink->getTLIndex()];
373 if (((tlsLink->haveRed() || tlsLink->haveYellow()) && (ls == 'g' || ls == 'G'))
374 || (tlsLink->haveGreen() && ls != 'g' && ls != 'G')) {
375 countOld = cur + i;
376 break;
377 }
378 result += phase->duration;
379 }
380 return STEPS2TIME(result);
381}
382
383
384double
385MSDevice_GLOSA::getTimeToNextSwitch(const MSLink* tlsLink, bool& currentPhaseGreen, bool& currentPhaseStop, int& countOld) {
386 // get time till the tls switches to a phase the vehicle can reach
387 assert(tlsLink != nullptr);
388 const MSTrafficLightLogic* const tl = tlsLink->getTLLogic();
389 assert(tl != nullptr);
390 const auto& phases = tl->getPhases();
391 const int n = (int)phases.size();
392 const int cur = countOld;
393 SUMOTime result = 0;
394
395 for (int i = 0; i < n; i++) {
396 const auto& phase = phases[(cur + i) % n];
397 const char ls = phase->getState()[tlsLink->getTLIndex()];
398 if (currentPhaseGreen && (ls == 'g' || ls == 'G')) {
399 countOld = (cur + i)%n;
400 break;
401 }
402 if (currentPhaseStop && (ls != 'g' && ls != 'G')) {
403 countOld = (cur + i)%n;
404 break;
405 }
406 result += phase->duration;
407 }
408 currentPhaseGreen = !currentPhaseGreen;
409 currentPhaseStop = !currentPhaseStop;
410 return STEPS2TIME(result);
411}
412
413double
415 assert(tlsLink != nullptr);
416 const MSTrafficLightLogic* const tl = tlsLink->getTLLogic();
417 assert(tl != nullptr);
418 const auto& phases = tl->getPhases();
419 const int n = (int)phases.size();
420 const int cur = tl->getCurrentPhaseIndex();
421 // As there are multiple "microphases G" in one Greenphase this function only gives back
422 // the already spent time in the current microphase
423 SUMOTime result = tl->getSpentDuration();
424
425 for (int i = 1; i < n; i++) {
426 const auto& phase = phases[(cur - i) % n];
427 const char ls = phase->getState()[tlsLink->getTLIndex()];
428 if ( ls != 'g' && ls != 'G') {
429 break;
430 }
431 result += phase->duration;
432 }
433 return STEPS2TIME(result);
434}
435
436
437
438double
439MSDevice_GLOSA::earliest_arrival(double distance, double vMax) {
440 // assume we keep acceleration until we hit maximum speed
441 const double v = myVeh.getSpeed();
442 const double a = myVeh.getCarFollowModel().getMaxAccel();
443 const double accel_time = MIN2((vMax - v) / a, time_to_junction_at_continuous_accel(distance, v));
444 const double remaining_dist = distance - distance_at_continuous_accel(v, accel_time);
445 const double remaining_time = remaining_dist / vMax;
446 return accel_time + remaining_time;
447}
448
449
450/*
451double
452MSDevice_GLOSA::latest_arrival(speed, distance, earliest) {
453 // assume we keep current speed until within myRange and then decelerate to myMinSpeed
454 speed = max(speed, GLOSA_MIN_SPEED)
455 potential_decel_dist = min(distance, GLOSA_RANGE)
456 decel_time = (speed - GLOSA_MIN_SPEED) / GLOSA_DECEL
457 avg_decel_speed = (speed + GLOSA_MIN_SPEED) / 2.0
458 decel_dist = decel_time * avg_decel_speed
459 if decel_dist > potential_decel_dist:
460 decel_dist = potential_decel_dist
461 # XXX actually avg_decel_speed is higher in this case
462 decel_time = decel_dist / avg_decel_speed
463 slow_dist = potential_decel_dist - decel_dist
464 fast_dist = distance - (decel_dist + slow_dist)
465 result = fast_dist / speed + decel_time + slow_dist / GLOSA_MIN_SPEED
466 if result < earliest:
467 if (distance > 15):
468 print("DEBUG: fixing latest arrival of %s to match earliest of %s" % (result, earliest))
469 result = earliest
470 return result
471 return 0;
472}
473*/
474
475
476double
478 const double v = speed;
479 const double t = time;
480 const double a = myVeh.getCarFollowModel().getMaxAccel();
481 // integrated area composed of a rectangle and a triangle
482 return v * t + a * t * t / 2;
483}
484
485
486double
488 // see distance_at_continuous_accel
489 // t^2 + (2v/a)t - 2d/a = 0
490 const double a = myVeh.getCarFollowModel().getMaxAccel();
491 const double p_half = v / a;
492 const double t = -p_half + sqrt(p_half * p_half + 2 * d / a);
493 return t;
494}
495
496
497void
498MSDevice_GLOSA::adaptSpeed(double distance, double /*timeToJunction*/, double timeToSwitch, bool &solved) {
499 // ensure that myVehicle arrives at the
500 // junction with maximum speed when it switches to green
501 // car performs a slowDown at time z to speed x for duration y
502 // there are two basic strategies
503 // a) maximize z -> this saves road space but leads to low x and thus excessive braking
504 // b) maximize x -> this saves fuel but wastes road
505 // c) compromise: b) but only when distance to junction is below a threshold
506
507 const double vMax = myVeh.getLane()->getSpeedLimit() * myOriginalSpeedFactor;
508
509 // need to start/continue maneuver
510 const double t = timeToSwitch;
511 const double a = myVeh.getCarFollowModel().getMaxAccel();
512 const double u = myMinSpeed;
513 const double w = vMax;
514 const double s = distance;
515 const double v = myVeh.getSpeed();
516 // x : target speed
517 // y : slow down duration
518 // s is composed of 1 trapezoid (decel), 1 rectangle (maintain), 1 trapezoid (accel)
519 // s = (v^2-x^2)/2d + x*(t-y-(w-x)/a) + (w^2-x^2)/2a
520 // y = (v-x)/d
521 // solution for x curtesy of mathomatic.org
522
523 // First, we calculate targetSpeed assuming we are driving that speed already (v=x)
524 // If this results in targetSpeed < currentSpeed, then we need to decelerate (and vice versa)
525 const double rootConst = a * a * t * t - 2.0 * a * w * t + 2 * a * s;
526 double vConst = 0;
527 if (rootConst >= 0) {
528 vConst = sqrt(rootConst) - a * t + w;
529 }
530 double d = myVeh.getCarFollowModel().getMaxDecel();
531 if (v < vConst) {
532 d = a;
533 }
534
535 // Second, we calculate the correct targetSpeed, knowing if we need to accelerate or decelerate
536 const double sign0 = -1; // quadratic formula solution x1 (choose solution with higher speed)
537 const double root_argument = a * d * ((2.0 * d * (s - (w * t))) - ((v - w) * (v - w)) + (a * ((d * (t * t)) + (2.0 * (s - (t * v))))));
538 if (root_argument < 0) {
539#ifdef DEBUG_GLOSA
540 WRITE_WARNINGF("GLOSA error 1 root_argument=% s=% t=% v=%", root_argument, s, t, v);
541#endif
542 // no reset of speedFactor because in this case, current speed can be kept
543 solved = true;
544
545 return;
546 }
547 const double x = (((a * (v - (d * t))) + (d * w) - sign0 * sqrt(root_argument)) / (d + a));
548 double y = (v - x) / d;
549 if (v < x) {
550 y = (x - v) / d;
551 }
552 if (s < (w * w - x * x) / 2.0 / a) {
553 // end maneuver
554 if (myIgnoreCFModel) {
555 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
556 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), myVeh.getSpeed()));
557 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(w - x / a), vMax));
558 myVeh.getInfluencer().setSpeedTimeLine(speedTimeLine);
559 } else {
561 }
562 mySpeedAdviceActive = false;
563 return;
564 }
565 if (!(x >= u && x <= w && y < t)) {
566#ifdef DEBUG_GLOSA
567 WRITE_WARNINGF("GLOSA error 2 x=% y=% s=% t=% v=%", x, y, s, t, v);
568#endif
569 if (x < u) {
570 #ifdef DEBUG_GLOSA
571 if (DEBUG_COND) {
572 std::cout << "veh=" << myVeh.getID() << " cant go slow enough" << "\n";
573 }
574#endif
575 // no reset of speedFactor because in this case, current speed can be kept
576 //myVeh.setChosenSpeedFactor(myOriginalSpeedFactor);
577 //mySpeedAdviceActive = false;
578 solved = true;
579 }
580 if (x > w) {
581#ifdef DEBUG_GLOSA
582 if (DEBUG_COND) {
583 std::cout << "veh=" << myVeh.getID() << " cant go fast enough" << "\n";
584 }
585#endif
586 }
587 return;
588 }
589 const double targetSpeed = x;
590 const double duration = MAX2(y, TS);
591 solved = true;
592#ifdef DEBUG_GLOSA
593 if (DEBUG_COND) {
594 std::cout << " targetSpeed=" << targetSpeed << " duration=" << duration << "\n";
595 }
596#endif
597 if (myIgnoreCFModel) {
598 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
599 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), myVeh.getSpeed()));
600 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), targetSpeed));
601 myVeh.getInfluencer().setSpeedTimeLine(speedTimeLine);
602 } else {
604 }
605 mySpeedAdviceActive = true;
606}
607
608
609void
611 /*
612 if (tripinfoOut != nullptr) {
613 tripinfoOut->openTag("glosa_device");
614 tripinfoOut->closeTag();
615 }
616 */
617}
618
619std::string
620MSDevice_GLOSA::getParameter(const std::string& key) const {
621 if (key == "minSpeed") {
622 return toString(myMinSpeed);
623 }
624 throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
625}
626
627
628void
629MSDevice_GLOSA::setParameter(const std::string& key, const std::string& value) {
630 double doubleValue;
631 try {
632 doubleValue = StringUtils::toDouble(value);
633 } catch (NumberFormatException&) {
634 throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
635 }
636 if (key == "minSpeed") {
637 myMinSpeed = doubleValue;
638 } else {
639 throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
640 }
641}
642
643
644/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:315
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SIMSTEP
Definition SUMOTime.h:61
#define TS
Definition SUMOTime.h:42
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
@ SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
void setChosenSpeedFactor(const double factor)
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
double getChosenSpeedFactor() const
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
SUMOTime getDeparture() const
Returns this vehicle's real departure time.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
double getMaxAccel() const
Get the vehicle type's maximum acceleration [m/s^2].
Definition MSCFModel.h:256
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:264
A device which collects info on the vehicle trip (mainly on departure and arrival)
void generateOutput(OutputDevice *tripinfoOut) const
Called on writing tripinfo output.
const MSLink * myNextTLSLink
the upcoming traffic light
MSVehicle & myVeh
myHolder cast to needed type
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
static double timeGreen(const MSLink *tlsLink)
bool mySpeedAdviceActive
If speedFactor is currently beeing changed by the GLOSA device.
bool myUseQueue
if true the queue in front of the TLS is used for calculation
double myAddSwitchTime
Additional time the vehicle shall need to reach the intersection after the signal turns green.
double myMaxSpeedFactor
maximum speed factor when trying to reach green light
double myRange
maximum communication range
void adaptSpeed(double distance, double timeToJunction, double timeToSwitch, bool &solved)
adapt speed to reach junction at green
double myMinSpeed
minimum approach speed towards red light
~MSDevice_GLOSA()
Destructor.
double time_to_junction_at_continuous_accel(double d, double v)
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_GLOSA-options.
static double getTimeToSwitch(const MSLink *tlsLink, int &countOld)
compute time to next (relevant) switch
double myDistance
the distance to the upcoming traffic light
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
updates next tls link
double distance_at_continuous_accel(double speed, double time)
double earliest_arrival(double speed, double distance)
return minimum number of seconds to reach the junction
double myOriginalSpeedFactor
original speed factor
static void cleanup()
resets counters
void setParameter(const std::string &key, const std::string &value)
try to set the given parameter for this device. Throw exception for unsupported key
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
updates distance and computes speed advice
static double getTimeToNextSwitch(const MSLink *tlsLink, bool &currentPhaseGreen, bool &currentPhaseStop, int &countOld)
compute time to next (relevant) switch the vehicle can reach
const std::string deviceName() const
return the name for this type of device
MSDevice_GLOSA(SUMOVehicle &holder, const std::string &id, double minSpeed, double range, double maxSpeedFactor, double addSwitchTime, bool useQueue, bool overrideSafety, bool ignoreCFModel)
Constructor.
bool myIgnoreCFModel
if true ignore non-critical speed calculations from the CF model, follow GLOSA's perfect speed calcul...
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc, const bool isPerson=false)
Adds common command options that allow to assign devices to vehicles.
Definition MSDevice.cpp:155
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, DEVICEHOLDER &v, bool outputOptionSet, const bool isPerson=false)
Determines whether a vehicle should get a certain device.
Definition MSDevice.h:195
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
static bool gUseMesoSim
Definition MSGlobals.h:106
Representation of a lane in the micro simulation.
Definition MSLane.h:84
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition MSLane.cpp:2619
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:592
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition MSLane.h:853
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:574
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
Notification
Definition of a vehicle state.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:185
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
The parent class for traffic light logics.
virtual int getCurrentPhaseIndex() const =0
Returns the current index within the program.
virtual double getTLQueueLength(const std::string) const
return the estimated queue length at the upcoming traffic light
virtual const Phases & getPhases() const =0
Returns the phases of this tls program.
SUMOTime getNextSwitchTime() const
Returns the assumed next switch time.
SUMOTime getSpentDuration(SUMOTime simStep=-1) const
Returns the duration spent in the current phase.
void setSpeedTimeLine(const std::vector< std::pair< SUMOTime, double > > &speedTimeLine)
Sets a new velocity timeline.
Abstract in-vehicle device.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
void updateBestLanes(bool forceRebuild=false, const MSLane *startLane=0)
computes the best lanes to use in order to continue the route
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
Influencer & getInfluencer()
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:965
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
const SUMOVTypeParameter & getParameter() const
const std::string & getID() const
Returns the id.
Definition Named.h:74
A storage for options typed value containers)
Definition OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
Representation of a vehicle, person, or container.
bool getBoolParam(const std::string &paramName, const bool required=false, const bool deflt=false) const
Retrieve a boolean parameter for the traffic object.
double getFloatParam(const std::string &paramName, const bool required=false, const double deflt=INVALID_DOUBLE) const
Retrieve a floating point parameter for the traffic object.
double getJMParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.
Representation of a vehicle.
Definition SUMOVehicle.h:62
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
#define DEBUG_COND