Sympy physics.vector 深度解析:向量、参考系与刚体运动学的符号化建模
2026/9/14 18:22:50 网站建设 项目流程

Sympy physics.vector 深度解析:向量、参考系与刚体运动学的符号化建模

【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy

在 sympy 中,sympy.physics.vector是为三维空间向量运算(包括随时间变化的向量)提供符号化支持的物理模块,它是sympy.physics体系内处理参考系(ReferenceFrame)、向量(Vector)、点(Point)、二重积(Dyadic)与向量场运算的核心组件,也是sympy.physics.mechanics等上层动力学模块的数学基础。读完本文,你将能够:在 sympy 中用ReferenceFrameorientdynamicsymbols等 API 完整描述多参考系系统的姿态与运动学,使用点定理方法求解点速度与加速度,并对标量/向量场执行梯度、散度、旋度与势函数计算——本文所有代码示例均取自该模块官方解释文档,实现细节均可在sympy/physics/vector/源码目录中查证。

模块定位与文档骨架

官方解释文档 index.rst 的开篇即点明模块设计目的:

the components of the sympy.physics.vector have been discussed. sympy.physics.vector has been written to facilitate the operations pertaining to 3-dimensional vectors, as functions of time or otherwise, in sympy.physics.

该文档以 toctree 组织了四个子文档,构成了理解本模块的完整骨架:

文档相对路径覆盖主题
Vector & ReferenceFramevectors.rst向量代数、参考系、方向余弦矩阵(DCM)、多参考系微分
Kinematicskinematics.rst角速度、导数定理、1 点/2 点定理、点在参考系中的速度加速度
Scalar and Vector Fieldfields.rst坐标符号(CoordinateSym)、curl/divergence/gradient、保守场与无散场
Advanced Topicsadvanced.rstDyadic、常见问题(打印/替换/加速度)、高级接口、向量方程求解

官方引用文献(index.rst)包括 Likins, Peter W.《Elements of Engineering Mechanics》(McGraw-Hill, 1973) 以及关于 Dyadics 与 Dyadic Product 的参考条目,可视为该模块数学表述的出处。

从源码结构看,模块的公开 API 集中在 sympy/physics/vector/__init__.py 中,导出的符号分为六类:

  • 核心类型CoordinateSymReferenceFrame(frame.py)、Dyadic(dyadic.py)、Vector(vector.py)、Point(point.py);
  • 函数接口crossdotexpresstime_derivativeouterkinematic_equationsget_motion_paramspartial_velocitydynamicsymbols(functions.py);
  • 打印工具vprintvsstrreprvsprintvpprintvlatexinit_vprinting(printing.py);
  • 场运算curldivergencegradientis_conservativeis_solenoidalscalar_potentialscalar_potential_difference(fieldfunctions.py)。

对应测试分布在 sympy/physics/vector/tests/ 下,包括test_frame.pytest_vector.pytest_point.pytest_dyadic.pytest_fieldfunctions.pytest_printing.py等,逐类覆盖了上述 API。

Vector 与 ReferenceFrame:模块的"积木块"

官方文档将向量与参考系称为动态系统的 "building blocks"(积木块)。数学上,向量是既有大小又有方向的几何对象;两个向量当且仅当大小与取向相同时相等。向量代数支持的基本运算包括:

  • 加法:满足平行四边形法则,交换律与结合律成立;
  • 数乘:结果方向不变、模长缩放;乘以 -1 等价于绕任意垂直轴旋转 180 度;
  • 单位向量:任意向量v可写为单位向量_v =v/‖v‖ 与标量之积;
  • 三种乘积:点积(映射为标量,交换律成立)、叉积(返回向量,反交换律a×b= -b×a,不满足结合律,平行向量叉积为零)、外积(在惯性矩/Dyadic 一节使用)。

常用恒等式包括分配律、标量三重积的轮换对称性(a × b) · c = a · (b × c) = (b × c) · a,以及双叉积展开式(a × b) × c = b(a · c) - a(b · c)等。

基向量与测度数

给定三个非共面单位向量_x,_y,_z 构成基(通常互正交且右手系,即正交归一基),任意向量可写成a= a_x_x + a_y_y + a_z_z,其中 a_x、a_y、a_z 称为测度数(measure numbers)。此时各运算有了分量形式:

  • 点积:a·b= a_x b_x + a_y b_y + a_z b_z;
  • 叉积:行列式形式 | n̂_x n̂_y n̂_z; a_x a_y a_z; b_x b_y b_z |;
  • 标量三重积:(a × b) · c 即 3×3 测度数矩阵的行列式;
  • 将向量写进指定基:a= (a·n̂_x)n̂_x + (a·n̂_y)n̂_y + (a·n̂_z)n̂_z。

