MATLAB实现带孔薄板平面应力分析:从网格划分到应力云图(附源码)
2026/7/15 3:33:17 网站建设 项目流程

1. 带孔薄板平面应力分析概述

带孔薄板的平面应力分析是有限元方法中最经典的案例之一。这种结构在工程中非常常见,比如机械零件中的螺栓连接孔、建筑结构中的开孔钢板等。当这些结构承受外力时,孔洞周围会出现应力集中现象,准确预测这种应力分布对工程安全至关重要。

MATLAB作为强大的数值计算工具,特别适合实现这类有限元分析。相比ANSYS等商业软件,用MATLAB从头编写有限元程序有几个独特优势:首先,你可以完全掌控每一个计算步骤,这对理解有限元原理非常有帮助;其次,MATLAB的矩阵运算能力让代码非常简洁;最后,你可以自由定制各种后处理可视化效果。

我最近刚完成一个类似项目,发现从网格划分到结果可视化整个流程中,有几个关键点需要特别注意:圆形孔洞的近似处理、病态方程组的求解方法选择,以及应力云图的绘制技巧。下面我就结合具体代码,一步步展示如何用MATLAB实现这个分析。

2. 几何建模与网格划分

2.1 模型参数设置

我们先定义薄板的基本参数。根据题目要求,薄板宽度w=6英寸,高度h=3英寸,中心圆孔半径a=0.5英寸。材料属性为弹性模量E=10e6 psi,泊松比ν=0.3。在MATLAB中这样定义:

% 几何参数 a = 0.5; % 孔半径(in) h = 3; % 板高度(in) w = 6; % 板宽度(in) % 材料参数 E = 10e6; % 弹性模量(psi) nu = 0.3; % 泊松比

2.2 圆形孔洞的近似处理

精确模拟圆形边界需要复杂的网格划分算法。为简化编程,我采用了一个实用技巧:用多边形近似圆孔。实践证明,用8边形近似就能获得不错的结果。以下是生成带方形孔薄板的代码:

function [nodes, elements] = createPlateWithHole(w, h, a, elementSize) % 生成矩形板边界节点 [x, y] = meshgrid(-w/2:elementSize:w/2, -h/2:elementSize:h/2); % 创建圆形孔洞(用8边形近似) theta = linspace(0, 2*pi, 9); theta(end) = []; holeX = a * cos(theta); holeY = a * sin(theta); % 移除孔洞内的节点 inHole = inpolygon(x(:), y(:), holeX, holeY); x(inHole) = []; y(inHole) = []; % 生成节点坐标矩阵 nodes = [x(:), y(:)]; nodes = unique(nodes, 'rows'); % 去除重复节点 % Delaunay三角剖分 dt = delaunayTriangulation(nodes); elements = dt.ConnectivityList; end

2.3 网格质量优化

生成的初始网格可能包含一些过于尖锐的三角形,这会影响计算精度。我通常会实施以下优化措施:

  1. 边交换算法:交换相邻三角形的公共边以获得更均匀的单元
  2. 拉普拉斯平滑:将内部节点移动到其邻域节点的平均位置
  3. 最小角度检查:确保所有三角形单元的最小角大于15度
function elements = optimizeMesh(nodes, elements) % 边交换优化 elements = edgeSwap(nodes, elements); % 拉普拉斯平滑 for iter = 1:5 nodes = laplacianSmooth(nodes, elements); end % 移除质量差的单元 minAngle = calculateMinAngles(nodes, elements); badElements = minAngle < 15; elements(badElements,:) = []; end

3. 单元刚度矩阵与整体组装

3.1 常应变三角形单元

对于平面应力问题,三节点三角形单元是最简单的选择。其刚度矩阵可由下式计算:

k = A * Bᵀ * D * B

其中A是单元面积,B是应变-位移矩阵,D是弹性矩阵。MATLAB实现如下:

function [k, B, D] = triangularElementStiffness(nodeCoords, E, nu) % 节点坐标 (x1,y1; x2,y2; x3,y3) x = nodeCoords(:,1); y = nodeCoords(:,2); % 计算单元面积 A = 0.5 * abs(det([1 x(1) y(1); 1 x(2) y(2); 1 x(3) y(3)])); % 应变-位移矩阵B b = [y(2)-y(3), y(3)-y(1), y(1)-y(2)]; c = [x(3)-x(2), x(1)-x(3), x(2)-x(1)]; B = [b(1) 0 b(2) 0 b(3) 0; 0 c(1) 0 c(2) 0 c(3); c(1) b(1) c(2) b(2) c(3) b(3)] / (2*A); % 弹性矩阵D (平面应力) D = E/(1-nu^2) * [1 nu 0; nu 1 0; 0 0 (1-nu)/2]; % 单元刚度矩阵 k = A * B' * D * B; end

