LoginSignup
0
2

More than 3 years have passed since last update.

オイラー・ラグランジュの運動方程式をPythonで計算させる

Last updated at Posted at 2020-03-28

目的と概要

オイラー・ラグランジュ方程式による、運動方程式の導出はエネルギーを利用しているため、計算ミスが小さいという特徴があります。
3次元という複雑化する運動方程式でも適用が簡単であり、便利な方法です。
しかし、ラグランジアンを導出後の偏微分の計算、連立方程式の解法、というめんどくささがあります。
今回、投稿する内容は、ラグランジアン導入後、偏微分、時間微分をさせて、オイラー法を用いてシミュレーションするという内容です。
文字式にはまだ対応させていません。
また、sin,cos,d/dt^2/dt^2の多項式にしか対応させていません。

matlabやscilabを使える人は、全く関係ない話なのでブラウザバック推奨です。

3次元のY字振り子
https://www.youtube.com/watch?v=eeizdZscRjU
https://www.youtube.com/watch?v=llBik9FsEDo
をシミュレーションした結果はPosition.png
結構、実験と一致する曲線がかけて満足しています。
計算シミュレーションでなく、実験をする場合は洗濯に使う粉を使うとうまくいきます。

ただ、3次元になると、オイラー角でいう特異状態になり、計算値が爆発的に増加したり、nanで止まってうまくいかなかったり難しいです。
とりあえず、ムーアの一般逆行列ということにして処理していますが、どうすべきかは勉強が足りない為、わかりません。誰か教えて
今のところ、シミュレーションにはオイラー法を使用していますが、ルンゲルクッタ法を使ったほうがいい可能性があります。
ただ、数値爆発は計算精度の問題とは違う気もしてます。

2次元2重振り子
https://www.youtube.com/watch?v=25feOUNQB2Y
をシミュレーションした結果は(jifアニメなのでクリックして見てください)
output2.gif
とりあえず、それっぽくなっています。

オイラー・ラグランジュ方程式

ラグランジアン$L$

L=T-U\\
T:運動エネルギー\\
U:位置エネルギー

に対し、

\frac {\partial L}{\partial x} - \frac{d}{dt} \frac{\partial L}{\partial \dot{x}} = 0

が運動方程式となります。xは一般化位置であり、位置座標や回転角度などになります。

プラグラム

anaconda環境のpython2で実行しています。

1

オイラー・ラグランジュ方程式の大変さは、前述のとおり、

  • 偏微分が多いため、計算ミスが起きやすい
  • 偏微分後に同じ項をまとめるのがめんどい
  • 多変数の一般座標になると、一般座標同士が絡み合い、$d^2 x_1 /dt^2=$ と $d^2 x_2 /dt^2 = $の形に分けるのが大変(シミュレーションをする分には分けなくても解ける)

実際に問題を解くと、たぶんうんざりします。

2

matlabやscilabを使える人は特に困らないでしょう。また、運動方程式導出後の微分方程式を解く際もode45等の解法が常備されているので、それでやればいいと思います。
ただ私は、$d^2 x_1 /dt^2=$ と $d^2 x_2 /dt^2 = $の形に直す方法が見つからず、力業で計算させることにしました。

3 コード

