All writing

Structural

The Stiffness Matrix from First Principles

Where the element stiffness matrix comes from, in full: virtual work, shape functions, the strain-displacement matrix, and the 12×12 frame element, with every step derived rather than quoted.

Updated 18 min read


On this page7 sections

Every finite element analysis — ETABS, SAP2000, ANSYS, a Python solver of your own — resolves to the same object: the element stiffness matrix.

It comes out of one principle and one assumption, and all of it fits inside a single integral. No black boxes.

The core idea

A structural element resists deformation. The stiffness matrix [K][K] captures how much — it maps nodal displacements {u}\{u\} to nodal forces {F}\{F\}:

[K]{u}={F}[K] \{u\} = \{F\}

For a single element with nn degrees of freedom, [K][K] is an n×nn \times n matrix. For a full structure, we assemble all element matrices into a global [K][K].

Deriving the bar element

The 2-node axial bar is the smallest element that shows every step, and every step generalises. Four moves get from a principle to a matrix.

Virtual work

Principle of virtual work

For a body in equilibrium, the virtual work done by external forces through any virtual displacement equals the virtual strain energy stored internally.

δWext=δWint\delta W_{ext} = \delta W_{int}

For a bar element under virtual nodal displacement {δu}\{\delta u\}:

{δu}T{F}=V{δε}T{σ}dV\{\delta u\}^T \{F\} = \int_V \{\delta \varepsilon\}^T \{\sigma\} \, dV

This is the foundation. Now we need to connect strains to displacements.

Shape functions

A 2-node bar element has 2 DOF: u1u_1 and u2u_2 (axial displacements). We assume the displacement varies linearly along the element:

u(x)=(1xL)N1(x)u1+xLN2(x)u2u(x) = \underbrace{\left(1 - \frac{x}{L}\right)}_{N_1(x)} u_1 + \underbrace{\frac{x}{L}}_{N_2(x)} u_2
Shape functionsN(x)

N₁ and N₂ define how the interior displacement field is interpolated from the nodal values.

In matrix form:

u(x)=[N(x)]{u}=[N1N2]{u1u2}u(x) = [N(x)] \{u\} = [N_1 \quad N_2] \begin{Bmatrix} u_1 \\ u_2 \end{Bmatrix}

Strain from displacement

For a bar in axial loading, strain is:

ε=dudx=[B]{u}\varepsilon = \frac{du}{dx} = [B] \{u\}

where [B][B] is the strain-displacement matrix, found by differentiating [N][N]:

[B]=d[N]dx=[1L1L][B] = \frac{d[N]}{dx} = \left[-\frac{1}{L} \quad \frac{1}{L}\right]

The integral

With linear elastic material, stress follows strain:

{σ}=E{ε}=E[B]{u}\{\sigma\} = E \{\varepsilon\} = E [B] \{u\}

Substituting into the virtual work equation:

{δu}T{F}=0L{δu}T[B]TE[B]{u}Adx\{\delta u\}^T \{F\} = \int_0^L \{\delta u\}^T [B]^T E [B] \{u\} \, A \, dx

Since {δu}T\{\delta u\}^T is arbitrary, we can factor it out:

{F}=(0L[B]TE[B]Adx)[K]{u}\{F\} = \underbrace{\left( \int_0^L [B]^T E [B] A \, dx \right)}_{[K]} \{u\}

For a bar with constant EE, AA:

[K]=EAL[1111][K] = \frac{EA}{L} \begin{bmatrix} 1 & -1 \\ -1 & 1 \end{bmatrix}

That’s the 2×2 stiffness matrix for an axial bar element — derived entirely from first principles.

The beam element

A 2D Euler–Bernoulli beam element has 4 DOF: two transverse displacements v1v_1, v2v_2 and two rotations θ1\theta_1, θ2\theta_2.

The shape functions are cubic (Hermite polynomials):

v(x)=N1v1+N2θ1+N3v2+N4θ2v(x) = N_1 v_1 + N_2 \theta_1 + N_3 v_2 + N_4 \theta_2

where:

N1=13ξ2+2ξ3,N2=L(ξ2ξ2+ξ3)N_1 = 1 - 3\xi^2 + 2\xi^3, \quad N_2 = L(\xi - 2\xi^2 + \xi^3) N3=3ξ22ξ3,N4=L(ξ2+ξ3),ξ=x/LN_3 = 3\xi^2 - 2\xi^3, \quad N_4 = L(-\xi^2 + \xi^3), \quad \xi = x/L

Curvature is the bending analogue of strain, and it plays exactly the same role in the integral:

κ=d2vdx2=[B]{u}\kappa = \frac{d^2v}{dx^2} = [B] \{u\}

So the stiffness matrix follows the same form:

[K]=0L[B]TEI[B]dx=EIL3[126L126L6L4L26L2L2126L126L6L2L26L4L2][K] = \int_0^L [B]^T EI [B] \, dx = \frac{EI}{L^3} \begin{bmatrix} 12 & 6L & -12 & 6L \\ 6L & 4L^2 & -6L & 2L^2 \\ -12 & -6L & 12 & -6L \\ 6L & 2L^2 & -6L & 4L^2 \end{bmatrix}

This is the Euler–Bernoulli beam stiffness matrix — you’ll find this exact matrix in every structural analysis textbook.

Putting numbers in it

