numryh.mws
Esimerkit : Numeerinen ratkaiseminen

Differentiaaliyhtälöryhmä

Ensimmäisen kertaluvun differentiaaliyhtälöryhmä — vaikkapa korkeamman kertaluvun yhtälöä vastaava normaaliryhmä — voidaan ratkaista numeerisesti täsmälleen samanlaisilla kaavoilla kuin ensimmäisen kertaluvun yhtälö y ' = f( x , y ). Edellytyksenä luonnollisesti on, että alkuehto on annettu.

Seuraavat koodit ovat täsmälleen samat kuin ensimmäisen kertaluvun yhtälöä koskevassa esimerkissä. (Solut on ajettava, jotta määritelmät tulevat voimaan.)

> restart;

> eulernum:=proc(f, x0, y0, h, xend)
local kend, x, y, i;
kend:= round((xend-x0)/h);
x[0]:= x0;
y[0]:= y0;
for i from 1 to kend do
x[i]:= x[i-1]+h;
y[i]:= y[i-1]+h*f(x[i-1], y[i-1]);
od;
return [seq([x[k], y[k]], k=0..kend)];
end:

> pareuler:= proc(f, x0, y0, h, xend)
local kend, x, y, i;
kend:= round((xend-x0)/h);
x[0]:= x0;
y[0]:= y0;
for i from 1 to kend do
x[i]:= x[i-1]+h;
y[i]:= y[i-1]+
h/2*(f(x[i-1],y[i-1])+
f(x[i],y[i-1]+h*f(x[i-1], y[i-1])));
od;
return [seq([x[k], y[k]], k=0..kend)];
end:

> rungekutta:= proc(f, x0, y0, h, xend)
local kend, x, y, i, k1, k2, k3, k4;
kend:= round((xend-x0)/h);
x[0]:= x0;
y[0]:= y0;
for i from 1 to kend do
x[i]:= x[i-1]+h;
k1:= h*f(x[i-1], y[i-1]);
k2:= h*f(x[i-1]+h/2, y[i-1]+k1/2);
k3:= h*f(x[i-1]+h/2, y[i-1]+k2/2);
k4:= h*f(x[i-1]+h, y[i-1]+k3);
y[i]:= y[i-1]+1/6*(k1+2*k2+2*k3+k4);
od;
return [seq([x[k], y[k]], k=0..kend)];
end:

> adamsbashforth:= proc(f, x0, y0, h, xend)
local kend, x, y, i, k1, k2, k3, k4;
kend:= round((xend-x0)/h);
x[0]:= x0;
y[0]:= y0;
for i from 1 to 3 do
x[i]:= x[i-1]+h;
k1:= h*f(x[i-1], y[i-1]);
k2:= h*f(x[i-1]+h/2, y[i-1]+k1/2);
k3:= h*f(x[i-1]+h/2, y[i-1]+k2/2);
k4:= h*f(x[i-1]+h, y[i-1]+k3);
y[i]:= y[i-1]+1/6*(k1+2*k2+2*k3+k4);
od;
for i from 4 to kend do
x[i]:= x[i-1]+h;
y[i]:= y[i-1]+h/24*(
55*f(x[i-1], y[i-1])-
59*f(x[i-2], y[i-2])+
37*f(x[i-3], y[i-3])-
9*f(x[i-4], y[i-4]))
od;
return [seq([x[k], y[k]], k=0..kend)];
end:

Esimerkkinä olkoon differentiaaliyhtälö x '' + xy = 0 alkuehtona y (0) = 0, y '(0) = 1 . Kyseessä on Airyn yhtälö, jossa x-akselin suunta on käännetty, ts. x :n merkki on vaihdettu. Yhtälöä vastaava normaaliryhmä muodostuu kahdesta yhtälöstä y ' = z , z ' = - xy alkuehtona y (0) = 0, z (0) = 1. Vektorimuodossa normaaliryhmä on Y ' = F( x , Y ); oikean puolen vektoriarvoinen funktio määritellään Maple lle seuraavasti:

> f:= unapply([Y[2], -x*Y[1]], x, Y);