官方文档给出的数值示例(a= n̂_x + 5n̂_y,b= n̂_y + αn̂_z):a + b = n̂_x + 6n̂_y + αn̂_z,a · b = 5,a × b = 5αn̂_x − αn̂_y + n̂_z,b × a = -5αn̂_x + αn̂_y − n̂_z,可在 sympy/physics/vector/tests/test_vector.py 中找到对应的自动化验证。

向量微分与参考系

向量微积分的引入源于一个朴素观察:火车上的两名乘客互为静止,但相对站外观察者都有速度——同一向量的"变化率"依赖于观察所在的参考系。参考系 N 是一块虚拟的"观察平台",每个参考系配一组固定的正交基(如 N 配 n̂_x, n̂_y, n̂_z)。向量 e 若在参考系 B 中固定,则 B 中其导数为零,而在 A 中一般非零,因此微分记号必须显式带上参考系:

^A d e/dθ ≠ 0 (e 关于 θ 在参考系 A 中的导数) ^B d e/dθ = 0 (e 关于 θ 在参考系 B 中的导数)

向量微分满足与标量类似的结构:加法线性、乘积法则^A d/dt (γa) = (dγ/dt)a + γ ^A d a/dt、叉积乘积法则^A d/dt (a × b) = (^A d a/dt) × b + a × (^A d b/dt)

方向余弦矩阵(DCM)与简单旋转

两个参考系的联系用方向余弦矩阵(DCM)描述:

[â_x] [ A C B ] [b̂_x] [â_y] = | | [b̂_y] [â_z] [ ] [b̂_z]

当两参考系绕某一基向量方向做简单旋转(如绕 Z 轴转 θ,此时 â_z 与 b̂_z 仍对齐)时,DCM 有封闭形式;绕 Z 轴、X 轴、Y 轴的旋转矩阵分别为文档 vectors.rst 中给出的三个 3×3 矩阵(正方向由右手定则定义)。DCM 的每个元素就是对应基向量的点积,如 C_xy = â_x · b̂_y,且正交性保证了 ^A C^B = (^B C^A)^(-1) = (^B C^A)^T。

官方文档用一个完整的例子展示了 DCM 的实际价值:在绕 Z 轴相差 θ 的两个参考系中,向量b= b̂_x + b̂_y + b̂_z 在 A 系中表达为 (cos θ − sin θ)n̂_ax + (sin θ + cos θ)n̂_ay + n̂_az。更进一步,文档强调了一个对动力学建模极其重要的实践结论:同一导数结果用不同基表达时复杂度差异巨大——把 ^A d c/dt 先按 A 系基展开再换回 B 系,可得到更简洁的 ṫx b̂_x − θ̇x b̂_z 形式;用复杂形式定义向量会显著拖慢运动方程的建立并使其冗长到无法显示,这是该模块设计"表达系"概念的直接动机。

代码使用:从参考系创建到多参考系微分

官方文档刻意在所有数学关系讲完后才引入代码。第一步永远是创建参考系:

>>> from sympy.physics.vector import * >>> N = ReferenceFrame('N') >>> N.x # 基向量访问 N.x >>> N.y N.y >>> N.z N.z

向量代数层面:

>>> N.x == N.x True >>> N.x == N.y False >>> N.x + N.y N.x + N.y >>> 2 * N.x + N.y 2*N.x + N.y >>> from sympy import Symbol, symbols >>> x = Symbol('x') >>> x * N.x x*N.x

文档特别提醒:不要把标量加到向量上(N.x + 5会报错)。向量乘法提供了运算符、方法、函数三级接口:

>>> N.x.dot(N.x) # 方法接口 1 >>> N.x.dot(N.y) 0 >>> dot(N.x, N.y) # 函数接口(官方推荐) 0 >>> N.x.cross(N.x) 0 >>> N.x.cross(N.z) - N.y >>> cross(N.x, (N.y + N.z)) -N.y + N.z >>> (N.x + N.y).normalize() sqrt(2)/2*N.x + sqrt(2)/2*N.y >>> (N.x + N.y).magnitude() sqrt(2) >>> (x * N.x + 2 * x * N.y + 3 * x * N.z).to_matrix(N) Matrix([ [ x], [2*x], [3*x]])