class Formula :
    def __init__(self,L,num):
        self.L = L
        self.n = num                      #変数の種類数


    def __add__(self,other):
        self.L = np.append(self.L,other.L,axis =0)
        self.together()
        self.erase()

    def __sub__(self,other):
        self.L = np.append(self.L,-1*other.L,axis =0)
        self.together()
        self.erase()

    def together(self):               #同じ項の係数をまとめる
        expr,vari = self.L.shape
        if expr >=2:
            for i in range(expr-1):
                for j in range(i+1,expr):                    
                    m=0
                    while self.L[i][0+m*6:5+m*6].tolist() == self.L[j][0+m*6:5+m*6].tolist():
                        m += 1
                        if m == self.n:
                            break
                    if m== self.n:
                        self.L[i][5] += self.L[j][5]
                        for k in range(vari):
                            self.L[j][k] = 0

    def erase(self):    #係数が0の項を消す
        expr,vari = self.L.shape
        for i in list(reversed(range(expr))):
            if self.L[i][5] == 0:
                self.L = np.delete(self.L,i,axis = 0)

    def partial(self,moji,kind):  #kindの種類のもので項を偏微分する
        expr,vari = self.L.shape
        if kind == 0:   
            '''
            sin
            cos

            +moji*6
            '''
            #print self.L
            for i in range(expr):
                if self.L[i][3+moji*6] !=0:  #sin
                    hoge = copy.deepcopy(self.L[i])
                    hoge[5] = hoge[5]*hoge[3+moji*6]
                    hoge[3+moji*6] = hoge[3+moji*6]-1
                    hoge[4+moji*6] = hoge[4+moji*6]+1
                    self.L = np.append(self.L,hoge[np.newaxis,:],axis =0)
                    #print self.L
            for i in range(expr):
                if self.L[i][4+moji*6] !=0:  #cos
                    hoge = copy.deepcopy(self.L[i])
                    hoge[5] = hoge[5]*hoge[4+moji*6]*-1
                    hoge[4+moji*6]= hoge[4+moji*6]-1
                    hoge[3+moji*6] = hoge[3+moji*6]+1
                    self.L = np.append(self.L,hoge[np.newaxis,:],axis =0)
                    #print self.L
            '''
            そのままのもの
            次数を一つ下げる、0なら何もしない
            元の次数を係数に掛ける
            '''
            #print self.L
            for i in range(expr):
                if self.L[i][kind] !=0:
                    #print kind,self.L[i][5]
                    self.L[i][5] = self.L[i][5] * self.L[i][kind+moji*6]
                    #print self.L[i][5]
                    self.L[i][kind+moji*6] = self.L[i][kind+moji*6] -1
                else:
                    self.L[i][5] = 0   #含まないなら 0

        if kind == 1:   
            '''
            そのままのもの
            次数を一つ下げる、0なら何もしない
            元の次数を係数に掛ける
            '''
            for i in range(expr):
                if self.L[i][kind+moji*6] !=0:
                    self.L[i][5] = self.L[i][5] * self.L[i][kind+moji*6]
                    self.L[i][kind+moji*6] = self.L[i][kind+moji*6] -1

                else:
                    self.L[i][5] = 0   #含まないなら 0

        self.together()
        self.erase()

    def diff(self):  #時間微分
        '''
        4つのパターンで偏微分後
        θ・の次数を1上げる        
        '''
        L1=copy.deepcopy(self.L)

        for i in range(self.n):
            self.L =copy.deepcopy( L1)
            self.partial(i,0)
            expr,vari = self.L.shape
            #print expr
            #print self.L
            for j in range(expr):
                self.L[j][1+i*6] = self.L[j][1+i*6] + 1
            if i == 0:
                L2 = copy.deepcopy( self.L)
            else:
                L2 = np.append(L2,self.L,axis =0)

            self.L =copy.deepcopy( L1)         
            self.partial(i,1)
            expr,vari = self.L.shape
            for j in range(expr):
                self.L[j][2+i*6] += 1
            L2 = np.append(L2,self.L,axis =0)

        self.L = copy.deepcopy( L2)

        self.together()
        self.erase()

    def disp(self):  #多項式表示
        print "-------------------Formula--------------"
        expr,vari = self.L.shape
        for j in range(expr):
            hoge =""
            for i in range(self.n):
                hoge += str(self.L[j][5+i*6])
                hoge += " θ^"
                hoge += str(self.L[j][0+i*6])
                hoge += " θ・^"
                hoge += str(self.L[j][1+i*6])
                hoge += " θ・・^"
                hoge += str(self.L[j][2+i*6])
                hoge += " sin^"
                hoge += str(self.L[j][3+i*6])
                hoge += " cos^"
                hoge += str(self.L[j][4+i*6])
                hoge += "   "

            hoge += "  +  "
            print hoge

    def subst(self,x):            #代入 x ,x・の順に入れる
        vari =np.array(x).shape
        if vari[0] != self.n*2:
            print "cannot subst"
        else:
            '''
            行ベクトルを生成して
            dotでLと  をして、できたベクトルの全要素を足せばよい
            '''

            expr,vari = self.L.shape
            sum1 = 0
            hoge=0
            for j in range(expr):
                hoge=self.L[j][5]           #係数
                for i in range(self.n):

                    hoge = hoge*x[0+i*2]**self.L[j][0+i*6]                                hoge = hoge*x[1+i*2]**self.L[j][1+i*6]            #θ・
                    hoge = hoge*math.sin(x[0+i*2])**self.L[j][3+i*6]  #sin
                    hoge = hoge*math.cos(x[0+i*2])**self.L[j][4+i*6]  #cos


                sum1 += hoge

            return sum1


self.L = 多項式の情報
self.n = 変数の数
self.L = [ [1, 2 ,3 , 4, 5, 6]
           [7, 8, 9, 10,11,12]]

の場合

L = x^1*(\frac{d}{dt} x) ^2*(\frac{d^2}{dt^2} x) ^3  sin(x)^4 cos(x)^5 *6\\
+\\
x^7*(\frac{d}{dt} x) ^8*(\frac{d^2}{dt^2} x) ^9  sin(x)^{10} cos(x)^{11} *12\\

を表します。

関数は

L1+L2 : L1 = L1+L2 ちょっとわかりにくいですが
L1-L2 : L1 = L1-L2
*:実装していない

L1.partial(i,0) : $x_i$で偏微分
L1.partial(i,1) : $\frac{d}{dt} x_i$で偏微分

L1.diff() : 時間微分

L1.disp() : 多項式を表示
L1.disp2() : 表示をわかりやすくしたもの

を実装しています。

Y字振り子の運動方程式

次に、Y字振り子のシミュレーションをする方法について説明します。
Y字振り子は、V字角度は動きません。つまり、一方向の回転のみを許すピンジョインとといえます(Z-X平面のみを移動できる)。
天井にピンジョイントでつながった重りに、さらにボールジョイント(3つの回転を許す)で重りをつけるとY字振り子のモデルになります。
YPen.jpg
このように、回転角$\theta 123$を設定します。

