PaceDynamics Documentation Open the app
Contents

Tyres

Fitting tyre data

How the app turns a rig's measured points into a Magic Formula tyre, how close that gets, and how a rig tyre is scaled to the road.

Model as of 0.338Figures from the Formula Student single-car templateOctave check Close

A tyre file is a fit. Somebody ran the tyre on a rig, recorded its forces over a sweep of slip at a few loads, and chose the coefficients that bring the Magic Formula closest to those points. The Tyres tool does the same with rig runs you give it. This page fits a known tyre with it, so the answer can be checked against the truth, and then follows the fitted tyre from the rig's belt to the road.

The rig's points

Side force against slip angle at three loads: the rig points, scattered, the curves the fit draws through them, and the tyre they were made from−2500−1250012502500-12-8-404812Slip angle α (°)Side force Fy (N)450 N900 N1350 N
450 N: rig points and the fit900 N: rig points and the fit1350 N: rig points and the fitthe tyre the points were made from
Fig. 1
Through points scattered by 1 % of the load, the fit lands on the tyre they came from: a residual of 0.0109.
Measured

A cornering rig holds the tyre at a load and sweeps its slip angle, a few times over, at each of a handful of loads. The app sorts the samples into bins by load, camber and slip angle and fits the bins' averages, so a run's thousands of samples become a few hundred points.

The points in Fig. 1 are made rather than measured: the template's own tyre at 450, 900 and 1350 N, every 0.5° of slip angle out to 12°, with a scatter of 1 % of the load added to each. A real rig scatters more and not evenly, but this way the tyre the fit should find is known.

The loads that count are the car's. The app fits over the loads from the car's lightest wheel to its most loaded one on its own g-envelope, unless you type others, and never below 300 N, where a rig's load cell is mostly noise. A curve shaped by loads the car never sees is the wrong curve where it does.

What is minimised

The fit asks for the coefficients that make the formula's side force closest to the points, each point's miss divided by its load:

Show the equations with
r=1n∑i=1n(Fy(αi,Fz,i;p)−Fy,iFz,i)2(1)
r=0.0109,or 11.5 N rms in newtons(1)
Fy,i
the rig's side force in bin i, at slip angle αi and load Fz,i
p
the coefficients being fitted
r
the residual, in units of friction coefficient

Dividing by the load makes the residual a friction coefficient, so a miss of 10 N at 450 N counts as much as one of 30 N at 1350 N, and the light loads, where a car's inside wheels live, are not drowned out by the heavy ones.

The residual comes out a shade above the 0.01 of scatter put in: the fit cannot pass through the noise, and the template's curvature differs a little either side of zero, which the seven coefficients below cannot follow. On real data a fit almost never reaches the rig's own scatter, because runs on the same tyre disagree with each other. The Tyres tool places a fit's residual among the fits of a library of rig data, so it can be read as tight or loose against fits of the same kind.

What is fitted

A pure-slip sweep at one camber and one pressure can tell seven coefficients apart. The fit starts from the data itself and keeps each inside a range:

Coefficient What it sets Fitted Template's tyre
pCy1 the shape: how far the force falls past its peak 1.524 1.5
pDy1 the friction coefficient at the nominal load 1.813 1.8
pDy2 its fall with load −0.186 −0.2
pEy1, pEy2 the curvature near the peak, and its change with load −0.668, −0.344 −0.8, −0.4
pKy1 the cornering stiffness −36.37 −34.21
pKy2 the load at which the cornering stiffness peaks 2.118 2

Three ranges carry physics rather than convenience:

  • pKy1 stays on the side of zero the data's own slope through the origin is on. The far side of zero fits just as well and is a tyre that steers the car the wrong way.
  • pDy2 stays at or below zero, give or take a hair. A noisy set can otherwise report a tyre that grips better the harder it is pressed, and every analysis downstream would then find load transfer free (Load sensitivity).
  • When the data turns over, the fitted curve has to peak inside the sweep, within 15 % of the largest slip angle measured. Left free, a fit can put its peak far past the data and invent grip nobody measured. When the data is still climbing at the edge, the peak is not constrained and the app says it is extrapolated.

None of the seven shifts the curve off the origin, so every fit the app makes has no side force at zero slip at any load. A real tyre makes a little, from its ply and its conicity; the Tyres tool fits those offsets only when asked, to measure them, since a tyre that pushes at zero slip upsets the torque-vectoring sums.

The search is Nelder–Mead's, restarted four times from different seeds, keeping the best. Here no coefficient ended on its range and the data turns over, so the peak is measured.

How close it gets

