[1.1.91] Train air resistance is calculated incorrectly
Posted: Mon Oct 09, 2023 10:25 pm
A log: https://pastebin.com/9dmBKmSH
As it is now, since we're trying to approximate a quadratic function with a linear one, we can either 1. underestimate the air resistance and have trains be able to continue accelerating and reach much higher top speeds, or 2. overestimate the air resistance and have trains accelerate from a stop extremely slowly.
Reference code from the wiki:
Let's assume the following units that I feel are unambiguous:
The more ambiguous units:
For last, most important line in question, how can we algebraically manipulate this to match the previous lines (of the form speed = speed + acceleration * dt)? Distributing the multiplication by train_speed, we get:
Since we know the units for train_speed and train_weight, we can conclude that air_resistance_of_front_rolling_stock has units of "mass / time" (To convince yourself this is the case, substitute the units in, remembering the trailing delta-T, and observe that (m/s) * (kg/s) * (1/kg) * s = m/s, which is compatible with train_speed).
I hope by this point you can agree that something is definitely wrong. Specifically, the real equation for the drag force is proportional to the velocity squared (along with air density, cross-sectional area, and drag coefficient which can be baked into the air_resistance_of_front_rolling_stock constant with new dimensions mass / distance).
As far as I know I can't modify these equations in Lua to test the changes, but the existing coefficient should probably be increased to counteract the additional multiplication of the speed (I assumed an average speed of 100km/h, and that the speed variable is measured in meters / tick). It can of course be tweaked further to get as close as possible to the existing train behavior.
The Problem
Air resistance should be proportional to velocity squared, but it is currently only proportional to velocity.Symptoms
In vanilla, trains accelerate more than they should at high speeds and don't accelerate as much as they should at low speeds. With the max_speed cap of ~300km/h this is less noticeable than it otherwise would be; but removing the hard cap and relying on air resistance to cap the speed (using a mod that changes properties of RollingStockPrototypes, see https://mods.factorio.com/mod/ConfigTra ... icationsMU) makes the problem much worse: a train with N locomotives goes N times faster than a single locomotive!As it is now, since we're trying to approximate a quadratic function with a linear one, we can either 1. underestimate the air resistance and have trains be able to continue accelerating and reach much higher top speeds, or 2. overestimate the air resistance and have trains accelerate from a stop extremely slowly.
Corroborating quotes
These are some quotes indicating this is a real issue. Koub and Optera even seem to assume air resistance is correctly calculated proportional to velocity squared, when it actually isn't!Koub wrote: Tue Jun 18, 2019 5:40 am the difference further increases, due to the fact that air drag is proportional to the squared velocity, while rolling resistance is independant from speed.
Optera wrote: Tue Oct 17, 2017 5:24 pm At some point air_resistance becomes more pronounced than weight resulting in a nice curve.
[...] setting max_speed to higher values is the correct test to find out drag induced speed limits.
BlueTemplar wrote: Fri Jul 12, 2019 1:16 pm mass has no (direct) effect on top speed, only drag has (aerodynamic and wheel friction*). And drag depends solely on the shape of the object and the density of the fluid it's moving through. An extreme case is vacuum, with no top speed in newtonian mechanics.
danatron1 wrote: Sun Jul 07, 2019 3:24 pm That would make sense for justifying a longer stopping distance, but not a top speed. The energy input (force) is the same, so surely each train would have the same kinetic energy, but not the same top speed (F=MA).
Dimensional analysis
Factorio clearly strives to get fundamental relations between units correct (energy vs power vs heat vs efficiency, velocity vs acceleration vs force vs weight, etc). However, looking at the air resistance component to the train speed equation we can see that it immediately fails under simple dimensional analysis! This means that the application of air resistance to the train speed each tick does not make physical or in-game sense.Reference code from the wiki:
Code: Select all
train_speed = max(0, abs(train_speed) - train_friction_force ÷ train_weight)
train_speed = train_speed + (10 × number_of_locomotives_in_moving_direction × fuel_acceleration_bonus ÷ train_weight)
train_speed = train_speed × (1 - air_resistance_of_front_rolling_stock ÷ (train_weight ÷ 1000))
- train_speed :: distance / time (speed)
- train_weight :: mass
- train_friction_force :: mass * distance / time^2 (force)
The more ambiguous units:
- number_of_locomotives_in_moving_direction :: mass * distance / time^2 (force)
- fuel_acceleration_bonus :: unitless
- air_resistance_of_front_rolling_stock :: ???
For last, most important line in question, how can we algebraically manipulate this to match the previous lines (of the form speed = speed + acceleration * dt)? Distributing the multiplication by train_speed, we get:
Code: Select all
train_speed = train_speed - train_speed × air_resistance_of_front_rolling_stock ÷ (train_weight ÷ 1000)
I hope by this point you can agree that something is definitely wrong. Specifically, the real equation for the drag force is proportional to the velocity squared (along with air density, cross-sectional area, and drag coefficient which can be baked into the air_resistance_of_front_rolling_stock constant with new dimensions mass / distance).
Suggested (backwards-compatible) fix
The last line of the code should instead look like this:Code: Select all
train_speed = train_speed - 500 × train_speed × train_speed × air_resistance_of_front_rolling_stock ÷ train_weight