Jump to content
  • Advertisement
  • 12/19/14 07:53 AM

    Towards a Simpler, Stiffer, and more Stable Spring

    Math and Physics

    • Posted By h4tt3n
    Download article: Spring 0.5.2.pdf

    Towards a Simpler, Stiffer, and more Stable Spring

    Written by Michael Schmidt Nissen Version 0.5.2, December 18th 2014

    The trouble with springs

    The damped spring based on Hooke's law of elasticity is often regarded as a black sheep in the field of game physics, and some papers and websites even warn the reader against implementing them. There are a couple of good reasons for this. The most straight-forward reason is that springs are notoriously difficult to tune. It can be very time consuming to adjust the spring stiffness and damping coefficients in order to make a simulation behave just right. For large systems of interconnected particles and springs the task can be daunting. If a variable is changed, for instance a spring coefficient, the mass of a particle, or the simulation time-step, you might have to re-tune the entire system from scratch. A more profound reason for avoiding springs is that they are potentially unstable. When increasing the spring coefficients above some unknown threshold, the simulation will start to oscillate chaotically and explode in all directions. Everyone who ever worked with springs has experienced this frustrating phenomenon. The problem is that there's no good method to determine in advance if a given spring system will show this behavour or not. Thus, the programmers or game designers ability to balance a spring system often rely on experience and gut feeling, which makes it look more like black magic than actual physics. In this article I'll introduce a modified spring equation that is easy to tune, displays maximum stiffness and damping, and is guaranteed to keep the spring system stable under all conditions. The math behind the equation is surprisingly simple, which makes me wonder why it doesn't appear to have been mentioned or implemented earlier.

    Making a better spring

    The improved spring equation stems from trying to answer a simple question: Is it possible to make a spring that reaches its rest state in just one simulation loop? It turns out that the answer is yes! This wouldn't be possible in the real world, since it would require infinitely high stiffness and damping coefficients or zero mass. But in the not-quite real world of discrete, time-stepping physics simulation, this is achievable. To explain how this is done, let's look at a one dimensional harmonic oscillator with a damped spring attached to a fixed point in one end and to a moving body in the other. Assume that the body is displaced distance x from its rest position. Now let us try to find the exact amount of force required to move the mass this distance in one simulation loop. Distance can be expressed as velocity multiplied by time \[ \large x = -{v} {\Delta t} \] The minus sign simply means that we're moving in the opposite direction of the displacement. Velocity can be expressed as acceleration multiplied by time \[ \large x = -{a} {\Delta t^{2}} \] Newton's 2nd law of motion states that acceleration equals force over mass \[ \large x = -\dfrac{f}{m} {\Delta t^{2}} \] Now we can isolate force \[ \large f= -\dfrac{m}{\Delta t^{2}} x \] And since the spring force in Hooke's law of elasticity is defined as \[ \large f= -k x \] It becomes immediately clear that \[ \large k = \dfrac{m}{\Delta t^{2}} \] Which is the exact spring stiffness coefficient value required to move the particle back to its rest position in one simulation loop. However, since we are not doing anything to stop the particle, it will keep oscillating back and forth through the rest position. We need to add damping, which is done with the second part of the spring equation. Velocity is equal to acceleration multiplied by time step \[ \large v = -{a} {\Delta t} \] Which is equal to force over mass \[ \large v = -\dfrac{f}{m} {\Delta t} \] When isolating force we get \[ \large f = -\dfrac{m}{\Delta t} v \] And since the damping force is defined \[ \large f = -d v \] We immediately see by inspection that the damping coefficient is \[ \large d = \dfrac{m}{\Delta t} \] This is the exact damping coefficient value needed to stop the particle in one simulation loop. Now we can write the complete damped spring equation. \[ \large f= -\dfrac{m}{\Delta t^{2}} x -\dfrac{m}{\Delta t} v \] This spring equation has some very interesting properties. The first thing we notice is the lack of coefficients. We've simply replaced k with m/?t2 and d with m/?t. When implementing the equation we see that it really does work! The spring reaches equilibrium in one loop, completely independent of particle position, velocity, mass, and simulation time-step. This is the stiffest possible spring, and it displays behavior more similar to a rigid constraint than a soft, bouncy spring. The equation also has another interesting property. It simply cannot blow up no matter what values you feed it. Practically speaking, we can regard the spring as being unconditionally stable.

    Re-introducing the spring coefficients

    Now we have a really powerful spring equation. It is easy to implement, very stable, and reaches its rest state in just one loop. But in our quest towards a better spring it has lost its springiness. We need to somehow get the softness and bounciness back again, and for this purpose we will re-introduce the spring and damping coefficients. To avoid confusion, the new coefficients are named Ck and Cd. While the original coefficients could represent any positive numerical value, these both lie in the interval between zero and one. \[ \large f= -\dfrac{m}{\Delta t^{2}} C_{k} x -\dfrac{m}{\Delta t} C_{d} v \qquad [ 0 \leq C_{k}, C_{d} \leq 1 ] \] As we can see, the new coefficients are simply the fraction of completely rigid behavior we would like the spring to display. Soft, bouncy springs would usually have values in the range of 0.001 - 0.00001. In the other end of the scale, values of just 0.1 - 0.01 is enough to display rigid behavior. Setting both values to 1.0 would of course still satisfy the constraint in one loop. Please notice that spring behavior is determined exclusively by these two coefficients. Particle mass or simulation time-step has no influence on how the spring behaves, and changing them wouldn't make it necessary to tune the system! Interestingly, the spring will get less rigid and less stable if we increase Ck or Cd above 1. If we keep increasing the coefficient values, the system will start oscillating chaotically, and at some point it will explode. In other words, we have determined the exact upper limit for the two spring coefficients, which we define \[ \large k_{max} = \dfrac{m}{\Delta t^{2}} \] \[ \large d_{max} = \dfrac{m}{\Delta t} \] This allows us to simplify the spring equation \[ \large f= -k_{max} C_{k} x -d_{max} C_{d} v \] There is an important conclusion to be drawn from this. It is a misunderstanding to think that spring stiffness and damping can be increased towards infinity by simply increasing k and d. A system of very stiff springs doesn't necessarily blow up because the integration algorithm can't handle it, but because the coefficients might have been set to a value that simply does not make sense.

    Two connected particles with different mass

    It is only slightly more complicated to constrain two free-moving particles with the improved spring. To do this, we need to introduce the concept of reduced mass. This is a quantity that can be used to compute interactions between two bodies as if one body was stationary, which allows us to use the equation we've already derived. The reduced mass for two particles with mass m1 and m2 is defined as \[ \large m_{red} = \dfrac{m_1 m_2}{(m_1 + m_2)} \] Since the inverse mass quantity is often already pre-computed for other purposes, it can also be useful to define reduced mass as \[ \large m_{red}= \dfrac{1}{ ( \dfrac{1}{m_1} + \dfrac{1}{m_2} ) } \] For two connected particles, the maximum coefficient values are \[ \large k_{max} = \dfrac{m_{red}}{\Delta t^{2}} \] \[ \large d_{max} = \dfrac{m_{red}}{\Delta t} \] When replacing mass with reduced mass we get \[ \large f= -\dfrac{m_{red}}{\Delta t^{2}} C_{k} x -\dfrac{m_{red}}{\Delta t} C_{d} v \] This spring equation will bring the two connected particles to equilibrium distance in one loop and make them stand still relative to each other. However, since energy and momentum are conserved, the particles may rotate around each other, which will make the bodies come to rest at a larger distance depending on how fast they rotate.

    Angular springs

    The spring equation can also be used for angular springs, also commonly named rotational or torsional springs. Rather than keeping two particles at a fixed distance by applying opposite equal forces, the angular spring will try to keep two rotating bodies at a fixed angle by applying opposite equal torques. The equation introduces the concept reduced moment of inertia, which is calculated in a similar way as reduced mass \[ \large I_{red} = \dfrac{I_1 I_2}{(I_1 + I_2)} \] Or alternatively \[ \large I_{red}= \dfrac{1}{ ( \dfrac{1}{I_1} + \dfrac{1}{I_2} ) } \] The maximum coefficient values for angular springs are \[ \large k_{max} = \dfrac{I_{red}}{\Delta t^{2}} \] \[ \large d_{max} = \dfrac{I_{red}}{\Delta t} \] When replacing the variables of linear motion with those of angular motion we get \[ \large \tau = -\dfrac{I_{red}}{\Delta t^{2}} C_{k} \theta -\dfrac{I_{red}}{\Delta t} C_{d} \omega \] This spring equation will keep two rotating bodies at any given rest angle. If both coefficients are set to 1, the constraint will be solved in one loop. The spring allows for angular displacements larger than one full turn, making it possible to "wind up" bodies like the coil spring of a mechanical clock.

    Impulse-based springs

    Today a lot of physics engines and simulation methods are based on impulses - direct changes in velocities - rather than forces and acceleration. The linear and angular spring equations described above works equally well if we redesign them to work with impulses. Here are the equations without further ado \[ \large J_{linear}= -\dfrac{m_{red}}{\Delta t} C_{k} x - C_{d} v \] \[ \large J_{angular} = -\dfrac{I_{red}}{\Delta t} C_{k} \theta - C_{d} \omega \] In this particular case there is no difference between the force-based and impulse-based spring. They should return the exact same results.

    Limitations and pitfalls

    When connecting a multitude of springs and particles into larger bodies, we run into the same trouble as any other type of distance and velocity constraint. Rather than cooperating, the constraints tend compete against each other, and this spells trouble. When a spring moves two particles to satisfy distance and velocity, it usually means dissatisfying one or several other springs. It is outside the scope of this article to dig deeply into this problem, but the author would like to provide a bit of advice on how to prevent the worst disasters. When two or more springs are connected to the same particle, which is the case in any kind of rope, mesh, or deformable body, setting the coefficients to the maximum value of 1.0 will lead to stability problems. Although the spring equation is stable when used with a single or two particles, this is sadly not the case for higher number of particles. The author of this article has after some lengthy tampering worked out that a safe upper limit for both the stiffness and damping coefficient is \[ \large c_{max} \approx \dfrac{1}{n + 1} \] Where n denotes the highest number of springs attached to any of the two particles connected by the spring. So for example, in a rope where any particle is connected by at most two springs, Ck and Cd can both safely be set to 0.33, and in a square mesh, where any particle is at most connected by four springs, they can be set to 0.2.



      Report Article

    User Feedback

    One issue with parameterizing the damping like this is that you'll find that you need to change the damping coefficient every time you change the stiffness. It's easier to define the damping coefficient using the damping ratio. (https://en.wikipedia.org/wiki/Damping_ratio)


    d = cd * 2 * Sqrt(k * m)

    Once you expand out for the definition of k using the dimensionless coefficient ck, you get the following:

    d = cd * 2 * m / dt * Sqrt(ck)

    Share this comment

    Link to comment
    Share on other sites
    On 7/28/2019 at 9:03 PM, h4tt3n said:

    Here is the updated and expanded version of the article. It clarifies a few things and includes code samples.

    Stable springs 0.7.3.pdf

    Hi @h4tt3n, thank you for the amazing article!  I implemented your linear spring equation in Unity and it works amazingly. Very helpful to a complete physics beginner like me. But I was sad to see that you removed your angular spring info from your latest PDF version.

    I'm now trying to implement an angular spring with your equation, and I'm having trouble as Unity provides the inertia tensor as a Vector3 diagonal along with a Quaternion inertia tensor rotation, instead of a 3x3 matrix. I believe this is the way to apply the inertia tensor to torque using Unity's provided data: 

                var q = Rigidbody.rotation * Rigidbody.inertiaTensorRotation;
                var T = q * Vector3.Scale(Rigidbody.inertiaTensor, (Quaternion.Inverse(q) * torque));


    I'm unsure of how to use the inertia tensor diagonal/rotation with your angular spring equation, as I assume your equation expects 'I' to be a 3x3 matrix? Any advice on how I can implement your angular spring equation with the inertia tensor diagonal/rotation?

    Thank you!

    Edited by Junkman99

    Share this comment

    Link to comment
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!