Beam Deflection
Deflection limits often govern beam design more than stress. A beam might be strong enough but deflect too much, causing serviceability problems.
The Governing Equation
The relationship between bending moment and deflection:
$$EI\frac{d^2y}{dx^2} = M(x)$$
Sponsored
Ranjith switched from IT to core automotive industry
His inspiring career transition story with video
Or in terms of distributed load:
$$EI\frac{d^4y}{dx^4} = -w(x)$$
Where:
Sponsored
Srinithin now works at Xitadel as Design Engineer
Mechanical engineering graduate turned automotive designer
- $y$ = Deflection
- $E$ = Young's modulus
- $I$ = Moment of inertia
- $M(x)$ = Bending moment function
- $w(x)$ = Distributed load (positive upward)
Standard Beam Deflection Formulas
import numpy as np
import matplotlib.pyplot as plt
class BeamDeflection:
"""Collection of standard beam deflection formulas."""
@staticmethod
def cantilever_point_load(P, L, E, I, x=None):
"""
Cantilever beam with point load at free end.
P = Load (N)
L = Length (mm)
E = Young's modulus (MPa)
I = Moment of inertia (mm⁴)
x = Position(s) from fixed end (mm), default is full length array
"""
if x is None:
x = np.linspace(0, L, 100)
# Deflection formula: y = Px²(3L - x) / (6EI)
y = P * x**2 * (3*L - x) / (6 * E * I)
# Maximum deflection at free end
y_max = P * L**3 / (3 * E * I)
# Slope at free end
theta_max = P * L**2 / (2 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'theta_max_rad': theta_max,
'type': 'Cantilever with point load at end'
}
@staticmethod
def cantilever_udl(w, L, E, I, x=None):
"""
Cantilever beam with uniformly distributed load.
w = Load per unit length (N/mm)
"""
if x is None:
x = np.linspace(0, L, 100)
# y = wx²(6L² - 4Lx + x²) / (24EI)
y = w * x**2 * (6*L**2 - 4*L*x + x**2) / (24 * E * I)
y_max = w * L**4 / (8 * E * I)
theta_max = w * L**3 / (6 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'theta_max_rad': theta_max,
'type': 'Cantilever with UDL'
}
@staticmethod
def simply_supported_center_load(P, L, E, I, x=None):
"""
Simply supported beam with point load at center.
"""
if x is None:
x = np.linspace(0, L, 100)
# Piecewise formula
y = np.where(
x <= L/2,
P * x * (3*L**2 - 4*x**2) / (48 * E * I),
P * (L - x) * (3*L**2 - 4*(L-x)**2) / (48 * E * I)
)
y_max = P * L**3 / (48 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'type': 'Simply supported with center point load'
}
@staticmethod
def simply_supported_udl(w, L, E, I, x=None):
"""
Simply supported beam with uniformly distributed load.
"""
if x is None:
x = np.linspace(0, L, 100)
# y = wx(L³ - 2Lx² + x³) / (24EI)
y = w * x * (L**3 - 2*L*x**2 + x**3) / (24 * E * I)
y_max = 5 * w * L**4 / (384 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'type': 'Simply supported with UDL'
}
@staticmethod
def fixed_fixed_center_load(P, L, E, I, x=None):
"""
Fixed-fixed beam with point load at center.
"""
if x is None:
x = np.linspace(0, L, 100)
# For center load
y = np.where(
x <= L/2,
P * x**2 * (3*L - 4*x) / (48 * E * I),
P * (L - x)**2 * (3*L - 4*(L-x)) / (48 * E * I)
)
y_max = P * L**3 / (192 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'type': 'Fixed-fixed with center point load'
}
@staticmethod
def fixed_fixed_udl(w, L, E, I, x=None):
"""
Fixed-fixed beam with uniformly distributed load.
"""
if x is None:
x = np.linspace(0, L, 100)
y = w * x**2 * (L - x)**2 / (24 * E * I)
y_max = w * L**4 / (384 * E * I)
return {
'x': x,
'y': y,
'y_max': y_max,
'type': 'Fixed-fixed with UDL'
}
# Example usage
E = 200e3 # Steel, MPa
I = 8.33e6 # 100×200mm rectangle, mm⁴
L = 3000 # 3 meters
P = 10e3 # 10 kN
# Compare different support conditions
beam = BeamDeflection()
configs = [
('Cantilever', beam.cantilever_point_load(P, L, E, I)),
('Simply Supported', beam.simply_supported_center_load(P, L, E, I)),
('Fixed-Fixed', beam.fixed_fixed_center_load(P, L, E, I))
]
print("Beam Deflection Comparison")
print(f"Load: {P/1000:.1f} kN, Span: {L} mm")
print(f"E = {E/1000:.0f} GPa, I = {I:.2e} mm⁴")
print("-" * 50)
for name, result in configs:
print(f"{name}: δmax = {result['y_max']:.3f} mm")
Visualizing Deflection Curves
def plot_deflection_comparison():
"""Compare deflection curves for different support conditions."""
E = 200e3 # MPa
I = 5e6 # mm⁴
L = 2000 # mm
P = 5e3 # N
beam = BeamDeflection()
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. Cantilever with point load
ax1 = axes[0, 0]
result = beam.cantilever_point_load(P, L, E, I)
ax1.fill_between(result['x'], 0, -result['y'], alpha=0.3, color='blue')
ax1.plot(result['x'], -result['y'], 'b-', lw=2)
ax1.axhline(y=0, color='k', lw=1)
# Fixed support
ax1.fill_between([-50, 0], [-5, -5], [5, 5], color='gray', alpha=0.5)
# Load arrow
ax1.annotate('', xy=(L, -result['y_max']), xytext=(L, -result['y_max']-100),
arrowprops=dict(arrowstyle='->', lw=2, color='red'))
ax1.text(L, -result['y_max']-120, f'P={P/1000:.0f}kN', ha='center', color='red')
ax1.set_title(f"Cantilever: δmax = {result['y_max']:.2f} mm")
ax1.set_xlabel('x (mm)')
ax1.set_ylabel('Deflection (mm)')
ax1.grid(True, alpha=0.3)
ax1.set_xlim(-100, L+100)
# 2. Simply supported with center load
ax2 = axes[0, 1]
result = beam.simply_supported_center_load(P, L, E, I)
ax2.fill_between(result['x'], 0, -result['y'], alpha=0.3, color='green')
ax2.plot(result['x'], -result['y'], 'g-', lw=2)
ax2.axhline(y=0, color='k', lw=1)
# Supports
ax2.scatter([0, L], [0, 0], s=300, marker='^', color='gray', zorder=5)
# Load
ax2.annotate('', xy=(L/2, -result['y_max']), xytext=(L/2, -result['y_max']-100),
arrowprops=dict(arrowstyle='->', lw=2, color='red'))
ax2.set_title(f"Simply Supported: δmax = {result['y_max']:.2f} mm")
ax2.set_xlabel('x (mm)')
ax2.set_ylabel('Deflection (mm)')
ax2.grid(True, alpha=0.3)
# 3. Fixed-fixed with center load
ax3 = axes[1, 0]
result = beam.fixed_fixed_center_load(P, L, E, I)
ax3.fill_between(result['x'], 0, -result['y'], alpha=0.3, color='orange')
ax3.plot(result['x'], -result['y'], 'orange', lw=2)
ax3.axhline(y=0, color='k', lw=1)
# Fixed supports
ax3.fill_between([-50, 0], [-5, -5], [5, 5], color='gray', alpha=0.5)
ax3.fill_between([L, L+50], [-5, -5], [5, 5], color='gray', alpha=0.5)
ax3.set_title(f"Fixed-Fixed: δmax = {result['y_max']:.2f} mm")
ax3.set_xlabel('x (mm)')
ax3.set_ylabel('Deflection (mm)')
ax3.grid(True, alpha=0.3)
ax3.set_xlim(-100, L+100)
# 4. Comparison
ax4 = axes[1, 1]
for name, color, func in [
('Cantilever', 'blue', beam.cantilever_point_load),
('Simply Supported', 'green', beam.simply_supported_center_load),
('Fixed-Fixed', 'orange', beam.fixed_fixed_center_load)
]:
result = func(P, L, E, I)
# Normalize to compare shapes
y_norm = result['y'] / result['y_max']
ax4.plot(result['x']/L, y_norm, lw=2, label=name)
ax4.set_xlabel('Normalized Position (x/L)')
ax4.set_ylabel('Normalized Deflection (y/ymax)')
ax4.set_title('Shape Comparison (Normalized)')
ax4.legend()
ax4.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
plot_deflection_comparison()
Superposition Method
For beams with multiple loads, we can add individual deflections:
$$\delta_{total} = \delta_1 + \delta_2 + \delta_3 + ...$$
def superposition_example():
"""
Example: Simply supported beam with multiple loads.
|----a----|
P1 P2 w (UDL)
↓ ↓ ↓↓↓↓↓↓
================
△ △
|--------L---------|
"""
E = 200e3 # MPa
I = 10e6 # mm⁴
L = 4000 # mm
# Loads
P1 = 8e3 # N at x = 1000mm
P2 = 5e3 # N at x = 2500mm
w = 5 # N/mm (UDL over entire span)
x = np.linspace(0, L, 200)
# Individual deflections
beam = BeamDeflection()
# UDL deflection
y_udl = beam.simply_supported_udl(w, L, E, I, x)['y']
# Point loads (use general formula for load at distance 'a' from left)
def point_load_deflection(P, a, L, E, I, x):
"""Deflection for point load P at distance a from left support."""
b = L - a
y = np.zeros_like(x)
# For x <= a
mask1 = x <= a
y[mask1] = P * b * x[mask1] / (6 * L * E * I) * \
(L**2 - b**2 - x[mask1]**2)
# For x > a
mask2 = x > a
y[mask2] = P * b / (6 * L * E * I) * \
(L/b * (x[mask2] - a)**3 + (L**2 - b**2)*x[mask2] - x[mask2]**3)
return y
y_P1 = point_load_deflection(P1, 1000, L, E, I, x)
y_P2 = point_load_deflection(P2, 2500, L, E, I, x)
# Total deflection
y_total = y_udl + y_P1 + y_P2
# Plot
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
# Individual components
ax1 = axes[0]
ax1.plot(x, -y_udl, 'b--', lw=1.5, label=f'UDL (w={w} N/mm)')
ax1.plot(x, -y_P1, 'g--', lw=1.5, label=f'P1={P1/1000}kN at 1000mm')
ax1.plot(x, -y_P2, 'r--', lw=1.5, label=f'P2={P2/1000}kN at 2500mm')
ax1.axhline(y=0, color='k', lw=0.5)
ax1.set_xlabel('x (mm)')
ax1.set_ylabel('Deflection (mm)')
ax1.set_title('Individual Load Contributions')
ax1.legend()
ax1.grid(True, alpha=0.3)
# Total
ax2 = axes[1]
ax2.fill_between(x, 0, -y_total, alpha=0.3, color='purple')
ax2.plot(x, -y_total, 'purple', lw=2, label='Total deflection')
ax2.axhline(y=0, color='k', lw=0.5)
# Mark maximum
idx_max = np.argmax(y_total)
ax2.scatter([x[idx_max]], [-y_total[idx_max]], s=100, color='red', zorder=5)
ax2.annotate(f'δmax = {y_total[idx_max]:.2f} mm\nat x = {x[idx_max]:.0f} mm',
xy=(x[idx_max], -y_total[idx_max]),
xytext=(x[idx_max]+200, -y_total[idx_max]-1),
fontsize=10, color='red')
ax2.set_xlabel('x (mm)')
ax2.set_ylabel('Deflection (mm)')
ax2.set_title('Total Deflection (Superposition)')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"Maximum deflection: {max(y_total):.3f} mm")
print(f"Location: {x[np.argmax(y_total)]:.0f} mm from left support")
superposition_example()
Deflection Limits
Common serviceability limits:
Sponsored
Gaurav Jadhav is now a CAE Engineer
Practical projects and mock interviews made the difference
| Application | Deflection Limit |
|---|
| Floor beams | L/360 |
| Roof beams | L/240 |
| Cantilevers | L/180 |
| Industrial buildings | L/200 |
def check_deflection_limits(L_mm, delta_max_mm, application='floor'):
"""Check if deflection meets serviceability limits."""
limits = {
'floor': 360,
'roof': 240,
'cantilever': 180,
'industrial': 200
}
limit_ratio = limits.get(application, 360)
allowable = L_mm / limit_ratio
actual_ratio = L_mm / delta_max_mm if delta_max_mm > 0 else float('inf')
print(f"Deflection Check ({application}):")
print(f" Span: {L_mm} mm")
print(f" Maximum deflection: {delta_max_mm:.2f} mm")
print(f" Allowable (L/{limit_ratio}): {allowable:.2f} mm")
print(f" Actual ratio: L/{actual_ratio:.0f}")
print(f" Status: {'PASS ✓' if delta_max_mm <= allowable else 'FAIL ✗'}")
return delta_max_mm <= allowable
# Example
check_deflection_limits(L_mm=6000, delta_max_mm=20, application='floor')
Moment-Area Method
An alternative to integration, useful for complex loading:
First Moment-Area Theorem:
The angle between tangents at two points equals the area under the M/EI diagram.
Second Moment-Area Theorem:
The vertical distance from a point to the tangent drawn from another point equals the first moment of the M/EI area about the point.
def moment_area_cantilever(P, L, E, I):
"""
Use moment-area method for cantilever with end load.
"""
# M/EI diagram is triangular: M = -P(L-x) for cantilever
# At fixed end: M = -PL
# At free end: M = 0
# Area under M/EI diagram
area = 0.5 * L * (P * L) / (E * I)
# Centroid of triangle from free end
x_bar = L / 3
# Deflection at free end = moment of area about free end
delta = area * (L - L/3) # First moment about free end
# Actually, for cantilever it's simpler:
# Tangent at fixed end is horizontal
# Deflection at free end = first moment of M/EI about free end
delta_correct = (1/2 * L * P*L/(E*I)) * (2*L/3) # = PL³/3EI
print(f"Moment-Area Method - Cantilever")
print(f" Standard formula: δ = PL³/(3EI) = {P*L**3/(3*E*I):.3f} mm")
print(f" Moment-area result: {delta_correct:.3f} mm")
moment_area_cantilever(P=10e3, L=2000, E=200e3, I=5e6)
Key Takeaways
- Governing equation: $EI \cdot d²y/dx² = M(x)$
- Stiffer beams (higher EI) deflect less
- Fixed supports reduce deflection compared to simple supports
- Superposition: Add deflections from individual loads
- Deflection limits: Typically L/360 for floors, L/240 for roofs
Next lesson: We'll learn to generate shear force and bending moment diagrams automatically.