Do you need help?
Simutrans Wiki Manual can help you to play and extend Simutrans. In 9 languages.

Formula: top_speed = 50 * sqrt ( (power - weight) / weight )

Started by maxim13, August 27, 2022, 01:05:22 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


I think, I want to help comunity for balancing pak128 (or may be do it self).

So I have have researched, that the loaded rail vehicle top speed can be calculated by this formula:

top_speed = 50 * sqrt ( (power - weight) / weight ), if it < max_speed, or just max_speed if greater.

power = power in kW * gear    (defaut gear is 1.0)
weight: is total weight loaded vehicle in ton.
top_speed: already in km/h

Now how did I get this formula:
I was reading the source code and understand:
All values stored as int.
internal_speed is  speed * 64 / 5
internal_gear is  gear * 64 ( 64 = 1.00)
internal_weight calculated in kg
internal_power is power in in kW * internal_gear
Now when we understand value conversion, we can convert th source code formula:

static inline sint32 res_power(sint64 speed, sint32 total_power, sint64 friction_weight, sint64 total_weight)
  sint32 res = total_power - (sint32)( ( (sint64)speed * ( (friction_weight * (sint64)speed ) / 3125ll + 1ll) ) / 2048ll + (total_weight * 64ll) / 1000ll);
  return res;

It will be see like this:

                weight * speed
speed  * ( -------------- + 1 )              weight  * 64
--------------------------------  + -----------------------  = power
           2048                                  1000

The "+1" in the first numerator is needed for rounding up and does not affect the result much, so we can remove it.
now rewrite this formula using conversation from internal value to real (km/h, Kw, t):

(speed *(64/5)) * (weight*1000) * (speed *(64/5)) / (3125 * 2048) + (weight*1000) * 64 / 1000 = power * 64

devide all by 64:

power = weight + weight * speed * speed * 0,0004
and this is exactly the formula at the beginning



good approach!

From the experience of balancing pak192.comic, there's a couple of extra things you might want to add:

 - electric vehicles may be cheaper than those running by fossile fuels
 - different ways may want different costs (because the way itself is cheaper etc)
 - with speedbonus, inflation might be a thing too

if it helps, the balancing and pricing script I wrote for pak192.comic is open source and available here:
code quality and documentation might not be at best practice tho.


There is also an Excel sheet for pak64: which also uses this formula. However, you must also use the speed bonus, or the engines will become useless for passenger use, or generate way to much income.

Thus pak46 uses passengers for most rail engines. It calculates the maximum load the engine can pull, then finds the number of cars, and also calculates the speedbonus for pax for this engine at intro and retire year. Then it finds the maximum number of fill cars the engine can pull and from that the maximum revenue per tile for the maximum train at intro and retire year.

The actual cost per tile is then set to 1/10 of that maximum revenue, which usually results in a non-negative income even in the retire year. If the income in the retire year is negative, the costs are reduced. Trucks pay 1/5 of the maximum income per tile and ships and planes 45/100 (since almost no way maintenance).

Very slow but powerful engines are balanced for coal, but there are just three engines in pak64 I think, one is the E44.

All other specialised freight vehicles are balanced with the cheapest load in their category (or for piece good for medicine because of the speed bonus).

Indeed, electric vehicles should be cheaper, since more maintenance is needed. However, in practive electric vehicles tend to be more powerful and faster, and hence generate a higher income per tile and time intervall, which offsets these cost.


For engines we actually just have a value and a speedbonus on the good named "none".
The pricing script just uses that for every power output there is.


A speedbonus for None? Also then that script will fail on railcars ... I think automatism is very hard, since then there is no distinction possible between freight and passenger engines, which one usually has to make oneself. (THen of course one could put them into different folders.)


Script does just fine, even with rail cars 8) - and as a bonus there's also a version handling multiple goods for single vehicles for extended.

Simutrans doesn't care for the speedbonus / price for "none", and it's a convenient way to adjust it.

And honestly: adjusting engines for 8% speedbonus seems to work out quite well in the game.
At least I haven't had people complaining about it. And while playing the game, at least I don't really feel like the costs should be distributed even broader over the different speeds.


I would like to note upon formulas of initial post only, since i have zero knowledge upon code.
I miss the proof of why the suggested formula is better than existing one. For the
QuoteThe "+1" in the first numerator is needed for rounding up and does not affect the result much, so we can remove it.
the initial developer would have his reasons to add this and a more complete math or code explanation would prevent future developers to try insert it back once again.
Minimum and maximum functions belong to some decision making algorithm so it belongs to some AI decision maker. If physic laws are to be simulated, power and resistances are enough to determine max speed without those functions. I find these formulas accurate and i just read this interesting one.
On initial post code, as it is inserted, i see both "friction_weight" and "total_weight". How they converted, in simplified formula, in just "weight".
As i read the inserted code i understand that "res" variable is the available power to be used for further acceleration of a vehicle.The initial post develops the code assuming that the initial formula is right. Why? Would be it safer if we judge the rightness of initial formula first?
  • We have "air resistance". Affects mostly planes, then fast vehicles, then slow vehicles and trains. Can be used with modified coefficients to ships too, for the resistance due to creation of water waves. This could have the form "K_air*v^2". "K_air" depends only on vehicle and not on the road surface.
  • We have "rolling resistance". Affects road and rail vehicles. Could have the form "K_friction*v". "K_friction" depends both on vehicle and road.
  • We have "Gradient Resistance". Affects road and rail vehicles. Could have the form "weight*sin(theta)". "theta" depends  only on road or rail.
Lets ignore the "gradient resistance" that might be used only to extended simutrans. Then the available power to accelerate would be
The initial explained formula misses the velocity from last summation term. That errata is of no significant since it concerns only the explaination of code but the code itself should use the "friction_weight" on "speed" term only while the "total_weight" (that i expect to be analogous to the crossing area of the vehicle) should be related to "speed^2" only.
That inconsistency makes me skeptic and i hope that the initial code is right and the copy of it on initial post contains another errata too.


The physically correct formula does not look nice in Simutrans, since the scales are not to real scale. Or one would need gigantic maps (like the extended approach).

I tried it of course (my PhD was in Physics, and I lectured even physics at university level). But I settled on this one, which gave a decent acceleration of most vehicles to watch and still had a top speed limited by weight and was very easy to implement in terms of CPU power.

The real formula would need a lot of other parameters like drag coefficients, friction, tractive effort, etc. which would make vehicles even harder to compare than a single number like "power".

The formula you show propose needs a resistance depending on the weight, or an empty convoy would accelerate similar to a loaded one.