##### 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

*RollingStockPrototype*s, 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!BlueTemplar wrote: ↑Fri Jul 12, 2019 1:16 pmmass 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.

##### 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)

*train_friction_force ÷ train_weight*represents acceleration (distance / time^2), but it also has an implicit

*dt*which results in speed, letting us add it to

*train_speed*under our dimensional analysis.

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 :: ???

*10 * number_of_locomotives_in_moving_direction*", I assume the authors meant each locomotive to contribute some fixed force from the engine, leading to the same units as the first line, including the delta-T.

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)
```

*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*).

##### 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
```