Car Physics - Model 2: Load Transfer Without Traction Limits
Table of Content
Block
- Main reference: Marco Monster’s Car Physics
- Main Github repo: duy-phamduc68/Car-Physics.
Roadmap
Block
- Model 1: Longitudinal Point Mass (1D)
- Straight Line Physics
- Magic Constants
- Braking
- Model 2: Load Transfer Without Traction Limits (1D)
- Weight Transfer
- Model 3: Engine Torque + Gearing without Slip (1D)
- Engine Force
- Gear Ratios
- Drive Wheel Acceleration (simplified)
- Model 4: Wheel Rotational Dynamics (1D)
- Drive Wheel Acceleration (full)
- Model 5: Slip Ratio + Traction Curve (1D)
- Slip Ratio & Traction Force
- Model 6: Low-Speed Kinematic Turning (2D)
- Curves (low speed)
- Model 7: High-Speed Lateral Tire Model (2D)
- High Speed Turning
- Model 8: Full Coupled Tire Model (2D)
Model 2 Recap
Okay so the good news is that model 2 is actually really simple, I only added it because model 1 (the starting point) and model 3 is so complex, yet model 2’s theme: load transfer, is so essential, yet also simple and distinct from model 1 and 3 so i couldn’t really merge them together. This will probably be a short post.
Basically, if model 1 says that the car is a single point-mass, demonstrated in simulator 1 by ticking “True Form” here:

Then in model 2, the point mass is now assumed to sit inside a rigid body with two axles, allowing us to compute how the weight shifts between the front and rear wheels.

