Cantilever beam — first four bending modes#

Classical Bernoulli-beam eigenvalue problem. A clamped-free prismatic cantilever has bending natural frequencies (Rao 2017 §8.5 Table 8.1; Timoshenko 1974 §5.3)

\[f_n = \frac{(\beta_n\, L)^{2}}{2\pi\, L^{2}} \sqrt{\frac{E I}{\rho A}},\]

with the dimensionless eigenvalues \(\beta_n L\) defined as the positive roots of

\[1 + \cos(\beta L)\cosh(\beta L) = 0.\]

The first four roots are

\[\beta_1 L = 1.875104, \quad \beta_2 L = 4.694091, \quad \beta_3 L = 7.854757, \quad \beta_4 L = 10.995541.\]

Implementation#

A long-aspect HEX8 enhanced-strain prism (40 axial × 3 × 3, square cross-section \(b = h\)) clamped at one end. The mode-shape filter selects the lowest mode whose UY (or UZ — the square section is bi-degenerate) RMS dominates the axial UX response, then walks up the spectrum picking successive transverse-dominant modes.

We take the cantilever slender enough (\(h / L = 1/80\)) that the Timoshenko shear / rotary-inertia correction the FE truthfully captures stays under 0.5 % at mode 4 — bench geometries like \(h / L = 1/20\) would let the correction grow to ~4 % at the same mode, which is real physics that EB doesn’t capture but which would obscure the verification pass.

References#

  • Rao, S. S. (2017) Mechanical Vibrations, 6th ed., Pearson, §8.5 Table 8.1 (cantilever-beam eigenvalue roots).

  • Timoshenko, S. P. (1974) Vibration Problems in Engineering, 4th ed., Wiley, §5.3.

  • Cook, R. D., Malkus, D. S., Plesha, M. E., Witt, R. J. (2002) Concepts and Applications of Finite Element Analysis, 4th ed., Wiley, §11 (modal analysis).

  • Simo, J. C. and Rifai, M. S. (1990) “A class of mixed assumed-strain methods …”, IJNME 29 (8), 1595–1638.

from __future__ import annotations

import math

import numpy as np
import pyvista as pv

import femorph_solver
from femorph_solver import ELEMENTS

Problem data + closed-form eigenvalue roots#

E = 2.0e11  # Pa
NU = 0.30
RHO = 7850.0
b = 0.05  # square cross-section side [m]
A = b * b
I = b**4 / 12.0  # second moment about each principal axis  # noqa: E741
L = 4.0  # span [m]; h/L = 1/80 keeps EB asymptotic to within 0.5 %

BETA_L = (1.8751040687119611, 4.694091132974174, 7.854757438237613, 10.995540734875467)


def f_published(n: int) -> float:
    return BETA_L[n - 1] ** 2 / (2.0 * math.pi * L**2) * math.sqrt(E * I / (RHO * A))


print(f"L = {L} m, b = h = {b} m, EI = {E * I:.3e} N m^2, ρA = {RHO * A:.3f} kg/m")
for n in (1, 2, 3, 4):
    print(
        f"f_{n} = (β_{n} L)^2 / (2π L^2) √(EI/ρA) = {f_published(n):8.3f} Hz   "
        f"(β_{n} L = {BETA_L[n - 1]:.6f})"
    )
L = 4.0 m, b = h = 0.05 m, EI = 1.042e+05 N m^2, ρA = 19.625 kg/m
f_1 = (β_1 L)^2 / (2π L^2) √(EI/ρA) =    2.548 Hz   (β_1 L = 1.875104)
f_2 = (β_2 L)^2 / (2π L^2) √(EI/ρA) =   15.968 Hz   (β_2 L = 4.694091)
f_3 = (β_3 L)^2 / (2π L^2) √(EI/ρA) =   44.712 Hz   (β_3 L = 7.854757)
f_4 = (β_4 L)^2 / (2π L^2) √(EI/ρA) =   87.618 Hz   (β_4 L = 10.995541)

Build a 120 × 3 × 3 HEX8 EAS cantilever prism#

NX, NY, NZ = 120, 3, 3
xs = np.linspace(0.0, L, NX + 1)
ys = np.linspace(0.0, b, NY + 1)
zs = np.linspace(0.0, b, NZ + 1)
grid = pv.StructuredGrid(*np.meshgrid(xs, ys, zs, indexing="ij")).cast_to_unstructured_grid()

m = femorph_solver.Model.from_grid(grid)
m.assign(
    ELEMENTS.HEX8(integration="enhanced_strain"),
    material={"EX": E, "PRXY": NU, "DENS": RHO},
)

Clamp the x = 0 face#

pts = np.asarray(m.grid.points)
clamped = np.where(pts[:, 0] < 1e-9)[0]
m.fix(nodes=(clamped + 1).tolist(), dof="ALL")

Render the first four mode shapes as a 2 × 2 plotter grid#

plotter = pv.Plotter(shape=(2, 2), off_screen=True, window_size=(960, 720))
for n, k, f in matches:
    row, col = divmod(n - 1, 2)
    plotter.subplot(row, col)
    phi = shapes[:, :, k]
    warp = m.grid.copy()
    warp.points = m.grid.points + (b * 5.0 / np.max(np.abs(phi))) * phi
    warp["|phi|"] = np.linalg.norm(phi, axis=1)
    plotter.add_mesh(m.grid, style="wireframe", color="grey", opacity=0.3)
    plotter.add_mesh(warp, scalars="|phi|", cmap="plasma", show_edges=False, show_scalar_bar=False)
    plotter.add_text(
        f"mode {n}: f = {f:.1f} Hz  (β_{n} L = {BETA_L[n - 1]:.3f})",
        position="upper_edge",
        font_size=10,
    )
plotter.link_views()
plotter.show()
example verify cantilever higher modes

Total running time of the script: (0 minutes 1.417 seconds)

Gallery generated by Sphinx-Gallery