I was wondering if anyone could provide me with the formula simutrans uses to calculate acceleration / speed.
What I want to know (mathematically) is how gear, power, and weight combine so that I can calculate the number of tiles it takes a convoy to reach top speed on straight, flat track.
Can anyone help?
this is in the source code, in simconvoi.cc, convoi_t::calc_acceleration, lines 448ff
Given I can't read C code, but am used to other languages, will I be able to understand that and be able to turn it into a formula for something like Excel? If it's going to require deep knowledge of C, then can someone decode it into maths for me please?
this code should calculate the number of tiles a convoi can drive on full-speed in one game month, to give you an impression about the involved scaling of quantities:
tiles_per_month = (kmh_to_speed(max_kmh) * ticks_per_tag) >> (8+12); // 12: fahre_basis, 8: 2^8 steps per tile
- kmh_to_speed - just a transformation: (((speed) << 10) / 80)
- max_kmh - max speed in kmh
- ticks_per_tag - ticks per month, configurable in *.tab, default 18
- << and >> are shift operations: a<<b = a * 2^b, a>>b = a/ 2^b
here is the most relevant part of the code for you:
/* deacceleration due to friction */
deccel = ( ( (akt_speed*weight)>>6 )*(akt_speed>>2) ) / 25 + (weight*64)
/* resulting acceleration */
accel = (sum_gear_und_leistung - deccel) / weight
- akt_speed ... current speed
- sum_gear_und_leistung ... sum over all vehicles in convoi of their gear multiplied by their power
- weight ... weight of the convoi
So I guess, ****uming no friction would give
min_number_of_tiles_til_top_speed = ( kmh_to_speed(max_kmh) )^2 / ( 2* (sum_gear_und_leistung/weight -64) *2^20 )
which would yield a lower bound on the needed tiles
Thanks. I'm ****uming that no friction is incurred on straight track then?
No, even there, friction (deccel in the code above) depends quadratically on the velocity, which makes it impossible to calculate the quantity you want.
Oh OK. One more question - what are the units of akt_speed? km/h? tiles per tick? anything else?
akt_speed is measured in internal units, the methods kmh_to_speed and speed_to_kmh do the transformation between internal unit and km/h.
you could also use an N-term approximation:
tiles = 0
for i=1 to N
v0 = kmh_to_speed(max_kmh) * (i-1)/N
v1 = kmh_to_speed(max_kmh) * i/N
tiles = tiles + (v1^2-v0^2) / 2 / (sum_gear_und_leistung/weight -64 -v0^2 / 6400) / 2^20
end
This gives a lower bound on the number of tiles. Using -v1^2 in the denominator gives upper bounds. Just play with different values of N (10,100,1000..).
However, max_speed must be chosen smaller than the maximal possible speed of the convoi given its weight and power, otherwise this sum tends to be infinity I suspect.
OK thanks. I might change tack from the tiles to max speed approach (I was trying to use it as a way of getting acceleration right on pak128.Britain), but definitely helpful, as I need to make sure each convoy has enough power to reach a sensible speed (presumably can easily derive that from calculating the akt_speed at which accel = 0?
The max_speed a convoi can go at full load is displayed in the depot gui.
Clever - I'd never noticed that - is it new? Then again I haven't played for 2 years!
Even so I would still like a formula so I can just use it in a spreadsheet rather than recompiling sources and reloading simutrans every time I change the power or gear... I think I can probably do what I want now.
so this could allow also mph and knots for ships, right?
From James, earlier, somewhere else:
Unfortunately it isn't only calling arbitrary conversion everywhere instead of calling conversion to kph. Throughout the code, internal units and kph are mixed. You can define internal_to_whatever, but that will not fix anything since in some places are hardwired computations in kph which won't go away just like that.
I already tried once (http://forum.simutrans.com/index.php?topic=1002.0;all) and it is probably not impossible task, just really really unsatisfying to the coder, since relatively a lot of work would go into chasing all the places and ensuring nothing critical is broken - and what you get? Different number and three letters.
max_kmh = sqrt( (power/weight-64) * 6400 ) * 80/1024
this formula is correct for large values of max_kmh. Due to rounding errors it can happen, that this formula gives small max_kmh (1 or 2 km/h) but in simutrans the vehicle cannot move.
Thanks!
Couldn't you just replace the speed_to_kmh(uint32 speed) and kmh_to_speed(uint32 kmh) macros with functions like:
enum speed_type { kmh, mph, knotts };
uint32 speed_to_units(uint32 speed, speed_type = kmh);
and only activate the second parameter in cases where only the UI is affected?
I can believe it's unsatisfactory! I would say, though, that for sure the code would be cleaner if the conversion happened only when UI is involved. It could even allow different units in the same setup (e.g. kph for vehicles and knots for ships).
maybe those more involved in unit change (Britts and Americans) should look into it: for sure for them it would be more satisfactory ;)
I don't think both of you understood what I meant. It is impossible to write this cleanly by doing only display stuff. First the program would have to use consistently internal units everywhere. Then you can just generalize the conversion routine for more speed units. Otherwise you'll have to write stuff like
internal_to_units(kmh_to_internal(value), unit_type)
which isn't exactly the epitome of "nice" (I would rather go with "pointless" in that case). There is also the danger of losing precision in chained conversions, no idea if it's significant enough or not... of course anyone can probably go and make it just work like this, without much regard to cleanliness.
In short, the issue is not only making it work, but also making it serviceable under the hood.
VS, my point is that changing the cose to use internal units consistently would help cleanliness, regardless of multiple units. So it could be worthy per se.
on the other hand, it would make multi-unit possible if not easy, so that those more interested in multi-unit should first help changing kph to int units all through the code and then adding multi-units UI.
Oh! I'm sorry, I didn't realize what you meant here.