test_kane4.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from sympy.core.backend import (cos, sin, Matrix, symbols)
  2. from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point,
  3. KanesMethod, Particle)
  4. def test_replace_qdots_in_force():
  5. # Test PR 16700 "Replaces qdots with us in force-list in kanes.py"
  6. # The new functionality allows one to specify forces in qdots which will
  7. # automatically be replaced with u:s which are defined by the kde supplied
  8. # to KanesMethod. The test case is the double pendulum with interacting
  9. # forces in the example of chapter 4.7 "CONTRIBUTING INTERACTION FORCES"
  10. # in Ref. [1]. Reference list at end test function.
  11. q1, q2 = dynamicsymbols('q1, q2')
  12. qd1, qd2 = dynamicsymbols('q1, q2', level=1)
  13. u1, u2 = dynamicsymbols('u1, u2')
  14. l, m = symbols('l, m')
  15. N = ReferenceFrame('N') # Inertial frame
  16. A = N.orientnew('A', 'Axis', (q1, N.z)) # Rod A frame
  17. B = A.orientnew('B', 'Axis', (q2, N.z)) # Rod B frame
  18. O = Point('O') # Origo
  19. O.set_vel(N, 0)
  20. P = O.locatenew('P', ( l * A.x )) # Point @ end of rod A
  21. P.v2pt_theory(O, N, A)
  22. Q = P.locatenew('Q', ( l * B.x )) # Point @ end of rod B
  23. Q.v2pt_theory(P, N, B)
  24. Ap = Particle('Ap', P, m)
  25. Bp = Particle('Bp', Q, m)
  26. # The forces are specified below. sigma is the torsional spring stiffness
  27. # and delta is the viscous damping coefficient acting between the two
  28. # bodies. Here, we specify the viscous damper as function of qdots prior
  29. # forming the kde. In more complex systems it not might be obvious which
  30. # kde is most efficient, why it is convenient to specify viscous forces in
  31. # qdots independently of the kde.
  32. sig, delta = symbols('sigma, delta')
  33. Ta = (sig * q2 + delta * qd2) * N.z
  34. forces = [(A, Ta), (B, -Ta)]
  35. # Try different kdes.
  36. kde1 = [u1 - qd1, u2 - qd2]
  37. kde2 = [u1 - qd1, u2 - (qd1 + qd2)]
  38. KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1)
  39. fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces)
  40. KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2)
  41. fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces)
  42. # Check EOM for KM2:
  43. # Mass and force matrix from p.6 in Ref. [2] with added forces from
  44. # example of chapter 4.7 in [1] and without gravity.
  45. forcing_matrix_expected = Matrix( [ [ m * l**2 * sin(q2) * u2**2 + sig * q2
  46. + delta * (u2 - u1)],
  47. [ m * l**2 * sin(q2) * -u1**2 - sig * q2
  48. - delta * (u2 - u1)] ] )
  49. mass_matrix_expected = Matrix( [ [ 2 * m * l**2, m * l**2 * cos(q2) ],
  50. [ m * l**2 * cos(q2), m * l**2 ] ] )
  51. assert (KM2.mass_matrix.expand() == mass_matrix_expected.expand())
  52. assert (KM2.forcing.expand() == forcing_matrix_expected.expand())
  53. # Check fr1 with reference fr_expected from [1] with u:s instead of qdots.
  54. fr1_expected = Matrix([ 0, -(sig*q2 + delta * u2) ])
  55. assert fr1.expand() == fr1_expected.expand()
  56. # Check fr2
  57. fr2_expected = Matrix([sig * q2 + delta * (u2 - u1),
  58. - sig * q2 - delta * (u2 - u1)])
  59. assert fr2.expand() == fr2_expected.expand()
  60. # Specifying forces in u:s should stay the same:
  61. Ta = (sig * q2 + delta * u2) * N.z
  62. forces = [(A, Ta), (B, -Ta)]
  63. KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1)
  64. fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces)
  65. assert fr1.expand() == fr1_expected.expand()
  66. Ta = (sig * q2 + delta * (u2-u1)) * N.z
  67. forces = [(A, Ta), (B, -Ta)]
  68. KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2)
  69. fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces)
  70. assert fr2.expand() == fr2_expected.expand()
  71. # Test if we have a qubic qdot force:
  72. Ta = (sig * q2 + delta * qd2**3) * N.z
  73. forces = [(A, Ta), (B, -Ta)]
  74. KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1)
  75. fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces)
  76. fr1_cubic_expected = Matrix([ 0, -(sig*q2 + delta * u2**3) ])
  77. assert fr1.expand() == fr1_cubic_expected.expand()
  78. KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2)
  79. fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces)
  80. fr2_cubic_expected = Matrix([sig * q2 + delta * (u2 - u1)**3,
  81. - sig * q2 - delta * (u2 - u1)**3])
  82. assert fr2.expand() == fr2_cubic_expected.expand()
  83. # References:
  84. # [1] T.R. Kane, D. a Levinson, Dynamics Theory and Applications, 2005.
  85. # [2] Arun K Banerjee, Flexible Multibody Dynamics:Efficient Formulations
  86. # and Applications, John Wiley and Sons, Ltd, 2016.
  87. # doi:http://dx.doi.org/10.1002/9781119015635.