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.

233 lines
9.4 KiB

7 months ago
  1. from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point,
  2. RigidBody, LagrangesMethod, Particle,
  3. inertia, Lagrangian)
  4. from sympy.core.function import (Derivative, Function)
  5. from sympy.core.numbers import pi
  6. from sympy.core.symbol import symbols
  7. from sympy.functions.elementary.trigonometric import (cos, sin, tan)
  8. from sympy.matrices.dense import Matrix
  9. from sympy.simplify.simplify import simplify
  10. def test_disc_on_an_incline_plane():
  11. # Disc rolling on an inclined plane
  12. # First the generalized coordinates are created. The mass center of the
  13. # disc is located from top vertex of the inclined plane by the generalized
  14. # coordinate 'y'. The orientation of the disc is defined by the angle
  15. # 'theta'. The mass of the disc is 'm' and its radius is 'R'. The length of
  16. # the inclined path is 'l', the angle of inclination is 'alpha'. 'g' is the
  17. # gravitational constant.
  18. y, theta = dynamicsymbols('y theta')
  19. yd, thetad = dynamicsymbols('y theta', 1)
  20. m, g, R, l, alpha = symbols('m g R l alpha')
  21. # Next, we create the inertial reference frame 'N'. A reference frame 'A'
  22. # is attached to the inclined plane. Finally a frame is created which is attached to the disk.
  23. N = ReferenceFrame('N')
  24. A = N.orientnew('A', 'Axis', [pi/2 - alpha, N.z])
  25. B = A.orientnew('B', 'Axis', [-theta, A.z])
  26. # Creating the disc 'D'; we create the point that represents the mass
  27. # center of the disc and set its velocity. The inertia dyadic of the disc
  28. # is created. Finally, we create the disc.
  29. Do = Point('Do')
  30. Do.set_vel(N, yd * A.x)
  31. I = m * R**2/2 * B.z | B.z
  32. D = RigidBody('D', Do, B, m, (I, Do))
  33. # To construct the Lagrangian, 'L', of the disc, we determine its kinetic
  34. # and potential energies, T and U, respectively. L is defined as the
  35. # difference between T and U.
  36. D.potential_energy = m * g * (l - y) * sin(alpha)
  37. L = Lagrangian(N, D)
  38. # We then create the list of generalized coordinates and constraint
  39. # equations. The constraint arises due to the disc rolling without slip on
  40. # on the inclined path. We then invoke the 'LagrangesMethod' class and
  41. # supply it the necessary arguments and generate the equations of motion.
  42. # The'rhs' method solves for the q_double_dots (i.e. the second derivative
  43. # with respect to time of the generalized coordinates and the lagrange
  44. # multipliers.
  45. q = [y, theta]
  46. hol_coneqs = [y - R * theta]
  47. m = LagrangesMethod(L, q, hol_coneqs=hol_coneqs)
  48. m.form_lagranges_equations()
  49. rhs = m.rhs()
  50. rhs.simplify()
  51. assert rhs[2] == 2*g*sin(alpha)/3
  52. def test_simp_pen():
  53. # This tests that the equations generated by LagrangesMethod are identical
  54. # to those obtained by hand calculations. The system under consideration is
  55. # the simple pendulum.
  56. # We begin by creating the generalized coordinates as per the requirements
  57. # of LagrangesMethod. Also we created the associate symbols
  58. # that characterize the system: 'm' is the mass of the bob, l is the length
  59. # of the massless rigid rod connecting the bob to a point O fixed in the
  60. # inertial frame.
  61. q, u = dynamicsymbols('q u')
  62. qd, ud = dynamicsymbols('q u ', 1)
  63. l, m, g = symbols('l m g')
  64. # We then create the inertial frame and a frame attached to the massless
  65. # string following which we define the inertial angular velocity of the
  66. # string.
  67. N = ReferenceFrame('N')
  68. A = N.orientnew('A', 'Axis', [q, N.z])
  69. A.set_ang_vel(N, qd * N.z)
  70. # Next, we create the point O and fix it in the inertial frame. We then
  71. # locate the point P to which the bob is attached. Its corresponding
  72. # velocity is then determined by the 'two point formula'.
  73. O = Point('O')
  74. O.set_vel(N, 0)
  75. P = O.locatenew('P', l * A.x)
  76. P.v2pt_theory(O, N, A)
  77. # The 'Particle' which represents the bob is then created and its
  78. # Lagrangian generated.
  79. Pa = Particle('Pa', P, m)
  80. Pa.potential_energy = - m * g * l * cos(q)
  81. L = Lagrangian(N, Pa)
  82. # The 'LagrangesMethod' class is invoked to obtain equations of motion.
  83. lm = LagrangesMethod(L, [q])
  84. lm.form_lagranges_equations()
  85. RHS = lm.rhs()
  86. assert RHS[1] == -g*sin(q)/l
  87. def test_nonminimal_pendulum():
  88. q1, q2 = dynamicsymbols('q1:3')
  89. q1d, q2d = dynamicsymbols('q1:3', level=1)
  90. L, m, t = symbols('L, m, t')
  91. g = 9.8
  92. # Compose World Frame
  93. N = ReferenceFrame('N')
  94. pN = Point('N*')
  95. pN.set_vel(N, 0)
  96. # Create point P, the pendulum mass
  97. P = pN.locatenew('P1', q1*N.x + q2*N.y)
  98. P.set_vel(N, P.pos_from(pN).dt(N))
  99. pP = Particle('pP', P, m)
  100. # Constraint Equations
  101. f_c = Matrix([q1**2 + q2**2 - L**2])
  102. # Calculate the lagrangian, and form the equations of motion
  103. Lag = Lagrangian(N, pP)
  104. LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c,
  105. forcelist=[(P, m*g*N.x)], frame=N)
  106. LM.form_lagranges_equations()
  107. # Check solution
  108. lam1 = LM.lam_vec[0, 0]
  109. eom_sol = Matrix([[m*Derivative(q1, t, t) - 9.8*m + 2*lam1*q1],
  110. [m*Derivative(q2, t, t) + 2*lam1*q2]])
  111. assert LM.eom == eom_sol
  112. # Check multiplier solution
  113. lam_sol = Matrix([(19.6*q1 + 2*q1d**2 + 2*q2d**2)/(4*q1**2/m + 4*q2**2/m)])
  114. assert simplify(LM.solve_multipliers(sol_type='Matrix')) == simplify(lam_sol)
  115. def test_dub_pen():
  116. # The system considered is the double pendulum. Like in the
  117. # test of the simple pendulum above, we begin by creating the generalized
  118. # coordinates and the simple generalized speeds and accelerations which
  119. # will be used later. Following this we create frames and points necessary
  120. # for the kinematics. The procedure isn't explicitly explained as this is
  121. # similar to the simple pendulum. Also this is documented on the pydy.org
  122. # website.
  123. q1, q2 = dynamicsymbols('q1 q2')
  124. q1d, q2d = dynamicsymbols('q1 q2', 1)
  125. q1dd, q2dd = dynamicsymbols('q1 q2', 2)
  126. u1, u2 = dynamicsymbols('u1 u2')
  127. u1d, u2d = dynamicsymbols('u1 u2', 1)
  128. l, m, g = symbols('l m g')
  129. N = ReferenceFrame('N')
  130. A = N.orientnew('A', 'Axis', [q1, N.z])
  131. B = N.orientnew('B', 'Axis', [q2, N.z])
  132. A.set_ang_vel(N, q1d * A.z)
  133. B.set_ang_vel(N, q2d * A.z)
  134. O = Point('O')
  135. P = O.locatenew('P', l * A.x)
  136. R = P.locatenew('R', l * B.x)
  137. O.set_vel(N, 0)
  138. P.v2pt_theory(O, N, A)
  139. R.v2pt_theory(P, N, B)
  140. ParP = Particle('ParP', P, m)
  141. ParR = Particle('ParR', R, m)
  142. ParP.potential_energy = - m * g * l * cos(q1)
  143. ParR.potential_energy = - m * g * l * cos(q1) - m * g * l * cos(q2)
  144. L = Lagrangian(N, ParP, ParR)
  145. lm = LagrangesMethod(L, [q1, q2], bodies=[ParP, ParR])
  146. lm.form_lagranges_equations()
  147. assert simplify(l*m*(2*g*sin(q1) + l*sin(q1)*sin(q2)*q2dd
  148. + l*sin(q1)*cos(q2)*q2d**2 - l*sin(q2)*cos(q1)*q2d**2
  149. + l*cos(q1)*cos(q2)*q2dd + 2*l*q1dd) - lm.eom[0]) == 0
  150. assert simplify(l*m*(g*sin(q2) + l*sin(q1)*sin(q2)*q1dd
  151. - l*sin(q1)*cos(q2)*q1d**2 + l*sin(q2)*cos(q1)*q1d**2
  152. + l*cos(q1)*cos(q2)*q1dd + l*q2dd) - lm.eom[1]) == 0
  153. assert lm.bodies == [ParP, ParR]
  154. def test_rolling_disc():
  155. # Rolling Disc Example
  156. # Here the rolling disc is formed from the contact point up, removing the
  157. # need to introduce generalized speeds. Only 3 configuration and 3
  158. # speed variables are need to describe this system, along with the
  159. # disc's mass and radius, and the local gravity.
  160. q1, q2, q3 = dynamicsymbols('q1 q2 q3')
  161. q1d, q2d, q3d = dynamicsymbols('q1 q2 q3', 1)
  162. r, m, g = symbols('r m g')
  163. # The kinematics are formed by a series of simple rotations. Each simple
  164. # rotation creates a new frame, and the next rotation is defined by the new
  165. # frame's basis vectors. This example uses a 3-1-2 series of rotations, or
  166. # Z, X, Y series of rotations. Angular velocity for this is defined using
  167. # the second frame's basis (the lean frame).
  168. N = ReferenceFrame('N')
  169. Y = N.orientnew('Y', 'Axis', [q1, N.z])
  170. L = Y.orientnew('L', 'Axis', [q2, Y.x])
  171. R = L.orientnew('R', 'Axis', [q3, L.y])
  172. # This is the translational kinematics. We create a point with no velocity
  173. # in N; this is the contact point between the disc and ground. Next we form
  174. # the position vector from the contact point to the disc's center of mass.
  175. # Finally we form the velocity and acceleration of the disc.
  176. C = Point('C')
  177. C.set_vel(N, 0)
  178. Dmc = C.locatenew('Dmc', r * L.z)
  179. Dmc.v2pt_theory(C, N, R)
  180. # Forming the inertia dyadic.
  181. I = inertia(L, m/4 * r**2, m/2 * r**2, m/4 * r**2)
  182. BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc))
  183. # Finally we form the equations of motion, using the same steps we did
  184. # before. Supply the Lagrangian, the generalized speeds.
  185. BodyD.potential_energy = - m * g * r * cos(q2)
  186. Lag = Lagrangian(N, BodyD)
  187. q = [q1, q2, q3]
  188. q1 = Function('q1')
  189. q2 = Function('q2')
  190. q3 = Function('q3')
  191. l = LagrangesMethod(Lag, q)
  192. l.form_lagranges_equations()
  193. RHS = l.rhs()
  194. RHS.simplify()
  195. t = symbols('t')
  196. assert (l.mass_matrix[3:6] == [0, 5*m*r**2/4, 0])
  197. assert RHS[4].simplify() == (
  198. (-8*g*sin(q2(t)) + r*(5*sin(2*q2(t))*Derivative(q1(t), t) +
  199. 12*cos(q2(t))*Derivative(q3(t), t))*Derivative(q1(t), t))/(10*r))
  200. assert RHS[5] == (-5*cos(q2(t))*Derivative(q1(t), t) + 6*tan(q2(t)
  201. )*Derivative(q3(t), t) + 4*Derivative(q1(t), t)/cos(q2(t))
  202. )*Derivative(q2(t), t)