3. 平面梁单元弯曲问题有限元实现

平面梁单元弯曲问题有限元实现 学习卡片

欧拉-伯努利梁单元的核心假设与刚度矩阵

平面梁单元与杆单元的本质区别在于:杆单元只有轴向自由度,而梁单元每个节点包含横向位移 w和截面转角 θ两个自由度。欧拉-伯努利梁理论建立在以下假设之上:

  • 变形前垂直于中面的横截面,变形后仍保持平面且垂直于变形后的中面(直法线假设);
  • 忽略剪切变形的影响,即截面转角等于挠度的一阶导数:θ = dw/dx;
  • 梁为等截面直梁,材料在线弹性范围内工作。

基于上述假设,两节点梁单元(长度 L,抗弯刚度 EI)的节点位移向量为 d = [w₁, θ₁, w₂, θ₂]ᵀ,对应的单元刚度矩阵为:

k = (EI/L³) ×
[  12      6L     -12      6L  ]
[  6L     4L²     -6L     2L²  ]
[ -12     -6L      12     -6L  ]
[  6L     2L²     -6L     4L²  ]

该矩阵的物理含义:对角线元素代表单位位移引起的节点力,非对角线元素代表耦合效应。例如 k₁₁ = 12EI/L³ 表示节点1产生单位横向位移(θ₁=0, w₂=0, θ₂=0)时所需的横向力;k₁₂ = 6EI/L² 表示节点1单位转角引起的节点1横向力。

关键对比:杆单元刚度系数为 EA/L(仅轴向),梁单元刚度系数涉及 EI/L³、EI/L²、EI/L 三种量纲,分别对应横向位移-力、转角-力、转角-弯矩的耦合关系。
平面梁单元:节点自由度、刚度矩阵与两种典型边界条件 两节点梁单元(长度 L,抗弯刚度 EI) 节点1 w₁, θ₁ 节点2 w₂, θ₂ w₁ w₂ θ₁ θ₂ L 单元刚度矩阵 k(4×4 对称) k w₁ θ₁ w₂ θ₂ w₁ 12 6L -12 6L θ₁ 6L 4L² -6L 2L² w₂ -12 -6L 12 -6L θ₂ 6L 2L² -6L 4L² 系数 = EI/L³ × 表中数值 简支梁(两端铰支) 均布载荷 q 挠曲线(虚线) 边界条件:w₁=0, w₂=0(θ₁, θ₂ 自由) 解析解:w_max = 5qL⁴/(384EI),跨中 悬臂梁(左端固定) P 挠曲线(虚线) 边界条件:w₁=0, θ₁=0(w₂, θ₂ 自由) 解析解:w_max = PL³/(3EI),自由端

有限元求解流程与关键实现

以悬臂梁为例,取 4 个单元(5 个节点),每个节点 2 个自由度,总自由度数为 10。整体刚度矩阵由各单元刚度矩阵按节点自由度编号组装而成。施加边界条件时,固定端节点 1 的 w₁ 和 θ₁ 被约束,对应行列从方程组中消去。

求解线性方程组 K·d = F 后,可提取自由端节点的挠度和转角。与解析解对比时需注意:有限元节点位移是精确的(对于欧拉-伯努利梁单元,节点位移在无分布载荷时与解析解完全一致),但单元内部的挠度需要形函数插值,存在一定误差。

实现要点:组装整体刚度矩阵时,单元 e 的 4 个自由度对应整体编号为 [2e-1, 2e, 2e+1, 2e+2]。例如单元 1 连接节点 1 和 2,对应整体自由度 [1, 2, 3, 4];单元 2 连接节点 2 和 3,对应 [3, 4, 5, 6]。重叠部分(节点 2 的 w₂ 和 θ₂)需要叠加。

Python 实现与结果验证

以下代码实现悬臂梁的有限元求解,并与解析解对比。梁参数:L=1m,EI=1000 N·m²,端部集中力 P=10 N。

import numpy as np

