Contents
Loads
Load transfer
How cornering and braking move the car's weight between its wheels, and which parts of the car decide where it goes.
A car that corners or brakes does not change its weight, but it changes where the weight sits. The inertia force acts at the centre of gravity, above the road, and the tyres push at road level: the couple between them loads the outside wheels and unloads the inside ones, or the front and the rear. How much moves is set by the CG height and the track or wheelbase. How it divides between the front and rear axles is set by the suspension, and it is one of the strongest levers on a car's balance.
Three paths to the road
In a steady corner each axle carries its share of the sideways force, and the load it moves from its inside to its outside wheel takes three paths:
- Elastic. The sprung mass rolls on its springs. The roll moment is the sideways force times the CG's height above the roll axis, and each axle takes a share of it by its share of the roll stiffness.
- Geometric. The force reaches each axle's roll centre and goes through the links without rolling the body. Its moment arm is the roll-centre height.
- Unsprung. The wheels, uprights and brakes are pushed sideways at their own height and go straight to the tyres.
The lateral transfer
For a steady corner at lateral acceleration , each axle moves a load from its inside wheel to its outside one:
- the sprung mass, and the share of it the axle carries
- the CG's height above the roll axis, where the CG is
- the roll gain from the CG swinging outboard, from Ride and roll rates
- the axle's share of the roll stiffness
- the axle's roll-centre height
- the axle's two unsprung masses and the height of their CG, about the wheel centre
The rear moves 359.4 N per g. On the template almost all of it is elastic: its roll centres are only a few millimetres above the road, so the geometric path carries about one per cent of the transfer.
The front's share of the total is the total lateral load transfer distribution (TLLTD):
A tyre's grip grows less than its load, so the axle that moves more load loses more of its pair's grip. Moving TLLTD forward, by stiffening the front roll element or raising the front roll centre, makes a car understeer more; moving it back makes it oversteer more. It is the reason anti-roll bars exist.
Braking and drive
In a straight line the inertia force acts at the CG height , and the couple moves load between the axles over the wheelbase . Braking () moves it forward:
- the CG height the car settles at, not the one it stands at
- the load the CG puts on the front axle by moving forward as the car pitches
The transfer pitches the car: under braking at 1.2 g the template's front drops 12.6 mm and its rear rises 11.7 mm. Pitching moves the CG. It goes forward, which loads the front a little more, and its height changes with the two axles' travel. The new height changes the transfer, and so on. The app follows this loop until the CG moves less than 10⁻⁹ mm, a few passes. On the template the settled CG is 300.23 mm high instead of 300: more of the car's mass rides on the rear, which rises, than on the front, which drops.
The anti features take some of this transfer through the links instead of the springs (Roll and pitch centres). They change how far the car pitches, not how much load moves.
What the model assumes
- The corner is steady: constant and , no transient and no damper forces.
- The roll centres and the roll axis stay at the static ride. The roll axis is a straight line from front to back.
- Lateral and longitudinal transfer add: in a corner under braking each wheel gets both.
- The tyres stay on the road. When a wheel's load would go below zero the app holds it at zero, flags the wheel as lifted, and puts its share where the car's balance sends it; the formulas above stop applying there.
- Two more terms the examples here do not need: the aerodynamic load, which grows with the square of speed, and the load the steering linkage shifts across the diagonal as the wheels steer, which is zero with them straight.
In the app
Vehicle Dynamics › Balance & loads draws "Wheel loads vs lateral g", the four lines of Fig. 3, and "Axle loads vs longitudinal g", negative for braking. Under "Ride & roll (steady state)" it lists "TLLTD front" next to "Roll-stiffness front", and "TLLTD front (%) — ARB front × rear" maps it over both bars.
Every model in the app, from the grip envelope to the lap, places the loads on the tyres this way.
Check it yourself
The script builds the three terms of equation (1) for each axle, the wheel loads at 1.2 g left, and the braking loads with the settled CG, from example_car.m. Run it yourself and it also draws Fig. 3.
>> load_transfer Quantity This script PaceDynamics Diff ----------------------------------------------------------------------------- Front elastic [N/(m/s^2)] 33.3552 33.3552 0% Front geometric [N/(m/s^2)] 0.337484 0.337484 0% Front unsprung [N/(m/s^2)] 2.95617 2.95617 1.5e-14% Rear elastic [N/(m/s^2)] 33.4159 33.4159 0% Rear geometric [N/(m/s^2)] 0.316753 0.316753 0% Rear unsprung [N/(m/s^2)] 2.90771 2.90771 1.5e-14% Front share of the transfer [-] 0.500058 0.500058 0% Left turn at 1.2 g, FL [N] 260.174 260.174 4.4e-14% Left turn at 1.2 g, FR [N] 1123.04 1123.04 0% Left turn at 1.2 g, RL [N] 348.565 348.565 1.6e-14% Left turn at 1.2 g, RR [N] 1211.22 1211.22 0% Braking: settled CG height [mm] 300.231 300.231 0% Braking: CG moved forward [N] 7.50396 7.50396 0% Braking at 1.2 g, FL [N] 1026.7 1026.7 0% Braking at 1.2 g, RL [N] 444.8 444.8 0% All 15 quantities agree with PaceDynamics (largest difference 4.4e-14 %).
The script
%% Load transfer: where the tyres' forces put the car's weight % % Companion to the documentation page "Load transfer". Runs unchanged in GNU Octave (7 or % later) and MATLAB. Edit the car in example_car.m and run: % % >> load_transfer % % Lateral, per axle, for a steady corner at lateral acceleration a_y: % % dFz = a_y / t * ( elastic + geometric + unsprung ) % % elastic = m_s * h_ra * G * K_axle / K_total the sprung mass rolling on its springs % geometric = m_s,axle * h_rc,axle the sprung mass pushing through the links % unsprung = m_u,axle * h_u wheels, uprights and brakes on their own % % with G = 1 / (1 - m_s g h_ra / K_total), the extra roll from the CG swinging outboard. % % Longitudinal, for a straight-line acceleration a_x (negative: braking): % % dFz,rear = m a_x h / L - noseLoad % % where h is the CG height the car settles at, not the one it stands at: the transfer % pitches the car, the pitch lowers (or raises) the CG and carries it forward, and the % CG going forward puts noseLoad on the front axle. The app solves that loop to 1e-9 mm; % so does this script, in the same steps. % % Reference: W. F. Milliken and D. L. Milliken, Race Car Vehicle Dynamics (SAE, 1995), ch. 18. % % Part of the PaceDynamics documentation, https://pacedyn.dev/docs % SPDX-License-Identifier: MIT [car, app] = example_car(); app = app.transfer; g = 9.81; % m/s^2 mm = 1e-3; % m per mm series = @(a, b) a .* b ./ (a + b); %% Masses m_u = 4 * car.unsprungPerCorner; % kg, all four corners m_s = car.massTotal - m_u; % kg, sprung m_sf = m_s * car.frontMassFrac; % kg, sprung on the front axle m_sr = m_s * (1 - car.frontMassFrac); % kg, sprung on the rear axle %% Roll stiffness per axle (page "Ride and roll rates") k_f = series(car.wheelRateFront + car.arbFront, car.tireRateFront); % N/mm at the wheel k_r = series(car.wheelRateRear + car.arbRear, car.tireRateRear); K_f = (k_f / mm) * (car.trackFront * mm)^2 / 2; % N*m/rad K_r = (k_r / mm) * (car.trackRear * mm)^2 / 2; K = K_f + K_r; %% Roll axis: the line through the two roll centres, read where the CG is h_rc = (car.rcHeightFront + (car.rcHeightRear - car.rcHeightFront) * (1 - car.frontMassFrac)) * mm; h_ra = car.cgHeight * mm - h_rc; % m, CG above the roll axis G = 1 / (1 - m_s * g * h_ra / K); %% The three terms, per unit a_y [N per m/s^2, per wheel] t_f = car.trackFront * mm; t_r = car.trackRear * mm; h_u = car.unsprungCgHeight * mm; front.elastic = m_s * h_ra * G * (K_f / K) / t_f; front.geometric = m_sf * car.rcHeightFront * mm / t_f; front.unsprung = 2 * car.unsprungPerCorner * h_u / t_f; rear.elastic = m_s * h_ra * G * (K_r / K) / t_r; rear.geometric = m_sr * car.rcHeightRear * mm / t_r; rear.unsprung = 2 * car.unsprungPerCorner * h_u / t_r; c_f = front.elastic + front.geometric + front.unsprung; c_r = rear.elastic + rear.geometric + rear.unsprung; tlltd = c_f / (c_f + c_r); % front share of the load moved %% Wheel loads in a steady left turn W = car.massTotal * g; Wf = W * car.frontMassFrac; Wr = W * (1 - car.frontMassFrac); a_y = app.corner.ayG * g; corner = [Wf / 2 - c_f * a_y, Wf / 2 + c_f * a_y, Wr / 2 - c_r * a_y, Wr / 2 + c_r * a_y]; %% Braking: the CG the car settles at a_x = app.braking.axG; % g, negative Lmm = car.wheelbase; kF = 2 * series(car.wheelRateFront + car.heaveSpringFront, car.tireRateFront); % N/mm, front axle in heave kR = 2 * series(car.wheelRateRear + car.heaveSpringRear, car.tireRateRear); % How far the CG sinks per mm each axle drops: the sprung mass at its station, the % unsprung mass by the tyre's share of the drop. share = @(k_ride, k_t) min(1, k_ride / k_t); aF = (m_sf + 2 * car.unsprungPerCorner * share(kF / 2, car.tireRateFront)) / car.massTotal; aR = (m_sr + 2 * car.unsprungPerCorner * share(kR / 2, car.tireRateRear)) / car.massTotal; lambda = car.massTotal * a_x * g / Lmm; % N of rearward transfer per mm of CG height h = car.cgHeight; % mm, start where the car stands for pass = 1:6 % Front load per mm of nose-down rake, from the CG going forward with it. sigma = min(m_s * g * h / Lmm^2, 0.5 * kF * kR / (kF + kR)); nF = -lambda * h; nR = lambda * h; % what each axle carries beyond static [N] d = kF * kR - sigma * (kF + kR); dropF = (nF * (kR - sigma) - sigma * nR) / d; dropR = (nR * (kF - sigma) - sigma * nF) / d; next = car.cgHeight - (aF * dropF + aR * dropR); moved = abs(next - h); h = next; if moved < 1e-9, break; end end noseLoad = sigma * (dropF - dropR); % N, onto the front axle dLong = car.massTotal * a_x * g * h / Lmm - noseLoad; % N, + rearward braking = [Wf / 2 - dLong / 2, Wf / 2 - dLong / 2, Wr / 2 + dLong / 2, Wr / 2 + dLong / 2]; %% Against the app pd_compare('Front elastic [N/(m/s^2)]', front.elastic, app.front.elastic); pd_compare('Front geometric [N/(m/s^2)]', front.geometric, app.front.geometric); pd_compare('Front unsprung [N/(m/s^2)]', front.unsprung, app.front.unsprung); pd_compare('Rear elastic [N/(m/s^2)]', rear.elastic, app.rear.elastic); pd_compare('Rear geometric [N/(m/s^2)]', rear.geometric, app.rear.geometric); pd_compare('Rear unsprung [N/(m/s^2)]', rear.unsprung, app.rear.unsprung); pd_compare('Front share of the transfer [-]', tlltd, app.tlltd); names = {'FL', 'FR', 'RL', 'RR'}; for i = 1:4 pd_compare(sprintf('Left turn at %.1f g, %s [N]', app.corner.ayG, names{i}), corner(i), app.corner.(names{i})); end pd_compare('Braking: settled CG height [mm]', h, app.braking.cgHeight); pd_compare('Braking: CG moved forward [N]', noseLoad, app.braking.noseLoad); for i = [1, 3] pd_compare(sprintf('Braking at %.1f g, %s [N]', -a_x, names{i}), braking(i), app.braking.(names{i})); end pd_compare(); % prints the verdict %% The page's figure: four wheel loads against lateral acceleration % Drawn when you run the script yourself; the strict run in CI has no screen and skips it. if ~strcmp(getenv('PD_STRICT'), '1') ay = linspace(0, 1.6, 17) * g; % left turn: load goes right figure('Name', 'Wheel loads in a steady left turn'); plot(ay / g, Wf / 2 + c_f * ay, '-', ay / g, Wf / 2 - c_f * ay, '--', ... ay / g, Wr / 2 + c_r * ay, '-', ay / g, Wr / 2 - c_r * ay, '--', 'LineWidth', 1.5); grid on; xlabel('Lateral acceleration [g]'); ylabel('Vertical load [N]'); legend('FR (outside)', 'FL (inside)', 'RR (outside)', 'RL (inside)', 'Location', 'northwest'); end
Download: load_transfer.m · example_car.m · pd_compare.m. The scripts are MIT licensed.
Further reading
- W. F. Milliken and D. L. Milliken, Race Car Vehicle Dynamics (SAE, 1995), ch. 18, on wheel loads.
- T. D. Gillespie, Fundamentals of Vehicle Dynamics (SAE, 1992), ch. 2, 3 and 7.