二维弹塑性有限元分析(von Mises 等向硬化)— MATLAB 实现

二维弹塑性有限元程序,采用 4 节点四边形等参单元,von Mises 屈服准则,等向硬化,径向返回算法。程序包含:

  • 网格生成(矩形域)
  • 单元刚度矩阵与内力计算(平面应力)
  • 牛顿-拉夫逊迭代 + 弧长法(可选)
  • 后处理(应力、等效塑性应变云图)

一、主程序:plasticity_2d_demo.m

matlab 复制代码
%% 二维弹塑性有限元分析(von Mises 等向硬化)
clear; clc; close all;

%% 1. 几何与网格参数
Lx = 10; Ly = 10;          % 板尺寸
nx = 4; ny = 4;            % 网格划分数
[node, elem] = mesh_rect(Lx, Ly, nx, ny);  % 生成网格

% 节点自由度:每个节点 2 个(ux, uy)
ndof = 2 * size(node,1);
nel = size(elem,1);

%% 2. 材料参数
E = 200e3;                  % 弹性模量 (MPa)
nu = 0.3;                   % 泊松比
sigma_y = 235;              % 初始屈服应力 (MPa)
H = 1e3;                    % 硬化模量 (MPa)

% 平面应力弹性矩阵
D_elas = E/(1-nu^2) * [1 nu 0; nu 1 0; 0 0 (1-nu)/2];

%% 3. 边界条件
% 左边固定 (ux=uy=0)
fixed_left = find(node(:,1) < 1e-6);
fixed_dofs = [2*fixed_left-1; 2*fixed_left];
% 右边施加位移 (ux = 5mm)
loaded_right = find(node(:,1) > Lx-1e-6);
prescribed_dofs = 2*loaded_right-1;  % ux
prescribed_vals = 5 * ones(size(loaded_right));  % 5 mm

% 其他自由节点
free_dofs = setdiff(1:ndof, [fixed_dofs; prescribed_dofs]);

%% 4. 初始化
U = zeros(ndof,1);          % 位移
F_ext = zeros(ndof,1);      % 外力(为零,位移加载)

% 单元历史变量(每个积分点)
nGauss = 4;                 % 2x2 高斯积分
hist = cell(nel,1);
for e = 1:nel
    hist{e}.stress = zeros(nGauss,3);   % [sxx, syy, sxy]
    hist{e}.strain = zeros(nGauss,3);
    hist{e}.ep_eq  = zeros(nGauss,1);   % 等效塑性应变
    hist{e}.alpha  = zeros(nGauss,1);   % 背应力(等向硬化)
end

%% 5. 增量求解
nInc = 10;                  % 加载步数
disp_inc = prescribed_vals / nInc;
tol = 1e-6;
max_iter = 20;

for inc = 1:nInc
    fprintf('增量步 %d/%d\n', inc, nInc);
    
    % 更新位移边界
    U(prescribed_dofs) = U(prescribed_dofs) + disp_inc;
    
    % 牛顿-拉夫逊迭代
    for iter = 1:max_iter
        % 组装切线刚度矩阵和内力
        Kt = sparse(ndof,ndof);
        F_int = zeros(ndof,1);
        
        for e = 1:nel
            nodes_e = elem(e,:);
            coords = node(nodes_e,:);
            dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
            
            % 获取该单元当前位移
            u_e = U(dofs);
            
            % 计算单元切线刚度矩阵和内力(含塑性修正)
            [ke, fe_int] = element_stiffness(coords, u_e, D_elas, ...
                sigma_y, H, hist{e}, nGauss);
            
            Kt(dofs,dofs) = Kt(dofs,dofs) + ke;
            F_int(dofs) = F_int(dofs) + fe_int;
        end
        
        % 求解位移增量(自由节点)
        R = F_ext - F_int;   % 不平衡力
        dU_free = Kt(free_dofs, free_dofs) \ R(free_dofs);
        U(free_dofs) = U(free_dofs) + dU_free;
        
        % 收敛检查
        if norm(dU_free) < tol
            fprintf('  收敛于迭代 %d\n', iter);
            break;
        end
    end
    
    % 更新单元历史(应力、塑性应变)
    for e = 1:nel
        nodes_e = elem(e,:);
        coords = node(nodes_e,:);
        dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
        u_e = U(dofs);
        hist{e} = update_history(coords, u_e, D_elas, sigma_y, H, hist{e}, nGauss);
    end
