问题
I am doing a multiple DOF dynamics problem, using 2nd order Lagrangian equations. I used sympy to get to the equations of motion. Now these equations after calculating the derivatives got quite long, seems though that sympy simplify cant simplify it further. My problem actually is how to solve this system of three 2nd order ode from here. I don't know how to get these equations converted so they can be used with scipy.odeint(). Substitution came to mind, but there are a lot of symbols. So Im searching for phi0,phi1 and phi2 and also for their first and second derivatives. Initial conditions are all phi[0]=0 and all dphi[0]=0. I hope there is a way to solve this without going from scratch. Thanks in advance.
def derivativeLagranga(Lagrange,n):
"""left side of lagrange"""
f0 = sym.Function('f0')(t)
f1 = sym.Function('f1')(t)
f2 = sym.Function('f2')(t)
f3 = sym.Function('f3')(t)
L_i = []
L_it = []
L_j =[]
L_leva = []
x=0
y=0
for i in range(0,n-1):
x = Lagrange.diff(kot[i].diff(t))
L_i.append(x)
for i in range(0,n-1):
x = L_i[i].diff(t)
x = x.replace(sym.sin(kot[i]),kot[i])
L_it.append(x)
for i in range(0,n-1):
x = L.diff(kot[i])
L_j.append(x)
for i in range(0,n-1):
x = L_it[i]+L_j[i]
L_leva.append(x)
return L_left
left_side_L = derivativeLagranga(Lagrange, n)
f0 = sym.simplify(left_side_L[0].subs(values))
f1 = leva_stran_L[1].subs(values)
f2 = leva_stran_L[2].subs(values)
f0
So my f0 is the one of the equations, I couldn't copy the output so I will post a picture.
54.51345(−(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+2.0𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡))(0.5(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))−1.0cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡)−1.0cos(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡)+1.0cos(𝜑2(𝑡))𝑑𝑑𝑡𝜑2(𝑡))+54.51345((𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡))(0.5(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+0.5𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡)+1.0sin(𝜑2(𝑡))𝑑𝑑𝑡𝜑2(𝑡))+54.51345(2.0(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡))(1.0(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+0.5𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡)+1.0sin(𝜑2(𝑡))𝑑𝑑𝑡𝜑2(𝑡)+0.5sin(𝜑4(𝑡))𝑑𝑑𝑡𝜑4(𝑡))−54.51345(2.0cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡)+1.0cos(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡))𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡)+54.51345(𝜑0(𝑡)+sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡)))((0.5𝑑𝑑𝑡𝜑0(𝑡)+0.5𝑑𝑑𝑡𝜑1(𝑡)−0.5𝑑𝑑𝑡𝜑2(𝑡))(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+(0.5𝑑2𝑑𝑡2𝜑0(𝑡)+0.5𝑑2𝑑𝑡2𝜑1(𝑡)−0.5𝑑2𝑑𝑡2𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+0.5𝜑0(𝑡)𝑑2𝑑𝑡2𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡)+1.0sin(𝜑2(𝑡))𝑑2𝑑𝑡2𝜑2(𝑡)+0.5cos(𝜑0(𝑡))(𝑑𝑑𝑡𝜑0(𝑡))2+0.5cos(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2+1.0cos(𝜑2(𝑡))(𝑑𝑑𝑡𝜑2(𝑡))2)+54.51345(𝜑0(𝑡)+2.0sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡)))((𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))(1.0𝑑𝑑𝑡𝜑0(𝑡)+1.0𝑑𝑑𝑡𝜑1(𝑡)−1.0𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+(1.0𝑑2𝑑𝑡2𝜑0(𝑡)+1.0𝑑2𝑑𝑡2𝜑1(𝑡)−1.0𝑑2𝑑𝑡2𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+0.5𝜑0(𝑡)𝑑2𝑑𝑡2𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡)+1.0sin(𝜑2(𝑡))𝑑2𝑑𝑡2𝜑2(𝑡)+0.5sin(𝜑4(𝑡))𝑑2𝑑𝑡2𝜑4(𝑡)+0.5cos(𝜑0(𝑡))(𝑑𝑑𝑡𝜑0(𝑡))2+0.5cos(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2+1.0cos(𝜑2(𝑡))(𝑑𝑑𝑡𝜑2(𝑡))2+0.5cos(𝜑4(𝑡))(𝑑𝑑𝑡𝜑4(𝑡))2)+54.51345(cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))−2.0cos(𝜑0(𝑡)))(−(0.5𝑑𝑑𝑡𝜑0(𝑡)+0.5𝑑𝑑𝑡𝜑1(𝑡)−0.5𝑑𝑑𝑡𝜑2(𝑡))(𝑑𝑑𝑡𝜑0(𝑡)+𝑑𝑑𝑡𝜑1(𝑡)−𝑑𝑑𝑡𝜑2(𝑡))sin(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+(0.5𝑑2𝑑𝑡2𝜑0(𝑡)+0.5𝑑2𝑑𝑡2𝜑1(𝑡)−0.5𝑑2𝑑𝑡2𝜑2(𝑡))cos(𝜑0(𝑡)+𝜑1(𝑡)−𝜑2(𝑡))+1.0𝜑0(𝑡)(𝑑𝑑𝑡𝜑0(𝑡))2+1.0sin(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2−1.0sin(𝜑2(𝑡))(𝑑𝑑𝑡𝜑2(𝑡))2−1.0cos(𝜑0(𝑡))𝑑2𝑑𝑡2𝜑0(𝑡)−1.0cos(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡)+1.0cos(𝜑2(𝑡))𝑑2𝑑𝑡2𝜑2(𝑡))+54.51345(0.5𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡)+0.5sin(𝜑2(𝑡))𝑑𝑑𝑡𝜑2(𝑡))cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡)−54.51345(2.0cos(𝜑0(𝑡))𝑑𝑑𝑡𝜑0(𝑡)+2.0cos(𝜑1(𝑡))𝑑𝑑𝑡𝜑1(𝑡)−1.0cos(𝜑2(𝑡))𝑑𝑑𝑡𝜑2(𝑡))𝜑0(𝑡)𝑑𝑑𝑡𝜑0(𝑡)+54.51345(−2.0𝜑0(𝑡)(𝑑𝑑𝑡𝜑0(𝑡))2−1.0sin(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2+2.0cos(𝜑0(𝑡))𝑑2𝑑𝑡2𝜑0(𝑡)+1.0cos(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡))cos(𝜑0(𝑡))+54.51345(−2.0𝜑0(𝑡)(𝑑𝑑𝑡𝜑0(𝑡))2−2.0sin(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2+1.0sin(𝜑2(𝑡))(𝑑𝑑𝑡𝜑2(𝑡))2+2.0cos(𝜑0(𝑡))𝑑2𝑑𝑡2𝜑0(𝑡)+2.0cos(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡)−1.0cos(𝜑2(𝑡))𝑑2𝑑𝑡2𝜑2(𝑡))cos(𝜑0(𝑡))+54.51345(0.5𝜑0(𝑡)𝑑2𝑑𝑡2𝜑0(𝑡)+0.5sin(𝜑1(𝑡))𝑑2𝑑𝑡2𝜑1(𝑡)+0.5sin(𝜑2(𝑡))𝑑2𝑑𝑡2𝜑2(𝑡)+0.5cos(𝜑0(𝑡))(𝑑𝑑𝑡𝜑0(𝑡))2+0.5cos(𝜑1(𝑡))(𝑑𝑑𝑡𝜑1(𝑡))2+0.5cos(𝜑2(𝑡))(𝑑𝑑𝑡𝜑2(𝑡))2)𝜑0(𝑡)−2123.406𝑑𝑑𝑡𝜑0(𝑡)+45.427875𝑑2𝑑𝑡2𝜑0(𝑡)−2123.406𝑑𝑑𝑡𝜑1(𝑡)+9.085575𝑑2𝑑𝑡2𝜑1(𝑡)−9.085575𝑑2𝑑𝑡2𝜑2(𝑡)
And lambdify output:
NameError Traceback (most recent call last)
<ipython-input-14-ee077b324a2e> in <module>
2 en2 = sym.lambdify([kot_0,kot_1,kot_2],f1)
3 en3 = sym.lambdify([kot_0,kot_1,kot_2],f2)
----> 4 en1(kot_0,kot_1,kot_2)
5
6
<lambdifygenerated-4> in _lambdifygenerated(_Dummy_227, _Dummy_226, _Dummy_225)
9 # Derivative
10 # Derivative
---> 11 22.722525*_Dummy_227**2*Derivative(_Dummy_227, (t, 2)) + 90.8901*_Dummy_227*(-0.5*cos(_Dummy_226)*Derivative(_Dummy_226, t) - 1.0*cos(_Dummy_227)*Derivative(_Dummy_227, t))*Derivative(_Dummy_227, t) + 90.8901*_Dummy_227*(0.5*cos(_Dummy_225)*Derivative(_Dummy_225, t) - 1.0*cos(_Dummy_226)*Derivative(_Dummy_226, t) - 1.0*cos(_Dummy_227)*Derivative(_Dummy_227, t))*Derivative(_Dummy_227, t) - 22.722525*_Dummy_227*(-_Dummy_227*Derivative(_Dummy_227, (t, 2)) - sin(_Dummy_225)*Derivative(_Dummy_225, (t, 2)) - sin(_Dummy_226)*Derivative(_Dummy_226, (t, 2)) - cos(_Dummy_225)*Derivative(_Dummy_225, t)**2 - cos(_Dummy_226)*Derivative(_Dummy_226, t)**2 - cos(_Dummy_227)*Derivative(_Dummy_227, t)**2) + 0.5*Jm*(-2*Derivative(_Dummy_225, (t, 2)) + 2*Derivative(_Dummy_226, (t, 2)) + 2*Derivative(_Dummy_227, (t, 2))) + 1.0*Jm*Derivative(_Dummy_227, (t, 2)) + 45.44505*(-1.0*_Dummy_227 - 2.0*sin(-_Dummy_225 + _Dummy_226 + _Dummy_227))*(-0.5*_Dummy_227*Derivative(_Dummy_227, (t, 2)) + (-Derivative(_Dummy_225, t) + Derivative(_Dummy_226, t) + Derivative(_Dummy_227, t))*(1.0*Derivative(_Dummy_225, t) - 1.0*Derivative(_Dummy_226, t) - 1.0*Derivative(_Dummy_227, t))*cos(-_Dummy_225 + _Dummy_226 + _Dummy_227) + (1.0*Derivative(_Dummy_225, (t, 2)) - 1.0*Derivative(_Dummy_226, (t, 2)) - 1.0*Derivative(_Dummy_227, (t, 2)))*sin(-_Dummy_225 + _Dummy_226 + _Dummy_227) - 1.0*sin(_Dummy_225)*Derivative(_Dummy_225, (t, 2)) - 0.5*sin(_Dummy_226)*Derivative(_Dummy_226, (t, 2)) - 0.5*sin(varphi_4(t))*Der
https://imgur.com/a/2UOW0NR
EDIT2: So after a lof of simplification i some how got 3 ordinary differential equations. But they are in sympy form, how can i solve them numericaly?
−800000.0𝜑0+800000.0𝜑2−1770.174𝜑˙0+242.3736𝜑¨0−1770.174𝜑˙1+166.63185𝜑¨1−75.74175𝜑¨2+4245.8661
−1200000.0𝜑1+400000.0𝜑2−1770.174𝜑˙0+166.63185𝜑¨0−1770.174𝜑˙1+151.4835𝜑¨1−75.74175𝜑¨2+2830.5774
800000.0𝜑0+400000.0𝜑1−2000000.0𝜑2−75.74175𝜑¨0−75.74175𝜑¨1+60.5934𝜑¨2−1415.2887
回答1:
I'll present the execution of the Euler-Lagrange formalism for the example of the double pendulum as a non-trivial, complete, standard example, and this without using the specialized functions in sympy.physics, only using basic differentiation and code-writing facilities of sympy. Hopefully it is general enough in that the second part should be problem-independent and thus also be directly applicable to your situation.
from sympy import sin, cos, Symbol, symbols, solve
from sympy.utilities.lambdify import lambdify
Lagrangian for the physical model
First the physical setup for the Lagrangian using the two angles as the main dependent functions and construct kinetic and potential energy via the Cartesian coordinates.
# Symbols for the parameters of the problem
t,m1,m2,l1,l2,g = symbols("t,m_1 m_2 l_1 l_2 g")
# Variables of the problem
th1, th2 = Function("θ_1")(t), Function("θ_2")(t)
x1,y1 = l1*sin(th1), -l1*cos(th1)
x2,y2 = x1+l2*sin(th2), y1-l2*cos(th2)
# kinetic energy
vx1,vy1,vx2,vy2 = ( xx.diff(t) for xx in (x1,y1,x2,y2))
K1 = m1/2*(vx1**2+vy1**2)
K2 = m2/2*(vx2**2+vy2**2)
K = K1+K2
# potential energy
V = g*(m1*y1+m2*y2)
# Lagrangian
L = K - V
L = L.expand().simplify()
To get an abstract treatment use abstract parameter arrays and coordinate vectors
params = [m1, l1, m2, l2, g]
q = [th1, th2]
dotq = [ qq.diff(t) for qq in q]
From Euler-Lagrange to a first-order ODE system
It gets rather messy in the resulting expressions if one goes to the second derivatives of the angles, one gets a more structured approach and hopefully a correspondingly faster evaluation using impulse variables
pk = diff(L, dotqk)
d(pk)/dt = diff(L, qk)
where the first relation is seen as a system of equations to compute dotq
from p
.
Prepare the new variables, prepare to replace the function symbols with simple variables.
N = len(q)
p = [ Symbol(f"p_{k+1}") for k in range(N)]
dotq_func, dotq = dotq, [ Symbol(f"Dq_{k+1}") for k in range(N)]
q_func, q = q, [ Symbol(f"q_{k+1}") for k in range(N)]
Now replace all function terms by simple variables
L=L.subs(list(zip(dotq_func, dotq))).subs(list(zip(q_func, q)))
Now establish the function to compute dotq
from q,p
p_eqns = [ p[k] - L.diff(dotq[k]) for k in range(N)]
dotq_expr = solve(p_eqns, dotq)
dotq_func = lambdify([*q, *p, *params],[ dotq_expr[dq] for dq in dotq])
Next generate a function that computes the derivatives of p
dotp_expr = [ L.diff(q[k]) for k in range(N)]
dotp_func = lambdify([*q,*dotq,*params],dotp_expr)
Now assemble the generated functions into a complete ODE function and solve a test problem with it to confirm that it works
def odefunc(t,u,args):
q, p = u[:N], u[N:]
dotq = dotq_func(*q, *p, *args)
dotp = dotp_func(*q, *dotq, *args)
return [*dotq, *dotp]
Confirmation via numerical solution
myparams = [1,10,5,5,9.81]
t = np.linspace(0,25,301)
u = odeint(odefunc,[2,1.2, 0,0],t,args=(myparams,), tfirst=True)
%matplotlib inline
plt.figure(figsize=(8,5))
plt.plot(t,u[:,0],t,u[:,1]);
plt.grid(); plt.show()
This produces the following plot for the angle functions
Outlook
Even better performance could be expected if the kinetic term is (as is usual in classical mechanics) guaranteed to be quadratic in the velocities. Then by directly extracting the matrix of this quadratic form, one could delegate the system solution in the conversion of impuls to velocity to a numerical linear system solver, so not keep the symbolic expressions for the matrix inversion. These could be large in higher dimensions.
来源:https://stackoverflow.com/questions/61044226/solving-a-system-of-2nd-order-differential-equations-from-sympy