Traktor/myenv/Lib/site-packages/sympy/physics/mechanics/jointsmethod.py
2024-05-26 05:12:46 +02:00

280 lines
8.3 KiB
Python

from sympy.physics.mechanics import (Body, Lagrangian, KanesMethod, LagrangesMethod,
RigidBody, Particle)
from sympy.physics.mechanics.method import _Methods
from sympy.core.backend import Matrix
__all__ = ['JointsMethod']
class JointsMethod(_Methods):
"""Method for formulating the equations of motion using a set of interconnected bodies with joints.
Parameters
==========
newtonion : Body or ReferenceFrame
The newtonion(inertial) frame.
*joints : Joint
The joints in the system
Attributes
==========
q, u : iterable
Iterable of the generalized coordinates and speeds
bodies : iterable
Iterable of Body objects in the system.
loads : iterable
Iterable of (Point, vector) or (ReferenceFrame, vector) tuples
describing the forces on the system.
mass_matrix : Matrix, shape(n, n)
The system's mass matrix
forcing : Matrix, shape(n, 1)
The system's forcing vector
mass_matrix_full : Matrix, shape(2*n, 2*n)
The "mass matrix" for the u's and q's
forcing_full : Matrix, shape(2*n, 1)
The "forcing vector" for the u's and q's
method : KanesMethod or Lagrange's method
Method's object.
kdes : iterable
Iterable of kde in they system.
Examples
========
This is a simple example for a one degree of freedom translational
spring-mass-damper.
>>> from sympy import symbols
>>> from sympy.physics.mechanics import Body, JointsMethod, PrismaticJoint
>>> from sympy.physics.vector import dynamicsymbols
>>> c, k = symbols('c k')
>>> x, v = dynamicsymbols('x v')
>>> wall = Body('W')
>>> body = Body('B')
>>> J = PrismaticJoint('J', wall, body, coordinates=x, speeds=v)
>>> wall.apply_force(c*v*wall.x, reaction_body=body)
>>> wall.apply_force(k*x*wall.x, reaction_body=body)
>>> method = JointsMethod(wall, J)
>>> method.form_eoms()
Matrix([[-B_mass*Derivative(v(t), t) - c*v(t) - k*x(t)]])
>>> M = method.mass_matrix_full
>>> F = method.forcing_full
>>> rhs = M.LUsolve(F)
>>> rhs
Matrix([
[ v(t)],
[(-c*v(t) - k*x(t))/B_mass]])
Notes
=====
``JointsMethod`` currently only works with systems that do not have any
configuration or motion constraints.
"""
def __init__(self, newtonion, *joints):
if isinstance(newtonion, Body):
self.frame = newtonion.frame
else:
self.frame = newtonion
self._joints = joints
self._bodies = self._generate_bodylist()
self._loads = self._generate_loadlist()
self._q = self._generate_q()
self._u = self._generate_u()
self._kdes = self._generate_kdes()
self._method = None
@property
def bodies(self):
"""List of bodies in they system."""
return self._bodies
@property
def loads(self):
"""List of loads on the system."""
return self._loads
@property
def q(self):
"""List of the generalized coordinates."""
return self._q
@property
def u(self):
"""List of the generalized speeds."""
return self._u
@property
def kdes(self):
"""List of the generalized coordinates."""
return self._kdes
@property
def forcing_full(self):
"""The "forcing vector" for the u's and q's."""
return self.method.forcing_full
@property
def mass_matrix_full(self):
"""The "mass matrix" for the u's and q's."""
return self.method.mass_matrix_full
@property
def mass_matrix(self):
"""The system's mass matrix."""
return self.method.mass_matrix
@property
def forcing(self):
"""The system's forcing vector."""
return self.method.forcing
@property
def method(self):
"""Object of method used to form equations of systems."""
return self._method
def _generate_bodylist(self):
bodies = []
for joint in self._joints:
if joint.child not in bodies:
bodies.append(joint.child)
if joint.parent not in bodies:
bodies.append(joint.parent)
return bodies
def _generate_loadlist(self):
load_list = []
for body in self.bodies:
load_list.extend(body.loads)
return load_list
def _generate_q(self):
q_ind = []
for joint in self._joints:
for coordinate in joint.coordinates:
if coordinate in q_ind:
raise ValueError('Coordinates of joints should be unique.')
q_ind.append(coordinate)
return Matrix(q_ind)
def _generate_u(self):
u_ind = []
for joint in self._joints:
for speed in joint.speeds:
if speed in u_ind:
raise ValueError('Speeds of joints should be unique.')
u_ind.append(speed)
return Matrix(u_ind)
def _generate_kdes(self):
kd_ind = Matrix(1, 0, []).T
for joint in self._joints:
kd_ind = kd_ind.col_join(joint.kdes)
return kd_ind
def _convert_bodies(self):
# Convert `Body` to `Particle` and `RigidBody`
bodylist = []
for body in self.bodies:
if body.is_rigidbody:
rb = RigidBody(body.name, body.masscenter, body.frame, body.mass,
(body.central_inertia, body.masscenter))
rb.potential_energy = body.potential_energy
bodylist.append(rb)
else:
part = Particle(body.name, body.masscenter, body.mass)
part.potential_energy = body.potential_energy
bodylist.append(part)
return bodylist
def form_eoms(self, method=KanesMethod):
"""Method to form system's equation of motions.
Parameters
==========
method : Class
Class name of method.
Returns
========
Matrix
Vector of equations of motions.
Examples
========
This is a simple example for a one degree of freedom translational
spring-mass-damper.
>>> from sympy import S, symbols
>>> from sympy.physics.mechanics import LagrangesMethod, dynamicsymbols, Body
>>> from sympy.physics.mechanics import PrismaticJoint, JointsMethod
>>> q = dynamicsymbols('q')
>>> qd = dynamicsymbols('q', 1)
>>> m, k, b = symbols('m k b')
>>> wall = Body('W')
>>> part = Body('P', mass=m)
>>> part.potential_energy = k * q**2 / S(2)
>>> J = PrismaticJoint('J', wall, part, coordinates=q, speeds=qd)
>>> wall.apply_force(b * qd * wall.x, reaction_body=part)
>>> method = JointsMethod(wall, J)
>>> method.form_eoms(LagrangesMethod)
Matrix([[b*Derivative(q(t), t) + k*q(t) + m*Derivative(q(t), (t, 2))]])
We can also solve for the states using the 'rhs' method.
>>> method.rhs()
Matrix([
[ Derivative(q(t), t)],
[(-b*Derivative(q(t), t) - k*q(t))/m]])
"""
bodylist = self._convert_bodies()
if issubclass(method, LagrangesMethod): #LagrangesMethod or similar
L = Lagrangian(self.frame, *bodylist)
self._method = method(L, self.q, self.loads, bodylist, self.frame)
else: #KanesMethod or similar
self._method = method(self.frame, q_ind=self.q, u_ind=self.u, kd_eqs=self.kdes,
forcelist=self.loads, bodies=bodylist)
soln = self.method._form_eoms()
return soln
def rhs(self, inv_method=None):
"""Returns equations that can be solved numerically.
Parameters
==========
inv_method : str
The specific sympy inverse matrix calculation method to use. For a
list of valid methods, see
:meth:`~sympy.matrices.matrices.MatrixBase.inv`
Returns
========
Matrix
Numerically solvable equations.
See Also
========
sympy.physics.mechanics.kane.KanesMethod.rhs:
KanesMethod's rhs function.
sympy.physics.mechanics.lagrange.LagrangesMethod.rhs:
LagrangesMethod's rhs function.
"""
return self.method.rhs(inv_method=inv_method)