\vec{R_{m1}} = 
\left(
    \begin{array}{ccc}
      R_1*cos( \theta 1)\\
0\\
-R_1*sin(\theta2)
    \end{array}
  \right)
,
\vec{R_{m2}} = \vec{R_{m1}} +
\left(
    \begin{array}{ccc}
     R_3*sin(\theta3) * cos(\theta2)\\
R_3*sin(\theta3) * sin(\theta2)\\
-R_3*cos(\theta3)
    \end{array}
  \right)

となります。
これを時間微分し、速度ベクトルを出し、速度ベクトルの大きさから、運動エネルギーを出します。

T=\frac{1}{2} m_1 (R_1\dot{\theta})^2+\frac{1}{2} m_2 (R_1^2 \dot{\theta}^2 + R_3^2 sin(\theta 3)^2 \dot{\theta 2}^2 + R_3^2 \dot{\theta 3}^2
\\
-2*cos(\theta 1) sin(\theta 2) R_1 R_3 sin(\theta 3) \dot{\theta 1} \dot{\theta 2}\\
+2*(cos(\theta 1) cos(\theta 2) cos(\theta 3) + sin(\theta 1) sin(\theta 2)     )R_1 R_3 \dot{\theta 1} \dot{\theta 3}  

位置エネルギーは

U=m_1 g R_1 (1- cos(\theta 1)) + m_2 g (R_1 (1- cos(\theta 1)) + R_3(1-cos(\theta 3))

となる。

これを用いてラグランジアンを計算すると

  L=   m_1*r_1^2 /2 + m_2*r_1^2/2 \dot{ x_1}^{2.0}               +  
  m_2 /2 *r_3^2      \dot{ x_2}^{2.0}      sin( x_3)^{2.0}     +  
  m_2 /2 *r_3^2           \dot{ x_3}^{2.0}     +  
  m_2 /2 *(-2*r_1*r_3) \dot{ x_1}^{1.0} cos( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  m_2 /2 *(2*r_1*r_3)  \dot{ x_1}^{1.0} cos( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
  m_2 /2 *(2*r_1*r_3)  \dot{ x_1}^{1.0} sin( x_1)^{1.0}           \dot{ x_3}^{1.0} sin( x_3)^{1.0}     +  
  -1*(g*(m_1*r1+m_2*(r_1+r_3)))               +  
  -1*(-1*g*(m_1*r1+m_2*r_1)) cos( x_1)^{1.0}               +  
  -1*(-1*g*m_2*r_3)           cos( x_3)^{1.0}         

となります。θとxを入れ替えて表示しています

x_1 = \theta 1 
x_2 = \theta 2
x_3 = \theta 3 

運動方程式を導くと

   (m_2 /2 *(2*r_1*r_3) *1.0)  + -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) \dot{ x_1}^{1.0} cos( x_1)^{1.0}           \dot{ x_3}^{1.0} sin( x_3)^{1.0}     +  
   (m_2 /2 *(-2*r_1*r_3)*(-1)*1.0)  + -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *(-1)*1.0) ) \dot{ x_1}^{1.0} sin( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
   (m_2 /2 *(2*r_1*r_3) *(-1)*1.0)  + -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0) ) \dot{ x_1}^{1.0} sin( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
   (-1*(-1*g*(m_1*r1+m_2*r_1))*(-1)*1.0)  sin( x_1)^{1.0}               +  
  0 + 0 + 0               +  
  0 + 0               +  
  0               +  
  -1*( ( (m_1*r_1^2 /2 + m_2*r_1^2/2*2.0) *1.0) ) \ddot { x_1}^{1.0}               +  
  -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) cos( x_1)^{1.0}      \dot{ x_2}^{2.0} cos( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0)  +  ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) cos( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) cos( x_1)^{1.0}      \ddot { x_2}^{1.0} sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) sin( x_1)^{1.0}           \dot{ x_3}^{2.0} cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0) ) cos( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{2.0} sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) cos( x_1)^{1.0}      cos( x_2)^{1.0}      \ddot { x_3}^{1.0} cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) sin( x_1)^{1.0}           \ddot { x_3}^{1.0} sin( x_3)^{1.0}     =0\\

  (m_2 /2 *(-2*r_1*r_3)*1.0)  + -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) \dot{ x_1}^{1.0} cos( x_1)^{1.0}      \dot{ x_2}^{1.0} cos( x_2)^{1.0}      sin( x_3)^{1.0}     +  
   (m_2 /2 *(2*r_1*r_3) *(-1)*1.0)  + -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) \dot{ x_1}^{1.0} cos( x_1)^{1.0}      sin( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *(-1)*1.0) ) \dot{ x_1}^{2.0} sin( x_1)^{1.0}      sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(-2*r_1*r_3)*1.0) *1.0) ) \ddot { x_1}^{1.0} cos( x_1)^{1.0}      sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  0 + 0               +  
  -1*( ( (m_2 /2 *r_3^2*2.0) *1.0) )      \ddot { x_2}^{1.0}      sin( x_3)^{2.0}     +  
  -1*( ( (m_2 /2 *r_3^2*2.0) *2.0) )      \dot{ x_2}^{1.0}      \dot{ x_3}^{1.0} sin( x_3)^{1.0} cos( x_3)^{1.0}   =0\\


   (m_2 /2 *r_3^2*2.0)       \dot{ x_2}^{2.0}      sin( x_3)^{1.0} cos( x_3)^{1.0}     +  
   (m_2 /2 *(-2*r_1*r_3)*1.0)  + -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0) ) \dot{ x_1}^{1.0} cos( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      cos( x_3)^{1.0}     +  
   (m_2 /2 *(2*r_1*r_3) *1.0)  + -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) \dot{ x_1}^{1.0} sin( x_1)^{1.0}           \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
   (m_2 /2 *(2*r_1*r_3) *(-1)*1.0)  + -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0) ) \dot{ x_1}^{1.0} cos( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{1.0} sin( x_3)^{1.0}     +  
   (-1*(-1*g*m_2*r_3)*(-1)*1.0)            sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) \dot{ x_1}^{2.0} cos( x_1)^{1.0}           sin( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *(-1)*1.0) ) \dot{ x_1}^{2.0} sin( x_1)^{1.0}      cos( x_2)^{1.0}      cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) \ddot { x_1}^{1.0} cos( x_1)^{1.0}      cos( x_2)^{1.0}      cos( x_3)^{1.0}     +  
  -1*( ( (m_2 /2 *(2*r_1*r_3) *1.0) *1.0) ) \ddot { x_1}^{1.0} sin( x_1)^{1.0}           sin( x_3)^{1.0}     +  
  0 + 0 + 0               +  
  0 + 0               +  
  0               +  
  -1*( ( (m_2 /2 *r_3^2*2.0) *1.0) )           \ddot { x_3}^{1.0}   =0


