GNU Octave/Numeryczne rozwiązywanie równań różniczkowych

Z testwiki
Przejdź do nawigacji Przejdź do wyszukiwania

Numeryczne rozwiązywanie równań różniczkowych zwyczajnych pierwszego rzędu

Rozwiązanie równania y=ax,y(0)=1,a=0.1, na przedziale [0,10]

Za pomocą funkcji lsode rozwiązać równania różniczkowe, tj. znaleźć funkcję y=y(x), taką, że:

  1. {y=ay,x[0,1],a=±0.1,±1,±100y(0)=1
  2. {y=y2,x[0,3]y(0)=1
  3. {y=yxsin(ax),x[0,20]y(0)=1

Rozwiązania powyższych równań można wyznaczyć symbolicznie, są to:

  1. y=eax
  2. y=11x
  3. y=e(sin(ax)axcos(ax))/a2, gdzie a=100
Rozwiązanie równania y=y2,y(0)=1, na przedziale [0, 0.99]

Zdefiniujmy funkcje, które występują w równaniach:

 function y=linfun(x)
    global a;
    y=a.*x;
 endfunction;

 function y=kwadfun(x)
    y=x.*x;
 endfunction;

 function y=mixfun(x,t)
    y=x.*t.*sin(t*100);
 endfunction;
Rozwiązanie równania y=yxsin(x) na przedziale [0,20]. Dosalismy fale o bardzo dużym nachyleniu i coraz większych amplitudach.

Rozwiążmy pierwsze równanie: Zadajemy wartość dla współczynnika a:

 global a;
 a=0.1;
 %Zadajemy przedział, na którym będziemy rozwiązywać równanie:
  t=[0:0.01:1];
 %Zadajemy warunek brzegowy w pierwszym punkcie czasowym <tt>t(1)</tt>, czyli w <tt>t=0</tt>:
  x0=1; 
 %Rozwiązujemy równanie:
  Z=lsode("linfun", x0, t);
 %Rysujemy rozwiązanie:
  plot(t,Z,"-r")

Podobnie rozwiązujemy drugie równanie:

 t=[0:0.01:0.99];
 x0=1;
 Z=lsode("kwadfun", x0, t);

Funkcja 1/(1x) wybucha w x=1.

Rozwiązujemy trzecie równanie:

 t=[0:0.01:20];
 x0=1;
 Z=lsode("mixfun", x0, t);
 axis([0, 20, 0, 2]);
 plot(t, Z, "-r");

Numeryczne rozwiązywanie równań różniczkowych zwyczajnych wyższych rzędów

Rozwiązać równanie różniczkowe 2. rzędu:

{x=f(x)=xx(0)=0x(0)=1

Równanie to można scałkować symbolicznie, a jego rozwiązaniem jest x(t)=sin(t).

Aby rozwiązać równanie numerycznie, przekształcimy je do równania pierwszego rzędu, w którym zmienna jest wektorem i rozwiążemy za pomocą funkcji lsode. Przekształcone równanie dla zmiennej x=[x1,x2]=[x(t),x(t)] ma postać:

{x1=x2x2=f(x1)=x1x1(0)=0x2(0)=1
Wykres rozwiązania [x,x] równania x=x z warunkami początkowymi x(0)=0, x(0)=1

Zdefiniujmy funkcję:

 function y=ujfun(x)
    y(1)= x(2);
    y(2)=-x(1);
 endfunction;
%Rozwiązujemy równanie <math>\overline{x}'=\texttt{ujfun}(\overline{x})</math>: 
 x0=[1;0];
 t=[0:0.005:100];
 Z=lsode("ujfun", x0, t);

Zauważmy, że warunek początkowy jest pionowym 2-elementowym pionowym wektorem [1;0]. Narysujmy wykres [x1,x2]:

 plot(Z(:,2),Z(:,1),"-r");

Wynikiem jest okrąg, czyli zbiór {[sin(t),cos(t)]:t[0,2π]}, co zgadza się z rozwiązaniem teoretycznym.

Numeryczne rozwiązywanie równań różniczkowych zwyczajnych z "odwróconym" warunkiem początkowym

Rozpatrzmy zagadnienie Cauchy'ego dla równania różniczkowego:

{x=f(x,t),x[0,1]x(0)=s

Równanie jest sparametryzowane parametrem s[0,1] i dla zadanej funkcji f. Oznaczmy ys(t) rozwiązanie równania dla ustalonego s. Dla jakiego s dostaniemy ys(1)=12? Innymi słowy, jeśli oznaczymy F(s)=ys(1) należy rozwiązać równanie:

F(s)=12

Jak wygląda potok ys(t) i wykres F(s)? Rozważmy funkcję f(y,t)=sin(y2+1)*y*(1y).

Wykres potoku dla zagadnienia Cauchy'ego dla równania różniczkowego x=sin(x2+1)x(1x) z warunkiem początkowym x(0)=s na przedziale t[0,1] parametryzowanego parametrem s[0,1]. Linia, która "kończy" się w (1,0.5) zaczyna się w przybliżeniu w (0,0.3).

Najpierw rozwiążemy szukane równanie. Zdefiniujmy funkcję występującą w równaniu:

 function y=dfun(x)
    y=sin(x.^2.+1).*x.*(1.0.-x);
 endfunction;

%Rozwiązujemy równanie dla zadanego parametru <math>s</math> na przedziale <math>[0,1]</math>:
 function y=dfunSolveODE(s)
    t=[0:0.01:1];
    y=lsode("dfun", s, t);
 endfunction;

%Rysujemy wykres funkcji <math>F(s)=y_s(1)=dfunsolve(s)</math>:
 s=[0:0.01:1];
 y=dfunSolveODE(s);
 plot(s,y);

%Rozwiązujemy równanie <math>F(s)-\frac{1}{2}=0</math>. Zdefiniujmy funkcję:
 function y=dfunMinusPol(s)
    z=dfunSolveODE(s);
    y=z(length(z))-0.5;
 endfunction;

% i znajdźmy jej [[w:miejsce zerowe|miejsce zerowe]]:
 fsolve("dfunMinusPol",0.3)
 ans = 0.28628

Numeryczne rozwiązywanie równań różniczkowych zwyczajnych z warunkami brzegowymi

Znaleźć funkcję u=u(t) spełniającą równanie różniczkowe z warunkami brzegowymi:

{u+u2=f(t)u(0)=0,u(1)=0

Dla funkcji f(t)=sin(t).

Aby rozwiązać to zagadnienie trzeba znaleźć taki parametr s0, żeby rozwiązanie zagadnienia

{u+u2=f(t)u(0)=0,u(0)=s0

spełniało zadany warunek brzegowy w drugim końcu przedziału, tj. u(1)=0. Można to zrobić metodą z "odwróconym" warunkiem początkowym, opisaną wcześniej. Przekształćmy zagadnienie na równanie pierwszego rzędu zmiennej [x1,x2]=[u(t),u(t)]:

{x1=x2x2=x12+f(t)x1(0)=0x2(0)=s0
Potok fazowy dla równania u+u2=sin(t) z warunkami początkowymi u(0)=0 i u(0)=s dla parametrów s[1,1].

Zdefiniujmy funkcje występujące w równaniu:

 function y=d1fun(x,t)
    y(1)=x(2);
    y(2)=-x(1)^2+d1funF(t);
 endfunction;
 function y=d1funF(t)
    y=sin(t);
 endfunction;

%Zdefiniujmy funkcję, która rozwiązuje równanie dla zadanego parametru:
 function y=d1funSolveODE(s)
    t=[0:0.01:1];
    x0=[0;s];
    y=lsode("d1fun", x0, t);
 endfunction;

Narysujmy potok fazowy dla tego równania dla wartości s0[1,1]. (Dokładniej: Funkcja d1funSolveODE działa poprawnie dla pojedynczej wartości parametru s. Aby wywołać rysowanie tak, jak poniżej, trzeba lekko zmienić jej treść).

 s=[-1:0.03:1];
 y=d1funSolveODE(s);
 plot(t,y);

Widzimy, że szukana krzywa przechodząca przez punkty (0,0) oraz (1,0) ma w t=0 nachylenie bliskie 0.

Rozwiązanie równania u+u2=sin(t) z warunkami brzegowymi u(0)=0 i u(1)=0.

Wyznaczymy teraz tę wartość dokładnie. Zdefiniujmy funkcję us(1)

 function y=d1funFunIn1(s)
    z=d1funSolveODE(s);
    w=z(:,1);
    y=w(length(w));
 endfunction;
% i rozwiążmy równanie:
 s0=fsolve("d1funFunIn1", 0)

%Dostajemy wartość: 
 s0 = -0.15769

%Rysujemy rozwiązanie:
 z=d1funSolveODE(s0);
 plot(t, z(:,1);

Rozwiązanie rzeczywiście przechodzi przez punkty (0,0) i (1,0).


Szablon:Nawigacja