f := proc (x, Y) options operator, arrow; [Y[2], -x...

Askelpituus ja arvo, jolla alkuehto annetaan:

> h:= 0.1;

h := .1

> x0:= 0;

x0 := 0

Tuntemattomana funktiona on vektori Y = ( y , z ), joten alkuarvo on myös vektori:

> y0:= [0,1];

y0 := [0, 1]

Lasketaan välillä [0, 10]:

> xend:= 10;

xend := 10

Ratkaisufunktion approksimaatio jokaisessa pisteessä x[k] saadaan kaksikomponenttisena vektorina. Edellinen komponentti on itse funktion y arvo, jälkimmäinen sen derivaatan z = y ' arvo:

> eulerdata:= eulernum(f, x0, y0, h, xend):

Muuttujaan eulerdata talletettu tulostus on huomattavan pitkä.

Tästä voidaan poimia vain argumentin x ja funktion y arvot indeksoimalla, minkä jälkeen voidaan piirtää kuva:

> poiminta:= [seq([eulerdata[k][1], eulerdata[k][2][1]], k=1..xend/h+1)]:

> eulerkuva:= plot(poiminta, style=point):
eulerkuva;

[Maple Plot]

Vastaavat laskut muita menetelmiä käyttäen:

> pareulerdata:= pareuler(f, x0, y0, h, xend):

> poiminta:= [seq([pareulerdata[k][1], pareulerdata[k][2][1]], k=1..xend/h+1)]:

> pareulerkuva:= plot(poiminta, style=point):
pareulerkuva;

[Maple Plot]

> rungekuttadata:= rungekutta(f, x0, y0, h, xend):

> poiminta:=[seq([rungekuttadata[k][1], rungekuttadata[k][2][1]], k=1..xend/h+1)]:

> rungekuttakuva:= plot(poiminta, style=point):
rungekuttakuva;

[Maple Plot]

> adamsbashforthdata:= adamsbashforth(f, x0, y0, h, xend):

> poiminta:= [seq([adamsbashforthdata[k][1], adamsbashforthdata[k][2][1]], k=1..xend/h+1)]:

> adamsbashforthkuva:= plot(poiminta, style=point):
adamsbashforthkuva;

[Maple Plot]

Esimerkkinä oleva alkuarvoprobleema voidaan ratkaista myös tarkasti Airyn funktioiden avulla.

> dyht:= diff(y(x), x, x)+x*y(x)=0 ;

dyht := diff(y(x),`$`(x,2))+x*y(x) = 0

> tarkkaratkaisu:= dsolve({dyht, y(0)=0, D(y)(0)=1}, y(x));

tarkkaratkaisu := y(x) = -1/3*Pi*3^(1/3)*AiryBi(-x)...

> tarkkakuva:= plot(rhs(tarkkaratkaisu), x=0..xend):
tarkkakuva;

[Maple Plot]

Eri menetelmillä saadut approksimaatiot ja tarkka ratkaisu verrattuina:

> with(plots):

Warning, the name changecoords has been redefined

> display(eulerkuva, pareulerkuva, rungekuttakuva, adamsbashforthkuva, tarkkakuva);

[Maple Plot]

Tarkan ratkaisun tarkkuus riippuu luonnollisesti siitä, miten Maple laskee ratkaisussa esiintyvien Airyn funktioiden ja gammafunktion arvot.

Vertailun vuoksi alkuarvoprobleema voidaan ratkaista myös
Maple n käyttämällä numeerisen ratkaisemisen algoritmilla, joka edellä esitettyjä menetelmiä kehittyneempi:

> numeerinenratkaisu:= dsolve({dyht, y(0)=0, D(y)(0)=1}, y(x));

numeerinenratkaisu := proc (rkf45_x) local i, rkf45...

Tulos on ratkaisua approksimoiva proseduuri, jonka arvo välin päätepisteessä voidaan laskea tavalliseen tapaan. Eri ratkaisujen antamat arvot loppupisteessä :

> eulerdata[-1][2][1],
pareulerdata[-1][2][1],
rungekuttadata[-1][2][1],
adamsbashforthdata[-1][2][1],
evalf(subs(x=xend, rhs(tarkkaratkaisu))),
subs(numeerinenratkaisu(xend), y(x));

7.325357344, .3173048438, .4290569759, .4331992818,...
7.325357344, .3173048438, .4290569759, .4331992818,...


Teoria: korkeamman kertaluvun yhtälön numeerinen ratkaiseminen
Ratkaiseminen: Eulerin menetelmä
Ratkaiseminen: parannettu Eulerin menetelmä
Ratkaiseminen: Rungen – Kuttan menetelmä
Ratkaiseminen: Adamsin – Bashforthin menetelmä
Teoria: normaaliryhmä

SKK & MS 31.05.2001