Table of Content

  • Table of Content
  • Roadmap
  • Model 2 Recap
  • Core Math
  • Total Vehicle Weight
  • Static Weight Distribution
  • Dynamic Weight Transfer
  • Final Axle Loads
  • Sign Behavior
  • New Parameters
  • Minimal Implementation Logic
  • Interactive Plots
  • Front vs Rear Load vs Acceleration
  • Weight Transfer vs Acceleration
  • Final Takeaways
  • The Load Transfer Equations
  • The Updated Implementation
  • Simulator 2
  • Moving to Model 3
Block

Roadmap

Block

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:

pointmass simulator 1

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.

rigidbody example

However, these weight shifts WON’T affect motion yet until model 3, which is why our master ODE will remain the same:

dvdt=1m(uFmaxBCbrakingCrrvCdragv2)\frac{dv}{dt} = \frac{1}{m} \left( u \cdot F_{max} - B \cdot C_{braking} - C_{rr} v - C_{drag} v^2 \right)
Block

Core Math

Total Vehicle Weight

We now introduce gravity:

W=MgW = M \cdot g
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:

1
2
3
L = wheelbase
b = distance from CG → front axle
c = distance from CG → rear axle
Markdown

These should satisfy b + c = L


Static Weight Distribution

  • Front axle
Wfstatic=cLWW_f^{static} = \frac{c}{L} W
Block
  • Rear axle
Wrstatic=bLWW_r^{static} = \frac{b}{L} W
Block

If you assume 50/50 (b = c = L/2), then:

Wfstatic=Wrstatic=W2W_f^{static} = W_r^{static} = \frac{W}{2}
Block

Dynamic Weight Transfer

Acceleration produces a pitching moment:

1
moment = Ma × h
Markdown

where

1
h = CG height above ground
Markdown

macro monster model 2

This produces a load shift:

ΔW=hLMa\Delta W = \frac{h}{L} M a
Block

Final Axle Loads

  • Front axle:
Wf=cLWhLMaW_f = \frac{c}{L}W - \frac{h}{L}Ma
Block
  • Rear axle:
Wr=bLW+hLMaW_r = \frac{b}{L}W + \frac{h}{L}Ma
Block

The loads always sum to total weight:

Wf+Wr=WW_f + W_r = W
Block

So model 2 only redistributes weight. It never creates or removes it.


Sign Behavior

Acceleration (a > 0)

1
2
front load decreases
rear load increases
Markdown

Braking (a < 0)

1
2
front load increases
rear load decreases
Markdown

New Parameters

These are the only new constants you need:

1
2
3
4
5
g   gravity
L   wheelbase
h   CG height
b   CG → front axle
c   CG → rear axle
Markdown

In a simplified version you can reduce this to:

1
2
3
g
L
h
Markdown

by assuming

1
b = c = L/2
Markdown

Minimal Implementation Logic

Conceptually:

1
2
3
4
5
6
7
a = F_net / M

W  = M*g
dW = (h/L)*M*a

Wf = W/2 - dW
Wr = W/2 + dW
Python

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

Model 2 computes derived values from model 1.

Block

Those derived values are:

1
2
3
4
W  = Mg
ΔW = (h/L) M a
Wf = static_front − ΔW
Wr = static_rear + ΔW
Markdown

Now for some interactive plots, assume we still use these constants:

1
2
3
4
5
6
# === 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
Python

And we have some new constants:

1
2
3
4
5
6
# === 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
Python

And our master ODE remains unchanged:

dvdt=1m(uFmaxBCbrakingCrrvCdragv2)\frac{dv}{dt} = \frac{1}{m} \left( u \cdot F_{max} - B \cdot C_{braking} - C_{rr} v - C_{drag} v^2 \right)
Block

Front vs Rear Load vs Acceleration





Vehicle Specs:
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:

Wfstatic=cLW=1.12.8(14715)5781 NW_f^{static} = \frac{c}{L}W = \frac{1.1}{2.8}(14715) \approx 5781\text{ N}
Block
Wrstatic=bLW=1.72.8(14715)8934 NW_r^{static} = \frac{b}{L}W = \frac{1.7}{2.8}(14715) \approx 8934\text{ N}
Block

Which matches the panel under the plot exactly.

The two linear lines in the plot tell us that the slope magnitude here is:

hLM=0.52.8(1500)267.86 N per (m/s2)\frac{h}{L}M = \frac{0.5}{2.8}(1500) \approx 267.86\text{ N per }(\text{m/s}^2)
Block

Meaning for every $+1\text{ m/s}^2$ acceleration:

1
2
front axle loses ~268 N
rear axle gains ~268 N
Markdown

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

Wf+Wr=14715 NW_f + W_r = 14715\text{ N}
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:

a5.89 m/s2a \approx -5.89\text{ m/s}^2
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:

CG placement sets your baseline balance, and acceleration only tilts that baseline linearly.

Block

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





Vehicle Specs:
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:

ΔW=hLMa=0.52.8(1500)a267.86a\Delta W = \frac{h}{L}Ma = \frac{0.5}{2.8}(1500)a \approx 267.86a
Block

So the line slope is about:

267.86 N per (m/s2)267.86\text{ N per }(\text{m/s}^2)
Block

Which means:

1
2
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)
Markdown

The panel showing Max Load Transfer (at 10 m/s²): 2679 N is exactly consistent:

ΔW(10)267.86102679 N\Delta W(10) \approx 267.86 \cdot 10 \approx 2679\text{ N}
Block

and similarly at the other end:

ΔW(10)2679 N\Delta W(-10) \approx -2679\text{ N}
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:

1
2
static distribution is set by b and c
dynamic shift magnitude is set by M, h, and L
Markdown

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

W=MgW = M g
Block

Static axle loads:

Wf,static=cLWW_{f,static} = \frac{c}{L} W
Block
Wr,static=bLWW_{r,static} = \frac{b}{L} W
Block

Dynamic load transfer caused by acceleration:

ΔW=hLMa\Delta W = \frac{h}{L} M a
Block

Final axle loads:

Wf=cLWΔWW_f = \frac{c}{L} W - \Delta W
Block
Wr=bLW+ΔWW_r = \frac{b}{L} W + \Delta W
Block

Subject to the constraint:

Wf+Wr=WW_f + W_r = W
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# === 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
Python

Simulator 2

Simulator 2 with Load Transfer, new sprite, sky at dusk:

sim2

True form:

sim2 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 :).