文档明确指出,函数接口是"官方"接口,所有示例都采用它,原因是运算符层面的优先级不正确,用运算符写向量乘法时必须格外注意括号。to_matrix(frame)将向量转成列矩阵,常用于数值场景;由于矩阵本身不携带参考系信息,必须显式传入参考系。

向量微分方面,SymPy 的diff目前不能直接作用于Vector(因为它无法表达"在哪个参考系中求导"这一必要参数),应使用Vectordiff方法(第二参数为参考系)或dt

>>> (x * N.x + N.y).diff(x, N) N.x

引入第二个参考系后,未定义姿态关系前只能做加法而不能做向量乘法:

>>> A = ReferenceFrame('A') >>> A.x + N.x N.x + A.x

要定义姿态,用orient方法;A.orient(N, 'Axis', [x, N.y])表示 A 相对 N 绕 Y 轴简单旋转 x 弧度,此后随时可用A.dcm(N)查看 DCM ^A C^N。除 Axis 外,还支持 Body 旋转、Space 旋转、四元数和任意轴旋转。文档给出了一段很有代表性的等价性示例:三次 Axis 串联旋转(Bpp 绕 N.x 转 q1,Bp 绕 Bpp.y 转 q2,B 绕 Bp.z 转 q3)得到的N.dcm(B)矩阵,与直接执行B.orient(N, 'Body', [q1, q2, q3], 'XYZ')的结果逐元素相同。Space 旋转则从系到体应用;关键约束是每次简单旋转必须绕不同的轴,'ZZX' 这样的序列无法完全确定基向量姿态(对应 frame.py 中 orient 系列的实现,测试见 test_frame.py)。

orientnew是"创建并取向"的一步式封装:C = N.orientnew('C', 'Axis', [q1, N.x])。四元数(Euler 参数)与任意轴旋转的完整用法见orient/orientnew的方法文档。

dynamicsymbols 与向量打印

多参考系微分需要"时间的未定函数",dynamicsymbols就是为此设计的快捷函数:

>>> from sympy import diff >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') >>> diff(q1, Symbol('t')) Derivative(q1(t), t)

默认打印不够直观,模块提供向量专用打印工具:非交互会话用vprint,交互会话用init_vprinting;与 SymPy 的vprint/vpprint/latex分别对应vprint/vpprint/vlatex

>>> q1d = diff(q1, Symbol('t')) >>> vprint(q1) q1 >>> vprint(q1d) q1' >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q1d q1'

文档要求:任何时变量(坐标、速度、力)都应表示为 dynamicsymbol。有了它,多参考系微分变得直接:

>>> N = ReferenceFrame('N') >>> B = N.orientnew('B', 'Axis', [q1, N.x]) >>> (B.y*q2 + B.z).diff(q2, N) B.y >>> (B.y*q2 + B.z).dt(N) (-q1' + q2')*B.y + q2*q1'*B.z

注意输出向量保持在其原有参考系中,即使向量含多个参考系的基向量也成立:(B.y*q2 + B.z + q2*N.x).diff(q2, N)返回N.x + B.y

源码视角:Vector 是如何存储的

官方文档专门有一节 "How Vectors are Coded",可对照 vector.py 理解:

  • 每个Vector的主要信息存在args属性中:一个列表,元素个数等于该向量分量中出现的唯一参考系数量(含 A、B 两系基向量为长度 2,三系则为 3);
  • 每个元素是一个二元组:(Matrix, ReferenceFrame)——SymPy 矩阵存该系下的测度数,参考系指明归属;
  • 向量在代码中必须先有ReferenceFrame才能存在:参考系的x/y/z属性是不可变Vector,测度数分别为 [1,0,0]、[0,1,0]、[0,0,1],一切新向量都由基向量的代数运算生成;
  • ReferenceFrame存名字(name属性)与 DCM 字典:键为参考系、值为 SymPyMatrix。取向是双向设置的——A取向到N时,A 的字典加入 N 及其矩阵,N 的字典同时加入 A 及该矩阵的转置。

Kinematics:角速度、导数定理与点定理

运动学文档 kinematics.rst 给出了刚体运动的数学框架:刚体运动分解为平动与转动,转动再分为简单转动(总有一条线保持平行)与一般转动。

角速度与加法定理