Load μy fitted μy true Off by Cα fitted Cα true Off by
450 N 1.906 1.905 0.01 % 14 635 N/rad 14 574 N/rad 0.41 %
900 N 1.813 1.811 0.12 % 25 271 N/rad 25 143 N/rad 0.51 %
1350 N 1.720 1.716 0.23 % 30 876 N/rad 30 687 N/rad 0.61 %

The fit finds the tyre's grip to a few tenths of a per cent and its cornering stiffness to about half a per cent, from points scattered by a whole per cent. Its coefficients are another matter: pEy1 is −0.67 where the template's is −0.8. The template's file has a nominal load of 950 N where the fit takes the bins' mean, 900 N, and it carries a curvature term the fit leaves at zero. Different coefficients make nearly the same curve. Compare tyres by their curves, μy and Cα at the loads you run, not coefficient by coefficient.

Which model

The Tyres tool fits four models. They differ in what they can represent, whatever the data:

Model Coefficients Cannot represent
Simple 8 camber, the aligning moment, pressure; its combined slip is a friction ellipse
MF 5.2 about 19 pressure; camber enters as a shift of the slip angle
MF 6.1 about 19 pressure; camber enters through its own stiffness
MF 6.1 + pressure about 27 nothing more in the app, which runs every tyre at its nominal pressure

The fit here is MF 6.1, and of its coefficients only the seven above, since the data has one camber and no drive or brake runs. "Compare models" fits every model to the same bins and puts each residual beside its count of coefficients. A model with eight more coefficients and the same residual has fitted the rig's afternoon, not the tyre. The pressure model earns its place another way: without it a fit has to choose one pressure and discard the runs at the others.

From the rig to the road

The template tyre’s side force against slip angle as its file states it and scaled to the road, with the slope through the origin of each050010001500200003691215Slip angle α (°)Side force Fy (N)as the file states iton the road: peak × 0.7, slope × 0.85
as the file states iton the road, × 0.7 grip and × 0.85 stiffnessthe slope through the origin, the cornering stiffness
Fig. 2
With the page’s example factors, the peak scaled by 0.7 and the slope by 0.85: the curve keeps its shape between them.
Measured

A rig runs the tyre on a belt of abrasive paper, not on the road it will race on, and the tyre's grip and stiffness differ between the two. Two factors take the fit to the road, one for the peak and one for the slope:

Show the equations with
D=μyλμyFz,Kyα→λKyKyα,B=KyαCD(2)
μy=0.7⋅1.800=1.260,Cα=0.85⋅25996=22095 N/rad(Fz=950 N)(2)
λμy
the grip scale, rig to road; it scales the drive direction's peak too
λKy
the stiffness scale, rig to road; it scales the slip stiffness too

B follows from the other two, so the curve keeps its shape and each end lands where it is put. Fig. 2 is the template's tyre at 0.7 and 0.85, values chosen to show the two apart, not a rule. How far each falls depends on the surface, the tyre and its temperature, and nothing ties one to the other, which is why there are two factors and not one on the whole force. Set them from your own data. The Calibration tool can set the grip scale from the car's logs; the stiffness scale you set yourself.

What the model assumes

  • Pure slip only. Combined slip, the aligning moment and the relaxation length come from other runs: drive and brake runs at a slip angle, the moment channel, step-steer tests. A fit with no data for them says so and names what stands in.
  • Load dependence is the Magic Formula's: straight in the friction coefficient, a sine of an arctangent in the cornering stiffness. A tyre that bends otherwise leaves a residual no coefficient can take up.
  • The rig's slip angle, load and force are what it says they are. A rig with an offset in its slip angle shifts every fit by the same amount.
  • One factor per direction takes the rig to the road, at every load and slip.

In the app

Tyres › Fit takes rig runs in four steps: Runs, what the rig measured; Channels, how it was read; Fit, the model over the data; Keep, into the library and onto the car. Fit sets the model, the load window and the offsets, and "Compare models" fits all four. Its "Fitted data" charts draw the fit over the bins in the file's own sense, so the template's side force is negative there for positive slip.

In the car's setup, under "Tyres", "Grip scale (rig → road)" and "Stiffness scale (rig → road)" are equation (2)'s two factors. Both default to 1, the tyre as its file states it.

Check it yourself

example_rig.m holds the rig points of Fig. 1. The script fits them with Octave's fminsearch, from the same start, and compares the residual, μy and Cα at the three loads with the app's to 0.01 %. Two searches on the same residual land on the same curve to a tolerance, not to the last digit, so this page is checked as Close. The rig-to-road scaling is exact.

