dersblog



Bir ODE Sistemi Sayısal Olarak Nasıl Çözülür

Yazıda scipy paketinin içindeki odeint çözücüyü işleyeceğiz. Sayısal çözümler önemli çünkü çoğu ODE sisteminin analitik çözümü yoktur. Onları sayısal paketler kullanarak çözmek gerekir.

Bir sarkaç denklemi düşünelim, bu denklem ikinci dereceden $\theta$'yi baz alan bir denklemdir,

$$ \ddot{\theta}(t) + \frac{b}{m} \dot{\theta}(t) + \frac{g}{L} \sin(\theta(t)) = 0 $$

Ya da $m = 1$ dersek ve $\frac{g}{L} = c$ ile

$$ \ddot{\theta}(t) + b \dot{\theta}(t) + c \sin(\theta(t)) = 0 $$

ki $b,c$ dışarıdan tanımlanan sabitler, ve üst nokta zamansal türevi temsil ediyor.

Bu denklemi odeint ile çözmek için onu ilk önce bir birinci derece denklemler sistemine çevirmemiz gerekiyor.

$$ \omega(t) = \dot{\theta}(t) $$

dersek (okunuş olarak $\omega$ omega, $\theta$ theta),

$$ \dot{\theta} = \omega(t) $$

$$ \dot{\omega}(t) = -b \omega(t) - c\sin(\theta(t)) $$

elde ederiz. Şimdi pend adlı bir fonksiyon tanımlayalım,

b = 0.25
c = 5.0

def pend(y, t):
    theta, omega = y
    return [omega, -b*omega - c*np.sin(theta)]

Bu fonksiyon ana ODE çözücünün denklemimiz hakkında bilgi aldığı nokta, y dizini içinde $\dot{\theta}$ ve $\dot{\omega}$ var, onları $y$ içinde aynen bu sırada almayı bekliyoruz ve yenilerini hesapladıktan sonra geri döndürürken de aynen bu sırada döndürüyoruz. Mesela döndürülen dizinde ilk öğe omega var, bu doğru, çünkü biraz önce $\dot{\theta} = \omega(t)$ tanımını yapmıştık, yani ilk öğede theta turevi geri vermiş olduk, alırken theta,omega=y ile theta aldığımız gibi.

t değişkeninde çoğunlukla zaman tanımlanır, ve bu zaman ilgilendiğimiz zaman aralığı belli (çoğunlukla eşit aralıklı) noktalar üzerinden dizin olarak odeint'e verilir, bunu linspace ile yapabiliriz. $y$ için başlangıç şartlarını ayrı bir değişken içinde, mesela y0, tanımlarız, bu aynen y büyüklüğünde bir dizin olacaktır ve y için olduğu gibi ilk öğe theta ikinci öğe omega için başlangıç değerini tanımlayacak.

Hepsi bir arada

from scipy.integrate import odeint

b = 0.25
c = 5.0

def pend(y, t):
    theta, omega = y
    return [omega, -b*omega - c*np.sin(theta)]

t = np.linspace(0, 10, 101)

y0 = [np.pi - 0.1, 0.0]

sol = odeint(pend, y0, t)

print (sol.shape)
(101, 2)

Başlangıç noktası $\theta$ için $\pi - 0.1$, yani şarkacın en üst noktasından biraz yanda. Açı olarak $\theta=0$ sarkacın nötr durduğu nokta, $\pi$ en üst noktası.

Sayısal çözüm sırasında bir dizi $\theta,\omega$ elde edildi. Bu değerler hesaplandıkları gibi zamansal sırada, bir dizin içindeler ve üstte gördüğümüz gibi 101,2 boyutlu bir dizin bu. En son varılan değer

print (sol[-1])
[0.02001168 1.56781812]

Degiskenleri grafiklersek

import matplotlib.pyplot as plt
plt.plot(t, sol[:, 0], 'b', label='theta(t)')
plt.plot(t, sol[:, 1], 'g', label='omega(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.savefig('ode_mattuck_70_odeint_01.png')

Şarkaçın hareketini görmek istiyorsak,

L = 9.8 / c
x1 = L*np.sin(sol[:,0])
y1 = -L*np.cos(sol[:,0])
from matplotlib.patches import Circle
import matplotlib.pyplot as plt
from numpy import cos, sin

def make_plot(fout,x1,y1):
    r = 0.05
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.set_xlim(-3,3)
    ax.set_ylim(-3,3)
    plt.plot([0, x1], [0, y1], lw=2, c='k')
    c0 = Circle((0, 0), r/2, fc='k', zorder=10)
    c1 = Circle((x1, y1), r, fc='b', ec='b', zorder=10)
    ax.add_patch(c0)
    ax.add_patch(c1)
    plt.savefig(fout)

for i in range(len(x1)):
    if i % 5 == 0: 
        make_plot('frames/img{:04d}.png'.format(i),x1[i],y1[i])

Animasyon yaratabiliriz,

! convert -loop 0 -delay 100 frames/*.png frames/pend.gif

Sonuç [2]'de görülebilir.

Not: Bir ODE sistemini çözmek hakkında konuşurken bazen onu "entegre ettiğimiz" de söylenir. Bu aslında yanlış bir tarif değil, çünkü eşitliklerin sol tarafında $\dot{x}_1$, $\dot{x}_2$ gibi değişkenler var, bizim ilgilendiğimiz, çözerek elde etmek istediğimiz sonuç $x_1$, $x_2$ değerleri. Aslında yapılanın bir bakıma sistemi "ileri doğru işletmek" olduğu da söylenebilir, değişim denklemlerini kullanarak sistemın simülasyonunu yapıyoruz bir bakıma.

Kaynaklar

[1] SciPy.org, scipy.integrate.odeint, https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.odeint.html

[2] Bayramlı, Sarkac Animasyonu, https://github.com/burakbayramli/classnotes/blob/master/ode/ode_mattuck_70_odeint/frames/pend.gif


Yukarı