Helical Spring Analysis and Design

This notebook and associated python functions are meant to be first order tools for the design and analysis of helical springs.

The first Section introduces the governing equations which model ideal helical spring behavior as a function of its geometrical and material properties.

The second section calculates the spring properties of an example spring on the Efunda website as a test of the implementation used here.

The third section works through an example spring design given a set of design requirements.

Governing Equations

The spring constant of a helical spring may be calculated: $$ k = \frac{Gd^4}{8n_aD^3} $$ Where $G$ is the shear modulus, $d$ is the diameter of the wire, $n_a$ is the number of coils active in the spring, and $D$ is the mean diameter of the coil. (The figure above has 6 active coils.)

The shear modulus is a property of the material. $$ G = \frac{E}{2(1+v)} $$ Where $E$ is Young's modulus of the material and $v$ is Poisson's ratio.

The pitch of the coil is then: $$ p = \frac{L_{free}}{n_a} $$ Where $L_{free}$ is the free length of the spring.

and the coil angle is then: $$ \alpha = tan^{-1}\frac{p}{\pi D} $$

Design Rules

These governing equations only hold when their underlying assumptions about the material are valid. After working through the mathematics, it is worthwhile to check to make sure that the material will behave properly for this design.

Spring Index

The spring index is the ratio of mean spring diameter to wire diameter $$ C=\frac{D}{d} $$ If the spring index is small, that means that the wire diameter is large compared to the overall spring diameter and the curvatures of the spring wire are very high. This requires high stresses in the material and on the tooling used to create the tooling. As a rule of thumb, spring indexes smaller than about 4-5 are hard to manufacture.

If the spring index is too large, then the wire diameter is quite small compared to the spring diameter and the spring does not have a great deal of mechanical integrity on its own. Springs with indexes above about 15 tend to yield higher variability and are difficult to manufacture precisely.

Spring indexes between 6-12 are considered ideal and 13-15 generally doable.

Shear strength

These equations assume that the material stress-strain relationship is linear and elastic. For this to be true the spring must operate at stresses bellow the yield stress, especially for large numbers of cycles. A good design rule of thumb is that the shear stresses should be no more than 30% to 50% of the ultimate stress of the material.

The shear stresses may be calculated by first considering the maximum axial force on the spring: $$ F_{max} = k(L_{free} - L_{solid}) $$ The free length is often given, and the solid length can be found by multiplying the wire wire thickness by the number of coils. $$ L_{solid} = d(n_a+2) $$ The solid length can be though of the length of the spring when is is fully compressed. The maximum shear is then: $$ \tau_{max}=F_{max}\frac{8DW}{\pi d^3} $$ Where $W$ is the Wahl correction factor (a geometric correction factor taking into account the curvature of the coils): $$ W = \frac{4C-1}{4C-4} + \frac{0.615}{C} $$

Test Case

The implementation will be tested by comparing results to the Efunda example here.

Spring properties

First we will solve for spring properties given material and physical parameters


In [1]:
from springs import Material, Spring
import units as u

steel   =  Material(Material.STEEL)
d_mean  = (0.500-0.035)*u.inch
d_wire  = 0.035*u.inch
L_free  = 1*u.inch
n_coils = 8
efunda  = Spring(d_mean, d_wire, L_free, n_coils, steel)
efunda.print_properties('En', 'efunda')


-------------------------------------
Spring: efunda
-------------------------------------
Outer diameter       :0.500 in
Mean diameter        :0.465 in
Inside diameter      :0.430 in
Wire diameter        :0.035 in
Free length          :1.000 in
Number of coils      :8.0 
Spring constant      :2.60e+00 lbf/in
Spring index [5-15]  :13.3
Max force possible   :1.69e+00 lbf
Max shear stress     :5.17e+01 ksi
Solid height         :0.350 in
Max displacement     :0.650 in
Coil pitch           :0.125 in per coil 
Rise angle           :4.89 deg
Spring wire length   :14.651 in

These numbers match the efunda calculator reference within displayed precision.

Here we can see that the spring has a spring constant $k$=2.6 lb/in and a spring index $C$=13.3 which is toward the upper end of desirable.

The shear stress in the wire is maximally 51 ksi which is less than 30% of ~250 ksi, a typical yield stress for drawn music wire in this diameter range.

Solving for wire diameter

Now going backward, solve for the spring diameter to yield the desired spring rate.


In [2]:
d_mean  = (0.5-0.035)*u.inch
n_coils = 8
k       = 2.6*u.lbf/u.inch
d_wire  = Spring.solve_diameter(d_mean, n_coils, k, steel)
print 'The recommended spring diameter is: %.3f in (efunda)' % \
    (d_wire / u.inch)


The recommended spring diameter is: 0.035 in (efunda)

The wire diameter calculator correctly returned $d$=0.035 in, the value we input in the forward equation above.

Worked Example

The process of homing in on a spring design is often iterative. Given these requirements:

  1. The inside diameter is 3/8 in
  2. The spring travel is 1 in
  3. The spring preload shall be 2 lb
  4. The spring force at full travel shall be 4 lb

