简介:这份资源面向土木、机械与力学方向的学生及工程技术人员,提供基于MATLAB的杆系结构有限元分析程序与配套代码,帮助读者理解从建模到求解的完整实现流程。压缩包共359个文件,以207个.m源码文件和151个.asv自动备份文件为主,另含1个doc说明文档,整体约402KB,源码覆盖结构读取、荷载读取与数据输出等模块,便于对照学习程序组织方式。资源围绕杆系结构分析展开,涉及杆件几何与材料属性定义、边界条件与荷载施加、网格离散、静力与动力求解以及位移应力结果可视化等环节,可配合桁架、框架等典型结构案例加深对有限元方法的理解。目前已有872人学习下载,适合希望借助MATLAB动手实践结构分析、逐步掌握建模与求解思路的读者参考。
1. 杆系有限元:为什么几行矩阵运算就能算出整座桁架的位移
很多人第一次看到杆系结构分析的 MATLAB 程序,都会有一个疑问:一座几十根杆件组成的桁架,凭什么用几十行代码就能把每个节点的位移算出来?更反直觉的是,程序里几乎看不到任何力学公式,全是矩阵乘法和线性方程组求解。这背后的东西,就是有限元方法最核心的设计哲学——把连续体的力学问题,离散成一组线性代数问题。
杆系结构(桁架、网架)是有限元里最干净的入门场景:每根杆只承受轴力,节点只有平动自由度,没有弯曲、没有剪切。正因为约束少,它的刚度矩阵推导可以手算,组装逻辑可以一眼看穿。搞懂杆系有限元的底层机制,再去理解梁单元、壳单元、实体单元,会发现它们只是自由度更多、形函数更复杂,骨架完全一样。这份 MATLAB 程序的价值不在于它能算多大的结构,而在于它把「力学问题如何变成矩阵问题」这条链路完整暴露出来了。
2. 从一根杆到整体刚度矩阵:离散化的数学骨架
2.1 单元刚度矩阵是怎么推出来的
杆系有限元的第一步,是把每根杆单独拿出来分析。假设一根杆两端节点编号为 i 和 j,杆长为 L,轴向刚度 EA(弹性模量乘截面积),杆与整体坐标系的夹角为 θ。在局部坐标系下,杆只沿轴向变形,轴向刚度就是 EA/L,写成矩阵形式:
k_local = (EA/L) * [ 1 -1 ] [-1 1 ]这个 2×2 矩阵的物理含义很直白:左端伸长单位位移需要 EA/L 的力,同时右端会受到反向的 EA/L 力。但问题在于,实际结构里杆是斜着放的,节点位移是沿整体坐标 X、Y 方向的。所以必须做坐标变换,把局部坐标下的 2×2 矩阵扩展成整体坐标下的 4×4 矩阵。
变换的核心是方向余弦。设杆轴向与 X 轴夹角余弦为 c,与 Y 轴夹角余弦为 s,那么变换矩阵 T 为:
T = [ c s 0 0 ] [ 0 0 c s ]整体坐标下的单元刚度矩阵就是 k = T' * k_local * T,展开后得到一个 4×4 矩阵。这个矩阵的每个元素都对应「某个节点某个方向的位移」对「某个节点某个方向的力」的贡献。常见的实现思路是直接写出展开后的显式表达式,避免每次做矩阵乘法,因为 c 和 s 在单元循环里是常数。
2.2 组装:为什么刚度矩阵是稀疏的
单根杆的 4×4 矩阵只涉及两个节点的四个自由度。一个结构有 n 个节点,总自由度是 2n(平面桁架)。整体刚度矩阵 K 是 2n × 2n 的方阵,但每根杆只往其中 4 行 4 列里填数。这意味着 K 里绝大多数元素是零——一个节点只和与它直接相连的杆件发生刚度耦合,不相连的节点之间刚度贡献为零。
这就是稀疏性的来源。组装过程用一句话概括:遍历每根杆,把它的 4×4 单元刚度矩阵按节点编号「对号入座」累加到整体矩阵对应位置。MATLAB 里用循环实现组装非常直观:
% K 为整体刚度矩阵,初始化为零 K = zeros(2*n, 2*n); for e = 1:num_elem % 取出该单元两个节点的自由度编号 dof = [2*node_i-1, 2*node_i, 2*node_j-1, 2*node_j]; % 计算单元刚度矩阵 ke (4x4) ke = elem_stiffness(E, A, L, c, s); % 累加到整体矩阵 K(dof, dof) = K(dof, dof) + ke; end这段代码里K(dof, dof) = K(dof, dof) + ke是组装的核心。MATLAB 的索引赋值天然支持这种「按编号取子块再累加」的操作,不需要手动写四层循环。参数说明:node_i、node_j是单元两端节点编号,dof是四个自由度在整体矩阵中的行列位置,ke是已经变换到整体坐标系的单元刚度矩阵。
组装完成后,K 是一个对称、稀疏、半正定的矩阵。对称性来自功的互等定理,稀疏性来自节点连接的局部性,半正定性来自结构在没有约束时存在刚体位移。这三个性质决定了后面求解器的选择。
2.3 边界条件:为什么不能直接求逆
组装完 K 之后,方程是 K * u = F,其中 u 是待求位移向量,F 是节点荷载向量。但此时 K 是奇异的——结构可以整体平动而不产生任何内力,数学上表现为 K 的行列式为零,直接求逆会报错或得到无穷大位移。
处理边界条件的常见做法有两种。第一种是划行划列法:把已知位移为零的自由度对应的行和列从方程组中删掉,只保留未知自由度的子矩阵。第二种是对角线置大数法:把约束自由度对应的对角线元素改成一个极大的数(比如 1e10 倍),同时把荷载项改成「大数 × 已知位移」,这样解出来的约束位移近似等于给定值。MATLAB 程序里更常用第一种,因为杆系问题里约束通常是固定铰支座,位移为零,直接删行列最干净。
% fixed_dofs 为已知位移为零的自由度编号 free_dofs = setdiff(1:2*n, fixed_dofs); K_reduced = K(free_dofs, free_dofs); F_reduced = F(free_dofs); % 求解线性方程组 u_reduced = K_reduced \ F_reduced; % 回填到位移向量 u = zeros(2*n, 1); u(free_dofs) = u_reduced;这里用反斜杠\而不是inv(K)*F,是因为 MATLAB 的反斜杠会根据矩阵性质自动选择最优求解算法——对稀疏对称正定矩阵用 Cholesky 分解,对一般方阵用 LU 分解。显式求逆既慢又不稳定,是数值计算里的经典踩坑点。
3. 杆件内力与后处理:位移算完之后怎么反推轴力
3.1 从整体位移回到单元局部变形
位移向量 u 解出来之后,每个节点的 X、Y 方向位移都已知。但工程上更关心的是每根杆的轴力——杆是受拉还是受压,数值多大。轴力的计算路径是:先从整体位移里取出该单元两端节点的位移,再用变换矩阵转回局部坐标,得到杆的轴向伸长量,最后乘以 EA/L 得到轴力。
具体来说,单元节点位移向量 ue 是 4×1 的,局部轴向位移等于 c*(u_jx - u_ix) + s*(u_jy - u_iy)。这个量就是杆的伸长量 ΔL。轴力 N = EA/L * ΔL。正号表示受拉,负号表示受压。
% 遍历每个单元计算轴力 for e = 1:num_elem % 取出两端节点位移 ue = [u(2*node_i-1); u(2*node_i); u(2*node_j-1); u(2*node_j)]; % 局部轴向伸长量 delta_L = [-c, -s, c, s] * ue; % 轴力 N(e) = E * A / L * delta_L; end这段代码里[-c, -s, c, s]是局部坐标下的应变-位移向量,它把整体坐标下的四个位移分量投影到杆轴方向。参数N(e)就是第 e 根杆的轴力,后续可以用来判断杆件是否屈曲或超过材料强度。
3.2 支座反力:整体平衡的验证手段
支座反力的计算是后处理里容易被忽略但很重要的一步。它的作用是验证整体平衡:所有外荷载加上所有支座反力,在 X 和 Y 方向上的合力应该为零。如果反力算出来不满足平衡,说明组装或边界条件处理有 bug。
反力的计算方式是 R = K * u - F,取约束自由度对应的分量。因为约束自由度上位移已知,K*u 在这些位置算出来的就是支座提供的力。这个步骤在程序里通常放在位移求解之后,作为自检输出。
% 计算支座反力 R = K * u - F; % 取出约束自由度上的反力 reactions = R(fixed_dofs);这里用完整的 K 和 u 做乘法,而不是缩减后的矩阵,因为反力需要约束自由度上的信息。R向量在自由自由度上理论上为零(因为 K*u = F 在那些位置已经满足),在约束自由度上就是反力值。实际编程时可以用norm(R(free_dofs))检查求解精度,如果这个值远大于零,说明线性方程组求解出了问题。
3.3 常见后处理量的物理含义
除了轴力和反力,杆系分析还会输出节点位移图、杆件内力图、应力比等。节点位移图直接画变形后的结构形状,通常放大一个系数让变形可见。杆件内力图用颜色或线宽表示轴力大小,受拉和受压用不同颜色区分。应力比是轴力除以杆件承载力,用来判断哪些杆件接近失效。
这些后处理量的计算都建立在位移解的基础上,逻辑链条是:位移 → 应变 → 应力 → 内力。杆系问题里应变就是轴向伸长率,应力就是轴力除以截面积,没有复杂的应力状态转换。这也是杆系适合入门的原因——后处理路径短,物理意义清晰。
4. 避坑与排查:杆系有限元程序最容易翻车的几个地方
4.1 节点编号与自由度编号错位
现象:组装出来的刚度矩阵不对称,或者求解结果明显不合理(位移大得离谱)。原因:节点编号从 0 开始还是从 1 开始没统一,导致自由度编号2*node-1和2*node算错。MATLAB 数组索引从 1 开始,如果节点编号从 0 开始,第一个节点的自由度编号会变成 -1 和 0,直接索引越界或错位。解决:在程序入口处统一检查节点编号的最小值,强制从 1 开始,或者在组装前做一次编号映射。
4.2 坐标变换角度算错
现象:结构在对称荷载下位移不对称,或者某些杆的轴力符号与手算不符。原因:杆与 X 轴夹角 θ 的计算用了atan而不是atan2,导致第二、三象限的杆角度差了 180 度,方向余弦 c 和 s 的符号全反。解决:统一用atan2(dy, dx)计算角度,或者直接算方向余弦c = dx/L、s = dy/L,避免引入角度这个中间量。
4.3 边界条件处理时删错自由度
现象:求解器报矩阵奇异,或者约束位置出现非零位移。原因:划行划列时把不该删的自由度删了,或者约束自由度编号和实际支座位置对不上。比如一个固定铰支座约束 X 和 Y 两个方向,如果只删了一个方向,另一个方向仍然奇异。解决:在删自由度之前,打印出所有约束自由度的编号和对应的节点坐标,人工核对一遍。对于杆系问题,固定铰支座约束两个平动自由度,滚动支座约束一个。
4.4 单元刚度矩阵未做坐标变换
现象:斜杆结构的位移结果和手算差很多,直杆结构却正常。原因:单元刚度矩阵直接在局部坐标下组装,没有乘以变换矩阵 T。直杆的 c=1、s=0,变换矩阵是单位矩阵,所以看不出问题;斜杆就全错了。解决:在单元刚度矩阵计算函数里强制做变换,或者在组装前检查每个单元的 c 和 s 是否满足 c²+s²=1。
4.5 荷载向量方向与整体坐标不一致
现象:位移方向与预期相反,或者反力平衡校验不通过。原因:节点荷载输入时用了局部坐标方向,但组装时按整体坐标处理。比如斜杆上的节点荷载,如果按杆轴方向输入,但程序按 X、Y 方向解释,方向就错了。解决:统一约定所有荷载都在整体坐标系下输入,程序内部不做荷载变换。如果需要施加沿杆轴方向的荷载,在输入前手动分解到 X、Y 方向。
5. 稀疏求解与向量化:从能算到算得快的取舍
杆系有限元程序的性能瓶颈几乎全在组装和求解两步。组装是 O(单元数 × 16) 的循环,求解是 O(自由度数³) 的稠密矩阵分解或 O(自由度数^1.5) 的稀疏分解。对于几百个节点的小结构,MATLAB 的稠密求解绰绰有余;但节点数上千之后,稠密矩阵的内存占用和分解时间会迅速膨胀。
常见的优化方向有两个。第一个是稀疏矩阵组装:用sparse函数或者三元组列表(I、J、V)累加,而不是先建全零稠密矩阵再填数。MATLAB 的sparse在组装阶段会慢一些,但求解阶段快得多,总体权衡取决于结构规模。第二个是向量化组装:把单元循环改成对单元数组的整体操作,用accumarray或者矩阵索引一次性完成累加。向量化代码更难读,但在 MATLAB 里通常能快几倍。
% 稀疏组装示例:用三元组列表 I = []; J = []; V = []; for e = 1:num_elem dof = [2*node_i-1, 2*node_i, 2*node_j-1, 2*node_j]; ke = elem_stiffness(E, A, L, c, s); % 把 4x4 矩阵展开成 16 个三元组 [ii, jj] = meshgrid(dof, dof); I = [I; ii(:)]; J = [J; jj(:)]; V = [V; ke(:)]; end K = sparse(I, J, V, 2*n, 2*n);这段代码把每个单元的 4×4 矩阵展开成 16 个三元组,最后一次性用sparse组装。meshgrid生成行列索引的笛卡尔积,ke(:)把矩阵按列展开成向量。这种写法在单元数多的时候比循环累加快,代价是内存里要暂存所有三元组。
设计取舍的核心问题是:程序是给人读的还是给机器跑的。教学用途的杆系程序,可读性优先,稠密组装加循环求解最直观;工程用途的程序,性能优先,稀疏组装加向量化是标配。MATLAB 的好处是两种风格可以混用——先用稠密版验证正确性,再逐步替换成稀疏版做规模测试,每一步都有对照。
我自己的习惯是,每次写完组装和求解部分,都强制用一个小规模算例(比如 3 根杆的三角形桁架)手算一遍对照。手算过的代码,后面改稀疏、改向量化,心里都有底。从那以后我每次写有限元程序,都强制走一遍「小算例手算对照」的流程,不管结构多简单。希望帮到你。
本文还有配套的精品资源,点击获取