刚体 B 在参考系 N 中的角速度记作 ^N ω^B(参考系同样可以有角速度)。它可由基向量导数严格定义:

^N ω^B = ((^N d b̂_y/dt) · b̂_z) b̂_x + ((^N d b̂_z/dt) · b̂_x) b̂_y + ((^N d b̂_x/dt) · b̂_y) b̂_z

角速度满足加法定理:^N ω^D = ^N ω^A + ^A ω^B + ^B ω^C + ^C ω^D。这意味着多体系统中每个体只需相对上一体定义角速度即可完成完整描述,例如 ^N ω^D = q̇_1 â_x − q̇_2 b̂_z + q̇_3 ĉ_y。文档特别强调该定理只适用于角速度,不能用于点的速度

另一个常用工具是导数定理:^N d v/dt = ^B d v/dt + ^N ω^B × v。先在 v 的"主场"参考系 B 中求导(通常 v 由 B 系基向量组成,求导最简),再加角速度与 v 的叉积。角加速度 ^N α^B = ^N d(^N ω^B)/dt,用导数定理展开后,当角速度以体固连分量 ω_x b̂_x + ω_y b̂_y + ω_z b̂_z 表示时,自叉积项恒为零,退化为简单的 α = ω̇_x b̂_x + ω̇_y b̂_y + ω̇_z b̂_z。

点的速度与加速度:1 点定理与 2 点定理

点 P 有三类特征量:位置向量 r^OP(不带参考系,因为无时间导数)、速度 ^N v^P、加速度 ^N a^P。平动速度没有加法定理,因此文档给出两个定理:

  • 2 点定理(S、P 均固定在刚体 B 上,已知 ^N v^S 与 ^N ω^B): ^N v^P = ^N v^S + ^N ω^B × r^SP; ^N a^P = ^N a^S + ^N α^B × r^SP + ^N ω^B × (^N ω^B × r^SP)。
  • 1 点定理(仅 S 固定在 B 上,另已知 ^B v^P): ^N v^P = ^B v^P + ^N v^S + ^N ω^B × r^SP, 加速度项中额外包含科里奥利项 2 ^N ω^B × ^B v^P。

文档配了三个经典算例:平面内平动加转动的圆盘(求 P 点速度 u_1 n̂_x + u_2 n̂_y + u_3 R b̂_y 与加速度 … − R u_3² b̂_x + R u̇_3 b̂_y)、双摆(两次套用 2 点定理得 ^N v^P = u_1 l b̂_y + u_2 l ĉ_y)、粒子在可旋转圆环上运动(先 2 点定理求环心 Q 速度,再 1 点定理求 P 速度,最终 ^N v^P = −R u_2 sin q_2 ĉ_x + (R u_2 cos q_2 + u_1 l) ĉ_y + R u_1 sin q_2 ĉ_z),以及无滑滚动的定义:两接触点在另一参考系中速度相同当且仅当无滑滚动。

运动学在代码中的表达

>>> from sympy import Symbol, sin, cos >>> from sympy.physics.vector import * >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> q1 = dynamicsymbols('q1') >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> A.ang_vel_in(N) q1'*N.x

值得注意的实现细节:orientnew创建参考系时会用 DCM 的时间导数按角速度定义自动计算角速度。也可显式设置:

>>> B = ReferenceFrame('B') >>> u1 = dynamicsymbols('u1') >>> B.set_ang_vel(N, u1 * B.y) >>> B.ang_vel_in(N) u1*B.y >>> N.ang_vel_in(B) - u1*B.y

角速度链式传递:

>>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A'); B = ReferenceFrame('B') >>> C = ReferenceFrame('C'); D = ReferenceFrame('D') >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> A.set_ang_vel(N, 0) >>> B.set_ang_vel(A, u1 * A.x) >>> C.set_ang_vel(B, -u2 * B.z) >>> D.set_ang_vel(C, u3 * C.y) >>> D.ang_vel_in(N) u1*A.x - u2*B.z + u3*C.y

从源码结构看(frame.py 中角速度存储与查询逻辑),查询D.ang_vel_in(N)时模块使用两参考系间的最短路径拼接角速度。官方文档也提示了一个陷阱:如果之后又执行D.set_ang_vel(N, 0),最短路径就变成这条直接定义,导致与原有链式定义不一致——应避免此类混用。

Point是平动的类比对象,创建方式与ReferenceFrame对称(先建后set_pos,或一步locatenew):