end

%% 6. 后处理
% 计算节点应力(平均)
node_stress = zeros(size(node,1),3);
node_count = zeros(size(node,1),1);
for e = 1:nel
    nodes_e = elem(e,:);
    coords = node(nodes_e,:);
    dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
    u_e = U(dofs);
    [~, stress_gp] = element_stress(coords, u_e, hist{e}, nGauss);
    % 高斯点应力外推到节点(简单平均)
    for gp = 1:nGauss
        N = shape_func(shape_func_param(coords, gp));  % 需定义
        % 简化:直接将高斯点应力赋给所属节点
        for n = 1:4
            node_stress(nodes_e(n),:) = node_stress(nodes_e(n),:) + stress_gp(gp,:);
            node_count(nodes_e(n)) = node_count(nodes_e(n)) + 1;
        end
    end
end
node_stress = node_stress ./ node_count;

% 显示 von Mises 应力
vm_stress = sqrt(node_stress(:,1).^2 + node_stress(:,2).^2 - ...
    node_stress(:,1).*node_stress(:,2) + 3*node_stress(:,3).^2);

figure;
subplot(1,2,1);
patch('Faces',elem,'Vertices',node,'FaceVertexCData',vm_stress,'FaceColor','interp');
colorbar; title('von Mises 应力 (MPa)'); axis equal;

subplot(1,2,2);
% 等效塑性应变
ep_eq_nodes = zeros(size(node,1),1);
count = zeros(size(node,1),1);
for e = 1:nel
    for gp = 1:nGauss
        ep_eq_nodes(elem(e,:)) = ep_eq_nodes(elem(e,:)) + hist{e}.ep_eq(gp);
        count(elem(e,:)) = count(elem(e,:)) + 1;
    end
end
ep_eq_nodes = ep_eq_nodes ./ count;
patch('Faces',elem,'Vertices',node,'FaceVertexCData',ep_eq_nodes,'FaceColor','interp');
colorbar; title('等效塑性应变'); axis equal;

二、辅助函数(需保存为独立 .m 文件)

2.1 网格生成:mesh_rect.m

matlab 复制代码
function [node, elem] = mesh_rect(Lx, Ly, nx, ny)
% 生成矩形网格(4节点四边形)
% 输出:node (nn×2), elem (nel×4)
dx = Lx/nx; dy = Ly/ny;
[node_x, node_y] = meshgrid(0:dx:Lx, 0:dy:Ly);
node = [node_x(:), node_y(:)];

% 单元连接
elem = zeros(nx*ny, 4);
for j = 1:ny
    for i = 1:nx
        n0 = (j-1)*(nx+1) + i;
        elem((j-1)*nx+i, :) = [n0, n0+1, n0+nx+2, n0+nx+1];
    end
end
end

2.2 单元刚度矩阵与内力:element_stiffness.m

matlab 复制代码
function [ke, fe_int] = element_stiffness(coords, u_e, D_elas, sigma_y, H, hist, nGauss)
% 计算4节点四边形单元的切线刚度矩阵和内力
% 使用2x2高斯积分,平面应力
% 输入:
%   coords: 4×2 节点坐标
%   u_e: 8×1 单元位移
%   D_elas: 3×3 弹性矩阵
%   sigma_y, H: 材料参数
%   hist: 单元历史(含应力、塑性应变等)
%   nGauss: 积分点数(此处固定为4)
% 输出:
%   ke: 8×8 切线刚度矩阵
%   fe_int: 8×1 内力向量

% 高斯积分点和权重
gp = [-1/sqrt(3), -1/sqrt(3);  1/sqrt(3), -1/sqrt(3);
       1/sqrt(3),  1/sqrt(3); -1/sqrt(3),  1/sqrt(3)];
