Combined Loading
Real engineering components rarely experience only one type of loading. A drive shaft might experience bending, torsion, and axial force simultaneously. Understanding combined loading is essential for safe design.
Superposition Principle
For linear elastic materials, stresses from different loads can be added:
$$\sigma_{total} = \sigma_{axial} + \sigma_{bending}$$
Sponsored
70% of India's auto industry trusts Skill-Lync
For training their engineers in CAD, CAE & simulation
$$\tau_{total} = \tau_{torsion} + \tau_{shear}$$
Common Combined Loading Cases
import numpy as np
import matplotlib.pyplot as plt
class CombinedLoading:
"""Analyze combined loading on structural members."""
@staticmethod
def axial_bending(P_kN, M_kNm, A_mm2, I_mm4, c_mm, position='top'):
"""
Combined axial load and bending.
Parameters:
-----------
P_kN : float - Axial force (positive = tension)
M_kNm : float - Bending moment (positive = tension at bottom)
A_mm2 : float - Cross-sectional area
I_mm4 : float - Moment of inertia
c_mm : float - Distance to extreme fiber
position : str - 'top' or 'bottom'
"""
# Convert units
P = P_kN * 1e3 # N
M = M_kNm * 1e6 # N·mm
# Individual stresses
sigma_axial = P / A_mm2 # MPa
if position == 'top':
sigma_bending = -M * c_mm / I_mm4 # Compression at top for positive M
else:
sigma_bending = M * c_mm / I_mm4 # Tension at bottom for positive M
# Combined stress
sigma_total = sigma_axial + sigma_bending
return {
'sigma_axial': sigma_axial,
'sigma_bending': sigma_bending,
'sigma_total': sigma_total,
'position': position
}
@staticmethod
def bending_torsion(M_kNm, T_kNm, I_mm4, J_mm4, c_mm):
"""
Combined bending and torsion (common for shafts).
Returns principal stresses using Mohr's circle.
"""
M = M_kNm * 1e6 # N·mm
T = T_kNm * 1e6 # N·mm
# Bending stress at extreme fiber
sigma_b = M * c_mm / I_mm4 # MPa
# Torsional shear stress at surface
tau = T * c_mm / J_mm4 # MPa
# At surface: σx = σb, σy = 0, τxy = τ
# Principal stresses
sigma_avg = sigma_b / 2
R = np.sqrt(sigma_avg**2 + tau**2)
sigma_1 = sigma_avg + R
sigma_2 = sigma_avg - R
tau_max = R
return {
'sigma_bending': sigma_b,
'tau_torsion': tau,
'sigma_1': sigma_1,
'sigma_2': sigma_2,
'tau_max': tau_max
}
@staticmethod
def axial_bending_torsion(P_kN, M_kNm, T_kNm, A_mm2, I_mm4, J_mm4, c_mm):
"""
Combined axial, bending, and torsion.
"""
P = P_kN * 1e3
M = M_kNm * 1e6
T = T_kNm * 1e6
# Normal stress at extreme fiber
sigma_axial = P / A_mm2
sigma_bending = M * c_mm / I_mm4
sigma_x = sigma_axial + sigma_bending # Combined normal stress
# Shear stress
tau_xy = T * c_mm / J_mm4
# Principal stresses
sigma_avg = sigma_x / 2
R = np.sqrt(sigma_avg**2 + tau_xy**2)
sigma_1 = sigma_avg + R
sigma_2 = sigma_avg - R
tau_max = R
return {
'sigma_axial': sigma_axial,
'sigma_bending': sigma_bending,
'sigma_x': sigma_x,
'tau_xy': tau_xy,
'sigma_1': sigma_1,
'sigma_2': sigma_2,
'tau_max': tau_max
}
# Example: Circular shaft properties
d = 50 # mm
A = np.pi * (d/2)**2
I = np.pi * d**4 / 64
J = np.pi * d**4 / 32
c = d / 2
print("Combined Loading Analysis")
print(f"Shaft diameter: {d} mm")
print("=" * 50)
# Case 1: Axial + Bending
print("\nCase 1: Axial + Bending")
result = CombinedLoading.axial_bending(
P_kN=20, M_kNm=0.5, A_mm2=A, I_mm4=I, c_mm=c, position='bottom'
)
print(f" Axial stress: {result['sigma_axial']:.2f} MPa")
print(f" Bending stress: {result['sigma_bending']:.2f} MPa")
print(f" Total stress ({result['position']}): {result['sigma_total']:.2f} MPa")
# Case 2: Bending + Torsion
print("\nCase 2: Bending + Torsion")
result = CombinedLoading.bending_torsion(
M_kNm=0.8, T_kNm=1.2, I_mm4=I, J_mm4=J, c_mm=c
)
print(f" Bending stress: {result['sigma_bending']:.2f} MPa")
print(f" Torsional shear: {result['tau_torsion']:.2f} MPa")
print(f" Principal stress σ₁: {result['sigma_1']:.2f} MPa")
print(f" Principal stress σ₂: {result['sigma_2']:.2f} MPa")
print(f" Max shear stress: {result['tau_max']:.2f} MPa")
# Case 3: All combined
print("\nCase 3: Axial + Bending + Torsion")
result = CombinedLoading.axial_bending_torsion(
P_kN=15, M_kNm=0.8, T_kNm=1.2, A_mm2=A, I_mm4=I, J_mm4=J, c_mm=c
)
print(f" Combined normal σx: {result['sigma_x']:.2f} MPa")
print(f" Shear τxy: {result['tau_xy']:.2f} MPa")
print(f" Principal σ₁: {result['sigma_1']:.2f} MPa")
print(f" Principal σ₂: {result['sigma_2']:.2f} MPa")
Failure Theories
Different materials fail in different ways. We use failure theories to predict when yielding or fracture will occur.
class FailureTheories:
"""Failure theory calculations for combined stress states."""
@staticmethod
def tresca(sigma_1, sigma_2, sigma_3=0):
"""
Maximum Shear Stress Theory (Tresca).
Conservative for ductile materials.
Failure when: τmax = Sy/2
"""
principals = sorted([sigma_1, sigma_2, sigma_3])
tau_max = (principals[2] - principals[0]) / 2
return {
'tau_max': tau_max,
'equivalent_stress': principals[2] - principals[0],
'theory': 'Tresca (Max Shear Stress)'
}
@staticmethod
def von_mises(sigma_1, sigma_2, sigma_3=0):
"""
Distortion Energy Theory (von Mises).
Best predictor for ductile materials.
Failure when: σ_vm = Sy
"""
sigma_vm = np.sqrt(0.5 * (
(sigma_1 - sigma_2)**2 +
(sigma_2 - sigma_3)**2 +
(sigma_3 - sigma_1)**2
))
return {
'sigma_vm': sigma_vm,
'equivalent_stress': sigma_vm,
'theory': 'von Mises (Distortion Energy)'
}
@staticmethod
def rankine(sigma_1, sigma_2, sigma_3=0):
"""
Maximum Principal Stress Theory (Rankine).
Used for brittle materials.
Failure when: σ_max = Sut or σ_min = -Suc
"""
sigma_max = max(sigma_1, sigma_2, sigma_3)
sigma_min = min(sigma_1, sigma_2, sigma_3)
return {
'sigma_max': sigma_max,
'sigma_min': sigma_min,
'theory': 'Rankine (Max Principal Stress)'
}
@staticmethod
def factor_of_safety(equivalent_stress, yield_strength):
"""Calculate factor of safety."""
return yield_strength / abs(equivalent_stress) if equivalent_stress != 0 else float('inf')
def analyze_combined_stress(sigma_1, sigma_2, Sy_MPa, material_type='ductile'):
"""
Complete failure analysis for plane stress state.
"""
print(f"Failure Analysis")
print(f"Principal Stresses: σ₁ = {sigma_1:.2f} MPa, σ₂ = {sigma_2:.2f} MPa")
print(f"Yield Strength: {Sy_MPa} MPa")
print("-" * 50)
# Tresca
tresca = FailureTheories.tresca(sigma_1, sigma_2)
fos_tresca = FailureTheories.factor_of_safety(tresca['equivalent_stress'], Sy_MPa)
print(f"\n{tresca['theory']}:")
print(f" τmax = {tresca['tau_max']:.2f} MPa")
print(f" Equivalent stress = {tresca['equivalent_stress']:.2f} MPa")
print(f" Factor of Safety = {fos_tresca:.2f}")
# von Mises
vm = FailureTheories.von_mises(sigma_1, sigma_2)
fos_vm = FailureTheories.factor_of_safety(vm['sigma_vm'], Sy_MPa)
print(f"\n{vm['theory']}:")
print(f" σ_vm = {vm['sigma_vm']:.2f} MPa")
print(f" Factor of Safety = {fos_vm:.2f}")
# Recommendation
if material_type == 'ductile':
print(f"\n→ For ductile materials, use von Mises (FoS = {fos_vm:.2f})")
else:
rankine = FailureTheories.rankine(sigma_1, sigma_2)
print(f"\n→ For brittle materials, use Rankine:")
print(f" Max tensile: {rankine['sigma_max']:.2f} MPa")
print(f" Max compressive: {abs(rankine['sigma_min']):.2f} MPa")
return {'fos_tresca': fos_tresca, 'fos_vm': fos_vm}
# Example
analyze_combined_stress(sigma_1=120, sigma_2=-40, Sy_MPa=250)
Visualizing Failure Envelopes
def plot_failure_envelopes(Sy=250):
"""
Plot failure envelopes for different theories.
"""
fig, ax = plt.subplots(figsize=(10, 10))
# Coordinate ranges
sigma = np.linspace(-Sy*1.5, Sy*1.5, 500)
s1, s2 = np.meshgrid(sigma, sigma)
# Tresca envelope (hexagon)
tresca = np.maximum(np.abs(s1 - s2), np.maximum(np.abs(s1), np.abs(s2)))
ax.contour(s1, s2, tresca, levels=[Sy], colors='blue', linewidths=2)
# von Mises envelope (ellipse)
von_mises = np.sqrt(s1**2 - s1*s2 + s2**2)
ax.contour(s1, s2, von_mises, levels=[Sy], colors='red', linewidths=2)
# Rankine envelope (square)
ax.axhline(y=Sy, color='green', linestyle='--', lw=1.5)
ax.axhline(y=-Sy, color='green', linestyle='--', lw=1.5)
ax.axvline(x=Sy, color='green', linestyle='--', lw=1.5)
ax.axvline(x=-Sy, color='green', linestyle='--', lw=1.5)
# Labels and formatting
ax.axhline(y=0, color='k', lw=0.5)
ax.axvline(x=0, color='k', lw=0.5)
ax.plot([0], [0], 'ko', ms=5)
# Example stress states
stress_states = [
(120, -40, 'State A'),
(200, 100, 'State B'),
(-100, -150, 'State C'),
]
for s1_pt, s2_pt, label in stress_states:
ax.scatter([s1_pt], [s2_pt], s=100, zorder=5)
ax.annotate(label, xy=(s1_pt, s2_pt), xytext=(s1_pt+20, s2_pt+20))
ax.set_xlabel('σ₁ (MPa)', fontsize=12)
ax.set_ylabel('σ₂ (MPa)', fontsize=12)
ax.set_title(f'Failure Envelopes (Sy = {Sy} MPa)', fontsize=14)
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
ax.set_xlim(-Sy*1.3, Sy*1.3)
ax.set_ylim(-Sy*1.3, Sy*1.3)
# Legend
from matplotlib.lines import Line2D
legend_elements = [
Line2D([0], [0], color='blue', lw=2, label='Tresca'),
Line2D([0], [0], color='red', lw=2, label='von Mises'),
Line2D([0], [0], color='green', lw=2, linestyle='--', label='Rankine')
]
ax.legend(handles=legend_elements, loc='upper left')
plt.tight_layout()
plt.show()
plot_failure_envelopes(Sy=250)
Design with Combined Loading
def design_shaft_combined(P_kW, rpm, F_radial_kN, L_bearing_mm, Sy_MPa, FoS_required=2.0):
"""
Design a shaft under combined bending and torsion.
Parameters:
-----------
P_kW : float - Power transmitted
rpm : float - Rotational speed
F_radial_kN : float - Radial load (e.g., from gear)
L_bearing_mm : float - Distance from load to bearing
Sy_MPa : float - Material yield strength
FoS_required : float - Required factor of safety
"""
# Calculate torque
T = P_kW * 1000 * 60 / (2 * np.pi * rpm) # N·m
T_mm = T * 1000 # N·mm
# Bending moment from radial load
M = F_radial_kN * 1000 * L_bearing_mm # N·mm
print(f"Shaft Design - Combined Loading")
print(f"Power: {P_kW} kW at {rpm} RPM")
print(f"Torque: {T:.2f} N·m")
print(f"Radial load: {F_radial_kN} kN at {L_bearing_mm} mm from bearing")
print(f"Bending moment: {M/1e6:.3f} kN·m")
print("=" * 50)
# Allowable stress
sigma_allow = Sy_MPa / FoS_required
print(f"Allowable stress (FoS={FoS_required}): {sigma_allow:.1f} MPa")
# For combined bending and torsion using ASME code:
# von Mises: σ_vm = sqrt(σ_b² + 3τ²) ≤ σ_allow
# Using d:
# σ_b = 32M/(πd³), τ = 16T/(πd³)
# σ_vm = (16/πd³) * sqrt(4M² + 3T²)
M_eq = np.sqrt(M**2 + 0.75 * T_mm**2) # Equivalent moment
# Required diameter
# σ_allow = 32*M_eq / (π*d³)
d_required = (32 * M_eq / (np.pi * sigma_allow)) ** (1/3)
# Standard sizes
standard_sizes = [25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
d_selected = next((s for s in standard_sizes if s >= d_required), standard_sizes[-1])
print(f"\nRequired diameter: {d_required:.1f} mm")
print(f"Selected standard: {d_selected} mm")
# Verify
I = np.pi * d_selected**4 / 64
J = np.pi * d_selected**4 / 32
c = d_selected / 2
sigma_b = M * c / I
tau = T_mm * c / J
sigma_vm = np.sqrt(sigma_b**2 + 3*tau**2)
actual_fos = Sy_MPa / sigma_vm
print(f"\nVerification (Ø{d_selected} mm):")
print(f" Bending stress: {sigma_b:.2f} MPa")
print(f" Shear stress: {tau:.2f} MPa")
print(f" von Mises stress: {sigma_vm:.2f} MPa")
print(f" Actual FoS: {actual_fos:.2f}")
return d_selected
# Example
d = design_shaft_combined(
P_kW=50,
rpm=1500,
F_radial_kN=8,
L_bearing_mm=150,
Sy_MPa=350,
FoS_required=2.5
)
Key Takeaways
- Superposition: Add stresses from different loads for linear elastic materials
- Mohr's Circle: Find principal stresses for any combined stress state
- von Mises: Best predictor for ductile material yielding
- Tresca: More conservative than von Mises
- Rankine: Use for brittle materials (max principal stress)
Next lesson: We'll study column buckling and stability.