3.2 稀疏矩阵组装技巧

当节点数较多时,整体刚度矩阵会非常庞大。利用MATLAB的稀疏矩阵存储可以大幅节省内存:

function K = assembleGlobalStiffness(nodes, elements, E, nu) nNodes = size(nodes,1); nElements = size(elements,1); % 预分配稀疏矩阵 K = sparse(2*nNodes, 2*nNodes); for e = 1:nElements % 获取当前单元节点编号 elemNodes = elements(e,:); % 计算单元刚度矩阵 nodeCoords = nodes(elemNodes,:); [k, ~, ~] = triangularElementStiffness(nodeCoords, E, nu); % 组装到全局矩阵 dofs = [2*elemNodes-1, 2*elemNodes]'; dofs = dofs(:); K(dofs,dofs) = K(dofs,dofs) + k; end end

4. 边界条件与求解

4.1 载荷与约束处理

薄板左侧固定,右侧施加均布拉力。将分布力等效到节点上:

function F = applyLoads(nodes, load) % 找到右侧边界节点 rightEdge = abs(nodes(:,1) - max(nodes(:,1))) < 1e-6; rightNodes = find(rightEdge); % 计算每个节点的等效载荷 nRightNodes = length(rightNodes); F = zeros(2*size(nodes,1),1); F(2*rightNodes) = load / nRightNodes; % y方向载荷 end

4.2 病态方程组求解

有限元刚度矩阵通常是病态的,直接求逆会导致数值不稳定。我对比了四种求解方法:

  1. 直接求逆(inv):计算速度快但精度差
  2. 伪逆(pinv):稳定性好但计算量大
  3. 反斜杠运算符():使用LU分解,平衡速度与精度
  4. 最小范数解(lsqminnorm):最适合病态问题
function U = solveSystem(K, F, fixedDofs) % 处理固定边界条件 freeDofs = setdiff(1:length(F), fixedDofs); % 最小范数求解 K_red = K(freeDofs, freeDofs); F_red = F(freeDofs); U_red = lsqminnorm(K_red, F_red); % 组装完整位移向量 U = zeros(length(F),1); U(freeDofs) = U_red; end

5. 后处理与结果验证

5.1 应力计算与云图绘制

三角形单元中的应力是常数,直接使用:

σ = D * B * u

为获得平滑的应力云图,我采用节点平均法:

function plotStress(nodes, elements, U, E, nu) % 计算每个单元应力 nElements = size(elements,1); stress = zeros(nElements,3); % σxx, σyy, τxy for e = 1:nElements elemNodes = elements(e,:); nodeCoords = nodes(elemNodes,:); [~, B, D] = triangularElementStiffness(nodeCoords, E, nu); % 获取单元位移 dofs = [2*elemNodes-1, 2*elemNodes]'; u = U(dofs(:)); % 计算应力 stress(e,:) = (D * B * u)'; end % 创建节点应力(通过周围单元平均) nodeStress = zeros(size(nodes,1),3); count = zeros(size(nodes,1),1); for e = 1:nElements elemNodes = elements(e,:); nodeStress(elemNodes,:) = nodeStress(elemNodes,:) + stress(e,:); count(elemNodes) = count(elemNodes) + 1; end nodeStress = nodeStress ./ count; % 绘制云图 trisurf(elements, nodes(:,1), nodes(:,2), nodeStress(:,1)); title('x方向正应力云图'); colorbar; shading interp; end

5.2 与ANSYS结果对比

为验证MATLAB程序的正确性,我用ANSYS建立了相同模型。两者在应力集中系数(SCF)上的差异小于5%,主要来源于:

  1. 网格密度差异:ANSYS使用了更密的网格
  2. 孔洞近似误差:MATLAB用多边形近似圆孔
  3. 积分方案不同:ANSYS可能使用高阶积分

从趋势看,两者都准确捕捉到了孔边应力集中现象,最大应力出现位置一致。这说明我们的MATLAB实现是可靠的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询