4.5. Diferencijalne jednadžbe¶
4.5.1. Simboličko rješavanje¶
Python sympy funkcija koja traži analitička rješenja običnih diferencijalnih
jednadžbi je desolve()
. Riješimo pomoću nje jednadžbu gušenog harmoničkog
oscilatora
Prilikom definiranja diferencijalne jednadžbe treba eksplicitno deklarirati
simboličku nezavisnu varijablu (obično je to vrijeme t
) i nepoznatu
simboličku funkciju (ovdje je to y(t)
), pomoću opcije funkcije symbols
:
>>> from sympy import *
>>> t = symbols('t')
>>> y = symbols('y', cls=Function)
>>> gsol = dsolve(y(t).diff(t, t) + 2*y(t).diff(t) + 4*y(t), y(t)); gsol
Eq(y(t), (C1*sin(sqrt(3)*t) + C2*cos(sqrt(3)*t))*exp(-t))
Napomene:
- Kao što je kod običnih jednadžbi trebalo eksplicirati po kojoj varijabli se traži rješenje, tako se kod diferencijalnih specificira po kojoj funkciji se traži rješenje
- Rješenje je izraženo kao sympy jednadžba (objekt tipa
Eq
) i za pristup samoj funkciji možemo koristiti metodurhs
- Rješenje je općenito tj. uključuje nepoznate konstante ( \(C_1\) i \(C_2\)) koje treba odrediti iz početnih uvjeta. To je moguće npr. na slijedeći način
>>> C1, C2 = symbols('C1, C2')
>>> consts = linsolve([gsol.rhs.subs(t,0) - 1, gsol.rhs.diff(t).subs(t, 0) -1], C1, C2); consts
{(2*sqrt(3)/3, 1)}
Sad možemo ove konstante uvrstiti u rješenje. Prvo ćemo tupl koji je element jednočlanog skupa rješenja pretvoriti u rječnik:
>>> dics = [{C1:c1, C2:c2} for c1, c2 in consts]; dics
[{C2: 1, C1: 2*sqrt(3)/3}]
>>> sol = gsol.rhs.subs(dics[0]); sol
(2*sqrt(3)*sin(sqrt(3)*t)/3 + cos(sqrt(3)*t))*exp(-t)
To je sad konkretno rješenje koje možemo nacrtati npr kao
>>> plot(sol, (t, 0, 10))

Zadatak 1
Riješite simbolički diferencijalnu jednadžbu
uz početni uvjet \(y(0)=1/2\), provjerite rješenje uvrštavanjem, te ga nacrtajte za t u rasponu \(0<t<1\).
4.5.2. Numeričko rješavanje¶
Neke jednadžbe se ne mogu riješiti analitički, pa moramo pribjeći numeričkom
integriranju. Za to ćemo koristiti funkciju odeint
iz paketa scipy.integrate
.
>>> from scipy.integrate import odeint
>>> import matplotlib.pyplot as plt
>>> import numpy as np
Kao prvi primjer integrirati ćemo jednadžbu iz gornjeg zadatka. Za odeint
tu jednadžbu treba transformirati u oblik
i korisnik treba definirati Python funkciju koja odgovara desnoj strani ove jednadžbe.
U našem slučaju je \(f(y, t) = y^2 + 1\) pa stoga imamo
>>> def func(y, t):
... return y**2 + 1
Funkciju odeint
treba pozvati s ovom funkcijom kao prvim argumentom,
početnom vrijednošću \(y(0)\) kao drugim argumentom i listom vremenskih
točaka za koje želimo odrediti položaj sustava kao trećim argumentom:
>>> y0 = 0.5
>>> ts = np.linspace(0, 1)
>>> ts.shape
(50,)
Funkcija odeint
vraća listu položaja u traženim vremenskim točkama:
>>> ys = odeint(func, y0, ts)
>>> ys.shape
(50, 1)
>>> print("\n{:8s} {:8s}".format('vrijeme', 'položaj'))
>>> print(18*'-')
>>> for t,y in zip(ts[:5], ys[:5, 0]):
... print("{:8f} {:8f}".format(t, y))
>>> print("{:8s} {:8s}".format(' (...) ', ' (...) '))
vrijeme položaj
------------------
0.000000 0.500000
0.020408 0.525777
0.040816 0.552113
0.061224 0.579049
0.081633 0.606630
(...) (...)
plt.plot(ts, ys)

Kao slijedeći primjer proučiti ćemo tzv. van der Polovu jednadžbu, koja je drugog reda:
Jednadžbe višeg reda se za numeričku analizu treba prirediti tako da se svaka pretvori u sustav od dvije jednadžbe prvog reda, što se izvodi uvođenjem nove funkcije \(y(t)=dx/dt\) uz pomoć koje gornju jednadžbu možemo pretvoriti u ekvivalentni sustav
Taj sustav sad treba zapisati u vektorskom obliku tako da poprimi strukturu
gdje je dvokomponentni vektor \(\vec{y} = (x, y)\equiv\) [y[0], y[1]]
. Sada
funkcija koju priređujemo za odeint
opet odgovara desnoj strani ove
jednadžbe i mora kao rezultat vratiti dvokomponentni
vektor \(\vec{f} = (f_1, f_2)\)
>>> def func(y, t):
... return [y[1], (1 - y[0]**2)*y[1] - y[0]]
Početni uvjet je isto vektor \((x(0), y(0))\), a i rezultat će biti NumPy
polje oblika (broj vremenskih točaka) x (broj nepoznatih funkcija)
.
>>> ts = np.linspace(0,15,150)
>>> y0 = [1., 1.]
>>> ys = odeint(func, y0, ts)
>>> ys.shape
(150, 2)
>>> fig, ax = plt.subplots(figsize=[7,3])
>>> ax.plot(ts, ys[:,0], label='x(t)')
>>> ax.plot(ts, ys[:,1], label='y(t)')
>>> ax.legend()

Zadatak 2
Nacrtajte graf brzine gornjeg rješenja Van der Polove jednadžbe \(y(t)=dx(t)/dt\), ali ne u ovisnosti o vremenu \(t\), već o položaju \(x(t)\) (tzv. fazni dijagram).
Zadatak 3
Riješite numerički diferencijalnu jednadžbu gušenog harmoničkog oscilatora.
Nacrtajte funkcije y(t)
i x(t)
, te, na posebnom grafu,
fazni dijagram y(x)
.