News:

Simutrans.com Portal
Our Simutrans site. You can find everything about Simutrans from here.

km/h, tiles, steps and ticks.

Started by inkelyad, August 01, 2011, 03:59:42 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

inkelyad

Please check my math.

Terminology from simunits.h

100 tiles = 256000 steps = 104857600 "yards"

100 km/h = (100 << 10) / 80 "yards"/tick = 1280 "yards"/tick.

For tile/km = 1 we have

1h = 104857600/1280 = 81920 ticks.
3min = 81920/20 = 4096 ticks

30 * ( tenth of minute ) = 4096 ticks

tenth of minute = 4096/30 ticks

So instead of

void convoi_t::laden() {
...
sint64 journey_time = ((arrival_time - last_departure_time) * 100) / 53248;

should be

sint64 journey_time = ((arrival_time - last_departure_time) * 30) / 4096;


EDIT:
I have found answer to my question. Vehicle speed is not scaled. Here is the code:

void convoi_info_t::zeichnen(koord pos, koord gr)
...
sprintf(tmp, translator::translate(min_speed == max_speed ? "%i km/h (max. %ikm/h)" : "%i km/h (max. %i %s %ikm/h)"),
                   speed_to_kmh(cnv->get_akt_speed()), min_speed, translator::translate("..."), max_speed );


Vehicle with speed 1280 yard/tick will travel 100 tiles in 81920 ticks, we will see its speed as 100 km/h.
But odometer will be different for different distance_per_tile.

What a mess.

EDIT2:
There is big loss of precision in increment_odometer. It is accamulated over time.
How to see it: Run vehicle for 100 tiles and compare odometer value with (tiles to distance value).

I suggest changing odometer unit to steps (instead of km).

jamespetts

#1
I must confess, I do not now recall the precise scaling that I worked out as between in-game km/h, steps and tiles - it took a long time to calculate, I do recall that, however. Mathematics is not my forte (which presents somewhat of a challenge when programming, but I digress).

I wonder whether there may be some conceptual confusion here, however. There are two completely separate measures of time in Simutrans (both Standard and Experimental): (1) that by which km/h is measured; and (2) that by which months and years are measured. In Experimental, the first measure is expanded to be used for journey and waiting times, and all that goes with that (the calculation of journey times is implicit in Standard, but made explicit and used in routing in Experimental). All things things that happen monthly are adjusted according to the bits per month setting such that, no matter what the bits per month setting, those things (invariably involving the payment of money) are functionally equivalent no matter how long that a "month" lasts. Monthly maintenance is a good example: for a month length of X and a monthly maintenance of Y, the bits per month adjustment system ensures that a month length of 2X will give rise to monthly maintenance of 2Y, which means that for any given unit of time in the first measure, the same amount of "monthly" maintenance is expended.

The distance per tile setting uses similar normalisation logic: if the distance per tile is X and the time that it takes a convoy to travel Y tiles at Z speed is N, then if the distance per tile is 2X, the time that it will take a convoy to travel Y tiles at Z speed is 2N (where "time" means here time in the second measure described above). The combination of normalisation methods for both measures of time mean that the same vehicle movement code and the same visual appearance of vehicle speed can be used no matter what the bits per month or distance per tile setting. This is important from a usability perspective, as the original authors of Standard tuned the vehicle movement code quite precisely to make it appear right at the default running speed.

As to the odometer - what distance per tile value did you use when you checked its loss of precision? The idea is that it measures tiles traversed and converts the tiles to km for display purposes.

Edit: Incidentally, as to this:

QuoteSo instead of
Code:

void convoi_t::laden() {
...
sint64 journey_time = ((arrival_time - last_departure_time) * 100) / 53248;

should be
Code:

sint64 journey_time = ((arrival_time - last_departure_time) * 30) / 4096;

the latter is about 7 times greater than the former (100 / 53248 = 0.00187...; 30 / 4096 = 0.00732...). I do not think that things are off by a factor of seven, are they?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

Quote from: jamespetts on August 01, 2011, 09:38:32 PM
There are two completely separate measures of time in Simutrans (both Standard and Experimental): (1) that by which km/h is measured; and (2) that by which months and years are measured.
Yes. My calculations is for first timescale.
Quote
The distance per tile setting uses similar normalisation logic: if the distance per tile is X and the time that it takes a convoy to travel Y tiles at Z speed is N, then if the distance per tile is 2X, the time that it will take a convoy to travel Y tiles at Z speed is 2N (where "time" means here time in the second measure described above).
It means, that ticks to minute conversion should use distance per tile somewhere.
Quote
As to the odometer - what distance per tile value did you use when you checked its loss of precision? The idea is that it measures tiles traversed and converts the tiles to km for display purposes.
250 m/tile

See attach. Hit 'Pause' when bus is at stop B. Now A to B distance is 100 km. Odometer value is only 73 km.

Quote
the latter is about 7 times greater than the former (100 / 53248 = 0.00187...; 30 / 4096 = 0.00732...). I do not think that things are off by a factor of seven, are they?

That why I asked about my math.

jamespetts

Ticks to minutes conversion does indeed use distance per tile (indeed, the name "distance per tile" was not originally used; the original name was something like "distance time factor" or the like).

Thank you for the saved game - I shall look into that when I have time. Might I ask - what pakset is it?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

#4
self-compiled Pak128.Britain-Ex
Quote from: jamespetts on August 02, 2011, 07:43:06 AM
Ticks to minutes conversion does indeed use distance per tile
Um. Where? It looks like connexion-table minutes is something different (thrid time scale? Brrr)

We should create static karte_t::ticks_to_tenth_of_minute and use it through code.

Quote
Thank you for the saved game - I shall look into that when I have time. Might I ask - what pakset is it?
It is self-compled pak128.Britain-Ex.

EDIT:About odometer bug. I think you shoud use total_steps instead if replace steps_since_last_odometer_increment. It is less confusing and it will not accumulate rounding error.

I am wrong here. It will not help(I have tested it). It looks like increment_odometer is not called as often as it should. It is not true(?) but it looks like it.


jamespetts

Hmm, that is odd. increment_odometer() is called whenever hop() is called; but it seems as though hop() is not called evenly: if one turns on the display of tile boundaries, one will see that it is sometimes called when the vehicle is just about to cross a tile boundary, sometimes when it is part way accross, and sometimes when it has crossed it fully and is nearly at the next boundary. Combined with the fact that when a vehicle traverses a tile, reverses, then traverses the tile again, hop() is only called once, this seems to lead to at least part of the inaccuracies.  However, I am not sure why hop() is performing erratically in the first place, as the code that calls hop(), being vehikel_basis_t::fahre_basis(uint32 distance), is not code that I have ever modified.

Edit: As to your question of where the distance per tile is set in journey time calculation, see line 684 of path_explorer.cc:


const uint32 journey_time_adjustment = (world->get_settings().get_meters_per_tile() * 6) / 10;
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

#6

Breakpoint 1, convoi_t::increment_odometer (this=0xbdc23f8) at simconvoi.cc:683
683 steps = vehikel_t::get_diagonal_vehicle_steps_per_tile();
(gdb) p fahr[0]->get_steps()
$1 = 252 '\374'

On a straight track.

Edit:
From vehikel_basis_t::fahre_basis:

// Update internal status, how far we got within the tile.
steps = steps_target;


I think that

   if(fahr[0]->get_steps() != 255)
       {
           // Diagonal
           steps = vehikel_t::get_diagonal_vehicle_steps_per_tile();
       }

is not right way do add tile length; And this commentary in vehicle/simvehikel.h

  // number of steps in this tile (255 per tile)
  uint8 steps, steps_next;

is somewhat misleading.

EDIT2:
Correct way seems to be:
1) use total_steps as odometer. Convert to km when necessary.
2) Don't check tile length in convoi_t::increment_odometer, just add fahr[0].steps_next + 1 ;
Or
1) use 'yards' in odometer
2) remove increment_odometer from hop() call chain. Put it at the end of vehikel_basis_t::fahre_basis.
 Use calculated distance_travelled here.