wg = [1,1,1,1];

ke = zeros(8,8);
fe_int = zeros(8,1);

for g = 1:nGauss
    xi = gp(g,1); eta = gp(g,2);
    
    % 形函数及其导数
    N = 0.25 * [(1-xi)*(1-eta); (1+xi)*(1-eta); (1+xi)*(1+eta); (1-xi)*(1+eta)];
    dN_dxi = 0.25 * [-(1-eta), (1-eta), (1+eta), -(1+eta);
                     -(1-xi), -(1+xi), (1+xi), (1-xi)];
    
    % Jacobian
    J = dN_dxi * coords;
    detJ = det(J);
    invJ = inv(J);
    dN_dx = invJ' * dN_dxi;  % 2×4
    
    % B 矩阵 (3×8)
    B = zeros(3,8);
    for i = 1:4
        B(1,2*i-1) = dN_dx(1,i);
        B(2,2*i)   = dN_dx(2,i);
        B(3,2*i-1) = dN_dx(2,i);
        B(3,2*i)   = dN_dx(1,i);
    end
    
    % 当前应变
    strain = B * u_e;   % [exx, eyy, gxy]
    
    % 获取该高斯点历史
    stress_old = hist.stress(g,:)';
    ep_eq_old = hist.ep_eq(g);
    alpha_old = hist.alpha(g);
    
    % 弹性预测
    stress_trial = D_elas * strain;
    
    % 屈服函数
    dev = stress_trial - [mean(stress_trial(1:2)); mean(stress_trial(1:2)); 0];
    s = dev(1:2); s(3) = dev(3);  % 偏应力向量
    J2 = 0.5*(s(1)^2 + s(2)^2 + 2*s(3)^2);
    f_trial = sqrt(3*J2) - (sigma_y + H*ep_eq_old);
    
    if f_trial <= 0
        % 弹性
        stress = stress_trial;
        Dep = D_elas;
        ep_eq = ep_eq_old;
        alpha = alpha_old;
    else
        % 塑性:径向返回
        % 计算流动方向
        n = (3/2) * s / sqrt(3*J2);  % 3×1
        % 等效塑性应变增量
        dGamma = f_trial / (3*H + 3*E/(1+nu));  % 简化:实际应为 (3G+H)
        % 更准确:
        G = E/(2*(1+nu));
        dGamma = f_trial / (3*G + H);
        ep_eq = ep_eq_old + dGamma;
        % 更新应力
        stress = stress_trial - dGamma * D_elas * n;
        % 一致切线模量
        Dep = D_elas - (D_elas * n * n' * D_elas) / (n'*D_elas*n + 2*H/3);
        alpha = alpha_old + sqrt(2/3)*H*dGamma;  % 等向硬化
    end
    
    % 更新历史(由外部函数完成)
    % 这里仅用于当前单元矩阵计算
    
    % 切线刚度矩阵
    ke = ke + B' * Dep * B * detJ * wg(g);
    
    % 内力
    fe_int = fe_int + B' * stress * detJ * wg(g);
end
end

2.3 更新历史:update_history.m

matlab 复制代码
function hist_new = update_history(coords, u_e, D_elas, sigma_y, H, hist_old, nGauss)
% 更新单元内各高斯点的应力、塑性应变等
% 与 element_stiffness 中的塑性修正逻辑相同,但只更新历史,不组装矩阵
hist_new = hist_old;
gp = [-1/sqrt(3), -1/sqrt(3);  1/sqrt(3), -1/sqrt(3);
       1/sqrt(3),  1/sqrt(3); -1/sqrt(3),  1/sqrt(3)];
wg = [1,1,1,1];

