SymPy 力学模块入门:质点、刚体、惯量、载荷与动能量函数 API 完全指南
【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy
SymPy 的sympy.physics.mechanics子模块为多体动力学建模提供了完整的符号计算基础:质点(Particle)、刚体(RigidBody)、惯量张量(Inertia)、载荷(Force / Torque),以及动量、动能、势能、拉格朗日量等系统级函数。本文以官方 API 参考页 part_bod.rst 为骨架,结合仓库源码与测试用例,系统讲解这些核心构件的数据结构、构造参数、物理公式与调用方式,帮助你直接写出可运行的多体系统动力学分析代码。
1. 总览:力学建模的基本构件
在 SymPy 多体动力学流程中,建模者通常先创建参考系(ReferenceFrame)与点(Point),再以它们为原料构造质点与刚体,最后通过Force/Torque施加载荷,并用动量、能量与拉格朗日函数做系统分析。这一流程对应的公共 API 全部由 mechanics/init.py 统一导出,包括Particle、RigidBody、inertia、inertia_of_point_mass、Inertia、Force、Torque、center_of_mass、linear_momentum、angular_momentum、kinetic_energy、potential_energy、Lagrangian、find_dynamicsymbols等。
所有"物体"类都继承自抽象基类 body_base.py 中的BodyBase,它统一提供了name、mass、masscenter、potential_energy四个属性,并声明了kinetic_energy、linear_momentum、angular_momentum、parallel_axis四个必须由子类实现的抽象方法。这意味着质点与刚体共享一致的"质量 + 质心 + 势能"接口,系统级函数可以对二者做统一遍历。
2. 质点 Particle
2.1 概念与构造参数
Particle表示一个具有非零质量但无空间延展的质点(见 particle.py)。构造时需提供三个参数,且初始化之后仍可修改:
| 参数 | 类型 | 含义 | 默认行为 |
|---|---|---|---|
name | str | 质点名称,必须为字符串(否则抛TypeError) | 必填 |
point | Point | 表示该质点位置、速度、加速度的点 | 缺省时自动生成名为{name}_masscenter的点 |
mass | Sympifyable | 质点的质量表达式 | 缺省时自动生成符号{name}_mass |
from sympy.physics.mechanics import Particle, Point from sympy import Symbol po = Point('po') m = Symbol('m') pa = Particle('pa', po, m) # 初始化指定 pa.mass = m # 或者之后再修改 pa.point = po从 body_base.py 的实现可以看到,缺省参数会被自动补齐:mass=None时创建符号Symbol(f'{name}_mass'),masscenter=None时创建点Point(f'{name}_masscenter'),且potential_energy初始为0。
2.2 动力学方法
Particle实现了BodyBase声明的四个抽象方法,公式与实现见 particle.py:
- 线性动量
linear_momentum(frame):L = m * v,其中v是质点在参考系frame中的速度。实现为self.mass * self.point.vel(frame)。 - 角动量
angular_momentum(point, frame):H = cross(r, m * v),r为从point指向质点的位置矢量。 - 动能
kinetic_energy(frame):T = 1/2 * dot(m * v, v),实现为S.Half * self.mass * dot(self.point.vel(frame), self.point.vel(frame))。 - 平行轴定理
parallel_axis(point, frame):返回该质点关于另一参考点与参考系的惯量并矢,内部直接调用inertia_of_point_mass。
from sympy.physics.mechanics import Particle, Point, ReferenceFrame, dynamicsymbols from sympy.physics.vector import init_vprinting init_vprinting(pretty_print=False) m, v = dynamicsymbols('m v') N = ReferenceFrame('N') P = Point('P') A = Particle('A', P, m) P.set_vel(N, v * N.x) A.linear_momentum(N) # m*v*N.x注意:set_potential_energy()方法自 SymPy 1.5 起已被弃用(sympy_deprecation_warning提示改用P.potential_energy = scalar属性赋值),新代码应直接使用BodyBase提供的potential_energy属性。
3. 刚体 RigidBody
3.1 概念与构造参数
RigidBody是一个"容器",存放描述理想刚体的全部要素:名称、质量、质心、固连参考系与惯量(见 rigidbody.py)。构造参数如下:
| 参数 | 类型 | 含义 | 默认行为 |
|---|---|---|---|
name | str | 刚体名称 | 必填 |
masscenter | Point | 刚体质心位置 | 缺省自动生成{name}_masscenter |
frame | ReferenceFrame | 与刚体固连的参考系 | 缺省自动生成ReferenceFrame(f'{name}_frame') |
mass | Sympifyable | 刚体质量 | 缺省自动生成符号{name}_mass |
inertia | (Dyadic, Point) | 关于某点的惯量并矢及参考点组成的二元组 | 缺省自动生成六个惯量符号{name}_ixx、{name}_iyy、{name}_izz、{name}_ixy、{name}_iyz、{name}_izx |
from sympy import Symbol from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody, outer m = Symbol('m') A = ReferenceFrame('A') P = Point('P') I = outer(A.x, A.x) # 惯量并矢 inertia_tuple = (I, P) # 必须为 (Dyadic, Point) 二元组 B = RigidBody('B', P, A, m, inertia_tuple) B.mass = Symbol('m2') # 之后仍可修改3.2 惯量属性与中央惯量
RigidBody的inertia属性存储的是"关于某参考点 O 的惯量"(Dyadic, Point),而动力学公式(角动量、动能)使用的是中央惯量(关于质心的惯量并矢)。在 rigidbody.py 的inertiasetter 中,SymPy 会自动用平行轴定理做换算:
I_S/S* = I_S/O - I_S*/O即central_inertia = I[0] - inertia_of_point_mass(mass, masscenter.pos_from(point), frame)。因此:
- 用户传入任意参考点的惯量,
RigidBody都会自动缓存对应的central_inertia; central_inertia也可以直接设置,此时要求传入Dyadic,并自动将参考点重置为质心。
RigidBody还提供frame、x、y、z属性,分别返回固连参考系及其三个基矢量;framesetter 会校验类型,非ReferenceFrame时抛TypeError。
3.3 动力学方法
- 线性动量
linear_momentum(frame):L = m * v,v为质心速度,实现为self.mass * self.masscenter.vel(frame)。 - 角动量
angular_momentum(point, frame):H = dot(I, w) + cross(r, m * v),其中I为中央惯量并矢,w为刚体在参考系frame中的角速度,r为参考点到质心的位置矢量。 - 动能
kinetic_energy(frame):T = 1/2 * (dot(dot(I, w), w) + dot(m * v, v)),即转动动能与平动动能之和;实现中将转动项S.Half * dot(self.frame.ang_vel_in(frame), dot(self.central_inertia, self.frame.ang_vel_in(frame)))与平动项分别计算后相加(见 rigidbody.py)。 - 平行轴定理
parallel_axis(point, frame=None):返回刚体关于另一参考点的惯量并矢central_inertia + inertia_of_point_mass(...),frame缺省时使用刚体自身固连系。
from sympy.physics.mechanics import Point, ReferenceFrame, outer, RigidBody, dynamicsymbols from sympy.physics.vector import init_vprinting init_vprinting(pretty_print=False) m, v, r, omega = dynamicsymbols('m v r omega') N = ReferenceFrame('N') b = ReferenceFrame('b') b.set_ang_vel(N, omega * b.x) P = Point('P') P.set_vel(N, v * N.x) I = outer(b.x, b.x) B = RigidBody('B', P, b, m, (I, P)) B.kinetic_energy(N) # m*v**2/2 + omega**2/2 B.angular_momentum(P, N) # omega*b.x4. 惯量 Inertia
4.1inertia()函数:按张量分量构造并矢
inertia.py 中的inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0)根据惯量张量的六个独立分量与一个固连参考系,构造惯量并矢:
| 参数 | 默认值 | 含义 |
|---|---|---|
frame | 无 | 惯量定义所在的参考系,必须是ReferenceFrame,否则抛TypeError |
ixx,iyy,izz | 必填 | 惯量张量的对角元(主惯量) |
ixy,iyz,izx | 0 | 惯量张量的非对角元(惯性积) |
实现中会先将所有分量sympify,再按对称张量展开为 9 项并矢求和:
from sympy.physics.mechanics import ReferenceFrame, inertia N = ReferenceFrame('N') inertia(N, 1, 2, 3) # (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z)由 test_inertia.py 的测试可见,六个分量齐全时输出完整的 9 项对称形式(ixy同时出现在N.x|N.y与N.y|N.x两个位置),且inertia(0, 0, 0, 0)这类非法首参会被raises(TypeError, ...)拦截。
4.2inertia_of_point_mass()函数:质点惯量
inertia_of_point_mass(mass, pos_vec, frame)返回关于点 O(pos_vec的起点)的质点惯量并矢,其数学形式为:
I = m * ((x̂x̂ + ŷŷ + ẑẑ) * (r·r) - r⊗r)其中r是从点 O 指向质点的位置矢量。例如质量为m、位于r * N.x的质点,惯量为m*r**2*(N.y|N.y) + m*r**2*(N.z|N.z)——这正是"轴向质量沿 x 轴时绕 y、z 轴有转动惯量"的物理结果,该断言同样出现在 test_inertia.py 中。
4.3Inertia类:并矢与参考点的成对封装
Inertia是一个namedtuple('Inertia', ['dyadic', 'point']),用于把惯量并矢与其参考点打包成一个对象(见 inertia.py):
- 构造:
Inertia(dyadic, point),也接受Inertia(point, dyadic)的颠倒顺序(内部自动交换);dyadic必须是Dyadic、point必须是Point,否则抛TypeError。 from_inertia_scalars(point, frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0):类方法,内部调用inertia()函数生成并矢后与点一起封装,参数含义与inertia()完全一致。- 矩阵视图:
I.dyadic.to_matrix(N)可直接输出 3×3 惯量矩阵,方便核对张量分量。 - 不可运算:
Inertia不支持+与*运算,会抛出带类型的TypeError,避免与普通元组混淆(测试见 test_inertia.py)。
RigidBody内部即以Inertia(I[0], I[1])形式保存惯量(见 rigidbody.py),因此body.inertia的取值与Inertia对象等价。
5. 载荷 Loads:Force 与 Torque
5.1Force:作用在点上的力
Force表示一个有作用线约束的力矢量(见 loads.py),存储"作用线上的一点 + 力矢量"二元组:
from sympy.physics.mechanics import Point, ReferenceFrame, Force N = ReferenceFrame('N') Po = Point('Po') Force(Po, 2 * N.x) # (Po, 2*N.x)要点:
- 首参可以是
Point,也可以是Particle/RigidBody等BodyBase对象——此时自动取该物体的质心body.masscenter; - 类型校验严格:位置必须是
Point、力必须是Vector,否则抛TypeError; - 提供
point与force两个只读属性,分别等价于元组的location与vector。
5.2Torque:作用在参考系上的力矩
Torque表示一个作用于参考系(进而作用于刚体)的自由矢量(见 loads.py):
from sympy.physics.mechanics import ReferenceFrame, Torque, RigidBody N = ReferenceFrame('N') Torque(N, 2 * N.x) # (N, 2*N.x) rb = RigidBody('rb', frame=N) Torque(rb, 2 * N.x) # 传入刚体时自动取 rb.frame同样地,首参可以是ReferenceFrame或BodyBase(自动取body.frame),且必须满足类型约束。
5.3 载荷的内部解析与配套工具
LoadBase是Force/Torque共同的抽象基类,同样禁止+/*运算(见 loads.py)。- 私有函数
_parse_load()(见 loads.py)负责把(Point, Vector)元组解析为Force、把(ReferenceFrame, Vector)元组解析为Torque;元组长度不为 2 或首元素类型错误时抛ValueError,非元组非载荷类型则抛TypeError。对应边界行为在 test_loads.py 中有完整覆盖。 loads.py还提供了gravity(acceleration, *bodies)辅助函数,为任意数量的Particle/RigidBody批量生成重力载荷列表,每个载荷为Force(body.masscenter, body.mass * acceleration)。
6. 系统级函数
以下函数位于 functions.py,均接受一个或多个Particle/RigidBody作为变长参数,对系统整体求值。
6.1center_of_mass(point, *bodies)
返回从给定点指向系统质心的位置矢量:Σ(mᵢ·rᵢ) / Σmᵢ。实现(见 functions.py)会遍历所有物体累计总质量与加权位置;对刚体取masscenter、对粒子取point属性;未传入任何物体时抛TypeError。文档中的完整示例同时混合了 4 个质点与 1 个刚体,并验证了加权质心表达式的正确性。
6.2 动量、能量与拉格朗日量
| 函数 | 签名 | 物理含义 | 实现要点 |
|---|---|---|---|
linear_momentum | (frame, *body) | 系统线性动量L = Σ m·v | 对所有物体调用各自的linear_momentum(frame)做矢量求和 |
angular_momentum | (point, frame, *body) | 系统角动量H = Σ Hᵢ | 对所有物体调用angular_momentum(point, frame)求和 |
kinetic_energy | (frame, *body) | 系统动能T = Σ Tᵢ(标量) | 求和各物体kinetic_energy(frame) |
potential_energy | (*body) | 系统势能V = Σ Vᵢ(标量) | 直接求和各物体potential_energy属性 |
Lagrangian | (frame, *body) | 拉格朗日量L = T - V | 实现为kinetic_energy(frame, *body) - potential_energy(*body) |
所有函数都会校验首参类型(ReferenceFrame/Point),并对非Particle/RigidBody的传入项抛TypeError(见 functions.py)。典型组合用法:
from sympy.physics.mechanics import (Point, Particle, ReferenceFrame, RigidBody, outer, linear_momentum, kinetic_energy, potential_energy, Lagrangian) from sympy import symbols M, m, g, h = symbols('M m g h') N = ReferenceFrame('N') O = Point('O') O.set_vel(N, 0 * N.x) P = O.locatenew('P', 1 * N.x) P.set_vel(N, 10 * N.x) Pa = Particle('Pa', P, 1) Ac = O.locatenew('Ac', 2 * N.y) Ac.set_vel(N, 5 * N.y) a = ReferenceFrame('a') a.set_ang_vel(N, 10 * N.z) I = outer(N.z, N.z) A = RigidBody('A', Ac, a, 20, (I, Ac)) Pa.potential_energy = m * g * h A.potential_energy = M * g * h linear_momentum(N, A, Pa) # 10*N.x + 500*N.y kinetic_energy(N, Pa, A) # 350 potential_energy(Pa, A) # M*g*h + g*h*m Lagrangian(N, Pa, A) # -M*g*h - g*h*m + 3506.3find_dynamicsymbols(expression, exclude=None, reference_frame=None)
查找表达式中出现的所有动力学符号(随时间变化的dynamicsymbols),返回符号集合。其工作方式是收集表达式中free_symbols == {t}的AppliedUndef与Derivative原子(见 functions.py):
from sympy.physics.mechanics import dynamicsymbols, find_dynamicsymbols, ReferenceFrame x, y = dynamicsymbols('x, y') expr = x + x.diff() * y find_dynamicsymbols(expr) # {x(t), y(t), Derivative(x(t), t)} find_dynamicsymbols(expr, exclude=[x, y]) # {Derivative(x(t), t)} v = dynamicsymbols('a, b, c')[0] * ReferenceFrame('A').x # 简化示意使用要点:
exclude可选,提供可迭代对象以排除已知符号;- 对矢量表达式必须同时传入
reference_frame,函数内部先to_matrix(frame)再分析,否则抛ValueError。
7. 与后续建模工具的衔接
这些构件并非孤立存在:Force/Torque元组正是 KanesMethod 与LagrangesMethod等建模器的载荷输入格式;functions.py内部的_f_list_parser()(见 functions.py)会把(Point, force)与(ReferenceFrame, torque)载荷列表解析为广义速度与广义力列表,供 Kane 方程与拉格朗日方程使用。RigidBody与Particle也可以直接作为System、关节(Joint)与执行器(Actuator)的构件输入。因此,熟练掌握本文的质点、刚体、惯量与载荷 API,是进一步使用KanesMethod、LagrangesMethod等高层多体工具的前提。
8. 参考文件索引
- 官方 API 参考页:part_bod.rst
- 质点实现:particle.py
- 刚体实现:rigidbody.py
- 惯量实现:inertia.py
- 载荷实现:loads.py
- 系统级函数:functions.py
- 物体抽象基类:body_base.py
- 公共导出:mechanics/init.py
- 相关测试:test_particle.py、test_rigidbody.py、test_inertia.py、test_loads.py、test_functions.py
【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考