Quick Start

The simple laws of friction are an amazingly good approximation in many circumstances, but real life tells us that there's more going on. Here we see how we can get squeal or stick slip behaviour when the simple assumptions are no longer valid.


The app is inspired by Ch 12 of the excellent book Contact Mechanics and Friction: Physical Principles and Applications by Prof Valentin L Popov, TU Berlin Inst. Mechanik.


Load kg
t s
c kg/s²
η kg/s
τ s
D m
V0 m/s
//One universal basic required here to get things going once loaded
window.onload = function () {
    //restoreDefaultValues(); //Un-comment this if you want to start with defaults

//Main() is hard wired as THE place to start calculating when inputs change
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
    //Save settings every time you calculate, so they're always ready on a reload

    //Send all the inputs as a structured object
    //If you need to convert to, say, SI units, do it here!
    const inputs = {
        mus: sliders.SlidemuStatic.value,
        muk: sliders.SlidemuKinetic.value,
        N: sliders.SlideLoad.value,
        tmax: sliders.Slidet.value,
        c: sliders.Slidec.value,
        eta: sliders.Slideeta.value,
        v0: sliders.Slidev0.value,
        va: sliders.Slideva.value,
        vb: sliders.Slidevb.value,
        tau: sliders.Slidetau.value,
        D: sliders.SlideD.value

    //Send inputs off to CalcIt where the names are instantly available
    //Get all the resonses as an object, result

    const result = CalcIt(inputs);

    //Set all the text box outputs
    document.getElementById('Frequency').value = result.freq;
    // document.getElementById('Solid').value = result.sInfo;
    //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //plotIt is part of the app infrastructure in
    if (result.plots) {
        for (let i = 0; i < result.plots.length; i++) {
            plotIt(result.plots[i], result.canvas[i]);

    //You might have some other stuff to do here, but for most apps that's it for Main!

//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ mus, muk, N, tmax, c, eta, v0, va, vb, tau, D }) {

    let FPts = [], TPts = [], FkPts = [], x = 0, v = 0, accel = 0, theta = 1, Fvt = 0, Fkv = 0
    let pNext = 0
    const Fk = N * muk, Fs = N * mus
    const tStep = 0.001
    const pStep = Math.max(tStep, tmax / 200)
    const resFrequency = Math.sqrt(c / N)
    for (let t = 0; t <= tmax; t += tStep) {
        theta += (1 - theta) / tau - v / D
        theta = Math.min(1, Math.max(theta, 0))
        Fkv = Math.max(0, Fk * (1 + va * Math.abs(v) + vb * Math.pow(v - v0, 2)))
        Fvt = Fkv + (Fs - Fkv) * theta
        accel = (c * v0 * t + eta * v0 - Fvt - eta * v - c * x) / N
        v += accel * tStep
        x += v * tStep
        if (v < 0) v = 0
        if (t >= pNext) {
            FPts.push({ x: t, y: v / v0 })
            TPts.push({ x: t, y: theta })
            FkPts.push({ x: t, y: Fkv / Fk })
            pNext += pStep
    //Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot
    const prmap = {
        plotData: [FPts, TPts, FkPts], //An array of 1 or more datasets
        lineLabels: ["v/v0", "θ", "Fk/Fk0"], //An array of labels for each dataset
        xLabel: 't&s', //Label for the x axis, with an & to separate the units
        yLabel: 'Relative values& ', //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'P3', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'P3', //F for Fixed, P for Precision, E for exponential

    return {
        freq: (resFrequency / (2 * Math.PI)).toFixed(2) + "Hz, " + resFrequency.toFixed(2) + "rad/s",
        plots: [prmap],
        canvas: ['canvas'],


If you have a mass N and try to push it along a surface, the force required to push it depends only on the friction coefficient, μ, and N. It doesn't depend on velocity nor on the contact area: a rectangular brick needs the same force to overcome friction whichever side is in contact.

OK, we know that's not quite true. If it's stationary we need a force FS = μSN, with a static coefficient, then when it's moving we need FK = μKN with a kinetic coefficient.

But you can't just go instantly from static to kinetic or back to static. There has to be some time-dependence and also some effect of the surface waviness. So we can say that the friction force F is given by:


where θ (an "internal variable") responds with a relaxation time τ and relaxation length D along distance x via:


We allow θ to vary from 0 (F=FK) to 1 (F=FS)

Finally, although F is often surprisingly independent of velocity, v, it's actually quite normal in the real world to have some dependence. In this app we have a convenient 2-parameter model which includes v0, the target velocity for our system:


Depending on relative sizes and signs of a and b you can have some interesting effects on FK.

When we (in this case) pull an object, we don't have an infinitely strong coupling to the object, so it has some springiness, with a spring constant c in kg/m² and a dashpot relaxation of η kg/s. The looser the coupling, the wilder the effects of friction, with all those complex interactions.

To describe what happens we have a master equation based on the assumption that we're basically pulling the stuff along at a constant master velocity of v0, with the system starting at v = 0. For a while, nothing happens till the force via the coupling assembly exceeds FS. We get an acceleration and depending on θ, we transition to FK, which, being lower, allows a faster acceleration so the velocity can overshoot. After that we have a complex interplay of all the factors. If the velocity dependence of FK is 0 or positive, the system can stabilize quickly. If FK gets smaller at higher velocities then things get very unstable and we head towards stick/slip, discussed below.

Here's the master equation. It is the "simplest phenomenological model that describes the typical dynamics of the contact state", but is more than complicated enough for our purposes. Although there are fancy mathematical techniques to analyse various special case, here the app just calculates the acceleration δv/δt at each time step (i.e. it puts all other terms to the right and divides by N), so calculates a new v and a new distance travelled x. With new values of v we can calculate FK and θ using the equations above and hence we have a new value of F for the equation. Using the Show Code button you can easily find the code doing this:


The plots of the various factors are all relative for convenience.

Squeal, Stick-slip and Sprag-slip

Once you loosen up the spring/dashpot, add some negative effects to FK and exaggerate the θ effects you soon find yourself with regular velocity oscillations at a frequency, ω, given by:


which is reported both as Hz (divide by 2π) and as rad/s. This is classic squeal, though real-world squeal is far harder to predict and contain than this simple model suggests. Go further with the controls and velocity goes shooting up then crashing down to 0 and staying there for a while. This is classic slip-stick behaviour.

What we don't have in this model are forces in the z-direction, making the device oscillate vertically. If we did then you can imagine that θ can have an interesting dependence on the overall motion. In an extreme we have sprag-slip, those little birds on springs that wobble down a vertical pole.

When writing apps I have to be very attentive to the units - it's very easy to be out by a factor of 10 or 1000. In this app I'm more interested in the user being able to see the broad range of friction-induced behaviours with some convenient sliders. If I've got some units wrong then I'll fix them, but then I'll need to change the range of various sliders to make sure we see interesting behaviour. In other words, don't use this app to solve your real friction problems - just use it to see the general phenomenology.