jamespetts

Inkelyad,

I have pushed a first attempt at a fix for at least part of this problem; I am not sure whether it covers it completely, but I should be interested in your comments.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

Quote from: jamespetts on August 03, 2011, 06:55:44 PM
I have pushed a first attempt at a fix for at least part of this problem; I am not sure whether it covers it completely, but I should be interested in your comments.
It is wrong for same reason. fahr[0].steps is _not_ length of current hop.

Can you test my suggestion from Standard topic
Something like this:


int hop_counter = 0;
while(steps_target>steps_next  &&  hop_check()) {
..
   hop_counter +=1;
..
}
if (hop_counter) {
   hop((steps_next+1) * hop_counter)
}

jamespetts

Hmm - but I don't use fahr[0] steps except to detect a diagonal, which is now done correctly (at least according to my testing, when all straight tiles had "steps" of at least 200, and all diagonal tiles had "steps" of less than 200).
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

Quote from: jamespetts on August 03, 2011, 07:17:21 PM
Hmm - but I don't use fahr[0] steps except to detect a diagonal, which is now done correctly (at least according to my testing, when all straight tiles had "steps" of at least 200, and all diagonal tiles had "steps" of less than 200).
I think fahr[0].steps can be arbitrary small. Vehecle can hop "just a a little farther then tile edge". Then see "Update internal status, how far we got within the tile."

Edit: you can test it. Set breakpoint inside 'if' and try different vehicles.

And why bother with guessing steps. We have perfectly correct calculations inside fahre_basis.

jamespetts

Sorry for the delay in the reply on this. Perhaps I am being dim, but can I clarify - what exactly would one do with the passed parameter inside hop()? What does this number represent? Is this the number of tile boundaries crossed?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

inkelyad

Increment_odometer needs number of steps. Instead of guessing it, pass it fahre_basis -> hop(steps) -> Increment_odometer(steps)

inkelyad

My own version for odometer fix. Maybe you like it better. I think it is more clear then guessing hop size.

jamespetts

This seems to work well - incorporated. Thank you!
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Quote from: inkelyad on August 01, 2011, 03:59:42 PM
Vehicle with speed 1280 yard/tick will travel 100 tiles in 81920 ticks, we will see its speed as 100 km/h.
But odometer will be different for different distance_per_tile.

What a mess.

"What a mess" is right.  The creation of simunits.h was only step one in untangling this mess.  I have been hoping to eventually make it not-a-mess, by causing Standard to understand the concepts of distance and time, and having speed conversions be *solely* based on distance and time, but I'm not nearly there yet.