fitting_tyre_data.mwith example_rig.m, example_tyre.m, pd_mf.m, pd_peak.m, pd_fy_rms.m, pd_compare.mClose: agrees to the tolerance the page states
>> fitting_tyre_data

          this script PaceDynamics  template's tyre
  PCY1         1.5237       1.5237           1.5000
  PDY1         1.8127       1.8127           1.8000
  PDY2        -0.1857      -0.1857          -0.2000
  PEY1        -0.6685      -0.6685          -0.8000
  PEY2        -0.3440      -0.3440          -0.4000
  PKY1       -36.3747     -36.3747         -34.2105
  PKY2         2.1185       2.1185           2.0000

  (the template's tyre has a nominal load of 950 N, the fit 900 N, and p_Ey3 = 0.1
  that the fit leaves at zero, so its coefficients are not the fit's to find)

  Quantity                                This script   PaceDynamics       Diff
  -----------------------------------------------------------------------------
  Residual, rms over the load [-]            0.010876       0.010876   1.4e-13% 
  Fitted mu_y at  450 N [-]                   1.90551        1.90551   6.1e-09% 
  Fitted mu_y at  900 N [-]                   1.81265        1.81265   4.9e-09% 
  Fitted mu_y at 1350 N [-]                   1.71979        1.71979     5e-09% 
  Fitted C_alpha at  450 N [N/rad]            14634.6        14634.6   5.3e-08% 
  Fitted C_alpha at  900 N [N/rad]            25270.6        25270.6   1.4e-08% 
  Fitted C_alpha at 1350 N [N/rad]            30875.5        30875.5   9.4e-08% 
  On the road: mu_y, x 0.7 [-]                1.25998        1.25998         0% 
  On the road: C_alpha, x 0.85 [N/rad]        22095.5        22095.5   3.3e-14% 

  All 9 quantities agree with PaceDynamics (largest difference 9.4e-08 %).
The script
%% Fitting tyre data: a Magic Formula fitted to rig points, and scaled to the road
%
% Companion to the documentation page "Fitting tyre data". Runs unchanged in GNU Octave
% (7 or later) and MATLAB. Run:
%
%   >> fitting_tyre_data
%
% A rig measures a tyre's side force at a few loads over a sweep of slip angle. A fit
% chooses the coefficients that bring the formula closest to those points, in the least-
% squares sense, with each point's error divided by its load:
%
%   minimise  sqrt( mean( ((F_y(alpha, F_z; p) - F_y,rig) / F_z)^2 ) )
%
% over the seven coefficients a pure-slip, one-camber sweep can tell apart: the shape
% p_Cy1, the friction p_Dy1 and its fall with load p_Dy2, the curvature p_Ey1 and p_Ey2,
% and the cornering stiffness p_Ky1 and the load at its peak p_Ky2.
%
% The points in example_rig.m are made from the template's own tyre with a seeded scatter
% of 1 % of the load added, so there is a known answer. The app fits them with its own
% search (Nelder-Mead, four restarts); this script with fminsearch, from the same start.
% Two searches on the same residual land on the same curve to a stated tolerance, not to
% the last digit, so this page is checked as Close.
%
% Then the rig-to-road scaling, which is exact: lambda_mu y scales the peak and lambda_Ky
% the cornering stiffness, and the formula's B = K / (C D) keeps the curve's shape.
%
% Reference: H. B. Pacejka, Tyre and Vehicle Dynamics, 3rd ed. (Butterworth-Heinemann,
% 2012), ch. 4.3.2 and 4.3.3.
%
% Part of the PaceDynamics documentation, https://pacedyn.dev/docs
% SPDX-License-Identifier: MIT

[t, app] = example_tyre();
[rig, fit] = example_rig();
deg = pi / 180;
TOL = 1e-4;                                 % Close: two searches agree to 0.01 %

%% The rig's points, one column each
na = numel(rig.alphaDeg);
Fz = kron(rig.loads(:), ones(na, 1));
alpha = repmat(rig.alphaDeg(:) * deg, numel(rig.loads), 1);
Fy = reshape(rig.fy', [], 1);

%% A blank tyre, as the fitter starts one
% Every coefficient the sweep cannot determine is zero, the scaling factors 1, and the
% nominal load is the points' mean load.
b = t;
for k = {'PEY3', 'PEY4', 'PHY1', 'PHY2', 'PVY1', 'PVY2', 'PVY3', 'PVY4', 'PDY3', 'PKY3', 'PKY5', 'PKY6', 'PKY7'}
  b.(k{1}) = 0;
end
b.PKY4 = 2;
b.FNOMIN = fit.fnomin;

%% The start, as the app takes it from the points
% The friction from the highest |F_y| / F_z, the cornering stiffness from the slope of
% F_y / F_z through the origin within 2 deg, on the side of zero the data is on.
D = max(abs(Fy) ./ max(1, Fz));
small = abs(alpha) > 1e-5 & abs(alpha) <= 2 * deg;
K = sum(alpha(small) .* Fy(small) ./ max(1, Fz(small))) / sum(alpha(small) .^ 2);
keys = {'PCY1', 'PDY1', 'PDY2', 'PEY1', 'PEY2', 'PKY1', 'PKY2'};
x0 = [1.4, D, -0.1, -0.5, 0, sign(K) * max(5, abs(K)), 1.8];

%% The fit
cost = @(x) pd_fy_rms(x, b, keys, Fz, alpha, Fy);
opts = optimset('MaxFunEvals', 40000, 'MaxIter', 40000, 'TolX', 1e-12, 'TolFun', 1e-14);
x = fminsearch(cost, x0, opts);
x = fminsearch(cost, x, opts);              % restarted once from where it stopped
for k = 1:numel(keys), b.(keys{k}) = x(k); end

fprintf('\n  %-6s %12s %12s %16s\n', '', 'this script', 'PaceDynamics', 'template''s tyre');
for k = 1:numel(keys)
  fprintf('  %-6s %12.4f %12.4f %16.4f\n', keys{k}, x(k), fit.coefficients.(keys{k}), t.(keys{k}));
end
fprintf('\n  (the template''s tyre has a nominal load of %g N, the fit %g N, and p_Ey3 = %g\n', t.FNOMIN, fit.fnomin, t.PEY3);
fprintf('  that the fit leaves at zero, so its coefficients are not the fit''s to find)\n');

%% What the fitted tyre does, at each rig load
mu = zeros(1, numel(rig.loads));
Ca = zeros(1, numel(rig.loads));
for i = 1:numel(rig.loads)
  F = rig.loads(i);
  Fy_at = @(a) getfield(pd_mf(b, F, a, 0), 'Fy0');
  mu(i) = pd_peak(@(a) Fy_at(a * deg), 45, 1) / max(1, F);
  e = 0.1 * deg;
  Ca(i) = abs((Fy_at(e) - Fy_at(-e)) / (2 * e));
end

%% Rig to road: scale the peak and the slope, each by its own factor
s = t;
s.LMUY = t.LMUY * app.road.grip;
s.LKY = t.LKY * app.road.stiffness;
Fy_road = @(a) getfield(pd_mf(s, s.FNOMIN, a, 0), 'Fy0');
mu_road = pd_peak(@(a) Fy_road(a * deg), 45, 1) / max(1, s.FNOMIN);
e = 0.1 * deg;
Ca_road = abs((Fy_road(e) - Fy_road(-e)) / (2 * e));

%% Against the app
pd_compare('Residual, rms over the load [-]', cost(x), fit.rmsMu, TOL);
for i = 1:numel(rig.loads)
  pd_compare(sprintf('Fitted mu_y at %4g N [-]', rig.loads(i)), mu(i), fit.muY(i), TOL);
end
for i = 1:numel(rig.loads)
  pd_compare(sprintf('Fitted C_alpha at %4g N [N/rad]', rig.loads(i)), Ca(i), fit.corneringStiffness(i), TOL);
end
pd_compare(sprintf('On the road: mu_y, x %g [-]', app.road.grip), mu_road, app.road.muY);
pd_compare(sprintf('On the road: C_alpha, x %g [N/rad]', app.road.stiffness), Ca_road, app.road.corneringStiffness);
pd_compare();

Download: fitting_tyre_data.m · example_rig.m · example_tyre.m · pd_mf.m · pd_peak.m · pd_fy_rms.m · pd_compare.m. The scripts are MIT licensed.

Further reading

  • H. B. Pacejka, Tyre and Vehicle Dynamics, 3rd ed. (Butterworth-Heinemann, 2012), ch. 4.3.2, on the Magic Formula's coefficients, and ch. 4.3.3, on the scaling factors.
  • W. F. Milliken and D. L. Milliken, Race Car Vehicle Dynamics (SAE, 1995), ch. 2, on tyre testing.
  • J. C. Lagarias, J. A. Reeds, M. H. Wright and P. E. Wright, "Convergence properties of the Nelder–Mead simplex method in low dimensions", SIAM Journal on Optimization 9 (1998), 112–147.
ChapterFitting tyre data
PartTyres
Model as of0.338
Example carthe Formula Student single-car template