* happen (computed from the current speed). (We don't take into
* account any already commanded but not necessarily happened
* deceleration; however if we are attempting to increase our speed,
- * current speed refers to the new speed.) If we're already emergency
- * stopping then we ignore the stopping distance and instead keep
- * advancing until we run out of segments we own.
+ * current speed refers to the new speed.) If we're already stopping
+ * then we advance by the stopping distance only (since we don't need
+ * to worry about not being told to stop until the next detection);
+ * also we stop advancing when we run out of segments we own (this
+ * deals with segment-sized rounding errors which might otherwise
+ * make us think we will overrun).
*
* At each new track location for our front end we hope to find a
* segment which no-one currently owns and which is currently set for
* movfeat changes.
*
* If not then we issue an signal stop command (we'd better not be
- * doing that already!) or countermand the speed increase or whatever.
- */
+ * doing that already!) or countermand the speed increase or whatever. */
/*
* Here is how we use the stuff in the Segment:
*
* adv. fdet 1 seg T N F
* adv. nose T F N
* adv. tail T F N
- * adv. fdet stopdist T N F N
+ * adv. fdet stopdist T N F
* adv. nose T F N
* adv. tail T F N
* +++++++++++|+++++++++++|++++++++++|XXXXXX
* adv. tail back T FN
* adv. nose find T F N
* +++++++++++|+++++++++++|++++++++++|XXXXXX
- * adv. fdet 1 seg T N F
- * adv. nose T N HorizonReached
+ * adv. fdet stopdist T N F } may give
+ * adv. nose T F N } HorizonReached
+ * adv. tail T F N instead
*
*/
typedef struct {
Train *train;
unsigned
+ done_first_new_fdet:1,
count_time:1,
accelerating:1,
+ stopping:1,
usecurrentposn:1, /* for pred_getmovpos */
optimistic:1, /* for autopoint */
alwaysusemotions:1, /* for report_train_ownerships only */
TrackLocation nose, fdet, tail;
TrackAdvanceContext nosec, tailc, fdetc;
TimeInterval elapsed; /* from now, minimum */
- Distance was_distance, autopoint_distance;
+ Distance was_distance, autopoint_distance, stopping_distance;
double maxspeed;
Segment *hindmost, *furthest;
/* Is it empty ? */
- if (!u->accelerating &&
- speedmanager_stopping(u->train) &&
- t->seg->owner != u->train)
+ if (u->stopping && t->seg->owner != u->train)
return EC_SignallingHorizonReached;
if (t->seg->owner) {
return predict_problem(u, t->seg, "cannot set track polarity");
}
- if (u->was_distance == TL_DIST_INF) {
+ if (!u->done_first_new_fdet) {
t->seg->det_expected= 1;
+ u->done_first_new_fdet= 1;
u->walk_compute_polarise= u->need_polarise=
(t->seg->seg_inverted ^ t->seg->tr_backwards ^
u->train_polarity_inverted);
+ }
+ if (u->was_distance == TL_DIST_INF) {
if (u->train->autopoint) {
const SegPosCombInfo *pci;
r= trackloc_getlink(t,c,&pci,0,-1); assert(!r);
/* Final adjustments, prepare for next iteration */
- if (u->was_distance == TL_DIST_INF) {
- c->distance= speedmanager_stoppingdistance(u->train);
- oprintf(DUPO("safety") " predict stoppingdistance=%d\n",
- c->distance);
- }
+ if (u->was_distance == TL_DIST_INF)
+ c->distance= u->stopping_distance;
u->was_distance= c->distance;
u->count_time= 1; /* we start counting time only after we've done the
u.problem_callback= ppc;
u.problem_callback_u= ppcu;
u.maxspeed= speedmanager_speed_maxestimate(u.train);
+ u.stopping_distance= speedmanager_stoppingdistance(u.train);
+ u.stopping= !accelerate && speedmanager_stopping(u.train);
oprintf(DUPO("safety") " predict starting %s%s maxspeed=%f"
- " (speed %f try %f, step %d%s) accel=%d\n",
+ " (speed %f try %f, step %d%s) stopdist=%d%s%s\n",
tra->backwards?"-":"",tra->pname,
u.maxspeed, tra->speed.speed, tra->speed.try_speed, tra->speed.step,
tra->speed.decel.running ? " decel" : "",
- accelerate);
+ u.stopping_distance,
+ accelerate ? " accel" : "",
+ u.stopping ? " stopping" : "");
FOR_SEG {
seg->det_expected= 0;
/* predict the future */
- u.fdetc.distance= u.was_distance= TL_DIST_INF;
+ u.fdetc.distance= u.was_distance=
+ u.stopping ? u.stopping_distance : TL_DIST_INF;
u.fdetc.nextseg= fdet_nextseg;
u.fdetc.getmovpos= pred_getmovpos;
u.fdetc.trackend= pred_trackend;
Train *tra;
ErrorCode ec;
Segment *interferer;
+ int stopdist, maxinto;
if (seg->det_ignore) return;
if (!seg->det_expected) {
if (seg->movposcomb < 0)
safety_panic(tra,seg, "track route not set and train has arrived");
- tra->foredetect= seg;
- tra->uncertainty= tra->maxinto=
- seg->i->poscombs[seg->movposcomb].dist;
+ stopdist= speedmanager_stoppingdistance(tra);
+ maxinto= seg->i->poscombs[seg->movposcomb].dist;
+ if (speedmanager_stopping(tra) && maxinto > stopdist) maxinto= stopdist;
+ tra->foredetect= seg;
+ tra->uncertainty= tra->maxinto= stopdist;
report_train_position(tra);
ec= predict(tra, 0, detection_report_problem, 0);
assert(ec == EC_SignallingPredictedProblem);
- tra->maxinto= tra->uncertainty= 1;
+ if (tra->maxinto > stopdist) {
+ tra->uncertainty= tra->maxinto= stopdist;
+ report_train_position(tra);
+ }
+
+ report_train_position(tra);
ec= speedmanager_speedchange_request(tra,0, 0,(char*)"detection sigstop");
/* that calls predict_confirm with our supplied arguments */