>>> O = Point('O') >>> P = O.locatenew('P', 3 * N.x + N.y) >>> P.pos_from(O) 3*N.x + N.y >>> Q = Point('Q') >>> Q.set_pos(P, N.z) >>> Q.pos_from(O) 3*N.x + N.y + N.z

位置向量同样按最短路径(中间点个数最少)查找;而速度必须显式设定,加速度默认取速度的时间导数、也可覆盖:

>>> O.set_vel(N, u1*N.x) >>> O.vel(N) u1*N.x >>> O.acc(N) u1'*N.x >>> O.set_acc(N, u2*u1*N.y) >>> O.acc(N) u1*u2*N.y

2 点/1 点定理对应Point的方法v2pt_theorya2pt_theoryv1pt_theory(point.py)。圆盘算例的代码化:

>>> N = ReferenceFrame('N') >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> R = Symbol('R') >>> B = ReferenceFrame('B') >>> O = Point('O') >>> O.set_vel(N, u1 * N.x + u2 * N.y) >>> P = O.locatenew('P', R * B.x) >>> B.set_ang_vel(N, u3 * B.z) >>> P.v2pt_theory(O, N, B) u1*N.x + u2*N.y + R*u3*B.y >>> P.a2pt_theory(O, N, B) u1'*N.x + u2'*N.y - R*u3**2*B.x + R*u3'*B.y

圆环粒子算例(1 点定理):

>>> N = ReferenceFrame('N') >>> u1, u2 = dynamicsymbols('u1 u2') >>> q1, q2 = dynamicsymbols('q1 q2') >>> l = Symbol('l'); R = Symbol('R') >>> C = N.orientnew('C', 'Axis', [q1, N.x]) >>> C.set_ang_vel(N, u1 * N.x) >>> O = Point('O'); O.set_vel(N, 0) >>> Q = O.locatenew('Q', -l * C.z) >>> P = Q.locatenew('P', R * (cos(q2) * C.x + sin(q2) * C.y)) >>> P.set_vel(C, R * u2 * (-sin(q2) * C.x + cos(q2) * C.y)) >>> Q.v2pt_theory(O, N, C) l*u1*C.y >>> P.v1pt_theory(Q, N, C) -R*u2*sin(q2)*C.x + (R*u2*cos(q2) + l*u1)*C.y + R*u1*sin(q2)*C.z

标量场与向量场

fields.rst 从物理概念入手:标量(质量、电荷、温度、距离)只有大小;向量(位移、速度、磁场)有大小和方向。以位移 3î + 4ĵ + 5k̂ 为例,其模为 √50 = 5√2,方向由单位向量 (3/5√2)î + (4/5√2)ĵ + (5/5√2)k̂ 给出。是空间中处处可指定的向量或标量(本模块只处理三维空间),因此场定义为 (x, y, z) 的函数——例如电势 T(x,y,z) 是标量场,重力加速度场 g(x,y,z) 是向量场。

场在模块中的实现

每个ReferenceFrame实例除x/y/z基向量外,还被赋予三个坐标符号(CoordinateSym,本质是特殊的 SymPySymbol),用R[0]R[1]R[2]访问,字符串表示分别为R_xR_yR_z

>>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> v = 3*R.x + 4*R.y + 5*R.z # 向量 >>> electric_potential = 2*R[0]**2*R[1] # 标量场 2*x^2*y >>> electric_potential 2*R_x**2*R_y

标量场就是普通 SymPy 表达式,可直接用diff求偏导(对应电场的 X 分量 4xy):

>>> from sympy import diff >>> diff(electric_potential, R[0]) 4*R_x*R_y

与向量类似,标量场也可换参考系表达——前提是两系间已定义取向关系。express函数把variables参数设为True即可连坐标符号一起替换:

>>> from sympy.physics.vector import dynamicsymbols, express >>> q = dynamicsymbols('q') >>> R1 = R.orientnew('R1', rot_type='Axis', amounts=[q, R.z]) >>> express(electric_potential, R1, variables=True) 2*(R1_x*sin(q(t)) + R1_y*cos(q(t)))*(R1_x*cos(q(t)) - R1_y*sin(q(t)))**2

标量场同样可以随时间变化,time_derivative的结果取决于表达式中的符号与所选参考系:

>>> from sympy.physics.vector import time_derivative >>> time_derivative(electric_potential, R) 0 >>> time_derivative(electric_potential, R1).simplify() # 2*(...)*Derivative(q(t), t) 形式,非零

