functions.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. from functools import reduce
  2. from sympy.core.backend import (sympify, diff, sin, cos, Matrix, symbols,
  3. Function, S, Symbol)
  4. from sympy.integrals.integrals import integrate
  5. from sympy.simplify.trigsimp import trigsimp
  6. from .vector import Vector, _check_vector
  7. from .frame import CoordinateSym, _check_frame
  8. from .dyadic import Dyadic
  9. from .printing import vprint, vsprint, vpprint, vlatex, init_vprinting
  10. from sympy.utilities.iterables import iterable
  11. from sympy.utilities.misc import translate
  12. __all__ = ['cross', 'dot', 'express', 'time_derivative', 'outer',
  13. 'kinematic_equations', 'get_motion_params', 'partial_velocity',
  14. 'dynamicsymbols', 'vprint', 'vsprint', 'vpprint', 'vlatex',
  15. 'init_vprinting']
  16. def cross(vec1, vec2):
  17. """Cross product convenience wrapper for Vector.cross(): \n"""
  18. if not isinstance(vec1, (Vector, Dyadic)):
  19. raise TypeError('Cross product is between two vectors')
  20. return vec1 ^ vec2
  21. cross.__doc__ += Vector.cross.__doc__ # type: ignore
  22. def dot(vec1, vec2):
  23. """Dot product convenience wrapper for Vector.dot(): \n"""
  24. if not isinstance(vec1, (Vector, Dyadic)):
  25. raise TypeError('Dot product is between two vectors')
  26. return vec1 & vec2
  27. dot.__doc__ += Vector.dot.__doc__ # type: ignore
  28. def express(expr, frame, frame2=None, variables=False):
  29. """
  30. Global function for 'express' functionality.
  31. Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame.
  32. Refer to the local methods of Vector and Dyadic for details.
  33. If 'variables' is True, then the coordinate variables (CoordinateSym
  34. instances) of other frames present in the vector/scalar field or
  35. dyadic expression are also substituted in terms of the base scalars of
  36. this frame.
  37. Parameters
  38. ==========
  39. expr : Vector/Dyadic/scalar(sympyfiable)
  40. The expression to re-express in ReferenceFrame 'frame'
  41. frame: ReferenceFrame
  42. The reference frame to express expr in
  43. frame2 : ReferenceFrame
  44. The other frame required for re-expression(only for Dyadic expr)
  45. variables : boolean
  46. Specifies whether to substitute the coordinate variables present
  47. in expr, in terms of those of frame
  48. Examples
  49. ========
  50. >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols
  51. >>> from sympy.physics.vector import init_vprinting
  52. >>> init_vprinting(pretty_print=False)
  53. >>> N = ReferenceFrame('N')
  54. >>> q = dynamicsymbols('q')
  55. >>> B = N.orientnew('B', 'Axis', [q, N.z])
  56. >>> d = outer(N.x, N.x)
  57. >>> from sympy.physics.vector import express
  58. >>> express(d, B, N)
  59. cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x)
  60. >>> express(B.x, N)
  61. cos(q)*N.x + sin(q)*N.y
  62. >>> express(N[0], B, variables=True)
  63. B_x*cos(q) - B_y*sin(q)
  64. """
  65. _check_frame(frame)
  66. if expr == 0:
  67. return expr
  68. if isinstance(expr, Vector):
  69. # Given expr is a Vector
  70. if variables:
  71. # If variables attribute is True, substitute the coordinate
  72. # variables in the Vector
  73. frame_list = [x[-1] for x in expr.args]
  74. subs_dict = {}
  75. for f in frame_list:
  76. subs_dict.update(f.variable_map(frame))
  77. expr = expr.subs(subs_dict)
  78. # Re-express in this frame
  79. outvec = Vector([])
  80. for i, v in enumerate(expr.args):
  81. if v[1] != frame:
  82. temp = frame.dcm(v[1]) * v[0]
  83. if Vector.simp:
  84. temp = temp.applyfunc(lambda x:
  85. trigsimp(x, method='fu'))
  86. outvec += Vector([(temp, frame)])
  87. else:
  88. outvec += Vector([v])
  89. return outvec
  90. if isinstance(expr, Dyadic):
  91. if frame2 is None:
  92. frame2 = frame
  93. _check_frame(frame2)
  94. ol = Dyadic(0)
  95. for i, v in enumerate(expr.args):
  96. ol += express(v[0], frame, variables=variables) * \
  97. (express(v[1], frame, variables=variables) |
  98. express(v[2], frame2, variables=variables))
  99. return ol
  100. else:
  101. if variables:
  102. # Given expr is a scalar field
  103. frame_set = set()
  104. expr = sympify(expr)
  105. # Substitute all the coordinate variables
  106. for x in expr.free_symbols:
  107. if isinstance(x, CoordinateSym) and x.frame != frame:
  108. frame_set.add(x.frame)
  109. subs_dict = {}
  110. for f in frame_set:
  111. subs_dict.update(f.variable_map(frame))
  112. return expr.subs(subs_dict)
  113. return expr
  114. def time_derivative(expr, frame, order=1):
  115. """
  116. Calculate the time derivative of a vector/scalar field function
  117. or dyadic expression in given frame.
  118. References
  119. ==========
  120. https://en.wikipedia.org/wiki/Rotating_reference_frame#Time_derivatives_in_the_two_frames
  121. Parameters
  122. ==========
  123. expr : Vector/Dyadic/sympifyable
  124. The expression whose time derivative is to be calculated
  125. frame : ReferenceFrame
  126. The reference frame to calculate the time derivative in
  127. order : integer
  128. The order of the derivative to be calculated
  129. Examples
  130. ========
  131. >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols
  132. >>> from sympy.physics.vector import init_vprinting
  133. >>> init_vprinting(pretty_print=False)
  134. >>> from sympy import Symbol
  135. >>> q1 = Symbol('q1')
  136. >>> u1 = dynamicsymbols('u1')
  137. >>> N = ReferenceFrame('N')
  138. >>> A = N.orientnew('A', 'Axis', [q1, N.x])
  139. >>> v = u1 * N.x
  140. >>> A.set_ang_vel(N, 10*A.x)
  141. >>> from sympy.physics.vector import time_derivative
  142. >>> time_derivative(v, N)
  143. u1'*N.x
  144. >>> time_derivative(u1*A[0], N)
  145. N_x*u1'
  146. >>> B = N.orientnew('B', 'Axis', [u1, N.z])
  147. >>> from sympy.physics.vector import outer
  148. >>> d = outer(N.x, N.x)
  149. >>> time_derivative(d, B)
  150. - u1'*(N.y|N.x) - u1'*(N.x|N.y)
  151. """
  152. t = dynamicsymbols._t
  153. _check_frame(frame)
  154. if order == 0:
  155. return expr
  156. if order % 1 != 0 or order < 0:
  157. raise ValueError("Unsupported value of order entered")
  158. if isinstance(expr, Vector):
  159. outlist = []
  160. for i, v in enumerate(expr.args):
  161. if v[1] == frame:
  162. outlist += [(express(v[0], frame, variables=True).diff(t),
  163. frame)]
  164. else:
  165. outlist += (time_derivative(Vector([v]), v[1]) +
  166. (v[1].ang_vel_in(frame) ^ Vector([v]))).args
  167. outvec = Vector(outlist)
  168. return time_derivative(outvec, frame, order - 1)
  169. if isinstance(expr, Dyadic):
  170. ol = Dyadic(0)
  171. for i, v in enumerate(expr.args):
  172. ol += (v[0].diff(t) * (v[1] | v[2]))
  173. ol += (v[0] * (time_derivative(v[1], frame) | v[2]))
  174. ol += (v[0] * (v[1] | time_derivative(v[2], frame)))
  175. return time_derivative(ol, frame, order - 1)
  176. else:
  177. return diff(express(expr, frame, variables=True), t, order)
  178. def outer(vec1, vec2):
  179. """Outer product convenience wrapper for Vector.outer():\n"""
  180. if not isinstance(vec1, Vector):
  181. raise TypeError('Outer product is between two Vectors')
  182. return vec1 | vec2
  183. outer.__doc__ += Vector.outer.__doc__ # type: ignore
  184. def kinematic_equations(speeds, coords, rot_type, rot_order=''):
  185. """Gives equations relating the qdot's to u's for a rotation type.
  186. Supply rotation type and order as in orient. Speeds are assumed to be
  187. body-fixed; if we are defining the orientation of B in A using by rot_type,
  188. the angular velocity of B in A is assumed to be in the form: speed[0]*B.x +
  189. speed[1]*B.y + speed[2]*B.z
  190. Parameters
  191. ==========
  192. speeds : list of length 3
  193. The body fixed angular velocity measure numbers.
  194. coords : list of length 3 or 4
  195. The coordinates used to define the orientation of the two frames.
  196. rot_type : str
  197. The type of rotation used to create the equations. Body, Space, or
  198. Quaternion only
  199. rot_order : str or int
  200. If applicable, the order of a series of rotations.
  201. Examples
  202. ========
  203. >>> from sympy.physics.vector import dynamicsymbols
  204. >>> from sympy.physics.vector import kinematic_equations, vprint
  205. >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3')
  206. >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3')
  207. >>> vprint(kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313'),
  208. ... order=None)
  209. [-(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']
  210. """
  211. # Code below is checking and sanitizing input
  212. approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131',
  213. '212', '232', '313', '323', '1', '2', '3', '')
  214. # make sure XYZ => 123 and rot_type is in lower case
  215. rot_order = translate(str(rot_order), 'XYZxyz', '123123')
  216. rot_type = rot_type.lower()
  217. if not isinstance(speeds, (list, tuple)):
  218. raise TypeError('Need to supply speeds in a list')
  219. if len(speeds) != 3:
  220. raise TypeError('Need to supply 3 body-fixed speeds')
  221. if not isinstance(coords, (list, tuple)):
  222. raise TypeError('Need to supply coordinates in a list')
  223. if rot_type in ['body', 'space']:
  224. if rot_order not in approved_orders:
  225. raise ValueError('Not an acceptable rotation order')
  226. if len(coords) != 3:
  227. raise ValueError('Need 3 coordinates for body or space')
  228. # Actual hard-coded kinematic differential equations
  229. w1, w2, w3 = speeds
  230. if w1 == w2 == w3 == 0:
  231. return [S.Zero]*3
  232. q1, q2, q3 = coords
  233. q1d, q2d, q3d = [diff(i, dynamicsymbols._t) for i in coords]
  234. s1, s2, s3 = [sin(q1), sin(q2), sin(q3)]
  235. c1, c2, c3 = [cos(q1), cos(q2), cos(q3)]
  236. if rot_type == 'body':
  237. if rot_order == '123':
  238. return [q1d - (w1 * c3 - w2 * s3) / c2, q2d - w1 * s3 - w2 *
  239. c3, q3d - (-w1 * c3 + w2 * s3) * s2 / c2 - w3]
  240. if rot_order == '231':
  241. return [q1d - (w2 * c3 - w3 * s3) / c2, q2d - w2 * s3 - w3 *
  242. c3, q3d - w1 - (- w2 * c3 + w3 * s3) * s2 / c2]
  243. if rot_order == '312':
  244. return [q1d - (-w1 * s3 + w3 * c3) / c2, q2d - w1 * c3 - w3 *
  245. s3, q3d - (w1 * s3 - w3 * c3) * s2 / c2 - w2]
  246. if rot_order == '132':
  247. return [q1d - (w1 * c3 + w3 * s3) / c2, q2d + w1 * s3 - w3 *
  248. c3, q3d - (w1 * c3 + w3 * s3) * s2 / c2 - w2]
  249. if rot_order == '213':
  250. return [q1d - (w1 * s3 + w2 * c3) / c2, q2d - w1 * c3 + w2 *
  251. s3, q3d - (w1 * s3 + w2 * c3) * s2 / c2 - w3]
  252. if rot_order == '321':
  253. return [q1d - (w2 * s3 + w3 * c3) / c2, q2d - w2 * c3 + w3 *
  254. s3, q3d - w1 - (w2 * s3 + w3 * c3) * s2 / c2]
  255. if rot_order == '121':
  256. return [q1d - (w2 * s3 + w3 * c3) / s2, q2d - w2 * c3 + w3 *
  257. s3, q3d - w1 + (w2 * s3 + w3 * c3) * c2 / s2]
  258. if rot_order == '131':
  259. return [q1d - (-w2 * c3 + w3 * s3) / s2, q2d - w2 * s3 - w3 *
  260. c3, q3d - w1 - (w2 * c3 - w3 * s3) * c2 / s2]
  261. if rot_order == '212':
  262. return [q1d - (w1 * s3 - w3 * c3) / s2, q2d - w1 * c3 - w3 *
  263. s3, q3d - (-w1 * s3 + w3 * c3) * c2 / s2 - w2]
  264. if rot_order == '232':
  265. return [q1d - (w1 * c3 + w3 * s3) / s2, q2d + w1 * s3 - w3 *
  266. c3, q3d + (w1 * c3 + w3 * s3) * c2 / s2 - w2]
  267. if rot_order == '313':
  268. return [q1d - (w1 * s3 + w2 * c3) / s2, q2d - w1 * c3 + w2 *
  269. s3, q3d + (w1 * s3 + w2 * c3) * c2 / s2 - w3]
  270. if rot_order == '323':
  271. return [q1d - (-w1 * c3 + w2 * s3) / s2, q2d - w1 * s3 - w2 *
  272. c3, q3d - (w1 * c3 - w2 * s3) * c2 / s2 - w3]
  273. if rot_type == 'space':
  274. if rot_order == '123':
  275. return [q1d - w1 - (w2 * s1 + w3 * c1) * s2 / c2, q2d - w2 *
  276. c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / c2]
  277. if rot_order == '231':
  278. return [q1d - (w1 * c1 + w3 * s1) * s2 / c2 - w2, q2d + w1 *
  279. s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / c2]
  280. if rot_order == '312':
  281. return [q1d - (w1 * s1 + w2 * c1) * s2 / c2 - w3, q2d - w1 *
  282. c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / c2]
  283. if rot_order == '132':
  284. return [q1d - w1 - (-w2 * c1 + w3 * s1) * s2 / c2, q2d - w2 *
  285. s1 - w3 * c1, q3d - (w2 * c1 - w3 * s1) / c2]
  286. if rot_order == '213':
  287. return [q1d - (w1 * s1 - w3 * c1) * s2 / c2 - w2, q2d - w1 *
  288. c1 - w3 * s1, q3d - (-w1 * s1 + w3 * c1) / c2]
  289. if rot_order == '321':
  290. return [q1d - (-w1 * c1 + w2 * s1) * s2 / c2 - w3, q2d - w1 *
  291. s1 - w2 * c1, q3d - (w1 * c1 - w2 * s1) / c2]
  292. if rot_order == '121':
  293. return [q1d - w1 + (w2 * s1 + w3 * c1) * c2 / s2, q2d - w2 *
  294. c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / s2]
  295. if rot_order == '131':
  296. return [q1d - w1 - (w2 * c1 - w3 * s1) * c2 / s2, q2d - w2 *
  297. s1 - w3 * c1, q3d - (-w2 * c1 + w3 * s1) / s2]
  298. if rot_order == '212':
  299. return [q1d - (-w1 * s1 + w3 * c1) * c2 / s2 - w2, q2d - w1 *
  300. c1 - w3 * s1, q3d - (w1 * s1 - w3 * c1) / s2]
  301. if rot_order == '232':
  302. return [q1d + (w1 * c1 + w3 * s1) * c2 / s2 - w2, q2d + w1 *
  303. s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / s2]
  304. if rot_order == '313':
  305. return [q1d + (w1 * s1 + w2 * c1) * c2 / s2 - w3, q2d - w1 *
  306. c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / s2]
  307. if rot_order == '323':
  308. return [q1d - (w1 * c1 - w2 * s1) * c2 / s2 - w3, q2d - w1 *
  309. s1 - w2 * c1, q3d - (-w1 * c1 + w2 * s1) / s2]
  310. elif rot_type == 'quaternion':
  311. if rot_order != '':
  312. raise ValueError('Cannot have rotation order for quaternion')
  313. if len(coords) != 4:
  314. raise ValueError('Need 4 coordinates for quaternion')
  315. # Actual hard-coded kinematic differential equations
  316. e0, e1, e2, e3 = coords
  317. w = Matrix(speeds + [0])
  318. E = Matrix([[e0, -e3, e2, e1],
  319. [e3, e0, -e1, e2],
  320. [-e2, e1, e0, e3],
  321. [-e1, -e2, -e3, e0]])
  322. edots = Matrix([diff(i, dynamicsymbols._t) for i in [e1, e2, e3, e0]])
  323. return list(edots.T - 0.5 * w.T * E.T)
  324. else:
  325. raise ValueError('Not an approved rotation type for this function')
  326. def get_motion_params(frame, **kwargs):
  327. """
  328. Returns the three motion parameters - (acceleration, velocity, and
  329. position) as vectorial functions of time in the given frame.
  330. If a higher order differential function is provided, the lower order
  331. functions are used as boundary conditions. For example, given the
  332. acceleration, the velocity and position parameters are taken as
  333. boundary conditions.
  334. The values of time at which the boundary conditions are specified
  335. are taken from timevalue1(for position boundary condition) and
  336. timevalue2(for velocity boundary condition).
  337. If any of the boundary conditions are not provided, they are taken
  338. to be zero by default (zero vectors, in case of vectorial inputs). If
  339. the boundary conditions are also functions of time, they are converted
  340. to constants by substituting the time values in the dynamicsymbols._t
  341. time Symbol.
  342. This function can also be used for calculating rotational motion
  343. parameters. Have a look at the Parameters and Examples for more clarity.
  344. Parameters
  345. ==========
  346. frame : ReferenceFrame
  347. The frame to express the motion parameters in
  348. acceleration : Vector
  349. Acceleration of the object/frame as a function of time
  350. velocity : Vector
  351. Velocity as function of time or as boundary condition
  352. of velocity at time = timevalue1
  353. position : Vector
  354. Velocity as function of time or as boundary condition
  355. of velocity at time = timevalue1
  356. timevalue1 : sympyfiable
  357. Value of time for position boundary condition
  358. timevalue2 : sympyfiable
  359. Value of time for velocity boundary condition
  360. Examples
  361. ========
  362. >>> from sympy.physics.vector import ReferenceFrame, get_motion_params, dynamicsymbols
  363. >>> from sympy.physics.vector import init_vprinting
  364. >>> init_vprinting(pretty_print=False)
  365. >>> from sympy import symbols
  366. >>> R = ReferenceFrame('R')
  367. >>> v1, v2, v3 = dynamicsymbols('v1 v2 v3')
  368. >>> v = v1*R.x + v2*R.y + v3*R.z
  369. >>> get_motion_params(R, position = v)
  370. (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)
  371. >>> a, b, c = symbols('a b c')
  372. >>> v = a*R.x + b*R.y + c*R.z
  373. >>> get_motion_params(R, velocity = v)
  374. (0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z)
  375. >>> parameters = get_motion_params(R, acceleration = v)
  376. >>> parameters[1]
  377. a*t*R.x + b*t*R.y + c*t*R.z
  378. >>> parameters[2]
  379. a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z
  380. """
  381. def _process_vector_differential(vectdiff, condition, variable, ordinate,
  382. frame):
  383. """
  384. Helper function for get_motion methods. Finds derivative of vectdiff
  385. wrt variable, and its integral using the specified boundary condition
  386. at value of variable = ordinate.
  387. Returns a tuple of - (derivative, function and integral) wrt vectdiff
  388. """
  389. # Make sure boundary condition is independent of 'variable'
  390. if condition != 0:
  391. condition = express(condition, frame, variables=True)
  392. # Special case of vectdiff == 0
  393. if vectdiff == Vector(0):
  394. return (0, 0, condition)
  395. # Express vectdiff completely in condition's frame to give vectdiff1
  396. vectdiff1 = express(vectdiff, frame)
  397. # Find derivative of vectdiff
  398. vectdiff2 = time_derivative(vectdiff, frame)
  399. # Integrate and use boundary condition
  400. vectdiff0 = Vector(0)
  401. lims = (variable, ordinate, variable)
  402. for dim in frame:
  403. function1 = vectdiff1.dot(dim)
  404. abscissa = dim.dot(condition).subs({variable: ordinate})
  405. # Indefinite integral of 'function1' wrt 'variable', using
  406. # the given initial condition (ordinate, abscissa).
  407. vectdiff0 += (integrate(function1, lims) + abscissa) * dim
  408. # Return tuple
  409. return (vectdiff2, vectdiff, vectdiff0)
  410. _check_frame(frame)
  411. # Decide mode of operation based on user's input
  412. if 'acceleration' in kwargs:
  413. mode = 2
  414. elif 'velocity' in kwargs:
  415. mode = 1
  416. else:
  417. mode = 0
  418. # All the possible parameters in kwargs
  419. # Not all are required for every case
  420. # If not specified, set to default values(may or may not be used in
  421. # calculations)
  422. conditions = ['acceleration', 'velocity', 'position',
  423. 'timevalue', 'timevalue1', 'timevalue2']
  424. for i, x in enumerate(conditions):
  425. if x not in kwargs:
  426. if i < 3:
  427. kwargs[x] = Vector(0)
  428. else:
  429. kwargs[x] = S.Zero
  430. elif i < 3:
  431. _check_vector(kwargs[x])
  432. else:
  433. kwargs[x] = sympify(kwargs[x])
  434. if mode == 2:
  435. vel = _process_vector_differential(kwargs['acceleration'],
  436. kwargs['velocity'],
  437. dynamicsymbols._t,
  438. kwargs['timevalue2'], frame)[2]
  439. pos = _process_vector_differential(vel, kwargs['position'],
  440. dynamicsymbols._t,
  441. kwargs['timevalue1'], frame)[2]
  442. return (kwargs['acceleration'], vel, pos)
  443. elif mode == 1:
  444. return _process_vector_differential(kwargs['velocity'],
  445. kwargs['position'],
  446. dynamicsymbols._t,
  447. kwargs['timevalue1'], frame)
  448. else:
  449. vel = time_derivative(kwargs['position'], frame)
  450. acc = time_derivative(vel, frame)
  451. return (acc, vel, kwargs['position'])
  452. def partial_velocity(vel_vecs, gen_speeds, frame):
  453. """Returns a list of partial velocities with respect to the provided
  454. generalized speeds in the given reference frame for each of the supplied
  455. velocity vectors.
  456. The output is a list of lists. The outer list has a number of elements
  457. equal to the number of supplied velocity vectors. The inner lists are, for
  458. each velocity vector, the partial derivatives of that velocity vector with
  459. respect to the generalized speeds supplied.
  460. Parameters
  461. ==========
  462. vel_vecs : iterable
  463. An iterable of velocity vectors (angular or linear).
  464. gen_speeds : iterable
  465. An iterable of generalized speeds.
  466. frame : ReferenceFrame
  467. The reference frame that the partial derivatives are going to be taken
  468. in.
  469. Examples
  470. ========
  471. >>> from sympy.physics.vector import Point, ReferenceFrame
  472. >>> from sympy.physics.vector import dynamicsymbols
  473. >>> from sympy.physics.vector import partial_velocity
  474. >>> u = dynamicsymbols('u')
  475. >>> N = ReferenceFrame('N')
  476. >>> P = Point('P')
  477. >>> P.set_vel(N, u * N.x)
  478. >>> vel_vecs = [P.vel(N)]
  479. >>> gen_speeds = [u]
  480. >>> partial_velocity(vel_vecs, gen_speeds, N)
  481. [[N.x]]
  482. """
  483. if not iterable(vel_vecs):
  484. raise TypeError('Velocity vectors must be contained in an iterable.')
  485. if not iterable(gen_speeds):
  486. raise TypeError('Generalized speeds must be contained in an iterable')
  487. vec_partials = []
  488. for vec in vel_vecs:
  489. partials = []
  490. for speed in gen_speeds:
  491. partials.append(vec.diff(speed, frame, var_in_dcm=False))
  492. vec_partials.append(partials)
  493. return vec_partials
  494. def dynamicsymbols(names, level=0, **assumptions):
  495. """Uses symbols and Function for functions of time.
  496. Creates a SymPy UndefinedFunction, which is then initialized as a function
  497. of a variable, the default being Symbol('t').
  498. Parameters
  499. ==========
  500. names : str
  501. Names of the dynamic symbols you want to create; works the same way as
  502. inputs to symbols
  503. level : int
  504. Level of differentiation of the returned function; d/dt once of t,
  505. twice of t, etc.
  506. assumptions :
  507. - real(bool) : This is used to set the dynamicsymbol as real,
  508. by default is False.
  509. - positive(bool) : This is used to set the dynamicsymbol as positive,
  510. by default is False.
  511. - commutative(bool) : This is used to set the commutative property of
  512. a dynamicsymbol, by default is True.
  513. - integer(bool) : This is used to set the dynamicsymbol as integer,
  514. by default is False.
  515. Examples
  516. ========
  517. >>> from sympy.physics.vector import dynamicsymbols
  518. >>> from sympy import diff, Symbol
  519. >>> q1 = dynamicsymbols('q1')
  520. >>> q1
  521. q1(t)
  522. >>> q2 = dynamicsymbols('q2', real=True)
  523. >>> q2.is_real
  524. True
  525. >>> q3 = dynamicsymbols('q3', positive=True)
  526. >>> q3.is_positive
  527. True
  528. >>> q4, q5 = dynamicsymbols('q4,q5', commutative=False)
  529. >>> bool(q4*q5 != q5*q4)
  530. True
  531. >>> q6 = dynamicsymbols('q6', integer=True)
  532. >>> q6.is_integer
  533. True
  534. >>> diff(q1, Symbol('t'))
  535. Derivative(q1(t), t)
  536. """
  537. esses = symbols(names, cls=Function, **assumptions)
  538. t = dynamicsymbols._t
  539. if iterable(esses):
  540. esses = [reduce(diff, [t] * level, e(t)) for e in esses]
  541. return esses
  542. else:
  543. return reduce(diff, [t] * level, esses(t))
  544. dynamicsymbols._t = Symbol('t') # type: ignore
  545. dynamicsymbols._str = '\'' # type: ignore