def beam_element_stiffness(EI, L):
    """返回两节点梁单元的4x4刚度矩阵"""
    k = EI / L**3 * 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]
    ])
    return k

def solve_cantilever(L_total, EI, P, n_elem):
    """悬臂梁有限元求解,返回节点位移向量"""
    L = L_total / n_elem
    n_node = n_elem + 1
    n_dof = 2 * n_node
    K = np.zeros((n_dof, n_dof))
    k_e = beam_element_stiffness(EI, L)

    # 组装整体刚度矩阵
    for e in range(n_elem):
        dofs = [2*e, 2*e+1, 2*e+2, 2*e+3]
        for i in range(4):
            for j in range(4):
                K[dofs[i], dofs[j]] += k_e[i, j]

    # 载荷向量:端部集中力 P 作用于最后一个节点的横向自由度
    F = np.zeros(n_dof)
    F[-2] = -P  # 向下为负

    # 边界条件:节点1的 w 和 theta 固定
    fixed = [0, 1]
    free = [i for i in range(n_dof) if i not in fixed]

    # 求解
    d = np.zeros(n_dof)
    d[free] = np.linalg.solve(K[np.ix_(free, free)], F[free])
    return d, n_node

# 参数
L_total = 1.0
EI = 1000.0
P = 10.0
n_elem = 4

d, n_node = solve_cantilever(L_total, EI, P, n_elem)

# 提取自由端挠度和转角
w_tip = d[-2]
theta_tip = d[-1]

# 解析解
w_exact = -P * L_total**3 / (3 * EI)
theta_exact = -P * L_total**2 / (2 * EI)

print(f"单元数: {n_elem}, 节点数: {n_node}")
print(f"自由端挠度  FEM: {w_tip:.6e} m,  解析: {w_exact:.6e} m")
print(f"自由端转角  FEM: {theta_tip:.6e} rad, 解析: {theta_exact:.6e} rad")
print(f"挠度相对误差: {abs((w_tip - w_exact)/w_exact)*100:.4f}%")
print(f"转角相对误差: {abs((theta_tip - theta_exact)/theta_exact)*100:.4f}%")

运行上述代码,预期输出如下(节点位移在集中力作用下与解析解一致,误差来自浮点运算):

单元数: 4, 节点数: 5
自由端挠度  FEM: -3.333333e-03 m,  解析: -3.333333e-03 m
自由端转角  FEM: -5.000000e-03 rad, 解析: -5.000000e-03 rad
挠度相对误差: 0.0000%
转角相对误差: 0.0000%
注意:上述零误差是因为集中力作用于节点,且欧拉-伯努利梁单元的节点位移是精确的。若载荷为均布载荷,需将其等效为节点力和节点弯矩,此时节点位移仍精确,但单元内部挠度需用形函数插值,会引入误差。简支梁在均布载荷下的跨中挠度解析解为 5qL⁴/(384EI),有限元需将均布载荷等效为节点载荷后求解。

简支梁均布载荷的等效节点载荷

对于长度为 L 的梁单元,承受均布载荷 q 时,等效节点载荷向量为:

f_eq = [qL/2, qL²/12, qL/2, -qL²/12]ᵀ

其中前两个分量对应节点 1 的横向力和弯矩,后两个对应节点 2。将各单元的等效节点载荷组装到整体载荷向量后,再施加简支边界条件(两端横向位移为零),即可求解。

对比项悬臂梁(端部集中力 P)简支梁(均布载荷 q)
边界条件w₁=0, θ₁=0w₁=0, w₂=0
最大挠度位置自由端跨中
解析解PL³/(3EI)5qL⁴/(384EI)
节点位移精度精确精确
单元内挠度需形函数插值需形函数插值
验证方法:增加单元数量,观察自由端挠度是否收敛到解析解。对于集中力工况,任意单元数下节点位移均精确;对于均布载荷工况,节点位移也精确,但若提取非节点位置的挠度,则需要更多单元来提高插值精度。