场算子:curl、divergence、gradient

三个场算子的实现集中在 fieldfunctions.py,数学定义与调用方式如下。

旋度描述向量场中无穷小旋转,方向由右手定则给出:

∇ × F = (∂F_z/∂y − ∂F_y/∂z) î + (∂F_x/∂z − ∂F_z/∂x) ĵ + (∂F_y/∂x − ∂F_x/∂y) k̂
>>> from sympy.physics.vector import curl >>> field = R[0]*R[1]*R[2]*R.x >>> curl(field, R) R_x*R_y*R.y - R_x*R_z*R.z

散度度量某点处源/汇的带符号标量强度,作用结果恒为标量:

∇ · F = ∂U/∂x + ∂V/∂y + ∂W/∂z
>>> from sympy.physics.vector import divergence >>> field = R[0]*R[1]*R[2] * (R.x + R.y + R.z) >>> divergence(field, R) R_x*R_y + R_x*R_z + R_y*R_z

梯度是标量场三个偏导数构成的向量:

>>> from sympy.physics.vector import gradient >>> scalar_field = R[0]*R[1]*R[2] >>> gradient(scalar_field, R) R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z

保守场、无散场与标量势

保守场是某标量场的梯度:其线积分只依赖端点、与路径无关;保守场必无旋(旋度为零)。is_conservative用于判定:

>>> from sympy.physics.vector import is_conservative, is_solenoidal >>> field = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z >>> is_conservative(field) True >>> curl(field, R) 0

**无散场(solenoidal field)**是处处散度为零的向量场,用is_solenoidal判定(上例中divergence(field, R)同样为 0)。

scalar_potential由保守场反求标量势(自然相差一个积分常数);传入非保守场会抛出ValueError

>>> from sympy.physics.vector import scalar_potential >>> conservative_field = (4*R[0]*R[1]*R[2]*R.x + 2*R[0]**2*R[2]*R.y ... + 2*R[0]**2*R[1]*R.z) >>> scalar_potential(conservative_field, R) 2*R_x**2*R_y*R_z

势差scalar_potential_difference计算保守场两个空间点之间标量势的差,是保守场线积分的快捷方式:

>>> from sympy.physics.vector import Point, scalar_potential_difference >>> O = Point('O') >>> P = O.locatenew('P', 1*R.x + 2*R.y + 3*R.z) >>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y >>> scalar_potential_difference(vectfield, R, O, P, O) 4

若传入标量表达式(而非向量场),该函数退化为标量场在两点处的差值。上述功能的回归测试见 sympy/physics/vector/tests/test_fieldfunctions.py。

高级主题:Dyadic、常见问题与隐藏接口

advanced.rst 覆盖模块的进阶能力与已知坑。

Dyadic(二重积)

sympy.physics.mechanics中,Dyadic 用于表示惯性。Dyadic 是两个向量的外积,是"单位 Dyadic 的线性多项式",类比向量是单位向量的线性多项式:â_x ⊗ â_x 写作 â_x â_x,顺序有意义(左向量当列、右向量当行)。基本性质包括标量提取 (xv) ⊗ w = v ⊗ (xw) = x(v ⊗ w) 与对加法的分配律。Dyadic 可用 3×3 张量或八项 Dyadic 和表示,每个 Dyadic 项的两个分量可以来自不同参考系(â_x ⊗ b̂_y 合法),从而保留"相对于哪个系定义"的信息。Dyadic 可与向量点乘/叉乘(顺序影响结果,如 â_x â_y · â_x = 0,â_x × â_y â_x = â_z â_x),也可像向量一样做时间导数和换系表达。实现见 dyadic.py,测试见 test_dyadic.py。

常见问题

文档列出了三类实战经验:

  1. 打印:默认对VectorDyadic的测度数排序,而vprint/vpprint/vlatex输出不排序。打印大型表达式时务必使用后三者——排序可能把打印时间从秒级拖到分钟级;
  2. 替换:对大型表达式做 substitution 可能耗时数分钟;
  3. 点的加速度:点至少要有速度定义(加速度可由同参考系下速度求时间导数得到)。但若速度是用 1 点/2 点定理算出的,对速度再求导得到的加速度通常比直接用加速度级别的 1 点/2 点定理(如a2pt_theory)更复杂——先用加速度级定理可以得到更短的表达式,后续(如构建 Kane 方程)都会受益。