The derivation stops at symbols, which is the right place for a derivation to stop and the wrong place to leave it. Two plots of what it already contains, then the same thing with a section in it.

Hermite shape functions of the Euler–Bernoulli beam elementFour cubic curves over the normalised element length. N₁ falls from 1 to 0 and N₃ rises from 0 to 1; N₂/L and N₄/L are the rotational shapes, each peaking near a quarter point and vanishing at both ends.-0.200.20.40.60.8100.250.50.751ξ = x / Lshape valueN₁ (v₁)N₂/L (θ₁)N₃ (v₂)N₄/L (θ₂)
Beam element stiffness terms against spanBoth terms normalised to their value at a 2 m element. The translational term 12EI/L³ collapses far faster than the rotational term 4EI/L: at 12 m it retains about half a percent of its 2 m value, against about seventeen percent for the rotational term.00.20.40.60.8124681012element length L (m)stiffness ÷ its value at L = 2 m12EI/L³ (sway)4EI/L (end rotation)
Figure 1Both plots are computed from the derivation above, not drawn to illustrate it. Shape functions: the four Hermite cubics of the section above, over ξ = x/L. Stiffness vs span: the two diagonal terms of equation (3) for a 210 GPa, 8360 cm⁴ section, each divided by its own value at L = 2 m.

Enter a section and a length below and both matrices are evaluated as you type.

Element properties

GPa

mm²

cm⁴

m

Axial (bar) element

EA/L 188,300 kN/m DOF order [u₁, u₂]

Axial (bar) element stiffness matrix in local coordinates, DOF order [u₁, u₂]. Row i is the force or moment at degree of freedom i; column j is a unit displacement or rotation at degree of freedom j.
u₁ per mu₂ per m
u₁188,300 kN/m-188,300 kN/m
u₂-188,300 kN/m188,300 kN/m

Euler–Bernoulli beam element

EI/L³ 81.28 kN/m DOF order [v₁, θ₁, v₂, θ₂]

Euler–Bernoulli beam element stiffness matrix in local coordinates, DOF order [v₁, θ₁, v₂, θ₂]. Row i is the force or moment at degree of freedom i; column j is a unit displacement or rotation at degree of freedom j.
v₁ per mθ₁ per radv₂ per mθ₂ per rad
v₁975.3 kN/m2,926 kN/rad-975.3 kN/m2,926 kN/rad
θ₁2,926 kN·m/m11,700 kN·m/rad-2,926 kN·m/m5,852 kN·m/rad
v₂-975.3 kN/m-2,926 kN/rad975.3 kN/m-2,926 kN/rad
θ₂2,926 kN·m/m5,852 kN·m/rad-2,926 kN·m/m11,700 kN·m/rad

Values are shown to 4 significant figures. Rotations are in radians, which are dimensionless — so kN/rad is kN, and kN·m/rad is kN·m. Local element coordinates; no transformation to global axes.

Figure 2Equations (2) and (3) evaluated for a section you choose. Every entry comes from the same closed forms derived above; nothing here is fitted, interpolated or looked up.

Note

Length is the interesting input. Double LL and the translational term 12EI/L312EI/L^3 falls by a factor of eight, while the rotational term 4EI/L4EI/L only halves — which is why a member’s resistance to end rotation survives a span increase far better than its resistance to sway does.

Warning

These are element matrices in local coordinates, not a structural analysis. They carry the same assumptions as the derivation above: a prismatic element with constant EE, AA and II, linear elastic material, small displacements, and Euler–Bernoulli bending — shear deformation is neglected. Assembling them, applying boundary conditions and solving is the next step, not this one.

The 3D frame element

Combining axial, bending (two planes), torsion, and shear DOF gives the full 12×12 matrix used in ETABS, SAP2000, and every general-purpose FEM solver.

The assembly process is always the same:

  1. Define shape functions for each DOF
  2. Compute [B][B] by differentiation
  3. Integrate [K]=[B]T[D][B]dV[K] = \int [B]^T [D] [B] \, dV
  4. Transform from local to global coordinates via [K]global=[T]T[K]local[T][K]_{global} = [T]^T [K]_{local} [T]

In code

import numpy as np

def bar_stiffness(E: float, A: float, L: float) -> np.ndarray:
    """2x2 stiffness matrix for an axial bar element."""
    k = (E * A / L)
    return k * np.array([[1, -1], [-1, 1]])

def beam_stiffness(E: float, I: float, L: float) -> np.ndarray:
    """4x4 Euler-Bernoulli beam element stiffness matrix.
    DOF order: [v1, θ1, v2, θ2]
    """
    k = E * I / L**3
    return k * np.array([
        [ 12,   6*L,  -12,   6*L],
        [6*L, 4*L**2, -6*L, 2*L**2],
        [-12,  -6*L,   12,  -6*L],
        [6*L, 2*L**2, -6*L, 4*L**2],
    ])

Both functions are the closed forms above, transcribed. Nothing in them is fitted or looked up — an error in either one is a typo, not a modelling decision.

What this tells you

Every result ETABS gives you flows from this integral. The “stiffness matrix” isn’t a magic number lookup — it’s a compact representation of how a physical element resists deformation, derived from strain energy and virtual work.

Understanding the derivation doesn’t change your day-to-day workflow. But when a model gives you a surprising result, it tells you where to look.