However, these weight shifts WON’T affect motion yet until model 3, which is why our master ODE will remain the same:
Block
Core Math
Total Vehicle Weight
We now introduce gravity:
Block
Where $ g = 9.81 $ m/s2. Assuming $ M = 1500 $ kg, $ W \approx 14715 $ N (newton).
We now assume the CG (Center of Gravity) sits somewhere between the axles. Then let:
L = wheelbase
b = distance from CG → front axle
c = distance from CG → rear axle
MarkdownThese should satisfy b + c = L
Static Weight Distribution
- Front axle
Block
- Rear axle
Block
If you assume 50/50 (b = c = L/2), then:
Block
Dynamic Weight Transfer
Acceleration produces a pitching moment:
moment = Ma × h
Markdownwhere
h = CG height above ground
Markdown
This produces a load shift:
Block
Final Axle Loads
- Front axle:
Block
- Rear axle:
Block
The loads always sum to total weight:
Block
So model 2 only redistributes weight. It never creates or removes it.
Sign Behavior
Acceleration (a > 0)
front load decreases
rear load increases
MarkdownBraking (a < 0)
front load increases
rear load decreases
MarkdownNew Parameters
These are the only new constants you need:
g gravity
L wheelbase
h CG height
b CG → front axle
c CG → rear axle
MarkdownIn a simplified version you can reduce this to:
g
L
h
Markdownby assuming
b = c = L/2
MarkdownMinimal Implementation Logic
Conceptually:
a = F_net / M
W = M*g
dW = (h/L)*M*a
Wf = W/2 - dW
Wr = W/2 + dW
PythonThat is the entire model 2 math.
Interactive Plots
Basically for model 2, our previous model 1 forces and values will affect values of model 2, but values of model 2 wont affect values of model 1 yet.
Or another way to phrase it:
BlockModel 2 computes derived values from model 1.
Those derived values are:
W = Mg
ΔW = (h/L) M a
Wf = static_front − ΔW
Wr = static_rear + ΔW
MarkdownNow for some interactive plots, assume we still use these constants:
# === CONSTANTS (from Model 1) ===
M = 1500 # kg
F_ENGINE_MAX = 3000 # N
C_RR = 13.0 # kg/s
C_DRAG = 0.43 # kg/m
C_BRAKING = 12000 # N
PythonAnd we have some new constants:
# === CONSTANTS (from Model 2) ===
g = 9.81 # m/s^2 gravity
L = 3.0 # m wheelbase
h = 0.5 # m CG height (from ground up)
b = 1.7 # m CG → front axle
c = 1.1 # m CG → rear axle
PythonAnd our master ODE remains unchanged:
Block
Front vs Rear Load vs Acceleration
Wheelbase (L = b + c): 3.00 m
Static Front Load: 7358 N | Static Rear Load: 7358 N
Inspect the plot, even before acceleration, this is already a rear-biased static car (CG is usually closer to rear axle than front axle but in the simulator we are going to default to the c = b = L/2 assumption, customizable of course).
With $W = Mg = 1500 \cdot 9.81 = 14715$ N:
Block
Block
Which matches the panel under the plot exactly.
The two linear lines in the plot tell us that the slope magnitude here is:
Block
Meaning for every $+1\text{ m/s}^2$ acceleration:
front axle loses ~268 N
rear axle gains ~268 N
MarkdownSo these lines are linear because model 2 is linear in $a$.
At the two ends of the plot:
- At $a = +10$: $W_f \approx 3102$ N, $W_r \approx 11613$ N
- At $a = -10$: $W_f \approx 8459$ N, $W_r \approx 6256$ N
Total always stays the same:
Block
No load is created. It only moves between axles.
The lines intersect where $W_f = W_r$.
For this setup, that occurs at roughly:
Block
So this car needs fairly strong braking before front and rear become equal-load. Before that point (including gentle braking), rear axle is still carrying more load due to static geometry.
This setup make one thing very clear:
BlockCG placement sets your baseline balance, and acceleration only tilts that baseline linearly.
And this is why model 3 matters next: once traction limits are introduced, these load shifts stop being just derived values and start controlling how much force each axle can actually deliver.
Weight Transfer vs Acceleration
Wheelbase (L = b + c): 2.80 m
Max Load Transfer (at 10 m/s²): 2679 N
This plot is actually the cleanest way to see model 2 behavior directly. we have:
Block
So the line slope is about:
Block
Which means:
each +1 m/s^2 acceleration adds about +268 N of rearward transfer
each -1 m/s^2 braking adds about +268 N of forward transfer (shown as negative DeltaW)
MarkdownThe panel showing Max Load Transfer (at 10 m/s²): 2679 N is exactly consistent:
Block
and similarly at the other end:
Block
So this graph is symmetric around the origin and passes through $(0,0)$, because at zero acceleration there is no dynamic transfer.
One subtle but important insight: this particular plot does not care about static front/rear split directly. It only cares about the ratio $h/L$ and mass $M$. In other words, changing $b$ and $c$ individually only affects this line through their sum $L=b+c$.
So the full picture is now:
static distribution is set by b and c
dynamic shift magnitude is set by M, h, and L
MarkdownFinal Takeaways
This section wraps up Model 2: Load Transfer without Traction Limits (1D) by summarizing what was added to the physics model and what role it will play later.
The Load Transfer Equations
Model 2 introduces gravity and vehicle geometry so we can compute how the vehicle weight is distributed across the axles.
Total vehicle weight:
Block
Static axle loads:
Block
Block
Dynamic load transfer caused by acceleration:
Block
Final axle loads:
Block
Block
Subject to the constraint:
Block
The total weight never changes - it only moves between axles.
The Updated Implementation
Importantly, the motion model itself is unchanged. We simply compute additional values after acceleration is known.
# === CONSTANTS (from Model 2) ===
g = 9.81
L = 2.8
h = 0.5
b = 1.7
c = 1.1
class CarModel:
def __init__(self):
self.x = 0.0
self.v = 0.0
def update(self, dt, u, B):
# --- MODEL 1 PHYSICS ---
F_engine = u * F_ENGINE_MAX
F_rr = C_RR * self.v
F_drag = C_DRAG * self.v * abs(self.v)
F_brake = C_BRAKING if (self.v > 0 and B == 1) else 0
F_net = F_engine - F_rr - F_drag - F_brake
a = F_net / M
self.v += dt * a
if self.v < 0:
self.v = 0
self.x += dt * self.v
# --- MODEL 2 DERIVED VALUES ---
W = M * g
dW = (h / L) * M * a
Wf = (c / L) * W - dW
Wr = (b / L) * W + dW
return Wf, Wr
PythonSimulator 2
Simulator 2 with Load Transfer, new sprite, sky at dusk:
![]()
True form:

Moving to Model 3
At first glance, Model 2 might feel almost pointless.
Even though we now compute front and rear axle loads, these values do not influence the vehicle motion yet. The main equation governing acceleration is still exactly the same as in Model 1.
So physically speaking, the simulator still behaves like a rocket or boat: a single thrust force pushes the vehicle forward, and the mass simply accelerates.
What Model 2 really does is introduce geometry into the system.
Instead of a pure point-mass, the car now has:
- a center of gravity
- a wheelbase
- two axles carrying different loads
Acceleration no longer just moves the car forward, it also shifts weight between the axles.
However, this shift is currently just a derived quantity. It does not limit traction, reduce engine force, or change braking capability.
That is why Model 3 is the natural next step.
Once traction limits are introduced, the axle loads computed here will directly control how much force the tires can actually produce. At that point, load transfer stops being a passive visualization and becomes a core part of the vehicle dynamics.
In other words:
- Model 1: the car is a particle with thrust
- Model 2: the particle now sits inside a body with two axles
- Model 3: those axles finally determine how force reaches the ground
And that is where things start to behave like a real car. With that being said, within the Main Github repo: duy-phamduc68/Car-Physics, the entry for simulator 2 will be very similar to simulator 1, so I don’t plan to give it much highlights, the real deal will be in Model 3: Engine Torque + Gearing without Slip (1D), so stay tuned for that :).