高级接口

ReferenceFrame支持自定义基向量下标与 LaTeX 字符串:

>>> from sympy.physics.vector import ReferenceFrame, vprint, vpprint, vlatex >>> N = ReferenceFrame('N', indices=['i', 'j', 'k']) >>> N['i'] N['i'] >>> N.x N['i'] >>> vlatex(N.x) '\\mathbf{\\hat{n}_{i}}' >>> N = ReferenceFrame('N', latexs=['n1', '\\mathbf{n}_2', 'cat']) >>> vlatex(N.x) 'n1' >>> vlatex(N.y) '\\mathbf{n}_2'

dynamicsymbols还有"隐藏"功能:修改dynamicsymbols._t可改变关联的时间变量,dynamicsymbols._str可改变导数的打印记号:

>>> q1 = dynamicsymbols('q1') # q1(t) >>> dynamicsymbols._t = symbols('T') >>> q2 = dynamicsymbols('q2') # q2(T) >>> q1 # q1(t),不受影响 >>> q1d = dynamicsymbols('q1', 1) >>> vprint(q1d) # q1' >>> dynamicsymbols._str = 'd' >>> vprint(q1d) # q1d >>> dynamicsymbols._str = '\'' >>> dynamicsymbols._t = symbols('t') # 恢复默认

注意两点:_t的修改只影响之后创建的 dynamicsymbol,而_str只影响打印,对已有符号同样生效;另外Vector.dt方法会读取dynamicsymbols._t不要混用不同的时间符号

解向量方程

不能直接对向量调用solve,需要先把向量方程转成标量方程组。典型场景:N 与 A 两系相差绕 z 轴 30 度,同一向量的两套分量符号之间求换算关系:

>>> from sympy import pi, symbols, solve >>> from sympy.physics.vector import ReferenceFrame >>> N = ReferenceFrame("N") >>> A = ReferenceFrame("A") >>> A.orient_axis(N, pi / 6, N.z) >>> v1x, v1y, v1z = symbols("v1x v1y v1z") >>> v2x, v2y, v2z = symbols("v2x v2y v2z") >>> v1 = v1x * N.x + v1y * N.y + v1z * N.z >>> v2 = v2x * A.x + v2y * A.y + v2z * A.z >>> solve((v1 - v2).to_matrix(N), [v2x, v2y, v2z]) {v2x: sqrt(3)*v1x/2 + v1y/2, v2y: -v1x/2 + sqrt(3)*v1y/2, v2z: v1z}

关键手法正是前面介绍过的to_matrix(frame):差向量在指定参考系下化为列矩阵后,就是一个普通的线性方程组。

源码结构速览与延伸阅读

模块源码文件与文档主题一一对应,便于按主题定位:

主题实现文件测试文件
参考系、取向、DCM、角速度sympy/physics/vector/frame.py(约 1576 行,模块中最大的实现文件)test_frame.py
Vector 类型与 args 存储sympy/physics/vector/vector.pytest_vector.py
Point、1/2 点定理sympy/physics/vector/point.pytest_point.py
Dyadicsympy/physics/vector/dyadic.pytest_dyadic.py
dot/cross/express/time_derivative/dynamicsymbolssympy/physics/vector/functions.pytest_functions.py
场算子与势函数sympy/physics/vector/fieldfunctions.pytest_fieldfunctions.py
向量打印sympy/physics/vector/printing.pytest_printing.py

官方解释文档的完整入口是 doc/src/explanation/modules/physics/vector/index.rst,四个子文档分别位于 vectors/vectors.rst、kinematics/kinematics.rst、fields.rst、advanced.rst。运动学子文档中还配有 kin_1.svg、kin_2pt.svg、kin_1pt.svg、kin_angvel1~3.svg、kin_rolling.svg 等示意图(位于 doc/src/explanation/modules/physics/vector/kinematics/ 目录),矢量与参考系子文档配有 vec_add.svg、vec_cross.svg、vec_dot.svg、simp_rot.svg 等(位于 doc/src/explanation/modules/physics/vector/vectors/ 目录),在线文档中可直接查看。

对刚体动力学建模的完整实践,sympy.physics.vector通常作为sympy.physics.mechanics的下层组件使用(Dyadic 表示惯性矩即为典型衔接点);理解本文的参考系、dynamicsymbols、点定理与打印约定后,即可在 sympy 中完整地符号化描述多刚体系统的运动学并推导其运动方程。

【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询