Klasyczne modele oparte na równaniach różniczkowych zwyczajnych zakładają, że w danej chwili reakcja systemu (zmiana wartości) jest natychmiastowa i zależy od jej wartości w tym momencie (czyli, że . Jednak bywają sytuacje, kiedy takie założenie jest nierealistyczne i należy uwzględnić fakt, iż — wskutek swego rodzaju bezwładności układu — wartość pochodnej rozwiązania może zależeć nie tylko od jego bieżącej kondycji, lecz również od wartości z chwil wcześniejszych. W pierwszym przybliżeniu taka koncepcja prowadzi to do tzw. równań różniczkowych ze stałym opóźnieniem :
Pakiet OdePkg, rozszerzający możliwości Octave i dostępny w Octave-Forge [20], zawiera w sobie kilka solverów równań różniczkowych ze stałym opóźnieniem . Drobną ich wadą jest to, że dopuszczają jedynie stały warunek początkowy (w równaniach z opóźnieniem warunek początkowy musi być zadany nie w jednym punkcie, ale na odcinku, . Wszystkie solvery wykorzystują tzw. włożone jawne metody Rungego–Kutty, od metody niskiego rzędu ode23d
, po metodę wysokiego rzędu ode78d
. Warto pamiętać, że w przypadku równań z opóźnieniem rozwiązania mogą nie być zbyt gładkie i wówczas korzystniej może być stosować schemat niższego rzędu.
Sposób wykorzystania pakietu jest bardzo dokładnie opisany w [25], na którym, jak się wydaje, opiera się zestaw solverów z OdePkg. My ograniczymy się do krótkiego omówienia sposobu rozwiązania jednego z najprostszych równań.
Rozważmy równanie postaci
(9.1) | ||||
(9.2) |
Jest to tzw.równanie logistyczne z opóźnieniem. Dodatni współczynnik jest bardzo istotnym parametrem. Okazuje się bowiem, że gdy , to — dla dostatecznie długich czasów — rozwiązania (9.1) stabilizują się na poziomie , natomiast dla rozwiązania wpadają w niegasnące, regularne oscylacje. Więcej na temat logistycznego równania z opóźnieniem można dowiedzieć się z wykładu Modelowanie matematyczne w biologii i medycynie.
Zacznijmy od zapisania skryptu, rozwiązującego nasze równanie dla wartości parametru równych , na przedziale czasowym długości (dostatecznie długim, byśmy zaobserwowali prawdopodobną tendencję rozwiązania).
global a; lag = 1; T = 100; % parametry solvera opts = odeset ('Stats', 'on', ... 'RelTol', 1e-4, ... % tolerancja bledu wzglednego 'AbsTol', 1e-4, ... % tolerancja bledu bezwzglednego 'InitialStep', 1e-5, ... % poczatkowy krok schematu 'MaxStep', 1e-2); % przy okazji steruje liczba punktow probkowania rozwiazania filename = 'logdel'; for a = [0.1, pi/2 - 0.1, pi/2 + 0.1] sol = ode23d(@logdelf, [0,T], 0.2, lag, 0.2, opts); t = sol.x; Y = sol.y; sol.stats Ylag = interp1(t,Y,t-lag,'cubic'); % rozwiazanie opoznione Ydot = logdelf(t,Y,Ylag); % pochodna rozwiazania plot(t,Y); xlabel('t'); ylabel('y(t)'); title('Rozwiazanie y(t)'); print('-depsc', strcat(filename, '-a-', ... strrep(num2str(a,'%g'),'.','p'), '.eps') ) pause(1); plot(Y,Ydot); xlabel('y(t)'); ylabel('y''(t)'); title('Wykres fazowy'); print('-depsc', strcat(filename, '-a-', ... strrep(num2str(a,'%g'),'.','p'), '-phase.eps') ) pause(1); end
Kluczowa jest linijka
sol = ode23d(@logdelf, [0,T], 0.2, lag, 0.2, opts);
która w rzeczywistości rozwiązuje nasze równanie. Parametrami funkcji
ode23d
są kolejno:
funkcja określająca prawą stronę23Funkcja musi być przekazana jako wskaźnik, a nie jako nazwa! (u nas jest
to logdelf
), do której parametr a
przekazujemy z przyzwyczajenia za
pomocą zmiennej globalnej24W rzeczywistości funkcje z pakietu OdePkg umożliwiają wygodne przekazywanie listy dodatkowych parametrów do wnętrza funkcji prawej strony.),
przedział czasowy, na którym wyznaczamy rozwiązanie, tutaj: ,
warunek początkowy,
wartości opóźnień (u nas jest tylko jedno, bo równanie jest skalarne) lag
= 1), no i ewentualnie
struktura, zmieniająca domyślne parametry pracy solvera.
function ydot = logdelf(t,y,ylag) global a; ydot = (a - ylag).*y; end
W odróżnieniu od lsode
, ode23d
zwraca wartości rozwiązania w
przez siebie wyznaczonych punktach przedziału . Aby więc określić jego
wartość w zadanych przez nas punktach,
t = linspace(0,T,10*T);musimy interpolować wartości; warto także wcześniej zadać w opcjach maksymalną długość kroku, która zagwarantuje nam wystarczającą rozdzielczość próbkowania; dla danych opóźnionych, a następnie wyznacz
Ylag = interp1(t,Y,t-lag,'cubic'); % rozwiązanie opóźnione Ydot = logdelf(t,Y,Ylag); % pochodna rozwiązania
która zwraca nam wartości obliczonego przybliżenia rozwiązania (i jego pochodnej!) w punktach . Potem wystarczy je tylko narysować, komendami
plot(t, Y); plot(Y, Ydot);
— najpierw rozwiązanie w zależności od czasu, potem — wykres fazowy.
Wyniki, które, przynajmniej w sposób jakościowy, zgadzają się z przewidywaniami teoretycznymi, przedstawiają poniższe wykresy.
Aby nabrać więcej przekonania do ilościowych wyników, zobaczymy, czy stukrotne zmniejszenie parametrów tolerancji błędu spowoduje wyraźną zmianę uzyskanych wartości rozwiązania. Sprawdzenie przeprowadzimy dla parametru .
Najpierw wyznaczymy w standardowy sposób wartości rozwiązania w interesujących nas punktach:
a = pi/2 + 0.1; opts = odeset ('Stats', 'on', ... 'RelTol', 1e-4, ... % tolerancja błędu względnego 'AbsTol', 1e-4, ... % tolerancja błędu bezwzględnego 'InitialStep', 1e-5, ... % początkowy krok schematu 'MaxStep', 1e-2); % przy okazji steruje liczbą punktów próbkowania sol = ode23d(@logdelf, [0,T], 0.2, lag, 0.2, opts); t = sol.x; Y = sol.y; sol.statsa następnie powtórzymy obliczenia dla ostrzejszych kryteriów:
opts = odeset ('Stats', 'on', ... 'RelTol', 1e-6, ... % tolerancja błędu względnego 'AbsTol', 1e-6, ... % tolerancja błędu bezwzględnego 'InitialStep', 1e-7, ... % początkowy krok schematu 'MaxStep', 1e-2); % przy okazji steruje liczbą punktów próbkowania sol = ode23d(@logdelf, [0,T], 0.2, lag, 0.2, opts); tref = sol.x; Yref = sol.y; sol.statsJednak kłopot w tym, że — w przeciwieństwie do
lsode
— funkcja ode23d
zwraca rozwiązanie nie we wskazanych przez nas wartościach , ale raczej zwraca wszystkie wyznaczone przez siebie wartości, co oznacza, że dla różnych parametrów wywołania solvera prawie na pewno dostaniemy inny zestaw sol.x
.
Dlatego musimy napierw sprowadzić wyznaczone wartości do wspólnego zestawu chwil czasowych . Wydaje się rozsądne, by za ten bazowy zestaw wziąć po prostu t
— wartości wyznaczone przy mniej restrykcyjnych parametrach pracy solvera. Następnie, musimy interpolować25To może wprowadzić dodatkowe zaburzenia w wynikach, więc musimy być czujni! wartości (tref
,Yref
) na t
, do czego idealnie nadaje się funkcja interp1
.
Yreft = interp1(tref, Yref, t);
Następnie sprawdzamy, jak bardzo różnią się rozwiązania Y
i Yref
:
octave:> norm(Yreft-Y, Inf) ans = 4.8362e-06 octave:> semilogy(abs(Yreft-Y));
A więc maksymalna różnica pomiędzy rozwiązaniami wynosi jedynie około , co jest raczej uspokajającą wiadomością (choć należałoby jeszcze wykluczyć na przykład zjawisko aliasingu, które mocno dało się nam we znaki, gdy rozwiązywaliśmy zadanie o transformatorze, z rozdziału 6).
Potwierdź eksperymentalnie, że właśnie dla następuje zmiana długoterminowego charakteru rozwiązań, z gasnących do zera, na oscylacyjne.
Napisz funkcję, pozwalającą rozwiązać równanie logistyczne z opóźnieniem o zadanych parametrach i jednocześnie od razu zweryfikować w opisany powyżej sposób jakość rozwiązania. Zadbaj o komunikaty i wizualizacje dla niecierpliwego użytkownika. Następnie sprawdź pozostałe uzyskane powyżej wyniki.
Napisz skrypt Octave lub MATLABa, rozwiązujący inną wersję równania logistycznego z opóźnieniem, pochodzącą z pewnego modelu wzrostu nowotworu u myszy [4]:
Dodatnie współczynniki i są parametrami modelu. Zweryfikuj jakość uzyskanych aproksymacji rozwiązania i jego pochodnej w przypadku, gdy , , a opóźnienie wynosi . Jako funkcję początkową przyjmij stałą równą .
Treść automatycznie generowana z plików źródłowych LaTeXa za pomocą oprogramowania wykorzystującego LaTeXML.
strona główna | webmaster | o portalu | pomoc
© Wydział Matematyki, Informatyki i Mechaniki UW, 2009-2010. Niniejsze materiały są udostępnione bezpłatnie na licencji Creative Commons Uznanie autorstwa-Użycie niekomercyjne-Bez utworów zależnych 3.0 Polska.
Projekt współfinansowany przez Unię Europejską w ramach Europejskiego Funduszu Społecznego.
Projekt współfinansowany przez Ministerstwo Nauki i Szkolnictwa Wyższego i przez Uniwersytet Warszawski.