m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

621 lines
20 KiB

7 months ago
  1. from .vector import Vector, _check_vector
  2. from .frame import _check_frame
  3. from warnings import warn
  4. __all__ = ['Point']
  5. class Point:
  6. """This object represents a point in a dynamic system.
  7. It stores the: position, velocity, and acceleration of a point.
  8. The position is a vector defined as the vector distance from a parent
  9. point to this point.
  10. Parameters
  11. ==========
  12. name : string
  13. The display name of the Point
  14. Examples
  15. ========
  16. >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
  17. >>> from sympy.physics.vector import init_vprinting
  18. >>> init_vprinting(pretty_print=False)
  19. >>> N = ReferenceFrame('N')
  20. >>> O = Point('O')
  21. >>> P = Point('P')
  22. >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3')
  23. >>> O.set_vel(N, u1 * N.x + u2 * N.y + u3 * N.z)
  24. >>> O.acc(N)
  25. u1'*N.x + u2'*N.y + u3'*N.z
  26. symbols() can be used to create multiple Points in a single step, for example:
  27. >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
  28. >>> from sympy.physics.vector import init_vprinting
  29. >>> init_vprinting(pretty_print=False)
  30. >>> from sympy import symbols
  31. >>> N = ReferenceFrame('N')
  32. >>> u1, u2 = dynamicsymbols('u1 u2')
  33. >>> A, B = symbols('A B', cls=Point)
  34. >>> type(A)
  35. <class 'sympy.physics.vector.point.Point'>
  36. >>> A.set_vel(N, u1 * N.x + u2 * N.y)
  37. >>> B.set_vel(N, u2 * N.x + u1 * N.y)
  38. >>> A.acc(N) - B.acc(N)
  39. (u1' - u2')*N.x + (-u1' + u2')*N.y
  40. """
  41. def __init__(self, name):
  42. """Initialization of a Point object. """
  43. self.name = name
  44. self._pos_dict = {}
  45. self._vel_dict = {}
  46. self._acc_dict = {}
  47. self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict]
  48. def __str__(self):
  49. return self.name
  50. __repr__ = __str__
  51. def _check_point(self, other):
  52. if not isinstance(other, Point):
  53. raise TypeError('A Point must be supplied')
  54. def _pdict_list(self, other, num):
  55. """Returns a list of points that gives the shortest path with respect
  56. to position, velocity, or acceleration from this point to the provided
  57. point.
  58. Parameters
  59. ==========
  60. other : Point
  61. A point that may be related to this point by position, velocity, or
  62. acceleration.
  63. num : integer
  64. 0 for searching the position tree, 1 for searching the velocity
  65. tree, and 2 for searching the acceleration tree.
  66. Returns
  67. =======
  68. list of Points
  69. A sequence of points from self to other.
  70. Notes
  71. =====
  72. It isn't clear if num = 1 or num = 2 actually works because the keys to
  73. ``_vel_dict`` and ``_acc_dict`` are :class:`ReferenceFrame` objects which
  74. do not have the ``_pdlist`` attribute.
  75. """
  76. outlist = [[self]]
  77. oldlist = [[]]
  78. while outlist != oldlist:
  79. oldlist = outlist[:]
  80. for i, v in enumerate(outlist):
  81. templist = v[-1]._pdlist[num].keys()
  82. for i2, v2 in enumerate(templist):
  83. if not v.__contains__(v2):
  84. littletemplist = v + [v2]
  85. if not outlist.__contains__(littletemplist):
  86. outlist.append(littletemplist)
  87. for i, v in enumerate(oldlist):
  88. if v[-1] != other:
  89. outlist.remove(v)
  90. outlist.sort(key=len)
  91. if len(outlist) != 0:
  92. return outlist[0]
  93. raise ValueError('No Connecting Path found between ' + other.name +
  94. ' and ' + self.name)
  95. def a1pt_theory(self, otherpoint, outframe, interframe):
  96. """Sets the acceleration of this point with the 1-point theory.
  97. The 1-point theory for point acceleration looks like this:
  98. ^N a^P = ^B a^P + ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B
  99. x r^OP) + 2 ^N omega^B x ^B v^P
  100. where O is a point fixed in B, P is a point moving in B, and B is
  101. rotating in frame N.
  102. Parameters
  103. ==========
  104. otherpoint : Point
  105. The first point of the 1-point theory (O)
  106. outframe : ReferenceFrame
  107. The frame we want this point's acceleration defined in (N)
  108. fixedframe : ReferenceFrame
  109. The intermediate frame in this calculation (B)
  110. Examples
  111. ========
  112. >>> from sympy.physics.vector import Point, ReferenceFrame
  113. >>> from sympy.physics.vector import dynamicsymbols
  114. >>> from sympy.physics.vector import init_vprinting
  115. >>> init_vprinting(pretty_print=False)
  116. >>> q = dynamicsymbols('q')
  117. >>> q2 = dynamicsymbols('q2')
  118. >>> qd = dynamicsymbols('q', 1)
  119. >>> q2d = dynamicsymbols('q2', 1)
  120. >>> N = ReferenceFrame('N')
  121. >>> B = ReferenceFrame('B')
  122. >>> B.set_ang_vel(N, 5 * B.y)
  123. >>> O = Point('O')
  124. >>> P = O.locatenew('P', q * B.x)
  125. >>> P.set_vel(B, qd * B.x + q2d * B.y)
  126. >>> O.set_vel(N, 0)
  127. >>> P.a1pt_theory(O, N, B)
  128. (-25*q + q'')*B.x + q2''*B.y - 10*q'*B.z
  129. """
  130. _check_frame(outframe)
  131. _check_frame(interframe)
  132. self._check_point(otherpoint)
  133. dist = self.pos_from(otherpoint)
  134. v = self.vel(interframe)
  135. a1 = otherpoint.acc(outframe)
  136. a2 = self.acc(interframe)
  137. omega = interframe.ang_vel_in(outframe)
  138. alpha = interframe.ang_acc_in(outframe)
  139. self.set_acc(outframe, a2 + 2 * (omega ^ v) + a1 + (alpha ^ dist) +
  140. (omega ^ (omega ^ dist)))
  141. return self.acc(outframe)
  142. def a2pt_theory(self, otherpoint, outframe, fixedframe):
  143. """Sets the acceleration of this point with the 2-point theory.
  144. The 2-point theory for point acceleration looks like this:
  145. ^N a^P = ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP)
  146. where O and P are both points fixed in frame B, which is rotating in
  147. frame N.
  148. Parameters
  149. ==========
  150. otherpoint : Point
  151. The first point of the 2-point theory (O)
  152. outframe : ReferenceFrame
  153. The frame we want this point's acceleration defined in (N)
  154. fixedframe : ReferenceFrame
  155. The frame in which both points are fixed (B)
  156. Examples
  157. ========
  158. >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
  159. >>> from sympy.physics.vector import init_vprinting
  160. >>> init_vprinting(pretty_print=False)
  161. >>> q = dynamicsymbols('q')
  162. >>> qd = dynamicsymbols('q', 1)
  163. >>> N = ReferenceFrame('N')
  164. >>> B = N.orientnew('B', 'Axis', [q, N.z])
  165. >>> O = Point('O')
  166. >>> P = O.locatenew('P', 10 * B.x)
  167. >>> O.set_vel(N, 5 * N.x)
  168. >>> P.a2pt_theory(O, N, B)
  169. - 10*q'**2*B.x + 10*q''*B.y
  170. """
  171. _check_frame(outframe)
  172. _check_frame(fixedframe)
  173. self._check_point(otherpoint)
  174. dist = self.pos_from(otherpoint)
  175. a = otherpoint.acc(outframe)
  176. omega = fixedframe.ang_vel_in(outframe)
  177. alpha = fixedframe.ang_acc_in(outframe)
  178. self.set_acc(outframe, a + (alpha ^ dist) + (omega ^ (omega ^ dist)))
  179. return self.acc(outframe)
  180. def acc(self, frame):
  181. """The acceleration Vector of this Point in a ReferenceFrame.
  182. Parameters
  183. ==========
  184. frame : ReferenceFrame
  185. The frame in which the returned acceleration vector will be defined in
  186. Examples
  187. ========
  188. >>> from sympy.physics.vector import Point, ReferenceFrame
  189. >>> N = ReferenceFrame('N')
  190. >>> p1 = Point('p1')
  191. >>> p1.set_acc(N, 10 * N.x)
  192. >>> p1.acc(N)
  193. 10*N.x
  194. """
  195. _check_frame(frame)
  196. if not (frame in self._acc_dict):
  197. if self._vel_dict[frame] != 0:
  198. return (self._vel_dict[frame]).dt(frame)
  199. else:
  200. return Vector(0)
  201. return self._acc_dict[frame]
  202. def locatenew(self, name, value):
  203. """Creates a new point with a position defined from this point.
  204. Parameters
  205. ==========
  206. name : str
  207. The name for the new point
  208. value : Vector
  209. The position of the new point relative to this point
  210. Examples
  211. ========
  212. >>> from sympy.physics.vector import ReferenceFrame, Point
  213. >>> N = ReferenceFrame('N')
  214. >>> P1 = Point('P1')
  215. >>> P2 = P1.locatenew('P2', 10 * N.x)
  216. """
  217. if not isinstance(name, str):
  218. raise TypeError('Must supply a valid name')
  219. if value == 0:
  220. value = Vector(0)
  221. value = _check_vector(value)
  222. p = Point(name)
  223. p.set_pos(self, value)
  224. self.set_pos(p, -value)
  225. return p
  226. def pos_from(self, otherpoint):
  227. """Returns a Vector distance between this Point and the other Point.
  228. Parameters
  229. ==========
  230. otherpoint : Point
  231. The otherpoint we are locating this one relative to
  232. Examples
  233. ========
  234. >>> from sympy.physics.vector import Point, ReferenceFrame
  235. >>> N = ReferenceFrame('N')
  236. >>> p1 = Point('p1')
  237. >>> p2 = Point('p2')
  238. >>> p1.set_pos(p2, 10 * N.x)
  239. >>> p1.pos_from(p2)
  240. 10*N.x
  241. """
  242. outvec = Vector(0)
  243. plist = self._pdict_list(otherpoint, 0)
  244. for i in range(len(plist) - 1):
  245. outvec += plist[i]._pos_dict[plist[i + 1]]
  246. return outvec
  247. def set_acc(self, frame, value):
  248. """Used to set the acceleration of this Point in a ReferenceFrame.
  249. Parameters
  250. ==========
  251. frame : ReferenceFrame
  252. The frame in which this point's acceleration is defined
  253. value : Vector
  254. The vector value of this point's acceleration in the frame
  255. Examples
  256. ========
  257. >>> from sympy.physics.vector import Point, ReferenceFrame
  258. >>> N = ReferenceFrame('N')
  259. >>> p1 = Point('p1')
  260. >>> p1.set_acc(N, 10 * N.x)
  261. >>> p1.acc(N)
  262. 10*N.x
  263. """
  264. if value == 0:
  265. value = Vector(0)
  266. value = _check_vector(value)
  267. _check_frame(frame)
  268. self._acc_dict.update({frame: value})
  269. def set_pos(self, otherpoint, value):
  270. """Used to set the position of this point w.r.t. another point.
  271. Parameters
  272. ==========
  273. otherpoint : Point
  274. The other point which this point's location is defined relative to
  275. value : Vector
  276. The vector which defines the location of this point
  277. Examples
  278. ========
  279. >>> from sympy.physics.vector import Point, ReferenceFrame
  280. >>> N = ReferenceFrame('N')
  281. >>> p1 = Point('p1')
  282. >>> p2 = Point('p2')
  283. >>> p1.set_pos(p2, 10 * N.x)
  284. >>> p1.pos_from(p2)
  285. 10*N.x
  286. """
  287. if value == 0:
  288. value = Vector(0)
  289. value = _check_vector(value)
  290. self._check_point(otherpoint)
  291. self._pos_dict.update({otherpoint: value})
  292. otherpoint._pos_dict.update({self: -value})
  293. def set_vel(self, frame, value):
  294. """Sets the velocity Vector of this Point in a ReferenceFrame.
  295. Parameters
  296. ==========
  297. frame : ReferenceFrame
  298. The frame in which this point's velocity is defined
  299. value : Vector
  300. The vector value of this point's velocity in the frame
  301. Examples
  302. ========
  303. >>> from sympy.physics.vector import Point, ReferenceFrame
  304. >>> N = ReferenceFrame('N')
  305. >>> p1 = Point('p1')
  306. >>> p1.set_vel(N, 10 * N.x)
  307. >>> p1.vel(N)
  308. 10*N.x
  309. """
  310. if value == 0:
  311. value = Vector(0)
  312. value = _check_vector(value)
  313. _check_frame(frame)
  314. self._vel_dict.update({frame: value})
  315. def v1pt_theory(self, otherpoint, outframe, interframe):
  316. """Sets the velocity of this point with the 1-point theory.
  317. The 1-point theory for point velocity looks like this:
  318. ^N v^P = ^B v^P + ^N v^O + ^N omega^B x r^OP
  319. where O is a point fixed in B, P is a point moving in B, and B is
  320. rotating in frame N.
  321. Parameters
  322. ==========
  323. otherpoint : Point
  324. The first point of the 1-point theory (O)
  325. outframe : ReferenceFrame
  326. The frame we want this point's velocity defined in (N)
  327. interframe : ReferenceFrame
  328. The intermediate frame in this calculation (B)
  329. Examples
  330. ========
  331. >>> from sympy.physics.vector import Point, ReferenceFrame
  332. >>> from sympy.physics.vector import dynamicsymbols
  333. >>> from sympy.physics.vector import init_vprinting
  334. >>> init_vprinting(pretty_print=False)
  335. >>> q = dynamicsymbols('q')
  336. >>> q2 = dynamicsymbols('q2')
  337. >>> qd = dynamicsymbols('q', 1)
  338. >>> q2d = dynamicsymbols('q2', 1)
  339. >>> N = ReferenceFrame('N')
  340. >>> B = ReferenceFrame('B')
  341. >>> B.set_ang_vel(N, 5 * B.y)
  342. >>> O = Point('O')
  343. >>> P = O.locatenew('P', q * B.x)
  344. >>> P.set_vel(B, qd * B.x + q2d * B.y)
  345. >>> O.set_vel(N, 0)
  346. >>> P.v1pt_theory(O, N, B)
  347. q'*B.x + q2'*B.y - 5*q*B.z
  348. """
  349. _check_frame(outframe)
  350. _check_frame(interframe)
  351. self._check_point(otherpoint)
  352. dist = self.pos_from(otherpoint)
  353. v1 = self.vel(interframe)
  354. v2 = otherpoint.vel(outframe)
  355. omega = interframe.ang_vel_in(outframe)
  356. self.set_vel(outframe, v1 + v2 + (omega ^ dist))
  357. return self.vel(outframe)
  358. def v2pt_theory(self, otherpoint, outframe, fixedframe):
  359. """Sets the velocity of this point with the 2-point theory.
  360. The 2-point theory for point velocity looks like this:
  361. ^N v^P = ^N v^O + ^N omega^B x r^OP
  362. where O and P are both points fixed in frame B, which is rotating in
  363. frame N.
  364. Parameters
  365. ==========
  366. otherpoint : Point
  367. The first point of the 2-point theory (O)
  368. outframe : ReferenceFrame
  369. The frame we want this point's velocity defined in (N)
  370. fixedframe : ReferenceFrame
  371. The frame in which both points are fixed (B)
  372. Examples
  373. ========
  374. >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
  375. >>> from sympy.physics.vector import init_vprinting
  376. >>> init_vprinting(pretty_print=False)
  377. >>> q = dynamicsymbols('q')
  378. >>> qd = dynamicsymbols('q', 1)
  379. >>> N = ReferenceFrame('N')
  380. >>> B = N.orientnew('B', 'Axis', [q, N.z])
  381. >>> O = Point('O')
  382. >>> P = O.locatenew('P', 10 * B.x)
  383. >>> O.set_vel(N, 5 * N.x)
  384. >>> P.v2pt_theory(O, N, B)
  385. 5*N.x + 10*q'*B.y
  386. """
  387. _check_frame(outframe)
  388. _check_frame(fixedframe)
  389. self._check_point(otherpoint)
  390. dist = self.pos_from(otherpoint)
  391. v = otherpoint.vel(outframe)
  392. omega = fixedframe.ang_vel_in(outframe)
  393. self.set_vel(outframe, v + (omega ^ dist))
  394. return self.vel(outframe)
  395. def vel(self, frame):
  396. """The velocity Vector of this Point in the ReferenceFrame.
  397. Parameters
  398. ==========
  399. frame : ReferenceFrame
  400. The frame in which the returned velocity vector will be defined in
  401. Examples
  402. ========
  403. >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
  404. >>> N = ReferenceFrame('N')
  405. >>> p1 = Point('p1')
  406. >>> p1.set_vel(N, 10 * N.x)
  407. >>> p1.vel(N)
  408. 10*N.x
  409. Velocities will be automatically calculated if possible, otherwise a ``ValueError`` will be returned. If it is possible to calculate multiple different velocities from the relative points, the points defined most directly relative to this point will be used. In the case of inconsistent relative positions of points, incorrect velocities may be returned. It is up to the user to define prior relative positions and velocities of points in a self-consistent way.
  410. >>> p = Point('p')
  411. >>> q = dynamicsymbols('q')
  412. >>> p.set_vel(N, 10 * N.x)
  413. >>> p2 = Point('p2')
  414. >>> p2.set_pos(p, q*N.x)
  415. >>> p2.vel(N)
  416. (Derivative(q(t), t) + 10)*N.x
  417. """
  418. _check_frame(frame)
  419. if not (frame in self._vel_dict):
  420. valid_neighbor_found = False
  421. is_cyclic = False
  422. visited = []
  423. queue = [self]
  424. candidate_neighbor = []
  425. while queue: #BFS to find nearest point
  426. node = queue.pop(0)
  427. if node not in visited:
  428. visited.append(node)
  429. for neighbor, neighbor_pos in node._pos_dict.items():
  430. if neighbor in visited:
  431. continue
  432. try:
  433. neighbor_pos.express(frame) #Checks if pos vector is valid
  434. except ValueError:
  435. continue
  436. if neighbor in queue:
  437. is_cyclic = True
  438. try :
  439. neighbor_velocity = neighbor._vel_dict[frame] #Checks if point has its vel defined in req frame
  440. except KeyError:
  441. queue.append(neighbor)
  442. continue
  443. candidate_neighbor.append(neighbor)
  444. if not valid_neighbor_found:
  445. vel = None
  446. for f in self.pos_from(neighbor).args:
  447. if f[1] in self._vel_dict.keys():
  448. if self._vel_dict[f[1]] != 0:
  449. vel = self._vel_dict[f[1]]
  450. break
  451. if vel is None:
  452. vel = self.pos_from(neighbor).dt(frame)
  453. self.set_vel(frame, vel + neighbor_velocity)
  454. valid_neighbor_found = True
  455. if is_cyclic:
  456. warn('Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.')
  457. if len(candidate_neighbor) > 1:
  458. warn('Velocity automatically calculated based on point ' +
  459. candidate_neighbor[0].name + ' but it is also possible from points(s):' +
  460. str(candidate_neighbor[1:]) + '. Velocities from these points are not necessarily the same. This may cause errors in your calculations.')
  461. if valid_neighbor_found:
  462. return self._vel_dict[frame]
  463. else:
  464. raise ValueError('Velocity of point ' + self.name + ' has not been'
  465. ' defined in ReferenceFrame ' + frame.name)
  466. return self._vel_dict[frame]
  467. def partial_velocity(self, frame, *gen_speeds):
  468. """Returns the partial velocities of the linear velocity vector of this
  469. point in the given frame with respect to one or more provided
  470. generalized speeds.
  471. Parameters
  472. ==========
  473. frame : ReferenceFrame
  474. The frame with which the velocity is defined in.
  475. gen_speeds : functions of time
  476. The generalized speeds.
  477. Returns
  478. =======
  479. partial_velocities : tuple of Vector
  480. The partial velocity vectors corresponding to the provided
  481. generalized speeds.
  482. Examples
  483. ========
  484. >>> from sympy.physics.vector import ReferenceFrame, Point
  485. >>> from sympy.physics.vector import dynamicsymbols
  486. >>> N = ReferenceFrame('N')
  487. >>> A = ReferenceFrame('A')
  488. >>> p = Point('p')
  489. >>> u1, u2 = dynamicsymbols('u1, u2')
  490. >>> p.set_vel(N, u1 * N.x + u2 * A.y)
  491. >>> p.partial_velocity(N, u1)
  492. N.x
  493. >>> p.partial_velocity(N, u1, u2)
  494. (N.x, A.y)
  495. """
  496. partials = [self.vel(frame).diff(speed, frame, var_in_dcm=False) for
  497. speed in gen_speeds]
  498. if len(partials) == 1:
  499. return partials[0]
  500. else:
  501. return tuple(partials)