|
from functools import reduce |
|
|
|
from sympy import (sympify, diff, sin, cos, Matrix, symbols, |
|
Function, S, Symbol, linear_eq_to_matrix) |
|
from sympy.integrals.integrals import integrate |
|
from sympy.simplify.trigsimp import trigsimp |
|
from .vector import Vector, _check_vector |
|
from .frame import CoordinateSym, _check_frame |
|
from .dyadic import Dyadic |
|
from .printing import vprint, vsprint, vpprint, vlatex, init_vprinting |
|
from sympy.utilities.iterables import iterable |
|
from sympy.utilities.misc import translate |
|
|
|
__all__ = ['cross', 'dot', 'express', 'time_derivative', 'outer', |
|
'kinematic_equations', 'get_motion_params', 'partial_velocity', |
|
'dynamicsymbols', 'vprint', 'vsprint', 'vpprint', 'vlatex', |
|
'init_vprinting'] |
|
|
|
|
|
def cross(vec1, vec2): |
|
"""Cross product convenience wrapper for Vector.cross(): \n""" |
|
if not isinstance(vec1, (Vector, Dyadic)): |
|
raise TypeError('Cross product is between two vectors') |
|
return vec1 ^ vec2 |
|
|
|
|
|
cross.__doc__ += Vector.cross.__doc__ |
|
|
|
|
|
def dot(vec1, vec2): |
|
"""Dot product convenience wrapper for Vector.dot(): \n""" |
|
if not isinstance(vec1, (Vector, Dyadic)): |
|
raise TypeError('Dot product is between two vectors') |
|
return vec1 & vec2 |
|
|
|
|
|
dot.__doc__ += Vector.dot.__doc__ |
|
|
|
|
|
def express(expr, frame, frame2=None, variables=False): |
|
""" |
|
Global function for 'express' functionality. |
|
|
|
Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame. |
|
|
|
Refer to the local methods of Vector and Dyadic for details. |
|
If 'variables' is True, then the coordinate variables (CoordinateSym |
|
instances) of other frames present in the vector/scalar field or |
|
dyadic expression are also substituted in terms of the base scalars of |
|
this frame. |
|
|
|
Parameters |
|
========== |
|
|
|
expr : Vector/Dyadic/scalar(sympyfiable) |
|
The expression to re-express in ReferenceFrame 'frame' |
|
|
|
frame: ReferenceFrame |
|
The reference frame to express expr in |
|
|
|
frame2 : ReferenceFrame |
|
The other frame required for re-expression(only for Dyadic expr) |
|
|
|
variables : boolean |
|
Specifies whether to substitute the coordinate variables present |
|
in expr, in terms of those of frame |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols |
|
>>> from sympy.physics.vector import init_vprinting |
|
>>> init_vprinting(pretty_print=False) |
|
>>> N = ReferenceFrame('N') |
|
>>> q = dynamicsymbols('q') |
|
>>> B = N.orientnew('B', 'Axis', [q, N.z]) |
|
>>> d = outer(N.x, N.x) |
|
>>> from sympy.physics.vector import express |
|
>>> express(d, B, N) |
|
cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) |
|
>>> express(B.x, N) |
|
cos(q)*N.x + sin(q)*N.y |
|
>>> express(N[0], B, variables=True) |
|
B_x*cos(q) - B_y*sin(q) |
|
|
|
""" |
|
|
|
_check_frame(frame) |
|
|
|
if expr == 0: |
|
return expr |
|
|
|
if isinstance(expr, Vector): |
|
|
|
if variables: |
|
|
|
|
|
frame_list = [x[-1] for x in expr.args] |
|
subs_dict = {} |
|
for f in frame_list: |
|
subs_dict.update(f.variable_map(frame)) |
|
expr = expr.subs(subs_dict) |
|
|
|
outvec = Vector([]) |
|
for v in expr.args: |
|
if v[1] != frame: |
|
temp = frame.dcm(v[1]) * v[0] |
|
if Vector.simp: |
|
temp = temp.applyfunc(lambda x: |
|
trigsimp(x, method='fu')) |
|
outvec += Vector([(temp, frame)]) |
|
else: |
|
outvec += Vector([v]) |
|
return outvec |
|
|
|
if isinstance(expr, Dyadic): |
|
if frame2 is None: |
|
frame2 = frame |
|
_check_frame(frame2) |
|
ol = Dyadic(0) |
|
for v in expr.args: |
|
ol += express(v[0], frame, variables=variables) * \ |
|
(express(v[1], frame, variables=variables) | |
|
express(v[2], frame2, variables=variables)) |
|
return ol |
|
|
|
else: |
|
if variables: |
|
|
|
frame_set = set() |
|
expr = sympify(expr) |
|
|
|
for x in expr.free_symbols: |
|
if isinstance(x, CoordinateSym) and x.frame != frame: |
|
frame_set.add(x.frame) |
|
subs_dict = {} |
|
for f in frame_set: |
|
subs_dict.update(f.variable_map(frame)) |
|
return expr.subs(subs_dict) |
|
return expr |
|
|
|
|
|
def time_derivative(expr, frame, order=1): |
|
""" |
|
Calculate the time derivative of a vector/scalar field function |
|
or dyadic expression in given frame. |
|
|
|
References |
|
========== |
|
|
|
https://en.wikipedia.org/wiki/Rotating_reference_frame#Time_derivatives_in_the_two_frames |
|
|
|
Parameters |
|
========== |
|
|
|
expr : Vector/Dyadic/sympifyable |
|
The expression whose time derivative is to be calculated |
|
|
|
frame : ReferenceFrame |
|
The reference frame to calculate the time derivative in |
|
|
|
order : integer |
|
The order of the derivative to be calculated |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols |
|
>>> from sympy.physics.vector import init_vprinting |
|
>>> init_vprinting(pretty_print=False) |
|
>>> from sympy import Symbol |
|
>>> q1 = Symbol('q1') |
|
>>> u1 = dynamicsymbols('u1') |
|
>>> N = ReferenceFrame('N') |
|
>>> A = N.orientnew('A', 'Axis', [q1, N.x]) |
|
>>> v = u1 * N.x |
|
>>> A.set_ang_vel(N, 10*A.x) |
|
>>> from sympy.physics.vector import time_derivative |
|
>>> time_derivative(v, N) |
|
u1'*N.x |
|
>>> time_derivative(u1*A[0], N) |
|
N_x*u1' |
|
>>> B = N.orientnew('B', 'Axis', [u1, N.z]) |
|
>>> from sympy.physics.vector import outer |
|
>>> d = outer(N.x, N.x) |
|
>>> time_derivative(d, B) |
|
- u1'*(N.y|N.x) - u1'*(N.x|N.y) |
|
|
|
""" |
|
|
|
t = dynamicsymbols._t |
|
_check_frame(frame) |
|
|
|
if order == 0: |
|
return expr |
|
if order % 1 != 0 or order < 0: |
|
raise ValueError("Unsupported value of order entered") |
|
|
|
if isinstance(expr, Vector): |
|
outlist = [] |
|
for v in expr.args: |
|
if v[1] == frame: |
|
outlist += [(express(v[0], frame, variables=True).diff(t), |
|
frame)] |
|
else: |
|
outlist += (time_derivative(Vector([v]), v[1]) + |
|
(v[1].ang_vel_in(frame) ^ Vector([v]))).args |
|
outvec = Vector(outlist) |
|
return time_derivative(outvec, frame, order - 1) |
|
|
|
if isinstance(expr, Dyadic): |
|
ol = Dyadic(0) |
|
for v in expr.args: |
|
ol += (v[0].diff(t) * (v[1] | v[2])) |
|
ol += (v[0] * (time_derivative(v[1], frame) | v[2])) |
|
ol += (v[0] * (v[1] | time_derivative(v[2], frame))) |
|
return time_derivative(ol, frame, order - 1) |
|
|
|
else: |
|
return diff(express(expr, frame, variables=True), t, order) |
|
|
|
|
|
def outer(vec1, vec2): |
|
"""Outer product convenience wrapper for Vector.outer():\n""" |
|
if not isinstance(vec1, Vector): |
|
raise TypeError('Outer product is between two Vectors') |
|
return vec1.outer(vec2) |
|
|
|
|
|
outer.__doc__ += Vector.outer.__doc__ |
|
|
|
|
|
def kinematic_equations(speeds, coords, rot_type, rot_order=''): |
|
"""Gives equations relating the qdot's to u's for a rotation type. |
|
|
|
Supply rotation type and order as in orient. Speeds are assumed to be |
|
body-fixed; if we are defining the orientation of B in A using by rot_type, |
|
the angular velocity of B in A is assumed to be in the form: speed[0]*B.x + |
|
speed[1]*B.y + speed[2]*B.z |
|
|
|
Parameters |
|
========== |
|
|
|
speeds : list of length 3 |
|
The body fixed angular velocity measure numbers. |
|
coords : list of length 3 or 4 |
|
The coordinates used to define the orientation of the two frames. |
|
rot_type : str |
|
The type of rotation used to create the equations. Body, Space, or |
|
Quaternion only |
|
rot_order : str or int |
|
If applicable, the order of a series of rotations. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import dynamicsymbols |
|
>>> from sympy.physics.vector import kinematic_equations, vprint |
|
>>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') |
|
>>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') |
|
>>> vprint(kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313'), |
|
... order=None) |
|
[-(u1*sin(q3) + u2*cos(q3))/sin(q2) + q1', -u1*cos(q3) + u2*sin(q3) + q2', (u1*sin(q3) + u2*cos(q3))*cos(q2)/sin(q2) - u3 + q3'] |
|
|
|
""" |
|
|
|
|
|
approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', |
|
'212', '232', '313', '323', '1', '2', '3', '') |
|
|
|
rot_order = translate(str(rot_order), 'XYZxyz', '123123') |
|
rot_type = rot_type.lower() |
|
|
|
if not isinstance(speeds, (list, tuple)): |
|
raise TypeError('Need to supply speeds in a list') |
|
if len(speeds) != 3: |
|
raise TypeError('Need to supply 3 body-fixed speeds') |
|
if not isinstance(coords, (list, tuple)): |
|
raise TypeError('Need to supply coordinates in a list') |
|
if rot_type in ['body', 'space']: |
|
if rot_order not in approved_orders: |
|
raise ValueError('Not an acceptable rotation order') |
|
if len(coords) != 3: |
|
raise ValueError('Need 3 coordinates for body or space') |
|
|
|
w1, w2, w3 = speeds |
|
if w1 == w2 == w3 == 0: |
|
return [S.Zero]*3 |
|
q1, q2, q3 = coords |
|
q1d, q2d, q3d = [diff(i, dynamicsymbols._t) for i in coords] |
|
s1, s2, s3 = [sin(q1), sin(q2), sin(q3)] |
|
c1, c2, c3 = [cos(q1), cos(q2), cos(q3)] |
|
if rot_type == 'body': |
|
if rot_order == '123': |
|
return [q1d - (w1 * c3 - w2 * s3) / c2, q2d - w1 * s3 - w2 * |
|
c3, q3d - (-w1 * c3 + w2 * s3) * s2 / c2 - w3] |
|
if rot_order == '231': |
|
return [q1d - (w2 * c3 - w3 * s3) / c2, q2d - w2 * s3 - w3 * |
|
c3, q3d - w1 - (- w2 * c3 + w3 * s3) * s2 / c2] |
|
if rot_order == '312': |
|
return [q1d - (-w1 * s3 + w3 * c3) / c2, q2d - w1 * c3 - w3 * |
|
s3, q3d - (w1 * s3 - w3 * c3) * s2 / c2 - w2] |
|
if rot_order == '132': |
|
return [q1d - (w1 * c3 + w3 * s3) / c2, q2d + w1 * s3 - w3 * |
|
c3, q3d - (w1 * c3 + w3 * s3) * s2 / c2 - w2] |
|
if rot_order == '213': |
|
return [q1d - (w1 * s3 + w2 * c3) / c2, q2d - w1 * c3 + w2 * |
|
s3, q3d - (w1 * s3 + w2 * c3) * s2 / c2 - w3] |
|
if rot_order == '321': |
|
return [q1d - (w2 * s3 + w3 * c3) / c2, q2d - w2 * c3 + w3 * |
|
s3, q3d - w1 - (w2 * s3 + w3 * c3) * s2 / c2] |
|
if rot_order == '121': |
|
return [q1d - (w2 * s3 + w3 * c3) / s2, q2d - w2 * c3 + w3 * |
|
s3, q3d - w1 + (w2 * s3 + w3 * c3) * c2 / s2] |
|
if rot_order == '131': |
|
return [q1d - (-w2 * c3 + w3 * s3) / s2, q2d - w2 * s3 - w3 * |
|
c3, q3d - w1 - (w2 * c3 - w3 * s3) * c2 / s2] |
|
if rot_order == '212': |
|
return [q1d - (w1 * s3 - w3 * c3) / s2, q2d - w1 * c3 - w3 * |
|
s3, q3d - (-w1 * s3 + w3 * c3) * c2 / s2 - w2] |
|
if rot_order == '232': |
|
return [q1d - (w1 * c3 + w3 * s3) / s2, q2d + w1 * s3 - w3 * |
|
c3, q3d + (w1 * c3 + w3 * s3) * c2 / s2 - w2] |
|
if rot_order == '313': |
|
return [q1d - (w1 * s3 + w2 * c3) / s2, q2d - w1 * c3 + w2 * |
|
s3, q3d + (w1 * s3 + w2 * c3) * c2 / s2 - w3] |
|
if rot_order == '323': |
|
return [q1d - (-w1 * c3 + w2 * s3) / s2, q2d - w1 * s3 - w2 * |
|
c3, q3d - (w1 * c3 - w2 * s3) * c2 / s2 - w3] |
|
if rot_type == 'space': |
|
if rot_order == '123': |
|
return [q1d - w1 - (w2 * s1 + w3 * c1) * s2 / c2, q2d - w2 * |
|
c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / c2] |
|
if rot_order == '231': |
|
return [q1d - (w1 * c1 + w3 * s1) * s2 / c2 - w2, q2d + w1 * |
|
s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / c2] |
|
if rot_order == '312': |
|
return [q1d - (w1 * s1 + w2 * c1) * s2 / c2 - w3, q2d - w1 * |
|
c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / c2] |
|
if rot_order == '132': |
|
return [q1d - w1 - (-w2 * c1 + w3 * s1) * s2 / c2, q2d - w2 * |
|
s1 - w3 * c1, q3d - (w2 * c1 - w3 * s1) / c2] |
|
if rot_order == '213': |
|
return [q1d - (w1 * s1 - w3 * c1) * s2 / c2 - w2, q2d - w1 * |
|
c1 - w3 * s1, q3d - (-w1 * s1 + w3 * c1) / c2] |
|
if rot_order == '321': |
|
return [q1d - (-w1 * c1 + w2 * s1) * s2 / c2 - w3, q2d - w1 * |
|
s1 - w2 * c1, q3d - (w1 * c1 - w2 * s1) / c2] |
|
if rot_order == '121': |
|
return [q1d - w1 + (w2 * s1 + w3 * c1) * c2 / s2, q2d - w2 * |
|
c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / s2] |
|
if rot_order == '131': |
|
return [q1d - w1 - (w2 * c1 - w3 * s1) * c2 / s2, q2d - w2 * |
|
s1 - w3 * c1, q3d - (-w2 * c1 + w3 * s1) / s2] |
|
if rot_order == '212': |
|
return [q1d - (-w1 * s1 + w3 * c1) * c2 / s2 - w2, q2d - w1 * |
|
c1 - w3 * s1, q3d - (w1 * s1 - w3 * c1) / s2] |
|
if rot_order == '232': |
|
return [q1d + (w1 * c1 + w3 * s1) * c2 / s2 - w2, q2d + w1 * |
|
s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / s2] |
|
if rot_order == '313': |
|
return [q1d + (w1 * s1 + w2 * c1) * c2 / s2 - w3, q2d - w1 * |
|
c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / s2] |
|
if rot_order == '323': |
|
return [q1d - (w1 * c1 - w2 * s1) * c2 / s2 - w3, q2d - w1 * |
|
s1 - w2 * c1, q3d - (-w1 * c1 + w2 * s1) / s2] |
|
elif rot_type == 'quaternion': |
|
if rot_order != '': |
|
raise ValueError('Cannot have rotation order for quaternion') |
|
if len(coords) != 4: |
|
raise ValueError('Need 4 coordinates for quaternion') |
|
|
|
e0, e1, e2, e3 = coords |
|
w = Matrix(speeds + [0]) |
|
E = Matrix([[e0, -e3, e2, e1], |
|
[e3, e0, -e1, e2], |
|
[-e2, e1, e0, e3], |
|
[-e1, -e2, -e3, e0]]) |
|
edots = Matrix([diff(i, dynamicsymbols._t) for i in [e1, e2, e3, e0]]) |
|
return list(edots.T - 0.5 * w.T * E.T) |
|
else: |
|
raise ValueError('Not an approved rotation type for this function') |
|
|
|
|
|
def get_motion_params(frame, **kwargs): |
|
""" |
|
Returns the three motion parameters - (acceleration, velocity, and |
|
position) as vectorial functions of time in the given frame. |
|
|
|
If a higher order differential function is provided, the lower order |
|
functions are used as boundary conditions. For example, given the |
|
acceleration, the velocity and position parameters are taken as |
|
boundary conditions. |
|
|
|
The values of time at which the boundary conditions are specified |
|
are taken from timevalue1(for position boundary condition) and |
|
timevalue2(for velocity boundary condition). |
|
|
|
If any of the boundary conditions are not provided, they are taken |
|
to be zero by default (zero vectors, in case of vectorial inputs). If |
|
the boundary conditions are also functions of time, they are converted |
|
to constants by substituting the time values in the dynamicsymbols._t |
|
time Symbol. |
|
|
|
This function can also be used for calculating rotational motion |
|
parameters. Have a look at the Parameters and Examples for more clarity. |
|
|
|
Parameters |
|
========== |
|
|
|
frame : ReferenceFrame |
|
The frame to express the motion parameters in |
|
|
|
acceleration : Vector |
|
Acceleration of the object/frame as a function of time |
|
|
|
velocity : Vector |
|
Velocity as function of time or as boundary condition |
|
of velocity at time = timevalue1 |
|
|
|
position : Vector |
|
Velocity as function of time or as boundary condition |
|
of velocity at time = timevalue1 |
|
|
|
timevalue1 : sympyfiable |
|
Value of time for position boundary condition |
|
|
|
timevalue2 : sympyfiable |
|
Value of time for velocity boundary condition |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import ReferenceFrame, get_motion_params, dynamicsymbols |
|
>>> from sympy.physics.vector import init_vprinting |
|
>>> init_vprinting(pretty_print=False) |
|
>>> from sympy import symbols |
|
>>> R = ReferenceFrame('R') |
|
>>> v1, v2, v3 = dynamicsymbols('v1 v2 v3') |
|
>>> v = v1*R.x + v2*R.y + v3*R.z |
|
>>> get_motion_params(R, position = v) |
|
(v1''*R.x + v2''*R.y + v3''*R.z, v1'*R.x + v2'*R.y + v3'*R.z, v1*R.x + v2*R.y + v3*R.z) |
|
>>> a, b, c = symbols('a b c') |
|
>>> v = a*R.x + b*R.y + c*R.z |
|
>>> get_motion_params(R, velocity = v) |
|
(0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z) |
|
>>> parameters = get_motion_params(R, acceleration = v) |
|
>>> parameters[1] |
|
a*t*R.x + b*t*R.y + c*t*R.z |
|
>>> parameters[2] |
|
a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z |
|
|
|
""" |
|
|
|
def _process_vector_differential(vectdiff, condition, variable, ordinate, |
|
frame): |
|
""" |
|
Helper function for get_motion methods. Finds derivative of vectdiff |
|
wrt variable, and its integral using the specified boundary condition |
|
at value of variable = ordinate. |
|
Returns a tuple of - (derivative, function and integral) wrt vectdiff |
|
|
|
""" |
|
|
|
|
|
if condition != 0: |
|
condition = express(condition, frame, variables=True) |
|
|
|
if vectdiff == Vector(0): |
|
return (0, 0, condition) |
|
|
|
vectdiff1 = express(vectdiff, frame) |
|
|
|
vectdiff2 = time_derivative(vectdiff, frame) |
|
|
|
vectdiff0 = Vector(0) |
|
lims = (variable, ordinate, variable) |
|
for dim in frame: |
|
function1 = vectdiff1.dot(dim) |
|
abscissa = dim.dot(condition).subs({variable: ordinate}) |
|
|
|
|
|
vectdiff0 += (integrate(function1, lims) + abscissa) * dim |
|
|
|
return (vectdiff2, vectdiff, vectdiff0) |
|
|
|
_check_frame(frame) |
|
|
|
if 'acceleration' in kwargs: |
|
mode = 2 |
|
elif 'velocity' in kwargs: |
|
mode = 1 |
|
else: |
|
mode = 0 |
|
|
|
|
|
|
|
|
|
conditions = ['acceleration', 'velocity', 'position', |
|
'timevalue', 'timevalue1', 'timevalue2'] |
|
for i, x in enumerate(conditions): |
|
if x not in kwargs: |
|
if i < 3: |
|
kwargs[x] = Vector(0) |
|
else: |
|
kwargs[x] = S.Zero |
|
elif i < 3: |
|
_check_vector(kwargs[x]) |
|
else: |
|
kwargs[x] = sympify(kwargs[x]) |
|
if mode == 2: |
|
vel = _process_vector_differential(kwargs['acceleration'], |
|
kwargs['velocity'], |
|
dynamicsymbols._t, |
|
kwargs['timevalue2'], frame)[2] |
|
pos = _process_vector_differential(vel, kwargs['position'], |
|
dynamicsymbols._t, |
|
kwargs['timevalue1'], frame)[2] |
|
return (kwargs['acceleration'], vel, pos) |
|
elif mode == 1: |
|
return _process_vector_differential(kwargs['velocity'], |
|
kwargs['position'], |
|
dynamicsymbols._t, |
|
kwargs['timevalue1'], frame) |
|
else: |
|
vel = time_derivative(kwargs['position'], frame) |
|
acc = time_derivative(vel, frame) |
|
return (acc, vel, kwargs['position']) |
|
|
|
|
|
def partial_velocity(vel_vecs, gen_speeds, frame): |
|
"""Returns a list of partial velocities with respect to the provided |
|
generalized speeds in the given reference frame for each of the supplied |
|
velocity vectors. |
|
|
|
The output is a list of lists. The outer list has a number of elements |
|
equal to the number of supplied velocity vectors. The inner lists are, for |
|
each velocity vector, the partial derivatives of that velocity vector with |
|
respect to the generalized speeds supplied. |
|
|
|
Parameters |
|
========== |
|
|
|
vel_vecs : iterable |
|
An iterable of velocity vectors (angular or linear). |
|
gen_speeds : iterable |
|
An iterable of generalized speeds. |
|
frame : ReferenceFrame |
|
The reference frame that the partial derivatives are going to be taken |
|
in. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import Point, ReferenceFrame |
|
>>> from sympy.physics.vector import dynamicsymbols |
|
>>> from sympy.physics.vector import partial_velocity |
|
>>> u = dynamicsymbols('u') |
|
>>> N = ReferenceFrame('N') |
|
>>> P = Point('P') |
|
>>> P.set_vel(N, u * N.x) |
|
>>> vel_vecs = [P.vel(N)] |
|
>>> gen_speeds = [u] |
|
>>> partial_velocity(vel_vecs, gen_speeds, N) |
|
[[N.x]] |
|
|
|
""" |
|
|
|
if not iterable(vel_vecs): |
|
raise TypeError('Velocity vectors must be contained in an iterable.') |
|
|
|
if not iterable(gen_speeds): |
|
raise TypeError('Generalized speeds must be contained in an iterable') |
|
|
|
vec_partials = [] |
|
gen_speeds = list(gen_speeds) |
|
for vel in vel_vecs: |
|
partials = [Vector(0) for _ in gen_speeds] |
|
for components, ref in vel.args: |
|
mat, _ = linear_eq_to_matrix(components, gen_speeds) |
|
for i in range(len(gen_speeds)): |
|
for dim, direction in enumerate(ref): |
|
if mat[dim, i] != 0: |
|
partials[i] += direction * mat[dim, i] |
|
|
|
vec_partials.append(partials) |
|
|
|
return vec_partials |
|
|
|
|
|
def dynamicsymbols(names, level=0, **assumptions): |
|
"""Uses symbols and Function for functions of time. |
|
|
|
Creates a SymPy UndefinedFunction, which is then initialized as a function |
|
of a variable, the default being Symbol('t'). |
|
|
|
Parameters |
|
========== |
|
|
|
names : str |
|
Names of the dynamic symbols you want to create; works the same way as |
|
inputs to symbols |
|
level : int |
|
Level of differentiation of the returned function; d/dt once of t, |
|
twice of t, etc. |
|
assumptions : |
|
- real(bool) : This is used to set the dynamicsymbol as real, |
|
by default is False. |
|
- positive(bool) : This is used to set the dynamicsymbol as positive, |
|
by default is False. |
|
- commutative(bool) : This is used to set the commutative property of |
|
a dynamicsymbol, by default is True. |
|
- integer(bool) : This is used to set the dynamicsymbol as integer, |
|
by default is False. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.vector import dynamicsymbols |
|
>>> from sympy import diff, Symbol |
|
>>> q1 = dynamicsymbols('q1') |
|
>>> q1 |
|
q1(t) |
|
>>> q2 = dynamicsymbols('q2', real=True) |
|
>>> q2.is_real |
|
True |
|
>>> q3 = dynamicsymbols('q3', positive=True) |
|
>>> q3.is_positive |
|
True |
|
>>> q4, q5 = dynamicsymbols('q4,q5', commutative=False) |
|
>>> bool(q4*q5 != q5*q4) |
|
True |
|
>>> q6 = dynamicsymbols('q6', integer=True) |
|
>>> q6.is_integer |
|
True |
|
>>> diff(q1, Symbol('t')) |
|
Derivative(q1(t), t) |
|
|
|
""" |
|
esses = symbols(names, cls=Function, **assumptions) |
|
t = dynamicsymbols._t |
|
if iterable(esses): |
|
esses = [reduce(diff, [t] * level, e(t)) for e in esses] |
|
return esses |
|
else: |
|
return reduce(diff, [t] * level, esses(t)) |
|
|
|
|
|
dynamicsymbols._t = Symbol('t') |
|
dynamicsymbols._str = '\'' |
|
|