safety:                safety.o utils.o trackloc.o ../layout/ours.layout-data.o
                $(LINK)
 
-%.speeds.ps %.speeds.record: ./analyse-speeds
-               ./$^ $*
+%.speeds.ps %.speeds.record: ./analyse-speeds ../layout/ours.redacted.shellvars
+               ./$< $*
 
 %:             %.gen
                ./$^ $o
 
-convert .stopping to appropriate .speeds.record
-
 either only POLARITY when we've had POLARISED or delete
  that bit from the docs
 
 
 acceltime=100000
 deceltime=30000
 
+exec 3>$o.stopping.tmp
+stops-from () {
+       printf >&3 '%d %d %s\n' $1 $(( $2 )) $3
+}
+. ../layout/ours.redacted.shellvars
 . $train.manual
+exec 3>&-
+
 for f in address length nondetfore nondetrear acceltime deceltime; do
 #                 [mm]   [mm]          [mm]    [ms]        [ms]
        eval "v=\$$f"
 plot '$o.all.tmp' smooth sbezier
 END
 
-perl <$o.table.tmp >$o.record.tmp -ne '
+sort -rn <$o.stopping.tmp >$o.stopping-sorted.tmp
+
+perl <$o.stopping-sorted.tmp >$o.record.tmp -ne '
+ BEGIN {
+       $last_step= 127;
+       $last_stoptime= undef;
+
+       print   "train '$train' is '$address'".
+               " '$nondetfore'".
+               "+'$(( $length - $nondetfore - $nondetrear ))'".
+               "+'$nondetrear'\n"
+                       or die $!;
+ }
+       die unless m/^(\d+)\s+(\d+)(?:\s+([-.0-9]+))?\s*$/;
+       ($step,$stopdist,$stoptime) = ($1,$2,$3);
+       die unless $step < $last_step;
+       if (defined $stoptime) {
+               $stoptime= eval $stoptime; defined $stoptime or die "$@ ?";
+       } else {
+               die unless $last_stoptime;
+               $stoptime= $last_stoptime;
+       }
+       printf "train '$train' stops %3d: %4d %5d\n", $step,$stopdist,
+               $stoptime*1000
+                       or die $!;
+       $last_step= $step;
+       $last_stoptime= $stoptime;
+'
+
+perl <$o.table.tmp >>$o.record.tmp -ne '
  BEGIN {
        use IO::Handle;
        $nxt= 1;
        $max= $speed;
        $nxt++;
  END {
-       warn "warning: '$train': decreases at steps @decreases\n"
+       die "'$train': decreases at steps @decreases\n"
                if @decreases;
        $steps= $nxt-1;
-       warn "warning: '$train': expected 126 steps, found $steps\n"
+       die "'$train': expected 126 steps, found $steps\n"
                unless $steps==126;
-       print   "train '$train' is '$address'".
-               " '$nondetfore'".
-               "+'$(( $length - $nondetfore - $nondetrear ))'".
-               "+'$nondetrear'\n"
-                       or die $!;
-       sub calcwait ($$) {
-               my ($step,$wholetime) = @_;
-               return 0 if $step<0 || $step>=$steps;
-               return $wholetime * 1000 *
-                       ($speed[$step+1] - $speed[$step]) / $max;
-       }
        for ($step=0; $step<$nxt; $step++) {
-               printf  "train %s step %d=%f %d/%d\n",
-                       "'$train'", $step, $speed[$step],
-                       calcwait($step-1,'$acceltime'),
-                       calcwait($step,'$deceltime')
+               printf  "train %s step %d=%f\n",
+                       "'$train'", $step, $speed[$step]
                                or die $!;
        }
        STDOUT->error and die $!;
  }
 '
 
-rm $o.all.tmp
+rm $o.{all,stopping,stopping-sorted}.tmp
 
 for f in ps record; do
        mv -f $o.$f.tmp $o.$f
 
 void record_train_home(Train *tra, int backw, Segment *seg);
 void record_train_step_speed(Train *tra, int step, double speed);
 void record_train_stopregime_count(void);
-void record_train_stopregime(Train *tra, double speed, int xs, int ts);
+void record_train_stopregime(Train *tra, int step, int xs, int ts);
 void record_seg_has(Segment *seg, int backw, Train *tra);
 void record_seg_at(Segment *seg, const char *movposcomb_pname);
 void record_feature_nmrafeat(FeaturesFeature*, FeaturesAddr*, int num);
 
        |       TRAIN train STEP NUM '=' dbl
        {         if ($2) record_train_step_speed($2,$4,$6);
        }
-       |       TRAIN train STOPS dbl NUM NUM
+       |       TRAIN train STOPS NUM ':' NUM NUM
        {         if (!trains) record_train_stopregime_count();
-                 else if ($2) record_train_stopregime($2,$4,$5,$6);
+                 else if ($2) record_train_stopregime($2,$4,$6,$7);
        }
        |       SEG seg HAS backwards train
        {         if ($2 && $5) record_seg_has($2,$4,$5);
 
  * File format:
  *
  *  max-trains num
- *  train <trainpn> at [-]<foredetectpn>:<maxinto>+-<uncertainty>
  *  train <trainpn> is <addr> <head>+<detectable>+<tail>
- *  train <trainpn> step <step>=<speed>
- *  train <trainpn> step <step> at <distance> after <milliseconds>
  *  train <trainpn> home [-]<segpn> [-]<segpn> [-]<segpn>
+ *  train <trainpn> step <step>=<speed>
+ *  train <trainpn> stops <step> at <distance> after <milliseconds>
  *  seg <segpn> has [-]<ownerpn>
  *  seg <segpn> at <movposcomb>
  *  feature <trainorfeatpn> <letter> is <addr> <nmranum>
   rangebufsz++;
 }
 
-void record_train_stopregime(Train *tra, double from, int xs, int ts) {
+void record_train_stopregime(Train *tra, int step, int xs, int ts) {
   Train *other;
   SpeedRange *new;
   int i;
 
+  if (step<1 || step>126) record_yyerror("stop regime step out of range");
+
   if (rangebufused >= rangebufsz)
     record_yyerror("more speed points on 2nd pass!");
 
   new= &tra->speedregimes[tra->n_speedregimes++];
   rangebufused++;
 
-  new->speed= from;
+  new->speed= step;
   new->xs= xs;
   new->ts= ts;
 }
 
 static void speeds_postprocess(void) {
   TRA_IV;
-  int step;
+  int step, i;
 
   FOR_TRA {
     if (!tra->speedregimes || tra->speedcurve[1]<0) {
 
     qsort(tra->speedregimes, tra->n_speedregimes,
          sizeof(*tra->speedregimes), speedregime_compare);
-    if (tra->speedregimes[tra->n_speedregimes-1].speed
-       <= tra->speedcurve[SPEEDSTEPS-1])
+    if (tra->speedregimes[tra->n_speedregimes-1].speed < 126)
       die("config: speed curve missing top point for %s", tra->pname);
 
     for (step=1; step<=SPEEDSTEPS; step++)
       if (tra->speedcurve[step] < 0)
        die("config: speed curve for %s missing step %d", tra->pname, step);
     tra->speedcurve[0]= 0;
+
+    for (i=0; i<tra->n_speedregimes; i++) {
+      step= tra->speedregimes[i].speed;
+      tra->speedregimes[i].speed= tra->speedcurve[step];
+    }
   }
 }
 
 
 length=1119
 nondetfore=29
 nondetrear=29
+
+# in tests with CV4 = 3:
+stops-from     126     $lX5+$lX6+$lX8P0+$lX10-123      34.9-28.4
+stops-from     100     $lX5+$lX6+321                   29.1-23.7
+stops-from     70      340                             28.8-25.1
+stops-from     30      62                              24.0-22.2
+stops-from     10      10                              19.7-18.5
+stops-from     1       1
 
+++ /dev/null
-# in tests with CV4 = 3
-
-stops-from     126     $lX5+$lX6+$lX8P0+$lX10-123      34.9-28.4
-stops-from     100     $lX5+$lX6+321                   29.1-23.7
-stops-from     70      340                             28.8-25.1
-stops-from     30      62                              24.0-22.2
-stops-from     10      10                              19.7-18.5
-stops-from     1       1