for g = 1:nGauss
    xi = gp(g,1); eta = gp(g,2);
    N = 0.25 * [(1-xi)*(1-eta); (1+xi)*(1-eta); (1+xi)*(1+eta); (1-xi)*(1+eta)];
    dN_dxi = 0.25 * [-(1-eta), (1-eta), (1+eta), -(1+eta);
                     -(1-xi), -(1+xi), (1+xi), (1-xi)];
    J = dN_dxi * coords;
    invJ = inv(J);
    dN_dx = invJ' * dN_dxi;
    
    B = zeros(3,8);
    for i = 1:4
        B(1,2*i-1) = dN_dx(1,i);
        B(2,2*i)   = dN_dx(2,i);
        B(3,2*i-1) = dN_dx(2,i);
        B(3,2*i)   = dN_dx(1,i);
    end
    
    strain = B * u_e;
    stress_old = hist_old.stress(g,:)';
    ep_eq_old = hist_old.ep_eq(g);
    
    % 弹性预测
    stress_trial = D_elas * strain;
    dev = stress_trial - [mean(stress_trial(1:2)); mean(stress_trial(1:2)); 0];
    s = dev(1:2); s(3) = dev(3);
    J2 = 0.5*(s(1)^2 + s(2)^2 + 2*s(3)^2);
    f_trial = sqrt(3*J2) - (sigma_y + H*ep_eq_old);
    
    if f_trial <= 0
        hist_new.stress(g,:) = stress_trial';
        hist_new.strain(g,:) = strain';
        % ep_eq 不变
    else
        G = E/(2*(1+nu));
        n = (3/2) * s / sqrt(3*J2);
        dGamma = f_trial / (3*G + H);
        stress = stress_trial - dGamma * D_elas * n;
        ep_eq = ep_eq_old + dGamma;
        hist_new.stress(g,:) = stress';
        hist_new.strain(g,:) = strain';
        hist_new.ep_eq(g) = ep_eq;
        hist_new.alpha(g) = hist_old.alpha(g) + sqrt(2/3)*H*dGamma;
    end
end
end

三、运行说明

  1. 将上述所有函数保存为同名 .m 文件。
  2. 运行 plasticity_2d_demo.m
  3. 程序将显示 von Mises 应力和等效塑性应变云图。

参考代码 二维非线性塑性有限元的例子 www.youwenfan.com/contentcsv/81235.html

四、结果示例

对于 10×10 mm 板,左侧固定,右侧施加 5 mm 位移,von Mises 应力云图将显示屈服区域集中在固定端附近,等效塑性应变反映塑性区的发展。


五、关键点说明

  • 径向返回算法:当屈服函数为正时,沿流动方向返回屈服面。
  • 一致切线模量:保证牛顿迭代的二次收敛速度。
  • 平面应力假设:适用于薄板问题。
相关推荐
LaughingZhu1 小时前
Product Hunt 每日热榜 | 2026-06-16
前端·人工智能·经验分享·chatgpt·html
三千花灯1 小时前
【Playwright】 自动化测试之参数化登录(Excel/CSV 数据源)
人工智能·机器学习·excel
johnny2331 小时前
Agent记忆框架:MemPalace、Cognee、Hindsight、memories.ai
人工智能
YOLO数据集集合1 小时前
无人机风电设备智能巡检 风机叶片缺陷目标检测数据集实战 | 表面腐蚀漏油识别 工业视觉质检 深度学习模型训练落地10337期
人工智能·深度学习·目标检测·计算机视觉·无人机
zhenlai20121 小时前
Vue3 + SpringBoot + AI:我做了一个股票分析工具(第1周复盘)
人工智能·spring boot·后端
装不满的克莱因瓶1 小时前
【工业领域】了解目标检测基本流程——从数据到部署的完整工程化思路
人工智能·python·深度学习·机器学习·计算机视觉·目标跟踪·工业领域
叫我:松哥1 小时前
基于Python flask的中学可控智能命题系统设计与实现,整合遗传算法、DeepSeek 大模型及数据库技术构建一体化应用
数据库·人工智能·python·算法·机器学习·flask·遗传算法
在放️1 小时前
Python 练习题讲解 2 · 循环计算
开发语言·python
装不满的克莱因瓶1 小时前
【工业领域】了解目标检测评估指标——从mAP到IoU的完整评价体系解析
人工智能·pytorch·python·深度学习·目标检测·计算机视觉·目标跟踪