の3本の運動方程式が立ちます。

m1=1.0
m2=10
r1=1.0
r3=1.0
g=9.81

とすると

5.5 \dot{ x_1}^{2.0}               +  
  5.0      \dot{ x_2}^{2.0}      sin( x_3)^{2.0}     +  
  5.0           \dot{ x_3}^{2.0}     +  
  -10.0 \dot{ x_1}^{1.0} cos( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  10.0 \dot{ x_1}^{1.0} cos( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
  10.0 \dot{ x_1}^{1.0} sin( x_1)^{1.0}           \dot{ x_3}^{1.0} sin( x_3)^{1.0}     +  
  206.01000000000002               +  
  -107.91000000000001 cos( x_1)^{1.0}               +  
  -98.10000000000001           cos( x_3)^{1.0}   

運動方程式を導くと

  -107.91000000000001 sin( x_1)^{1.0}               +  
  -11.0 \ddot { x_1}^{1.0}               +  
  10.0 cos( x_1)^{1.0}      \dot{ x_2}^{2.0} cos( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  20.0 cos( x_1)^{1.0}      \dot{ x_2}^{1.0} sin( x_2)^{1.0}      \dot{ x_3}^{1.0} cos( x_3)^{1.0}     +  
  10.0 cos( x_1)^{1.0}      \ddot { x_2}^{1.0} sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  -10.0 sin( x_1)^{1.0}           \dot{ x_3}^{2.0} cos( x_3)^{1.0}     +  
  10.0 cos( x_1)^{1.0}      cos( x_2)^{1.0}      \dot{ x_3}^{2.0} sin( x_3)^{1.0}     +  
  -10.0 cos( x_1)^{1.0}      cos( x_2)^{1.0}      \ddot { x_3}^{1.0} cos( x_3)^{1.0}     +  
  -10.0 sin( x_1)^{1.0}           \ddot { x_3}^{1.0} sin( x_3)^{1.0}   =0\\

  -10.0 \dot{ x_1}^{2.0} sin( x_1)^{1.0}      sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  10.0 \ddot { x_1}^{1.0} cos( x_1)^{1.0}      sin( x_2)^{1.0}      sin( x_3)^{1.0}     +  
  -10.0      \ddot { x_2}^{1.0}      sin( x_3)^{2.0}     +  
  -20.0      \dot{ x_2}^{1.0}      \dot{ x_3}^{1.0} sin( x_3)^{1.0} cos( x_3)^{1.0}     =0\\


10.0      \dot{ x_2}^{2.0}      sin( x_3)^{1.0} cos( x_3)^{1.0}     +  
  -98.10000000000001           sin( x_3)^{1.0}     +  
  -10.0 \dot{ x_1}^{2.0} cos( x_1)^{1.0}           sin( x_3)^{1.0}     +  
  10.0 \dot{ x_1}^{2.0} sin( x_1)^{1.0}      cos( x_2)^{1.0}      cos( x_3)^{1.0}     +  
  -10.0 \ddot { x_1}^{1.0} cos( x_1)^{1.0}      cos( x_2)^{1.0}      cos( x_3)^{1.0}     +  
  -10.0 \ddot { x_1}^{1.0} sin( x_1)^{1.0}           sin( x_3)^{1.0}     +  
  -10.0           \ddot { x_3}^{1.0}    = 0

の3本の運動方程式が立ちます。
この方程式を用いてシミュレーションさせます。

シミュレーションコード(オイラー法)

速度から位置を  $r_{n+1}= r_{n} +v{n} *DT$
加速度から速度を $v_{n+1}= v_{n} +a{n} *DT$
更新することで、シミュレーションします。

# -*- coding: utf-8 -*-
"""
Created on Sat Mar 21 14:11:03 2020

@author: kisim
"""
import numpy as np      #   Numpyライブラリ
import copy
import math
#import matplotlib.pyplot as plt

import matplotlib
#matplotlib.use('Agg') # -----(1)
import matplotlib.pyplot as plt

import matplotlib.animation as animation
from matplotlib.animation import PillowWriter
'''
数式処理プログラム
列 : 多項式
行 : θ θ・ θ・・ sinθ cosθ 係数  
の6個 × 変数数


'''
class Formula :
    def __init__(self,L,num):
        self.L = L
        self.n = num                      #変数の種類数


    def __add__(self,other):
        self.L = np.append(self.L,other.L,axis =0)
        self.together()
        self.erase()

    def __sub__(self,other):
        expr,vari = other.L.shape
        hoge = copy.deepcopy(other.L)
        for i in range(expr):
            hoge[i][5] = hoge[i][5] * -1
        self.L = np.append(self.L,hoge,axis =0)
        self.together()
        self.erase()

    def together(self):               #同じ項の係数をまとめる
        expr,vari = self.L.shape
        if expr >=2:
            for i in range(expr-1):
                for j in range(i+1,expr):                    
                    m=0
                    while self.L[i][0+m*6:5+m*6].tolist() == self.L[j][0+m*6:5+m*6].tolist():
                        m += 1
                        if m == self.n:
                            break
                    if m== self.n:
                        self.L[i][5] += self.L[j][5]
                        for k in range(vari):
                            self.L[j][k] = 0

    def erase(self):    #係数が0の項を消す
        expr,vari = self.L.shape
        for i in list(reversed(range(expr))):
            if self.L[i][5] == 0:
                self.L = np.delete(self.L,i,axis = 0)

    def partial(self,moji,kind):  #kindの種類のもので項を偏微分する
        expr,vari = self.L.shape
        if kind == 0:   
            '''
            sin
            cos

            +moji*6
            '''
            #print self.L
            for i in range(expr):
                if self.L[i][3+moji*6] !=0:  #sin
                    hoge = copy.deepcopy(self.L[i])
                    hoge[5] = hoge[5]*hoge[3+moji*6]
                    hoge[3+moji*6] = hoge[3+moji*6]-1
                    hoge[4+moji*6] = hoge[4+moji*6]+1
                    self.L = np.append(self.L,hoge[np.newaxis,:],axis =0)
                    #print self.L
            for i in range(expr):
                if self.L[i][4+moji*6] !=0:  #cos
                    hoge = copy.deepcopy(self.L[i])
                    hoge[5] = hoge[5]*hoge[4+moji*6]*-1
                    hoge[4+moji*6]= hoge[4+moji*6]-1
                    hoge[3+moji*6] = hoge[3+moji*6]+1
                    self.L = np.append(self.L,hoge[np.newaxis,:],axis =0)
                    #print self.L
            '''
            そのままのもの
            次数を一つ下げる、0なら何もしない
            元の次数を係数に掛ける
            '''
            #print self.L
            for i in range(expr):
                if self.L[i][kind] !=0:
                    #print kind,self.L[i][5]
                    self.L[i][5] = self.L[i][5] * self.L[i][kind+moji*6]
                    #print self.L[i][5]
                    self.L[i][kind+moji*6] = self.L[i][kind+moji*6] -1
                else:
                    self.L[i][5] = 0   #含まないなら 0

        if kind == 1:   
            '''
            そのままのもの
            次数を一つ下げる、0なら何もしない
            元の次数を係数に掛ける
            '''
            for i in range(expr):
                if self.L[i][kind+moji*6] !=0:
                    self.L[i][5] = self.L[i][5] * self.L[i][kind+moji*6]
                    self.L[i][kind+moji*6] = self.L[i][kind+moji*6] -1

                else:
                    self.L[i][5] = 0   #含まないなら 0

        self.together()
        self.erase()

    def diff(self):  #時間微分
        '''
        4つのパターンで偏微分後
        θ・の次数を1上げる        
        '''
        L1=copy.deepcopy(self.L)

        for i in range(self.n):
            self.L =copy.deepcopy( L1)
            self.partial(i,0)
            expr,vari = self.L.shape
            #print expr
            #print self.L
            for j in range(expr):
                self.L[j][1+i*6] = self.L[j][1+i*6] + 1
            if i == 0:
                L2 = copy.deepcopy( self.L)
            else:
                L2 = np.append(L2,self.L,axis =0)

            self.L =copy.deepcopy( L1)         
            self.partial(i,1)
            expr,vari = self.L.shape
            for j in range(expr):
                self.L[j][2+i*6] += 1
            L2 = np.append(L2,self.L,axis =0)

        self.L = copy.deepcopy( L2)

        self.together()
        self.erase()

    def disp(self):  #多項式表示
        print "-------------------Formula--------------"
        expr,vari = self.L.shape
        for j in range(expr):
            hoge =""
            for i in range(self.n):
                hoge += str(self.L[j][5+i*6])
                hoge += " θ^"
                hoge += str(self.L[j][0+i*6])
                hoge += " θ・^"
                hoge += str(self.L[j][1+i*6])
                hoge += " θ・・^"
                hoge += str(self.L[j][2+i*6])
                hoge += " sin^"
                hoge += str(self.L[j][3+i*6])
                hoge += " cos^"
                hoge += str(self.L[j][4+i*6])
                hoge += "   "

            hoge += "  +  "
            print hoge

    def disp2(self):  #多項式表示
        print "-------------------Formula--------------"
        expr,vari = self.L.shape
        for j in range(expr):
            hoge =""
            for i in range(self.n):
                hoge += "["+str(i+1)+"  "
                if self.L[j][5]!= 0:
                    if i == 0:
                        hoge += str(self.L[j][5+i*6])
                    if self.L[j][0+i*6]!= 0:   
                        hoge += " θ^"
                        hoge += str(self.L[j][0+i*6])

                    if self.L[j][1+i*6]!= 0:
                        hoge += " θ・^"
                        hoge += str(self.L[j][1+i*6])

                    if self.L[j][2+i*6]!= 0:
                        hoge += " θ・・^"
                        hoge += str(self.L[j][2+i*6])

                    if self.L[j][3+i*6]!= 0:
                        hoge += " sin^"
                        hoge += str(self.L[j][3+i*6])

                    if self.L[j][4+i*6]!= 0:
                        hoge += " cos^"
                        hoge += str(self.L[j][4+i*6])

                    hoge += " ]  "

            hoge += "  +  "
            print hoge

    def latex(self):
        variable = " x"
        k=1
        print "-------------------Formula--------------"
        expr,vari = self.L.shape
        for j in range(expr):
            hoge =""
            for i in range(self.n):
                hoge += "  "
                if self.L[j][5]!= 0:
                    if i == 0:
                        hoge += str(self.L[j][5+i*6])
                    if self.L[j][0+i*6]!= 0:   
                        hoge += variable+"_"+str(i+k)+"^{"
                        hoge += str(self.L[j][0+i*6])+"}"

                    if self.L[j][1+i*6]!= 0:
                        hoge += " \dot{"+variable+"_"+str(i+k)+"}^{"
                        hoge += str(self.L[j][1+i*6])+"}"

                    if self.L[j][2+i*6]!= 0:
                        hoge += " \ddot {"+variable+"_"+str(i+k)+"}^{"
                        hoge += str(self.L[j][2+i*6])+"}"

                    if self.L[j][3+i*6]!= 0:
                        hoge += " sin("+variable+"_"+str(i+k)+")^{"
                        hoge += str(self.L[j][3+i*6])+"}"

                    if self.L[j][4+i*6]!= 0:
                        hoge += " cos("+variable+"_"+str(i+k)+")^{"
                        hoge += str(self.L[j][4+i*6])+"}"

                    hoge += "   "

            hoge += "  +  "
            print hoge

    def subst(self,x):            #代入 x ,x・の順に入れる
        vari =np.array(x).shape
        if vari[0] != self.n*2:
            print "cannot subst"
        else:
            '''
            行ベクトルを生成して
            dotでLと  をして、できたベクトルの全要素を足せばよい
            '''

            expr,vari = self.L.shape
            sum1 = 0
            hoge=0
            for j in range(expr):
                hoge=self.L[j][5]           #係数
                for i in range(self.n):

                    hoge = hoge*x[0+i*2]**self.L[j][0+i*6]                                hoge = hoge*x[1+i*2]**self.L[j][1+i*6]            #θ・
                    hoge = hoge*math.sin(x[0+i*2])**self.L[j][3+i*6]  #sin
                    hoge = hoge*math.cos(x[0+i*2])**self.L[j][4+i*6]  #cos


                sum1 += hoge

            return sum1

    def separete(self):              #2変数と考えて、 1 2 b の3つに分割する
        a1=np.asarray([[]])
        a2=np.asarray([[]])
        expr,vari = self.L.shape
        for j in range(expr)[::-1]:
            if self.L[j][2] == 1:
                if len(a1[0]) == 0:
                    a1=(self.L[j]) [np.newaxis,:]
                else:
                    a1 = np.append(a1,(self.L[j]) [np.newaxis,:],axis =0)
                self.L = np.delete(self.L,j,0)
                continue

            if self.L[j][8] == 1:
                if len(a2[0]) == 0:
                    a2=(self.L[j]) [np.newaxis,:]
                else:
                    a2 = np.append(a1,(self.L[j]) [np.newaxis,:],axis =0)
                self.L = np.delete(self.L,j,0)
                continue

        if len(a1[0]) == 0:
            a1 =np.asarray([ [0,0,0,0,0,0  ,0,0,0,0,0,0]])
        if len(a2[0]) == 0:
            a2 = np.asarray([[0,0,0,0,0,0  ,0,0,0,0,0,0]])
        L1 = Formula(a1,2)
        L2 = Formula(a2,2)
        return L1,L2

    def separete3(self):              #3変数と考えて、 1 2 3 b の 4 つに分割する
        a1=np.asarray([[]])
        a2=np.asarray([[]])
        a3=np.asarray([[]])
        expr,vari = self.L.shape
        for j in range(expr)[::-1]:

            print "a1"
            print a1.shape
            print "a3"
            print a3.shape
            print "a2"
            print a2.shape

            if self.L[j][2] == 1:
                if len(a1[0]) == 0:
                    a1=(self.L[j]) [np.newaxis,:]
                else:
                    a1 = np.append(a1,(self.L[j]) [np.newaxis,:],axis =0)
                self.L = np.delete(self.L,j,0)
                continue

            if self.L[j][8] == 1:
                if len(a2[0]) == 0:
                    a2=(self.L[j]) [np.newaxis,:]
                else:
                    a2 = np.append(a2,(self.L[j]) [np.newaxis,:],axis =0)
                self.L = np.delete(self.L,j,0)
                continue

            if self.L[j][14] == 1:
                if len(a3[0]) == 0:
                    a3=(self.L[j]) [np.newaxis,:]
                else:
                     a3 = np.append(a3,(self.L[j]) [np.newaxis,:],axis =0)
                self.L = np.delete(self.L,j,0)
                continue

        if len(a1[0]) == 0:
            a1 =np.asarray([ [0,0,0,0,0,0  ,0,0,0,0,0,0  ,0,0,0,0,0,0]])
        if len(a2[0]) == 0:
            a2 = np.asarray([[0,0,0,0,0,0  ,0,0,0,0,0,0  ,0,0,0,0,0,0]])
        if len(a3[0]) == 0:
            a3 = np.asarray([[0,0,0,0,0,0  ,0,0,0,0,0,0  ,0,0,0,0,0,0]])

        L1 = Formula(a1,3)
        L2 = Formula(a2,3)
        L3 = Formula(a3,3)
        return L1,L2,L3



#L= np.asarray([[7,2,3,4,5,6,     7,2,3,4,5,6]])
#L= np.asarray([[2,2,0,5,4,5],[2,2,0,5,4,5]])

'''
L1,L2 の二つしか 式がなく、変数も2つの場合で考えよう

式 ≒ 0  として、
θ・・の項のみ取り出し新しいインスタンス化
除かれた方をbとして[L1_b,L2_b]ベクトルを作る
θ・・の項は
[L1_1   L1_2
 L2_1   L2_2 ] というインスタンスの行列 A を考える

 L1_2 = L1の式の中の θ2・・の項
 θ・・ = A^-1 b を計算

 オイラー法の陽解法でθ・ θ も出てくる

 ここまでやってみよう

 L1_b,L1_1,L1_2 を生成する 方法を考える

'''

m1=1.0
m2=10
r1=1.0
r3=1.0
g=9.81

T1=np.array([[0,2,0,0,0,m1*r1**2 /2 + m2*r1**2/2,
             0,0,0,0,0,1,
             0,0,0,0,0,1]])
T2=np.array([[0,0,0,0,0,m2 /2 *r3**2 ,
             0,2,0,0,0,1,
             0,0,0,2,0,1]])
T3=np.array([[0,0,0,0,0,m2 /2 *r3**2 ,
             0,0,0,0,0,1,
             0,2,0,0,0,1]])
T4=np.array([[0,1,0,0,1,m2 /2 *(-2*r1*r3),
             0,1,0,1,0,1,
             0,0,0,1,0,1]])
T5=np.array([[0,1,0,0,1,m2 /2 *(2*r1*r3) ,
             0,0,0,0,1,1,
             0,1,0,0,1,1]])
T6=np.array([[0,1,0,1,0,m2 /2 *(2*r1*r3) ,
             0,0,0,0,0,1,
             0,1,0,1,0,1]])


print "T1"
T=Formula(T1,3)
T.disp2()

print "T2"
R=Formula(T2,3)
R.disp2()
T+R

print "T3"
R=Formula(T3,3)
R.disp2()
T+R

print "T4"
R=Formula(T4,3)
R.disp2()
T+R

print "T5"
R=Formula(T5,3)
R.disp2()
T+R

print "T6"
R=Formula(T6,3)
R.disp2()
T+R

print "T"
T.disp2()

U1=np.array([[0,0,0,0,0,g*(m1*r1+m2*(r1+r3)),
              0,0,0,0,0,1,
              0,0,0,0,0,1]])
U2=np.array([[0,0,0,0,1,-1*g*(m1*r1+m2*r1),
              0,0,0,0,0,1,
              0,0,0,0,0,1]])
U3=np.array([[0,0,0,0,0,-1*g*m2*r3,
              0,0,0,0,0,1,
              0,0,0,0,1,1]])
U = Formula(U1,3)
hoge = Formula(U2,3)
U+hoge
hoge = Formula(U3,3)
U+hoge
print "U"
U.disp2()
T1=copy.deepcopy(T)
T1+U
T-U
L=copy.deepcopy(T)

#ラグランジュ方程式の構築
Lt_1=copy.deepcopy(T)
Lt_2=copy.deepcopy(T)
Lt_1.partial(0,0)
Lt_2.partial(0,1)
Lt_2.diff()
Lt_1-Lt_2

Ls_1=copy.deepcopy(T)
Ls_2=copy.deepcopy(T)
Ls_1.partial(1,0)
Ls_2.partial(1,1)
Ls_1.disp2()
print "Ls_2"
Ls_2.disp2()
Ls_2.diff()
Ls_2.disp2()
Ls_1-Ls_2

Lr_1=copy.deepcopy(T)
Lr_2=copy.deepcopy(T)
Lr_1.partial(2,0)
Lr_2.partial(2,1)
Lr_2.diff()
Lr_1-Lr_2

L1t=copy.deepcopy(Lt_1)
L1t_1,L1t_2,L1t_3 = L1t.separete3()
L2t=copy.deepcopy(Ls_1)
L2t_1,L2t_2,L2t_3 = L2t.separete3()
L3t=copy.deepcopy(Lr_1)
L3t_1,L3t_2,L3t_3 = L3t.separete3()



'''
オイラー法による数値解法を行う
初期値設定
解法
表示
の3プロセスを実装する必要がある
'''


DT = 0.0001              #時刻
x=np.array([0.1,0,0.1,0,0.1,0])            #初期値
saveX = x
T=10
N=int(T/DT)                 #計算時間/DT

saveEnergy = np.asarray([T1.subst(x)])

for i in range(N):
    b1 = L1t.subst(x) * -1
    b2 = L2t.subst(x) * -1
    b3 = L3t.subst(x) * -1
    a11 = L1t_1.subst(x)
    a12 = L1t_2.subst(x)
    a13 = L1t_3.subst(x)
    a21 = L2t_1.subst(x)
    a22 = L2t_2.subst(x)
    a23 = L2t_3.subst(x)
    a31 = L3t_1.subst(x)
    a32 = L3t_2.subst(x)
    a33 = L3t_3.subst(x)
    B=np.array([b1,b2,b3])
    B=B.reshape([3,1])
    A=np.array([a11,a12,a13,a21,a22,a23,a31,a32,a33])
    A=A.reshape([3,3])

    hoge = np.linalg.det(A)
    if hoge == 0:
        #N=i
        #print "hoge = 0 break"
        Aneg = np.linalg.pinv(A)

    else:
        Aneg = np.linalg.inv(A)

    '''
    if hoge < 0.001:
        N=i
        print "hoge > 10000 break"
        break
    '''


    K = np.dot(Aneg,B)

    x2 =np.array( x ) + np.array( [ x[1] ,K[0][0] ,x[3], K[1][0], x[5] ,K[2][0]  ] ) * DT

    x = x2
    saveX = np.append(saveX,x, axis=0)

    Energy = T1.subst(x)
    saveEnergy = np.append(saveEnergy,[Energy], axis=0)


saveX = saveX.reshape([6,N+1],order ='F')
t=[float(i)*DT for i in range(N+1)]
t= np.asarray(t)




#点履歴
position_x1=r1*np.sin(saveX[0]) +r3*np.sin(saveX[4])*np.cos(saveX[2])
position_y1=r3*np.sin(saveX[4])*np.sin(saveX[2])
plt.figure(figsize=(28, 20))  # (width, height)
plt.rcParams["font.size"] = 25
plt.plot(position_x1,position_y1,label ="1")

plt.legend(fontsize = 25)

plt.savefig('Position_test.png')




#グラフ化
#z=np.sin(saveX[0])*R1+np.sin(saveX[2])*r2
plt.figure(figsize=(28, 20))  # (width, height)
plt.rcParams["font.size"] = 25
plt.xlim(0,T)
#plt.plot(t,z,label ="z")

plt.plot(t,saveX[0],label="x0")
plt.plot(t,saveX[1],label="dt x0")
plt.plot(t,saveX[2],label="x1")
plt.plot(t,saveX[3],label="dt x1")
plt.plot(t,saveX[4],label="x2")
plt.plot(t,saveX[5],label="dt x2")
plt.legend(fontsize = 25)

plt.savefig('Pendulum_test.png')

plt.figure(figsize=(28, 20))  # (width, height)
plt.rcParams["font.size"] = 25
plt.xlim(0,T)
#plt.plot(t,z,label ="z")

plt.plot(t,saveEnergy,label="Energy")
plt.legend(fontsize = 25)

plt.savefig('Energy_test.png')

こんな感じで、リサージュ曲線がかけます。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2