Pick a spring that is easy to manufacture and reliable over its life.

As a starting point, we can solve for the desired spring rate:


In [3]:
F_pre   = 2*u.lbf
F_max   = 4*u.lbf
travel  = 1*u.inch
k       = (F_max - F_pre) / (travel)
print 'The desired spring rate is %.1f lbf/in \n' % (k / u.lbf * u.inch)


The desired spring rate is 2.0 lbf/in 

As starting points, lets guess .375in for the mean diameter and 8 coils per inch as in the above example.

We also know we want a 2 lb preload on the spring and 1 inch of travel at a spring rate of 2 lbf/in. Since the so the spring must be longer than 2 inches minimum to account for spring wire thickness, lets pick 3 in in as a starting guess.


In [4]:
steel   =  Material(Material.STEEL)
d_mean  = (0.375)*u.inch
L       = F_max / k + 1*u.inch
pitch   = 8 / u.inch                 #coils per inch
n_coils = L*pitch
d_wire = Spring.solve_diameter(d_mean, n_coils, k, steel)
s = Spring(d_mean, d_wire, L, n_coils, steel)
s.print_properties('En','Custom Spring')


-------------------------------------
Spring: Custom Spring
-------------------------------------
Outer diameter       :0.412 in
Mean diameter        :0.375 in
Inside diameter      :0.338 in
Wire diameter        :0.037 in
Free length          :3.000 in
Number of coils      :24.0 
Spring constant      :2.00e+00 lbf/in
Spring index [5-15]  :10.2
Max force possible   :4.09e+00 lbf
Max shear stress     :9.02e+01 ksi
Solid height         :0.954 in
Max displacement     :2.046 in
Coil pitch           :0.125 in per coil 
Rise angle           :6.06 deg
Spring wire length   :30.789 in

On the first iteration we see that quite a few assumptions are marginal. Lets first start with the understanding that the wire diameter will be in the neighborhood of .037 in and the inside diameter too small. Lets bump the mean diameter by 0.045 and see where we come out


In [5]:
steel   =  Material(Material.STEEL)
d_mean  = (0.375 + 0.045)*u.inch
L       = F_max / k + 1*u.inch
pitch   = 8 / u.inch                 #coils per inch
n_coils = L*pitch
d_wire = Spring.solve_diameter(d_mean, n_coils, k, steel)
s = Spring(d_mean, d_wire, L, n_coils, steel)
s.print_properties('En','Custom Spring')


-------------------------------------
Spring: Custom Spring
-------------------------------------
Outer diameter       :0.460 in
Mean diameter        :0.420 in
Inside diameter      :0.380 in
Wire diameter        :0.040 in
Free length          :3.000 in
Number of coils      :24.0 
Spring constant      :2.00e+00 lbf/in
Spring index [5-15]  :10.5
Max force possible   :3.92e+00 lbf
Max shear stress     :7.47e+01 ksi
Solid height         :1.039 in
Max displacement     :1.961 in
Coil pitch           :0.125 in per coil 
Rise angle           :5.41 deg
Spring wire length   :34.448 in

The inside diameter is now as desired plus a little clearance. Next on the list we see that the total spring travel is less than 2 in, and that the max force is less than our 4lb requirements. To accommodate for this, increase the free length to 4 in.


In [6]:
steel   =  Material(Material.STEEL)
d_mean  = (0.375 + 0.045)*u.inch
L       = F_max / k + 2*u.inch
pitch   = 8 / u.inch                 #coils per inch
n_coils = L*pitch
d_wire = Spring.solve_diameter(d_mean, n_coils, k, steel)
s = Spring(d_mean, d_wire, L, n_coils, steel)
s.print_properties('En','Custom Spring')


-------------------------------------
Spring: Custom Spring
-------------------------------------
Outer diameter       :0.463 in
Mean diameter        :0.420 in
Inside diameter      :0.377 in
Wire diameter        :0.043 in
Free length          :4.000 in
Number of coils      :32.0 
Spring constant      :2.00e+00 lbf/in
Spring index [5-15]  :9.8
Max force possible   :5.08e+00 lbf
Max shear stress     :7.88e+01 ksi
Solid height         :1.460 in
Max displacement     :2.540 in
Coil pitch           :0.125 in per coil 
Rise angle           :5.41 deg
Spring wire length   :45.051 in

On this final spring the diameters, travel, and max force all look good. The spring index is in a good range and the maximum shear stress is ~30% of the yield stress of music wire in this range.

Future work

  1. Include an estimate for the yield strengths of various diameters of music wire
  2. Calculate the % max shear stress directly
  3. Look for a way to set maximum shear as a parameter and solve for pitch or similar directly
  4. Incorporate a parameterized widget to allow real-time adjusting of the different parameters
  5. Add discussion on after treatment such as shot peening
  6. Add discussion around the influence of each free parameter

In [6]:


In [7]:
from IPython.display import HTML
from ipynb_utils import inject_css, toggle_js, inject_css2
HTML(inject_css2('custom.css'))


Out[7]:

In [7]: