Estimation of stiffness properties by classical laminate theory (CLT)

This python notebook goes through the steps of determining the stiffness of a fibre composite with a given layup.

Initially we initiate the packages necessary for the code:

In [1]:
import numpy as np

1. Definition of input parameters

Then, we will define the necessary input parameters for the calculations. Note that these stiffnesses are for each layer/ply in their own local coordinate system where the 1-direction is in the direction of the fibres and the 2-direction is in the direction transverse to the fibres.

In [2]:
layup = np.array([45,-45,0])                     # Orientation of the fibres for each layer/ply of the laminate

E1 = np.full((layup.shape[0],1), 40.)[:,0]       # Axial stiffness of each ply [GPa]
#E1 = np.array([45.6,45.6,45.6])                 # (Use this instead if layer properties are not the same for all layers)

E2 = np.full((layup.shape[0],1), 9.8)[:,0]       # transverse stiffness of each ply [GPa]
#E2 = np.array([16.2,16.2.16,2])                 # (Use this instead if layer properties are not the same for all layers)
v12 = np.full((layup.shape[0],1), 0.3)[:,0]      # Poisson's ratio
#v12 = np.array([0.278,0.278,0.278])             # (Use this instead if layer properties are not the same for all layers)
v21 = (v12*E2)/E1                                # (Since the compliance matrix is symmetric, v12/E1=v21/E2)

G12 = np.full((layup.shape[0],1), 2.8)[:,0]      # Shear modulus [GPa]
#G12 = np.array([5.83,5.83,5.83])                # (Use this instead if layer properties are not the same for all layers)

h0 = 0.1
h = np.array([4*h0,4*h0,2*h0])                   #height of each ply [mm]

2. Estimate the stiffness contribution of each layer of the laminate

Hook's Law for a thin orthotropic layer (a ply) can be written as:

\begin{equation*} \left( \begin{array}{c} \sigma_1 \\ \sigma_2 \\ \tau_{12} \end{array} \right) = \frac{1}{1-\nu_{12}\nu_{21}} \left[ \begin{array}{ccc} E_1 & \nu_{21}E_1 & 0\\ \nu_{12}E_2 & E_2 & 0 \\ 0 & 0 & G_{12}(1-\nu_{12}\nu_{21}) \end{array} \right] \left( \begin{array}{c} \varepsilon_1 \\ \varepsilon_2 \\ \gamma_{12} \end{array} \right) \end{equation*}

or in a shorther form

\begin{equation*} \sigma_l=Q_l\varepsilon_l \end{equation*}

where the $l$ stands for lamina or local, and Q is the local stiffness matrix of the ply.

To estimate the stiffness contribution of each layer of the composite, we calculate the local stiffness matrix for each ply and then transform them into the global coordinates. To do so, we start by calculating the local stiffness matrices for each layer of the composite. This is done by looping through each layer of the laminate as was defined by the "layup" parameter above, calculating the local stiffness matrices, and transforming them into global coordinates using the transformation matrix:

\begin{equation*} T=\left[ \begin{array}{ccc} c^2 & s^2 & -2sc\\ s^2 & c^2 & 2sc \\ sc & -sc & c^2-s^2 \end{array} \right] \end{equation*}

where s and c refer to $\sin\theta$ and $\cos\theta$, respectively. The global stiffness contribution from each layer can be found from: \begin{equation} Q=TQ_lT^T \end{equation}

Using this approach, Q is calculated for each layer in the following:

In [8]:
# Initiating Q as a list that can contain the stiffness matrices transformed into the global coordinates for each layer
# Looping through each layer of the laminate
for i in range(layup.shape[0]):
    theta = layup[i]*np.pi/180 # Current ply angle changed into radians
    # assigning the current material properties to temporary variables (could also be used directly):
    print('Ply no. ' + str(i+1) + ': theta='+ str(layup[i]) +', E1l=' + str(E1l), ' E2l=' + str(E2l))
    # Establishing current local stiffness matrix, Ql:
    Ql = 1/(1-v12l*v21l)*np.array([[E1l,v21l*E1l,0],\
    # Transformation matrix:
    T=np.array([[np.cos(theta)**2,np.sin(theta)**2,-2*np.sin(theta)*np.cos(theta)], \
    # Adding the current stiffness matrix in the global coordinate system to the Q-list variable:
Ply no. 1: theta=45, E1l=40.0  E2l=9.8
[[ 17.03385654  11.43385654   7.7202311 ]
 [ 11.43385654  17.03385654   7.7202311 ]
 [  7.7202311    7.7202311   11.22756787]]
Ply no. 2: theta=-45, E1l=40.0  E2l=9.8
[[ 17.03385654  11.43385654  -7.7202311 ]
 [ 11.43385654  17.03385654  -7.7202311 ]
 [ -7.7202311   -7.7202311   11.22756787]]
Ply no. 3: theta=0, E1l=40.0  E2l=9.8
[[ 40.9018866    3.00628867   0.        ]
 [  3.00628867  10.02096222   0.        ]
 [  0.           0.           2.8       ]]

With the stiffness matrices calculated in the global coordinate system for each of the layer orientations, the final contribution is calculated through the following:

\begin{equation*} A= \sum _{i=1}^N Q_i h_i \end{equation*}
In [4]:
for i in range(layup.shape[0]):

3. Calculating the average stiffness matrix and the global properties

The average stiffness matrix $Q^*$ can then be found from: $$ Q_*=\frac{A}{h_{tot}} $$ followed by the compliance matrix from which we can obtain the global stiffness properties of the total laminate as follows: $$ S^*=(Q^*)^{-1} \rightarrow E_x=1/S_{11}, \quad E_y = 1/S_{22}, \quad G_{xy}=1/S_{33} \quad and \quad \nu_{xy}=\frac{-S_{21}}{S_{1,1}} $$

This is done in the following:

In [7]:
Qstar = A/sum(h)
Sstar = np.linalg.inv(Qstar)
Ex = 1/Sstar[0,0]
Ey = 1/Sstar[1,1]
Gxy = 1/Sstar[2,2]

# Printing out the matrices
print('Q* Matrix')
print('S* Matrix')
Q* Matrix
[[ 21.80746255   9.74834296   0.        ]
 [  9.74834296  15.63127767   0.        ]
 [  0.           0.           9.5420543 ]]
S* Matrix
[[ 0.06358098 -0.03965186  0.        ]
 [-0.03965186  0.08870292  0.        ]
 [ 0.          0.          0.10479924]]
In [6]:
print('The total stiffness of the laminate is Ex='+ str(Ex)+ ' and Ey=' + str(Ey) + ', with a shear modulus Gxy='+ str(Gxy) + ' and a poissons ratio of vxy='+str(vxy))
The total stiffness of the laminate is Ex=15.7279729194 and Ey=11.2735863413, with a shear modulus Gxy=9.54205429725 and a poissons ratio of vxy=0.623643387729