Obliczenia z użyciem programu MATLAB

Transkrypt

Obliczenia z użyciem programu MATLAB
Obliczenia z użyciem
programu MATLAB
Skrypt powstał w ramach prac Centrum Korepetycji
Koła Naukowego Studentów Politechniki „Gambrinus”.
www.gambrinus.pwr.wroc.pl
Autorzy:
Karol Białowąs – rozdziały 1,2,4,7
Anna Borowska – rozdział 3
Paweł Góra – rozdział 5
Natalia Gemza - rozdział 6
Spis treści:
1. Podstawy, proste obliczenia .......................................................................
1
1.1 Interfejs ........................................................................................................ 1
1.2 Proste obliczenia .......................................................................................... 2
1.3 Wbudowane funkcje .................................................................................... 2
1.4 Zmienne ....................................................................................................... 3
1.5 Przydatne polecenia ..................................................................................... 4
1.6 Przenoszenie danych z arkusza kalkulacyjnego do Matlaba ....................... 5
2. Macierze i wektory .....................................................................................
6
2.1 Sposoby definiowania macierzy i wektorów ............................................... 6
2.2 Dostęp do elementów macierzy/wektorów .................................................. 7
2.3 Operacje na wybranym wierszu/kolumnie ................................................... 9
2.4 Podstawowe operacje rachunku macierzy ................................................... 10
2.5 Rozwiązywanie układów równań liniowych metodą macierzy odwrotnej .. 11
3. Wielomiany ................................................................................................
12
3.1 Obliczanie wartości wielomianu (polyval) .................................................. 12
3.2 Obliczanie pierwiastków wielomianu (roots) .............................................. 12
3.3 Mnożenie i dzielenie wielomianów (conv i deconv) ................................... 13
3.4 Pochodna wielomianu (polyder) .................................................................. 13
3.5 Aproksymacja wielomianowa (polyfit) ....................................................... 14
4. Funkcje i skrypty ........................................................................................
15
4.1 Skrypty ........................................................................................................ 15
4.2 Funkcje ........................................................................................................ 17
4.3 Zmienne globalne ........................................................................................ 21
4.4 Funkcja jako argument innej funkcji ........................................................... 22
4.5 Znajdowanie miejsc zerowych dowolnej funkcji (fzero) ............................ 23
5. Pętle i instrukcje warunkowe .....................................................................
25
5.1 Pętla for ....................................................................................................... 25
5.2 Pętla while ................................................................................................... 26
5.3 Instrukcja warunkowa if .............................................................................. 28
6. Grafika w Matlabie ....................................................................................
6.1 Funkcja plot ................................................................................................. 31
6.2 Edycja wykresu ............................................................................................ 31
31
6.3 Hold on ........................................................................................................ 35
6.4 Subplot ......................................................................................................... 36
6.5 Interpolacja .................................................................................................. 37
6.6 Funkcja fplot ................................................................................................ 38
7. Całkowanie ................................................................................................
7.1 Funkcja trapz ............................................................................................... 40
7.2 Funkcja ode45 ............................................................................................. 42
7.3 Funkcja ode45 – całkowanie układów równań ........................................... 45
7.4 Zdarzenia (Events) ...................................................................................... 46
40
1. Podstawy, proste obliczenia
Matlab to zaawansowane środowisko do obliczeń matematycznych. Udostępnia ogromną ilość
specjalistycznych funkcji oraz język skryptowy pozwalający nawet tworzyć programy z GUI
(graficznym interfejsem użytkownika). W kursie tym postaramy się przybliżyć niewielką część
najpotrzebniejszych inżynierowi – chemikowi funkcji programu.
1.1 Interfejs
Zacznijmy od przyjrzenia się interfejsowi.
Okno po uruchomieniu programu Matlab.
Elementy, które będą nas interesować wyróżniono czerwonym kolorem.
1 – przycisk uruchamiający edytor M-plików
2 – przycisk uruchamiający Simulink
3 – Command Window
4 – okno Workspace
O dwóch pierwszych pozycjach więcej powiemy w dalszych częściach kursu. Na razie korzystać
będziemy jedynie z:
●
Command Window – okno, w którym możemy bezpośrednio wpisywać polecenia i w
którym zobaczymy wyniki ich wykonania
●
Workspace – w tym oknie znajdują się zmienne utworzone w czasie aktualnej sesji
1
1.2 Proste obliczenia
Pierwsza operacja jaką wykonamy to zwykłe dodawanie. Wpiszmy w oknie Command Window:
>> 3+2
i wciśnijmy enter. Powinniśmy zobaczyć następujący wynik:
>> 3+2
ans =
5
>>
Zwróć uwagę, że w oknie Workspace pojawiła się zmienna o nazwie ans i wartości 5. Do zmiennej
tej będziemy mogli się później odwoływać. Analogicznie możemy obliczać wartości wszystkich
innych wyrażeń algebraicznych. Spróbuj teraz samodzielnie wykonać następujące operacje i
sprawdź ich wyniki:
3-2
3*2
3/2
3^2
Ostatnia z tych operacji to podnoszenie do potęgi. Spróbujmy teraz obliczyć wartość nieco bardziej
skomplikowanego wyrażenia:
2.3∗e 3.46∗10−3
1.23−3  4.2
>> (2.3*exp(3.4) + 6e-3)/(1.23 - 3*sqrt(4.2))
ans =
-14.0140
Zauważ, że w Matlabie mozesz stosować nawiasy. Kolejność wykonywania działań jest
standardowa, tj. potęgowanie, następnie mnożenie/dzielenie itd., z uwględnieniem nawiasów. W
przykładzie tym zwróć uwagę na to jak zapisano wyrażenie 6*10-3 - 6e-3. Jest to tak zwany zapis
wykładniczy. Warto pamiętać że liczby można w matlabie zapisywać właśnie w ten sposób.
1.3 Wbudowane funkcje
Kolejna istotna rzecz pokazana w tym przykładzie to funkcje.
exp(3.4) oraz sqrt(4.2)
Łatwo domyślić się co one oznaczają – exp to funkcja eksponent czyli „e do x” a sqrt to pierwiastek
kwadratowy z liczby. Matlab udostępnia jeszcze wiele funkcji. Kilkanaście często używanych
zebrano w tabeli poniżej.
Funkcja
Co oblicza:
exp(x)
e^x
sqrt(x)
Pierwiastek kwadratowy
log(x)
Logarytm naturalny
2
log10(x)
Logarytm dziesiętny
abs(x)
Wartość bezwzględna
sin(x), cos(x), tan(x)
Wartości funkcji trygonometrycznych (x – w radianach)
asin(x), acos(x, atan(x) Funkcje cyklometryczne, wynik w radianach
deg2rad(x), rad2deg(x) Przeliczanie odpowiednio stopni na radiany (deg2rad) i radianów na
stopnie(rad2deg)
sinh(x),cosh(x),tanh(x) Funkcje hiperboliczne
mod(x,y)
Reszta z dzielenia x przez y
round(x)
Zaokrąglanie do liczby całkowitej
floor(x)
Zaokrąglanie do najbliższej liczby całkowitej w górę
ceil(x)
Zaokrąglanie do najbliższej liczby całkowitej w dół
sum(X)
Oblicza sumę wszystkich elementów macierzy/wektora
min(X), max(X)
Wartość najmniejszego/największego elementu macierzy/wektora
Spróbuj wykonać kilka działań używając każdej z tych funkcji. W jednym z kolejnych rozdziałów
nauczysz się także pisać własne funkcje.
1.4 Zmienne
Podczas obliczeń w Matlabie możemy również wykorzystywać zmienne. Oto przykład ich użycia:
>> a=3
a =
3
>> b=2
b =
2
>> a+b
ans =
5
>> c=log(a)
c =
1.0986
>> d=b^c
d =
2.1415
Zmienne pozwalają zapamiętywać wartości pod postacią różnych symboli. Nie muszą to być
pojedyncze litery, mogą to być praktycznie dowolne ciągi znaków – ważne żeby znaki w nazwie
nie były rozdzielone spacją. Po wykonaniu powyższego ciągu poleceń przyjrzyj się zawartości okna
Workspace. Powinny się w nim pojawić nazwy i wartości naszych zmiennych.
Ze zmiennych będziemy korzystać do samego końca kursu zatem jeszcze zdążysz się z nimi
oswoić. Na razie przydadzą Ci się one jedynie podczas wykonywania dłuższych ciągów obliczeń,
gdy z danej wartości musisz skorzystać wielokrotnie. Zmienne przydadzą Ci się również podczas
obliczania skomplikowanych wyrażeń. Czasem łatwiej rozbić takie wyrażenie na kilka części i
każdą z nich obliczyć oddzielnie – w krotkich wzorach łatwiej uniknąć błędu. Oto prosty przykład
wykorzystania zmiennych w tym właśnie celu:
3
Spróbujmy obliczyć wartość wyrażenia:

3e2.1
2⋅
⋅
2−ln 2.8
  
2
3
2⋅sin 
2
⋅e
2
3.2⋅ln 2.2
3
2⋅sin 
2
2
>> a=(3+exp(2.1))/(2-log(2.8))
a =
11.5070
>> b=(2*sin(3/2*pi))/sqrt(2)
b =
-1.4142
>> c=exp(3.2*log(2.2)/b)
c =
0.1680
>> wynik=2*a*b^2*c
wynik =
7.7305
>>
Powyższe wyrażenie bez użycia zmiennych do przechowywania wyników obliczeń pośrednich
wygląda tak:
>> wynik=2*(3+exp(2.1))/(2-log(2.8))*((2*sin(3/2*pi))/sqrt(2))^2*
(exp(3.2*log(2.2)/((2*sin(3/2*pi))/sqrt(2))))
wynik =
7.7305
>>
Przy takim zapisie znacznie łatwiej o błąd który może być trudny do znalezienia, np.:
>> wynik=2*(3+exp(2.1)/(2-log(2.8)))*((2*sin(3/2*pi))/sqrt(2))^2*
(exp(3.2*log(2.2)/((2*sin(3/2*pi))/sqrt(2))))
wynik =
7.6690
1.5 Przydatne polecenia
Na koniec jeszcze kilka przydatnych poleceń/cech Matlab-a o których warto wiedzieć.
Historia poleceń: wciskając klawisz strzałki w górę w oknie Command Window cofamy się do
wykonywanych wcześniej operacji i możemy je powtórzyć lub lekko zmodyfikować i wykonać tę
zmodyfikowaną wersję.
clc – komenda, przy pomocy której czyścimy zawartość okna Command Window
who – wypisanie w oknie Command Window wszystkich utworzonych zmiennych
; - wyniki poleceń gdy linię zakończymy średnikiem nie będą wyświetlane, np.:
>> a=3+2;
>> a=3+2
a =
5
4
będzie to przydatne później – przy pisaniu własnych funkcji.
format long/short – format wyświetlania liczb rzeczywistych, np.:
>> a=sqrt(2);
>> a
a =
1.4142
>> format long
>> a
a =
1.414213562373095
>> format short
>> a
a =
1.4142
clear – usuwa wszystkie zmienne utworzone w danej sesji
clear nazwa_zmiennej – usuwa wybraną zmienną
1.6 Przenoszenie danych z arkusza kalkulacyjnego do Matlab-a
Aby przenieść dane z większości popularnych arkuszy kalkulacyjnych do programu Matlab,
wystarczy te dane zaznaczyć i po kliknięciu prawego klawisza myszki wybrać opcję kopiuj,
następnie w matlabie należy utworzyć tablicę, do której skopiujemy dane:
>> tab1=[]
tab1 =
[]
Nazwa tablicy pojawi się w okienku Workspace - tam należy kliknąć na nią dwukrotnie. Obok
powinna pojawić się wtedy tabela w której możemy w prosty sposób edytować zawartość tablicy.
Należy wtedy kliknąć prawym przyciskiem na komórkę tabeli i z rozwijanego meu wybrać paste
aby wkleić dane skopiowane wcześniej z arkusza.
Kopiowanie danych z arkusza kalkulacyjnego do Matlab-a
5
2. Macierze i wektory
Warto wiedzieć, że nazwa programu Matlab pochodzi od Matrix laboratory. Zgodnie z tym co
nazwa sugeruje, Matlab umożliwia bardzo proste wykonanie wielu operacji na macierzach i
wektorach. W zasadzie macierze i wektory stanowią typ danych, którym najczęściej będziesz się
posługiwał.
2.1 Sposoby definiowania macierzy i wektorów
Definiowanie macierzy w Matlabie jest bardzo proste:
>> A=[1 2 3 4;5 6 7 8;9 10 11 12]
A =
1
2
3
4
5
6
7
8
9
10
11
12
>>
Spacja oddziela kolejne wyrazy w wierszu, natomiast przejście do nowej linii lub średnik oznaczają
rozpoczęcie kolejnego wiersza. Jeszcze jeden przykład:
>> B=[1 2
3 4
5 6
7 8]
B =
1
3
5
7
>>
2
4
6
8
Istnieją jeszcze trzy bardzo przydatne sposoby tworzenia wektorów (macierzy posiadających tylko
jeden wiersz lub tylko jedną kolumnę) w programie Matlab. Tymi sposobami otrzymamy wektory
zawierające wartości z określonego przedziału w odstępach równych, lub w postaci ciągu
arytmetycznego.
Sposób pierwszy prezentuje poniższy przykład:
>> C=[0:10:50]
C =
0
10
>> D=[0:5:23]
D =
0
5
>>
20
30
40
10
15
20
50
Ogólnie możemy to zapisać jako
[początek : odstęp : wartość maksymalna]
Zauważ, że do wektora trafiają tylko wyrazy mniejsze lub równe wartości maksymalnej.
6
Dwa kolejne sposoby tworzenia wektora to funkcje linspace i logspace.
>> linspace(1,50,5)
ans =
1.0000
13.2500
>>
25.5000
37.7500
50.0000
pierwszy i drugi argument funkcji linspace to wartości pierwszego i ostatniego elementu wektora,
ostatni – liczba elementów wektora. Elementy wektora tworzonego funkcją linspace są od siebie
równo oddalone. Funkcja logspace generuje wektor w którym kolejne elementy to wartości 10^x.
Najlepiej zilustrować działanie tej funkcji przykładem:
>> logspace(-2,2,5)
ans =
0.0100
0.1000
>>
1.0000
10.0000
100.0000
Otrzymaliśmy wektor zawierający 5 wartości, od 10^-2 do 10^2. Wartości to kolejno 10^-2, 10^-1,
10^0 itd.
Przydatne polecenia do tworzenia macierzy to ones(m), eye(m), zeros(m) oraz te same funkcje
wywoływane z dwoma argumentami, tj.: ones(m,n) itd.... Funkcje te tworzą macierze kwadratowe o
wymiarze m gdy wywolamy je z jednym argumentem lub macierze posiadajace m wierszy i n
kolumn jeśli wywołamy je z dwoma argumentami. Spróbuj użyć każdej z tych funkcji w obu
formach aby zobaczyć jakie macierze powstają w wyniku ich działania.
2.2 Podstawowe operacje rachunku macierzy
Najprostsze operacje rachunku macierzy to dodawanie i odejmowanie macierzy. Macierze muszą
mieć ten sam wymiar. Dodawanie i odejmowanie macierzy wygląda dokładnie tak samo jak
dodawanie i odejmowanie od siebie dwu zmiennych. Oto przykład dodawania macierzy:
>> A=[1 2 3;4 5 6]
A =
1
2
3
4
5
6
>> B=[1 2 3;7 8 9]
B =
1
2
3
7
8
9
>> C=A+B
C =
2
4
6
11
13
15
>>
Analogicznie wygląda odejmowanie macierzy (spróbuj odjąć od siebie macierze A i B). Mnożenie
macierzy przez liczbę jest równie proste:
>> A=[1 2 3;4 5 6]
A =
1
2
3
4
5
6
7
>> A*2
ans =
2
8
>>
4
10
6
12
Mnożenie macierzy i podnoszenie jej do potęgi jest już nieco bardziej skomplikowane. Mamy tu do
wyboru dwie opcje. Albo mnożymy macierze zgodnie z zasadami rachunku macierzy albo
mnożymy/dzielimy przez siebie odpowiadające sobie elementy macierzy. W poniższej tabeli
podano odpowiednie przykłady. Najpierw zdefiniujemy dwie macierze:
>> A=[1 2 3;4 5 6;7 8 9]
A =
1
2
3
4
5
6
7
8
9
>> B=[11 12 13;14 15 16;17 18 19]
B =
11
12
13
14
15
16
17
18
19
>>
Wyniki wykonania komend z lewej kolumny znajdują się w prawej kolumnie tabeli.
>> A*B
90 96 102
216 231 246
342 366 390
>> A.*B
11 24 39
56 75 96
119 144 171
>> A./B
0.0909 0.1667 0.2308
0.2857 0.3333 0.3750
0.4118 0.4444 0.4737
Zatem zapis bez kropki poprzedzającej symbol mnożenia/dzielenia oznacza zwykłe
mnożenie/dzielenie macierzy, natomiast w przypadku użycia operatora .* lub ./
wymnażane/dzielone przez siebie są odpowiadające sobie elementy macierzy. Analogicznie
wygląda potęgowanie. W wypadku użycia operatora ^, Matlab wykonuje zwykle mnożenie
macierzy, natomiast .^ oznacza podniesienie każdego elementu macierzy do danej potęgi. Aby
lepiej zrozumieć różnicę, przyjżyj się poniższemu przykładowi:
>> A=[2 2
A =
2
2
2
>> B=A^3
B =
72
72
72
>> C=A.^3
C =
8
8
8
2; 2 2 2; 2 2 2]
2
2
2
2
2
2
72
72
72
72
72
72
8
8
8
8
8
8
8
Matlab umożliwia także proste wykonanie operacji takich jak transpozycja macierzy, wyliczenie
wyznacznika, wartości własnych oraz wyznaczenie macierzy odwrotnej. Aby otrzymać macierz
transponowaną, należy użyć operatora ' :
>> A=[1 1 1;2 2 2;3 3 3]
A =
1
1
1
2
2
2
3
3
3
>> B=A'
B =
1
2
3
1
2
3
1
2
3
>>
Pozostałe operacje:
●
●
●
inv(X) – wyznaczenie macierzy odwrotnej do macierzy X
det(X) – obliczenie wyznacznika macierzy X
eig(X) – wyznaczenie wartości własnch macierzy X
2.3 Dostęp do elementów macierzy/wektorów
Na początek utwórzmy przykładową macierz wielkości 7x7:
>> A=magic(7)
A =
30
39
38
47
46
6
5
14
13
15
21
23
22
31
>>
48
7
8
16
24
32
40
1
9
17
25
33
41
49
10
18
26
34
42
43
2
19
27
35
36
44
3
11
28
29
37
45
4
12
20
W przykładzie poszliśmy trochę na skróty – komenda magic tworzy macierz kwadratową o
zadanym wymiarze, w której sumy wszystkich wierszy i kolumn są równe i w której nie powtarza
się żaden element.
Odczytanie pojedynczego elementu:
>> A(1,1)
ans =
30
>> A(4,5)
ans =
34
>>
Jako pierwszy argument podajemy wiersz, jako drugi kolumnę, wiersze i kolumny macierzy
numerowane są od 1.
9
Odczytanie wybranego fragmentu macierzy wykonujemy tak:
>> A(2,2:5)
ans =
47
7
9
18
Operator : pozwala zdefiniować zakres interesujących nas elementów. Tu odczytaliśmy elementy
od 2 do 5 z wiersza 2. Operatora dostępu : możemy użyć również do odczytania całych
wierszy/kolumn – wtedy nie podajemy zakresu jaki chcemy odczytać a jedynie wstawiamy sam
operator :, tak jak w poniższych przykładach:
>> A(:,2)
ans =
39
47
6
14
15
23
31
>> A(2,:)
ans =
38
47
>>
7
9
18
27
29
Jak się łatwo domyślić A(:,:) oznacza całą zawartość macierzy A.
2.4 Operacje na wybranym wierszu/kolumnie
Zajmiemy się teraz operacjami w których chcemy wykonać działania tylko na wybranym wierszu
lub wybranej kolumnie macierzy, takimi jak: mnożenie wiersza/kolumny przez liczbę, dodawanie
wierszy/kolumn, usuwanie wierszy/kolumn
>> A=magic(7);
>> A(3,:)=2*A(3,:)
A =
30
39
48
1
38
47
7
9
92
12
16
34
5
14
16
25
13
15
24
33
21
23
32
41
22
31
40
49
>> A(4,:)=A(4,:)-A(3,:)
A =
30
39
48
1
38
47
7
9
92
12
16
34
-87
2
0
-9
13
15
24
33
21
23
32
41
22
31
40
49
>>
10
18
52
34
42
43
2
19
27
70
36
44
3
11
28
29
74
45
4
12
20
10
18
52
-18
42
43
2
19
27
70
-34
44
3
11
28
29
74
-29
4
12
20
W powyższym przykładzie najpierw pomnożono wiersz 3 macierzy przez 2 a następnie od wiersza
4 odjęto wiersz 3. Wybrany wiersz/kolumnę macierzy usuniemy w następujący sposób:
10
>> A(:,3)=[]
A =
30
39
38
47
92
12
-87
2
13
15
21
23
22
31
>>
1
9
34
-9
33
41
49
10
18
52
-18
42
43
2
19
27
70
-34
44
3
11
28
29
74
-29
4
12
20
W przykładzie tym usunęliśmy kolumnę 3 macierzy będącej wynikiem poprrzednich dwu operacji.
2.5 Rozwiązywanie układów równań liniowych metodą macierzy odwrotnej przykład
Na koniec rozwiążemy jeszcze prosty układ równań wykorzystując metodę macierzy odwrotnej:
x−2y3z=−7
3x y4z=5
2x5yz=18
Układ zapiszemy w postaci macierzowej:
A⋅X=B
1 −2 3 x −7
3 1 4⋅y = 5
2 5 1 z 18
Rozwiązanie ukłądu znajdziemy dzięki własnościom macierzy odwrotnej:
−1
A⋅X=B⇒ X =A ⋅B
Następnie zdefiniujmy w Matlabie odpowiednie macierze A i B oraz wyznaczymy rozwiązanie
układu:
>> A=[1 -2 3;3 1 4;2 5 1]
A =
1
-2
3
3
1
4
2
5
1
>> B=[-7;5;18]
B =
-7
5
18
>> X=inv(A)*B
X =
2.0000
3.0000
-1.0000
Zatem rozwiązanie układu równań to: x=2, y=3 i z=-1.
11
3. Wielomiany
Wielomiany w matlabie przechowywane są w postaci wierszowego wektora współczynników.
Pierwszy wyraz wektora zawiera współczynnik przy najwyższej potędze zmiennej niezależnej,
kolejne wyrazy to współczynniki przy kolejnych, coraz niższych potęgach zmiennej, ostatni to
wyraz wolny wielomianu. Dla przykładu wielomian:
Wprowadzamy do matlaba w postaci wektora:
>> p=[3,2,-1]
3.1 Obliczanie wartości wielomianu (polyval):
Funkcja polyval(p,x) oblicza wartość wielomianu o współczynnikach zawartych w wektorze p w
punktach wyspecyfikowanych w zmiennej x. Dla przykładu posłużono się powyższym
wielomianem p(x):
>> p=[3,2,-1]
p =
3
2
-1
>> polyval(p,1)
ans =
4
Oczywiście można od razu wprowadzić kilka zmiennych x w postaci wektora:
>> polyval(p,[1,3,0,7])
ans =
4
32
-1
160
3.2 Obliczanie pierwiastków wielomianu (roots):
Funkcja roots pozwala obliczyć pierwiastki wielomianu. Przykład:
>> roots(p)
ans =
-1.0000
0.3333
Oczywiście Matlab oblicza także pierwiastki zespolone:
>> q=[3,1,0,-1];
>> roots(q)
ans =
-0.4658 + 0.5834i
-0.4658 - 0.5834i
0.5982
12
3.3 Mnożenie i dzielenie wielomianów (conv i deconv):
Funkcja conv pozwala obliczyć wektor współczynników wielomianu będącego iloczynem
wielomianów reprezentowanych przez jej argumenty, tj:
>> p=[1,1];
>> q=[1,2,2];
>> c=conv(p,q)
c =
1
3
4
2
Funkcja deconv pozwala obliczyc iloraz oraz resztę z dzielenia jednego wielomianu przez drugi:
>> p=[2,2,2,1];
>> q=[1,2];
>> [w,r]=deconv(p,q)
w =
2
-2
6
r =
0
0
0
-11
3.4 Pochodna wielomianu (polyder):
Funkcja polder(p) oblicza wektor współczynników wielomianu będącego pochodną wielomianu
reprezentowanego przez p.
>> p=[3,2,-1];
>> polyder(p)
ans =
6
2
Można także obliczyć pochodną iloczynu wielomianów – po prawej stronie znaku równości
znajduje się pojedyncza zmienna:
>> p=[3,2,-1];
>> q=[4,0,-1,1];
>> k=polyder(p,q)
k =
60
32
-21
2
3
Powyższy wynik można uzyskać stosując znaną już funkcję conv:
>> p=[3,2,-1];
>> q=[4,0,-1,1];
>> polyder(conv(p,q))
ans =
60
32
-21
2
3
13
Oczywiście w łatwy sposób można obliczyć pochodną ilorazu wektorów. Składnia tej funkcji jest
taka sama jak w przypadku funkcji deconv – po prawej stronie znaku równości znajduje się tablica
z dwiema zmiennymi:
>> p=[3,2,-1];
>> q=[4,0,-1,1];
>> [w,r]=polyder(q,p)
w =
12
16
-9
-6
r =
9
12
-2
-1
-4
1
gdzie:
w – wynik dzielenia wielomianów,
r – reszta z dzielenia.
3.5 Aproksymacja wielomianowa (polyfit):
Główną funkcją wykorzystywaną przy aproksymacji wielomianowej jest polyfit. Oblicza ona
współczynniki wielomianu zadanego stopnia aproksymującego dane wejściowe w sensie minimum
sumy kwadratów. Składnia funkcji:
>> p=polyfit(x,y,n)
x,y – wektory zawierające dane
n – stopień wielomianu jaki chcemy otrzymać
>> x=[1 3 5 7 9 11];
>> y=[1 13 17 23 31 39];
>> p=polyfit(x,y,3)
p =
0.0463
-0.8512
7.8505
>> x2=1:0.5:11;
>> y2=polyval(p, x2);
>> plot(x,y,'x',x2,y2)
-5.5853
14
15
4. Funkcje i skrypty
Matlab posiada własny, rozbudowany język skryptowy pozwalający łatwo tworzyć zaawansowane
programy. W tym rozdziale omówimy krótko tworzenie prostych skryptów i funkcji. Skrypt to ciąg
poleceń zapisany w pliku, które po uruchomieniu skryptu zostają kolejno przez Matlab-a
wykonane. Z funkcji korzystałeś już wielokrotnie zatem pewnie wiesz już dobrze co to jest i do
czego służy. Skrypty i funkcje zapisywane są w postaci tzw. m-plików, czyli plików z
rozszerzeniem .m. W przypadku funkcji, każda funkcja musi być zdefiniowana w oddzielnym mpliku o nazwie takiej, jak nazwa danej funkcji. Aby otworzyć edytor plików m wybierz z menu:
File → New → M-File
Powinien zostać uruchomiony edytor (u Ciebie może wyglądać trochę inaczej):
Okno edytora m-plików
4.1 Skrypty
Napiszmy skrypt obliczający czas wypływu cieczy z cylindrycznego zbiornika. Jako dane
potrzebne będą (w nawiasach podano przyjęte w skrypcie wartości):
D – średnica zbiornika (3m)
h – wysokość do której zbiornik jest napełniony (4m)
d – średnica otworu, przez który wypływa ciecz (100mm = 0.1m)
µ - współczynnik wypływu (0.8)
g – przyspieszenie ziemskie (9.81 m/s2)
Całkowity czas wypływu ze zbiornika w sekundach obliczymy ze wzoru:
t wyp =
2⋅D2
⋅ h
u⋅d 2 2g
16
W edytorze m-plików wprowadź następującą treść:
D=3
h=4
d=0.1
u=0.8
g=9.81
t_wyp=(2*D^2)/(u*d^2*sqrt(2*g))*sqrt(h)
Teraz z menu edytora m-plików wybieramy Debug → Safe file and Run (lub podobną opcję –
nazwy mogą się nieznacznie różnić w zależności od wersji programu Matlab). Zostaniesz zapytany
pod jaką nazwą zapisać skrypt – nazwij skrypt t_wyplywu. Po zapisaniu skrypt zostanie
uchomiony. Przejdź do okna Command Window. Tam znajdziesz wyniki obliczeń:
D =
h =
d =
u =
g =
3
4
0.1000
0.8000
9.8100
t_wyp =
1.0159e+03
>>
Inna metoda wywołania skryptu to wpisanie jego nazwy w wierszu poleceń. Teraz wróć do edytora
i zmień wysokość cieczy w zbiorniku na 2 m. Ponownie wybierz z menu Debug opcję Safe file and
Run. Otrzymasz czas opróżniania zbiornika dla nowych danych. Tym razem program nie powinien
pytać o nazwę skryptu (skrypt zostanie ponownie zapisany pod podaną wcześniej nazwą). Wynik
powinien być następujący:
D =
h =
d =
u =
3
2
0.1000
0.8000
g =
9.8100
t_wyp =
718.3697
>>
Spróbuj jeszcze dodać znak średnika (;) na końcu pierwszych pięciu linii:
D=3;
h=4;
d=0.1;
u=0.8;
g=9.81;
t_wyp=(2*D^2)/(u*d^2*sqrt(2*g))*sqrt(h)
17
Sprawdź jak wtedy będzie wyglądał wynik uruchomienia skryptu. Jeśli nie wiesz dlaczego tak jest,
wróć do części 1.5 pierwszego rozdziału kursu – tam dowiesz się czym skutkuje zakończenie linii
średnikiem.
4.2 Funkcje
Funkcjom poświęcimy trochę więcej uwagi. Będziesz je wykorzystywał i pisał bardzo często
podczas pracy z programem Matlab. Własne funkcje będziesz pisał na przykład podczas
numerycznego obliczania całek. Z menu (edytora m-plików lub Matlaba) wybierz:
File → New → M-File
Funkcja, którą stworzymy na początek będzie obliczać objętość molową gazu doskonałego:
R⋅T
p⋅v=R⋅T ⇒ v  p , T =
p
function wynik=v(p,T)
%funkcja oblicza objętość molową [m^3/mol]
%p - ciśnienie [Pa]
%T - temperatura [K]
R=8.314; %[J/(mol*K)]
wynik=R*T/p;
end
Teraz zapisujemy nasz plik. Plik musi nazywać się dokładnie tak samo jak funkcja – czyli w
naszym przypadku będzie to v.m i taką właśnie nazwę zaproponuje nam Matlab. Zapamiętaj, w
jakim dokładnie folderze zapisujesz plik. Teraz przejdź do okna Command Window i wpisz:
>> v(101300,273.15)
ans =
0.0224
>>
Obliczyliśmy w ten sposób objętość, zajmowaną przez mol gazu doskonałego w warunkach
normalnych – 22.4 dm3 czyli 0.0224m3. Jeśli otrzymałeś komunikat:
>> v(101300,273.15)
??? Undefined function or method 'v' for input arguments of type
'double'.
>>
Nie przejmuj się. Prawdopodobnie folder w którym zapisałeś swoją funkcję nie znajduje się na
liście folderów w których Matlab szuka funkcji (tzw. Path). Musisz ten folder do ścieżki dodać. Z
menu w głównym oknie programu wybierz:
File → Set Path...
W oknie, które się pojawi wybierz Add Folder... a następnie wybierz folder, w którym zapisałeś
swoją funkcję. Teraz wszystko powinno działać.
Przyjrzyjmy się teraz bardziej szczegółowo napisanej przez nas funkcji.
18
function wynik=v(p,T)
Plik z definicją funkcji powinien się zaczynać słowem kluczowym function – informuje ono
Matlab-a, że zaraz zdefiniujemy funkcję. Po słowie kluczowym function podajemy nazwy
zmiennych, których wartości funkcja zwróci. W naszym przypadku jest to pojedyncza zmienna o
nazwie wynik ale może to być również wektor lub macierz (przykłady w dalszej części rozdziału).
Następnie znak równości i nazwa funkcji, po której w nawiasie znajduje się lista argumentów
przyjmowanych przez funkcję (u nas są to p i T).
%funkcja oblicza objętość molową [m^3/mol]
%p - ciśnienie [Pa]
%T - temperatura [K]
W kolejnych trzech linijkach zaczynających się od znaku % umieszczono komentarze mówiące co
funkcja liczy oraz w jakich jednostkach podawać agumenty wejściowe. Linie zaczynające się od
znaku % są ignorowane przez Matlab-a, możemy w nich wpisać co chcemy – zwykle właśnie
jednostki lub jakiś krótki opis działania znajdującego się w kolejnych linijkach kodu. Komentarze
takie nie są konieczne do działania funkcji ale warto je pisać, żeby potem nie mieć wątpliwości co
dokładnie robi nasza funkcja i jakich parametrów od nas oczekuje.
R=8.314; %[J/(mol*K)]
wynik=R*T/p;
end
Dalej podobnie jak w skrypcie piszemy ciąg poleceń, które Matlab ma wykonać, w tej części
obliczamy wartości które funkcja ma zwrócić – my w tej części definiujemy zmienną R –
uniwersalną stałą gazową oraz obliczamy wynik – molową objętość gazu. W obliczeniach
wykorzystujemy przekazane do funkcji argumenty (w naszym przykładzie argumenty to p i T).
Definiowanie funkcji powinniśmy kończyć słowem kluczowym end.
Poniżej przykład funkcji, zwracającej kilka wartości:
function [f g]=fg(x)
%funkcja oblicza wartości dwu funkcji :
%f(x)=2x+2
%g(x)=x^2+2x+1
f=2*x+2;
g=x^2+2*x+1;
end
>> [j k]=fg(2)
j =
6
k =
9
>> a=fg(2);
>>
Przyjżyj się ostatniemu wydanemu poleceniu – jak myślisz, co powinno się znaleźć w zmiennej a?
Pewnie spodziewasz się, że a będzie wektorem zawierającym wartości 6 i 9, czyli:
[6 9]
Nie. Zmienna a będzie miała wartość 6. Zostanie pod nią podstawiona pierwsza wartość z wektora
zwracanego przez funkcję. Pamiętaj o tym – dzięki temu unikniesz wielu błędów. Kolejnym często
19
popełnianym błędem jest używanie w funkcjach operatorów mnożenia i potęgowania
macierzowego zamiast operatorów wykonujących te operacje „element po elemencie”.
Aby zilostrować ten problem, stwórzmy kolejną funkcję – podobną do fg(x):
function [f g]=fg1(x)
%funkcja oblicza wartości dwu funkcji :
%f(x)=2x+2
%g(x)=x^2+2x+1
f=2.*x+2;
g=x.^2_2.*x+1;
end
Różnica między fg i fg1 polega wyłącznie na tym, że operatory mnożenia i potęgowania
macierzowego (* i ^) zastąpiono w funkcji fg1 operatorami mnożenia i potęgowania „element po
elemencie” (.^, .*). Wykonanie poniższych poleceń pozwoli nam zobaczyć różnice między obiema
funkcjami.
>> fg1(2)
ans =
6
>> [j k]=fg1(2)
j =
6
k =
9
>> x=[1:1:5]
x =
1
2
3
4
>> [j k]=fg(x)
??? Error using ==> mpower
Matrix must be square.
Error in ==> fg at 6
g=x^2+2*x+1;
>> [j k]=fg1(x)
j =
4
6
8
10
k =
4
9
16
25
>>
5
12
36
Jak widać dla pojedynczego argumentu funkcje fg i fg1 dają dokładnie takie same rezultaty. W
kolejnej operacji tworzymy wektor x. Chcemy obliczyć wartości funkcji f(x) i g(x) dla każdego
elementu wektora. W przypadku użycia funkcji fg otrzymujemy błąd:
??? Error using ==> mpower
Matrix must be square.
Error in ==> fg at 6
g=x^2+2*x+1;
Błąd wynika z tego, że chcemy podnosić do potęgi macierz, która nie jest kwadratową, co zgodnie
z definicją potęgowania macierzy jest operacją niedozwoloną. Funkcja fg1(x) daje pożądany
rezultat – w wektorach k i j znajdują się odpowiednio wartości funkcji f i g dla kolejnych liczb w
wektorze x. Podobnie w przypadku operatorów mnożenia i dzielenia:
20
function z=f(x,y)
z=y*x;
end
function z=f1(x,y)
z=y.*x;
end
>> fun1(1,2)
ans =
2
>>fun(1,2)
ans =
2
>> fun1(x,y)
ans =
0
0.5000
2.0000
4.5000
>> fun(x,y)
??? Error using ==> mtimes
Inner matrix dimensions must agree.
Error in ==> fun at 2
z=y*x;
>>
8.0000
W funkcjach zwykle powinniśmy używać operatorów wykonujących operacje „element po
elemencie”, zatem zapamiętaj aby operatorów macierzowych (czyli tych normalnych, „bez kropki”,
których poza Matlabem używamy praktycznie zawsze) używać tylko wtedy kiedy naprawdę chodzi
nam o wykonanie operacji potęgowania/mnożenia/dzielenia macierzy.
Poniżej znajduje się prosty przykład pokazujący działanie średnika na końcu linii wewnątrz funkcji.
Zmodfikuj funkcję fg1(x), usuwając średnik z końca linii, w której liczona jest wartość g(x):
function [f g]=fg1(x)
%funkcja oblicza wartości dwu funkcji :
%f(x)=2x+2
%g(x)=x^2+2x+1
f=2.*x+2;
g=x.^2_2.*x+1
end
>> x=[1:1:5]
x =
1
2
>> k=fg1(x)
g =
4
9
k =
4
6
>> k=fg1(x);
g =
4
9
>>
3
4
5
16
25
36
8
10
12
16
25
36
Zwróć uwagę, że gdy linijka w funkcji nie jest zakończona średnikiem, wynik przeprowadzonej w
niej operacji zawsze zostanie wyświetlony (zwróć uwagę na ostanie wywołanie). Spróbuj usunąć
średnik również z linii, w której liczona jest wartość funkcji f(x).
21
4.3 Zmienne globalne
Oprócz argumentów, różne wartości możemy przekazywać do funkcji także jako zmienne globalne.
Nie jest to „elegancki” sposób i raczej powinno się go unikać, jednak czasami sposób ten pozwala
znacznie uprościć skrypty i funkcje. Na początek utwórz funkcję:
function fn1(k)
k=k+1
m=m+2
end
Następnie wykonaj następujące polecenia:
>> j=4
j =
4
>> m=3
m =
3
>> fn1(j)
k =
5
??? Undefined function or variable 'm'.
Error in ==> fn1 at 3
m
>> j
j =
4
>>
Tworzymy dwie zmienne – j oraz m. Następnie wywołujemy funkcję, przekazując jej jako
argument m. W funkcji do argumentu dodawana jest liczba jeden ale zauważ, że po zakończeniu
działania funkcji wartość j pozostała niezmieniona. Funkcja zgłasza również błąd – nie
zdefiniowano zmiennej m. Teraz zmodyfikuj funkcję fn1:
function fn1(k)
global m
k=k+1
m=m+1
end
A następnie wydaj następujące polecenia w oknie Command Window:
>> clear
>> global m
>> j=3
j =
3
>> m=4
m =
4
>> fn1(j)
k =
4
m =
5
>> m
22
m =
5
>> j
j =
3
Teraz zmienną m definiujemy jako globalną. Pamiętaj, że aby użyć jakiejś zmiennej jako globalnej
musisz zdeklarować ją jako globalną zarówno w swoim skrypcie/w Command Window jak też w
każdej funkcji, która z niej korzysta. Następnie tworzymy zmienną j o wartości 3 oraz zmiennej
globalnej m nadajemy wartość 4. Wywołujemy funkcję fn1 – podobnie jak poprzednio. Zauważ, że
w wyniku działania funkcji wartość zmiennej m zmieniła się. Zatem kolejną rzeczą o której musisz
pamiętać jeśli używasz zmiennych jest to, że po zakończeniu działania funkcji operującej na takich
zmiennych ich wartości nie powracają automatycznie do stanu sprzed wywołania funkcji.
4.4 Funkcja jako argument innej funkcji
Przekazanie funkcji jako argumentu do innej funkcji jest bardzo przydatną możliwością.
Skorzystasz z niej np. podczas całkowania numerycznego funkcji. Stworz następujące pliki z
funkcjami:
function y=f1(x)
y=2*x.^2+3;
end
function y=f2(x)
y=2*exp(x+1);
end
function y=f3(x)
y=2*x+1;
end
Teraz stworzymy przykładową funkcję, do której będziemy przekazywać nasze funkcje jako
argumenty. Funkcja ta zwróci różnicę wartości funkcji prekazanej jako fn_1 i funkcji przekazanej
jako fn_2 dla argumentu x.
function y=diff_fun(fn_1,fn_2,x)
y=fn_1(x)-fn_2(x);
end
Następnie przejdź do okna Command Window i spróbuj wykonać następujące operacje:
>>format long
>> x=[1:1:10]
x =
1
2
3
4
5
6
7
8
9
10
>> diff_fun(@f1,@f2,x)
ans =
1.0e+05 *
Columns 1 through 3
-0.000097781121979 -0.000291710738464 -0.000881963000663
Columns 4 through 6
-0.002618263182052 -0.007538575869855 -0.021182663168569
Columns 7 through 9
-0.058609159740835 -0.160751678551508 -0.438879315896134
23
Column 10
-1.195452834303956
>> f1(1)-f2(1)
ans =
-9.778112197861301
>> -0.000097788e5
ans =
-9.778800000000000
>> diff_fun(f2,f3,x)
??? Input argument "x"
Error in ==> f2 at 2
y=2*exp(x+1);
>> diff_fun(@f2,@f3,x)
ans =
1.0e+05 *
Columns 1 through 3
0.000117781121979
Columns 4 through 6
0.002878263182052
Columns 7 through 9
0.059469159740835
Column 10
1.197272834303956
>>
is undefined.
0.000351710738464
0.001021963000663
0.007958575869855
0.021802663168569
0.161891678551508
0.440339315896134
Zwróć uwagę na sposób wywołania funkcji, do której jako parametry przekazujemy inne funkcje.
diff_fun(@f1,@f2,x)
Przed nazwą przekazywanej funkcji musimy umieścić znak @. Jest to operator zwracający tzw.
uchwyt funkcji, wystarczy jednak, żebyś zapamiętał że gdy przekazujesz jako argument funkcję,
przed jej nazwą powinienneś umieścić znak @ - inaczej możesz otrzymać błędy, takie jak np. ten:
>> diff_fun(f2,f3,x)
??? Input argument "x" is undefined.
Error in ==> f2 at 2
y=2*exp(x+1);
Unikniesz ich stawiając znak @ przed nazwą funkcji przekazywanej jako argument do innej
funkcji.
4.5 Znajdowanie miejsc zerowych dowolnej funkcji (fzero)
Jednym z przykładów funkcji do których przekazujesz jako argument własną funkcję, jest
wbuowana w Matlab-a fzero. Pozwala ona znaleźć punkt, w którym Twoja funkcja zwraca wartość
zero. Funkcję tę można zastosować do funkcji jednej zmiennej. Jej wywołanie wygląda tak:
x_szukane = fzero(@fn,x0)
pod zmienną x_szukane podstawiony zostanie wynik – x, przy którym wartość zwracana przez
funkcję fn jest równa zero. x0 to punkt, od którego należy rozpocząć poszukiwania. Miejsce zerowe
powinno znaleźć się w okolicy tego punktu. Jeśli wiemy na przykład do jakiego przedziału ma
należeć poszukiwana wartość – możemy jako x0 podać punkt, będący środkiem tego przedziału.
Działanie funkcji polega na znalezieniu w okolicy punktu x0 przedziału, na którego końcach
24
wartości zwracane przez funkcję mają różne znaki a następnie dokładne zlokalizowanie miejsca
zerowego w tym przedziale.
Rozwiążemy następujący problem:
Mając dane równanie:
2
=
 
11.17⋅1−x 
x
⋅
1−x
1−1.17⋅x
Należy znaleźć wartość x z przedziału (0;1), dla której =1.76 . Aby móc użyć funkcji fzero,
musimy przekształcić równanie do postaci:
2
 
0=
11.17⋅1−x 
x
⋅
−
1−x
1−1.17⋅x
Tworzymy funkcję:
function y=f4_5(x)
a=x./(1-x);
b=(1+1.17*(1-x))./(1-1.17*x);
y=a.^2*b – 1.76;
end
Zapisujemy ją i przechodzimy do okna CommandWindow. Tam wydajemy komendę:
>> x=fzero(@f4_5,0.5)
x =
0.4217
>>
Otrzymujemy punkt, w którym wartość funkcji f4_5 jest równa zero.
25
5. Pętle i instrukcje warunkowe
5.1 Pętla for
Załóżmy, że chcemy wypełnić jednowymiarową tablicę liczbami od 1 do 10. Wystarczy więc, że
zastosujemy następujący fragment kodu:
>> A(1) = 1;
>> A(2) = 2;
>> A(3) = 3;
i tak dalej aż do 10. Nieco prostszym i efektywniejszym sposobem jest np. zastosowanie
następującego kodu:
>> A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Wciąż jednak nie jest to jednak metoda najefektywniejsza. Gdybyśmy musieli wypełnić tablicę,
która posiada 1000 pozycji, jej wypełnianie byłoby dosyć męczące. Tutaj pojawia się możliwość
zastosowania pętli. Działanie pętli można określić w bardzo prosty sposób: powtarza pewien
fragment programu określoną ilość razy. Działanie pętli przybliżę teraz przykładem:
function f = fun(x)
f = x^2 +12*x -3;
Tworzymy skrypt o nazwie run.m:
k=5;
for a=1:k
fun(a)
end
Następnie w oknie Command Window wydajemy polecenie:
>> run
Naciskamy enter i na ekranie powinien pojawić się następujący kod:
ans =
10
ans =
25
ans =
42
ans =
61
ans =
82
Teraz wyjaśnienia:
Mamy funkcję daną następującym wzorem:
26
f(x) = x2 + 12x – 3
Chcemy obliczyć wartość tej funkcji dla x od 1 do 5 i użyć do tego celu programu Matlab. W tym
celu:
● tworzymy plik „fun.m”, w tym pliku umieszczamy funkcję, która następnie będzie
wywoływana dla kolejnych wartości „x”
● tworzymy plik „run.m”, ten plik jest plikiem wykonawczym i w nim umieszczamy
pętlę
● w „command window” wpisujemy „run” i otrzymujemy wyniki działania kodu
Ponieważ zakładam, że czytelnik posiadł już umiejętność pisania własnych funkcji, przejdę do
omówienia punktu, w którym tworzymy plik „run.m”. W 1. linijce kodu definiujemy zmienną „k” i
przypisujemy jej wartość „5”. W 3. linijce kodu rozpoczyna się pętla „for”. Budowa pętli for jest
następująca:
n= 1;
k= 5;
for a = n:k
„code”
end
Pętla zaczyna się słowem kluczowym „for”. Następnie podawany jest warunek działania pętli. Pętla
będzie się wykonywać k-n+1 razy. W wyżej wymienionym przypadku będzie to 5 razy, ale za k i n
można podstawić dowolne liczby naturalne oraz 0.
W miejscu gdzie znajduje się wyraz „code”, umieszcza się wszystkie instrukcje, które mają być
powtarzane. W rozpatrywanym wyżej przykładzie w miejscu „code” umieszczone jest wywołanie
funkcji od zmiennej „a”. Zmienna „a”, nazywana też licznikiem pętli, w trakcie działania pętli
zmienia swoją wartość w zakresie od n do k z krokiem równym „1”. Tak więc za każdym razem
gdy zostanie wywołana nasza funkcja, wartość zmiennej „a” będzie o „1” większa. Na końcu
znajduje się słowo kluczowe „end”, które kończy pętlę for.
Wyjaśniłem już na przykładzie podstawy działania pętli for. Teraz pora na bardziej szczegółowe
omówienie. Pętla zawsze wykonuje się określoną ilość razy. Ilość ta zawsze znana jest przed
definicją. Kolejne iteracje pętli są zależne od spełnienia warunku ilości wykonanych iteracji a nie
warunku logicznego, co ma miejsce w przypadku pętli „while". Zmienna, która jest licznikiem pętli
(w naszym przykładzie zmienna „a”), w każdej iteracji zmienia się o „1”.
5.2 Pętla while
Pętla while podobnie jak pętla for służy do wielokrotnego powtarzania kodu. W odróżnieniu od
pętli for ilość iteracji nie jest znana w momencie pisania kodu. Dla zobrazowania działania pętli
posłużymy się poprzednim przykładem. Za pomocą pętli while będziemy obliczać wartość funkcji:
f(x) = x2 + 12x – 3
w tym celu piszemy kod:
function f = fun(x)
f = x^2 +12*x -3;
27
oraz tworzymy skrypt run2.m
n=1;
k=5;
a=1;
while a<=k
fun(a)
a=a+1;
end
I uruchamiamy go, wpisując w oknie Command Window:
>> run2
wyniki:
ans =
10
ans =
25
ans =
42
ans =
61
ans =
82
Jak widać zastosowanie pętli while w tej postaci daje ten sam efekt jak pętla for. W tym jednak
przypadku powinniśmy zastosować pętlę while do innych zadań. Dobrym przykładem będzie
zastosowanie pętli while do obliczenia po ilu iteracjach wartość funkcji osiągnie lub przekroczy
oczekiwaną wartość. Przyjmijmy, że wartością graniczną w naszym przykładzie będzie z=1000.
Teraz piszemy kod:
function f = fun(x)
f = x^2 +12*x -3;
tworzymy skrypt run3.m
z=1000;
a=1;
y=0;
while y>=z
y = fun(a)
a=a+1;
end
a
I uruchamiamy go wpisując w oknie Command Window:
>> run3
wyniki:
a =
28
28
Otrzymana wartość „28” oznacza, że funkcja osiągnęła lub przekroczyła wartość „1000” po 28
iteracjach, czyli nasza funkcja f(x) dla x=28 przyjmuje wartość:
f(28) >= 1000.
5.3 Instrukcja warunkowa if
Instrukcje warunkowe, podobnie jak pętle, spotyka się we wszystkich językach programowania.
Stosuje się je w miejscach, w których chcemy w zależności od wartości jakieś zmiennej podjąć
jedno z kilku działań jakie opisaliśmy w programie. Dobrą analogią do instrukcji warunkowej jest
skrzyżowanie, na którym możemy skręcić w prawo lub lewo.
Najprostszym przykładem instrukcji warunkowej jest taka konstrukcja:
Skrypt przyklad.m
if w_ktora_strone == 'w prawo'
ulica = 'ul. Zielona'
end
Następnie przechodzimy do Command Window:
>> w_ktora_strona = 'w prawo';
>> przyklad
ulica =
ul. Zielona
W przykładzie stworzyliśmy plik przyklad.m , w którym umieszczona została instrukcja
warunkowa. Następnie po zapisaniu pliku definiujemy zmienną „w_ktora_strona” w command
window. Po nadaniu jej wartości wywołujemy plik z instrukcją warunkową. W tym przypadku
warunek został spełniony i wykonany został kod znajdujący się wewnątrz instrukcji.
Oprócz prostych konstrukcji, jak ta wyżej, można tworzyć bardzo rozbudowane wyrażenia z
wieloma opcjami. Aby to lepiej zobrazować zmodyfikujemy nasz przykład ze skrzyżowaniem.
Załóżmy, że chcemy jakoś uregulować ruch na skrzyżowaniu czterech ulic. Ponieważ nie chcemy,
żeby w każdą ulicę mógł wjechać dowolny samochód musimy postawić jakieś znaki, które pewnym
pojazdom zabraniałyby wjazdu na daną ulicę. Określiliśmy, że będziemy się kierować 3 kryteriami
- masą pojazdu
- wysokością pojazdu
- czy właściciel jest mieszkańcem osiedla
W tym celu tworzymy 3 zmienne:
masa [ton]
wysokosc [m]
wlasciciel [tak/nie]
Teraz modyfikujemy nasz plik przyklad.m do takiej postaci:
if (masa < 3.5)&(wysokosc < 5)
wynik = 'moze jechac w prawo'
29
elseif (masa < 3.5)&(wlasciciel == 'tak')
wynik = 'moze jechac w lewo'
elseif wysokosc < 3.5
wynik = 'moze jechac prosto'
else
wynik = 'nie moze jechac w zadnym kierunku'
end
Następnie przechodzimy do okna Command Window:
>>
>>
>>
>>
masa = 3;
wysokosc = 3.5;
wlasciciel = 'tak';
przyklad
wynik =
moze jechac w prawo
>> masa = 2.5;
>> wysokosc = 1.8;
>> wlasciciel = 'nie';
>> przyklad
wynik =
moze jechac w prawo
>> masa = 5;
>> wysokosc = 4;
>> wlasciciel = 'nie';
>> przyklad
wynik =
nie moze jechac w zadnym kierunku
Jak widać za pomocą bardziej złożonych instrukcji warunkowych możemy znacznie precyzyjniej
określać jaki kod ma zostać wykonany w zależności od grupy zmiennych. Jest to bardzo przydatne
przy pisaniu bardziej złożonych algorytmów. Dobrym przykładem jest np. dokładność równań
stanu gazów w zależności od ciśnienia i temperatury panujących w układzie. Gdybyśmy chcieli
obliczyć zależność ciśnienia od temperatury i objętości i narysować wykres dla bardzo dużego
zakresu ciśnienia, wówczas musielibyśmy użyć kilku równań stanu gazu, po to żeby
zminimalizować błąd obliczeń.
Tworzymy skrypt gaz.m
% deklarujemy zmienne
n = 1;
% licznosc = 1 mol
R = 8.314;
% stała gazowa
V = 0.0224; % objetość 1 mola w cum warunkach normalnych
% wspolczynniki rownania sztywnych kul i van der Waals'a dla
metanu
a = 0.228;
b = 42.8e-6;
% tworzymy petle
for T = 1:1500
%instrukcja warunkowa - wybieranie rownania stanu gazu
if T<500
% rownanie stanu gazu doskonalego
p = (n*R*T)/V;
elseif (T>=500)&(T<1000)
% rownanie sztywnych kul
p = (n*R*T)/(V-n*b);
elseif T>=1000
% rownanie van der Waals'a
p = ((n*R*T)/(V-n*b)) + (a*n^2)/(V^2);
30
end;
temperatura(T) = T;
cisnienie(T)
= p;
end;
plot(temperatura, cisnienie);
W Command Window uruchamiamy nasz skrypt.
>> gaz
Jako efekt jego działania powinniśmy otrzymać następujący wykres:
5
6
x 10
5
4
3
2
1
0
0
500
1000
1500
W kodzie uzależniliśmy wybór równania stanu gazu od temperatury panującej w układzie. W
rezultacie otrzymaliśmy tablicę punktów, z której wydrukowaliśmy wykres.
31
6. Grafika w Matlabie
Końcowym etapem większości obliczeń inżynierskich jest graficzna prezentacja otrzymanych
wyników. Interpretacja niektórych, bardzo skomplikowanych czasami, obliczeń nie byłaby możliwa
gdyby nie istnienie funkcji graficznych umożliwiających w prosty sposób tworzenie wykresów czy
diagramów. Jest to również jeden z prostszych sposobów na sprawdzenie poprawności obliczeń.
Operując macierzami o kilkunastu czy kilkudziesięciu wymiarach nie jesteśmy w stanie stwierdzić,
czy otrzymane wartości mają sens fizyczny a ich zmiany w czasie nie przeczą prawom natury.
6.1 Funkcja plot
Funkcja „plot” jest podstawowym narzędziem służącym do tworzenia dwuwymiarowych
wykresów. Argumentami tej funkcji są ciągi liczb, reprezentowanych przez nazwę lub
wpisywanych wprost.
Wpisując w okno poleceń:
>> a=[1.23 3.45 5.98 7.43 9.56];
>> b=[1 3 4 6 8];
>> plot(a,b)
w osobnym oknie otworzy się wykres automatycznie nazwany „Figure1”:
8
7
6
5
4
3
2
1
1
2
3
4
5
6
7
8
9
10
Wektory a i b są odpowiednio wartościami rzędnych i odciętych. Gdy argumentem jest natomiast
tylko jeden wektor, rzędną staje się jego indeks lub, w przypadku liczb zespolonych, OX staje się
osią rzeczywistą, a OY osią urojoną.
6.2 Edycja wykresu
Jak widać na powyższym przykładzie MATLAB domyślnie formatuje wykresy w pewien określony
32
sposób, ich wygląd można zmienić na dwa sposoby. Pierwszy z nich to edycja otrzymanego już
wykresu poprzez polecenia w pasku narzędzi ‘INSERT’ oraz ‘TOOLS⟶ EDIT PLOT’:
wstawianie nazwy osi OX
wstawianie nazwy osi OY
wstawienie tytułu
wstawienie legendy
Jest to sposób na szybkie zatytułowanie
wykresu bez potrzeby wchodzenia w
tryb edycji.
Tryb edycji umożliwia między innymi
zmianę:
-tytułu wykresu i osi
-grubości, koloru, typu linii i
znaczników
-skala i zakres wartości na osi
-rodzaj i wielkość czcionki
-koloru tła
-siatki
-a nawet danych (z dostępnych w
pamięci-o ile zgadza się wymiar obu
wektorów)
Zmiany te mogą być wprowadzane
również odpowiednimi instrukcjami z
okna poleceń, używanie trybu edycji
wykresu jest jednak znacznie prostsze
dla użytkowników poruszających się na
co dzień w świecie Windowsa.
Drugim sposobem formatowania wykresów jest wprowadzenie dodatkowej zmiennej do funkcji
PLOT. Decyduje ona o rodzaju, wielkości, kolorze znaczników oraz linii interpolacyjnej. Zmiany te
33
specyfikuje się używając odpowiednich oznaczeń wpisywanych w pojedynczych nawiasach:
Symbol
r
b
m
k
g
y
Kolor
Czerwony
Niebieski
Różowy
czarny
Zielony
Żółty
Symbol
-:
-.
Styl linii
Linia ciągła
Linia przerywana
Linia kropkowana
Linia punktowa
W domyślnych wykresach nie są stosowane znaczniki, co jest korzystne gdy operujemy na dużej
ilości punktów jednak zwykle warto dokładnie zaznaczyć punkty, gdy na jednym wykresie
umieszczamy kilka serii danych. Znacznikami mogą być: ’+’, ‘∘’, ‘*’, ‘x’, ‘.’, ‘d’-romb, ‘s’kwadrat.
Dzięki tym oznaczeniom można polepszyć wygląd powyższego wykresu, wpisując w okno poleceń:
>> plot(a,b,'*k--')%kolejność wpisywania symboli nie ma znaczenia
otrzymamy:
8
7
6
5
4
3
2
1
1
2
3
4
5
6
7
8
9
10
Jak widać grubość linii jest zawsze taka sama, kolor znaczników natomiast zawsze odpowiada
kolorowi linii. Można to zmienić stosując następujące polecenia:
polecenie
‘markersize’
‘linewidth’
‘markerfacecolor’
‘markeredgecolor’
Działanie
Zmiana wielkość znaczników
Zmiana grubości linii
Zmiana koloru wypełnienia znaczników
Zmiana koloru krawędzi znaczników
34
Polecenia te wpisuje się w pojedynczych nawiasach, oddzielając je od innych oznaczeń
przecinkiem (wartości grubości linii czy wielkości znaczników należy jednak wpisać bez
nawiasów), np.
>> plot(a,b,'*k--',’markersize’,20)
Dodatkowe komendy pomocne w tworzeniu wykresów:
>> title('tytul wykresu')
>> xlabel('nazwa osi OX')
>> ylabel('nazwa osi OY')
>> xlim([2 67])%ustawienie zakresu osi OX%
>> ylim('auto')%przywrócenie automatycznego ustawienia zakresu
osi OY%
Aby jednocześnie ustawić zakres obu osi można posłużyć się poleceniem „axis”, którego
argumentem jest wektor z zakresem wartości dla obu osi:
>> axis([2 4 6 9])
Dzięki komendom „axis” można sterować skalami osi:
polecenie
axis manual
funkcja
obecne zakresy osi są stosowane do
następnych wykresów tworzonych na tym
samym wykresie (z zastosowaniem polecenia
”hold on”
przywracane jest automatyczne dobieranie
skali osi przez program
zakres skali jest ściśle dostosowany do
wartości danych na wykresie
skala osi zmienia się by pole wykresu było
kwadratem
axis auto
axis tight
axis square
6
5
4
3
2
1
0
­1
­2
­3
­10
­5
asix equal
0
5
10
skale obu osi stają się takie same
35
8
6
4
2
0
­2
­4
­10
­8
­6
­4
­2
0
2
4
6
8
10
axis image
analogicznie do „axis equal” skale obu
osi są identyczne natomiast pole wykresu jest
dostosowywane ściśle do osiąganych
wartości
6
4
2
0
­2
­10
­8
­6
­4
­2
0
2
4
6
8
10
W praktyce inżynierskiej jak wiadomo często stosuje się skale logarytmiczne. I w tym przypadku
MATLAB przychodzi nam z pomocą. Aby jedna lub obie osie przestawić na skale logarytmiczną
wystarczy zastąpić polecenie „plot” jednym z następujących:
polecenie
semilogx
semilogy
loglog
funkcja
skala logarytmiczna dla osi
OX
skala logarytmiczna dla osi
OY
obie osie w skali
logarytmicznej
6.3.Hold on
Często również na jednym wykresie chcemy zamieścić kilka krzywych. Można to osiągnąć na dwa
sposoby. Jeden z nich wymaga użycia nowego polecenia: ‘hold on’lub ‘hold all’. Dzięki
niemu każde kolejne użycie „plot” (lub innego analogicznego polecenia) spowoduje dodanie
nowej krzywej do istniejącego już wykresu do momentu gdy zastosujemy ‘hold off’, przy
czym komenda ‘hold all’ zapewnia przydzielanie każdej kolejnej krzywej innego koloru.
Użycie ‘hold on’ natomiast oznacza identyczne formatowanie każdej kolejnej krzywej.
>> plot(y,x)
>> hold all
>> plot(x,y)
>> plot(x,y)
>> hold on
>> plot(y,x)
36
10
10
9
9
8
8
7
7
6
6
5
5
4
4
3
3
2
2
1
0
1
0
1
2
3
4
5
6
7
8
9
0
10
0
1
2
3
4
5
6
7
8
9
10
6.4 Subplot
W momencie gdy serie danych które chcemy umieścić na wykresie różnią się wartościami na tyle,
że jedne z nich są praktycznie niewidoczne warto użyć komendy ‘subplot’ dzięki której w
jednym oknie możemy umieścić kilka wykresów. Argumentami tej funkcji są trzy wartości: liczba
kolumn, liczba wierszy oraz numer pozycji w której ma się znaleźć dany wykres:
>> subplot(2,2,3)%tworzone są cztery pozycje, a dany wykres
znajduje się w trzeciej%
Pozycje numerowane są od strony lewej do prawej i od wiersza górnego w dół. Jeżeli chcemy dany
wykres umieścić w zajętym już miejscu wystarczy do polecenia wpisać ‘replace’:
>> subplot(2,2,3,'replace')
Po poleceniu ‘subplot’ musi wystąpić kolejne precyzujące co i jak chcemy wykreślić:
>> subplot(2,1,1);fplot(@(x)x^2+x-12,[1 3.5])
>> subplot(2,1,2);fplot(@(x)exp(x)-3.5*x,[0 2.4])
Po powyższych poleceniach otrzymamy nastepujące dwa wykresy:
5
0
­5
­10
1
1.5
2
2.5
3
3.5
3
2
1
0
­1
0
0.5
1
1.5
2
37
Podobny efekt można uzyskać edytując powstały już wykres:
Dodawanie nowych wykresów do
otwartego już okna
6.5 Interpolacja
Przy niezwykłej mnogości poleceń umożliwiających formatowanie wykresów jednej ich cechy nie
można zmienić wprost-charakteru linii interpolacyjnej. Przy dużej liczbie punktów nie ma to
znaczenia gdyż będzie praktycznie niewidoczna jednak dla kilkunastu punktów wykres może
okazać się zbyt ”kanciasty”. Aby to zmienić należy posłużyć się funkcją „interp1” , która służy
do interpolacji funkcji jednej zmiennej. Przy pracy z funkcjami dwóch zmiennych należy
posługiwać się „interp2” a dla ambitnych próbujących działać w przestrzeni trzech zmiennych
powstało „interp3”. Algorytm postępowania w przypadku każdej z powyższych funkcji jest taki
sam. Tworząc wykres, na który nanosimy punkty doświadczalne automatycznie są one łączone
prostą, dlatego przed dodaniem krzywej interpolacyjnej należy te prosta usunąć.
>> x=0:10;
>> y=atan(x);
>> plot(x,y,'o')
Kolejnym krokiem jest stworzenie punktów dla danego zakresu argumentów:
>> x1=linspace(0,10,200);%aby krzywa interpolacyjna była płynna
należy w danym przedziale wygenerować dość dużą liczbę argumentów
%
>> y1=interp1(x,y,x1,'spline');
W efekcie otrzymamy następujący wykres (dla porównania zamieszczono również wykres tej samej
funkcji bez użycia interpolacji):
1.5
1.5
1
1
0.5
0.5
0
0
1
2
3
4
5
6
7
8
9
10
0
0
1
2
3
4
5
6
7
8
9
10
Argumentami funkcji „interp1” są jak widać w powyższym przykładzie: punkty między którymi
38
ma przebiegać krzywa interpolacyjna, wygenerowane argumenty oraz element decydujący o
rodzaju interpolacji. Oprócz zastosowanego w przykładzie polecenia „spline”( jedna z
interpolacji kwadratowych) można wybrać również:
polecenie
linear
rodzaj krzywej
interpolacja liniowa-powstałe odcinki są
wielomianem pierwszego stopnia
interpolacja kwadratowa-powstałe odcinki są
wielomianami drugiego stopnia
metoda „najbliższego sąsiada”wygenerowane argumenty przyjmują wartość
dla najbliższego punktu
cubic
nearest
Jeżeli podczas interpolacji nie uściślimy jej rodzaju wykonane obliczenia będą dotyczyć
interpolacji liniowej, czyli uzyskany efekt będzie prawie identyczny jak w przypadku braku
jakiejkolwiek naszej ingerencji.
6.6 Funkcja fplot
Korzystając ze znanych już narzędzi , aby stworzyć wykres zdefiniowanej funkcji należy obliczyć
jej wartości dla zadanego zbioru argumentów:
>> x=linspace(2,10,5);
>> y=exp(x);
>> plot(x,y)
Proces ten znacznie ułatwia funkcja FPLOT, która wykonuje praktycznie cała pracę za nas.
Argumentami tej funkcji są: zdefiniowana wcześniej funkcja oraz zakres dla którego chcemy
stworzyć wykres. Zakres ten może dotyczyć zarówno argumentów jak i wartości funkcji:
>> fplot(@sin,[2 5 -0.6 0.6])
%wykres funkcji f(x)=sin(x) dla
argumentów z przedziału (2,5) z
ograniczeniem wartości funkcji
od -0.6 do 0.6%
>> fplot(@sin,[2 5])
%wykres funkcji f(x)=sin(x) dla
argumentów z przedziału (2,5)
1
0.5
0.8
0.4
0.6
0.3
0.4
0.2
0.1
0.2
0
0
­0.1
­0.2
­0.2
­0.4
­0.3
­0.4
­0.6
­0.5
­0.8
2
2.5
3
3.5
4
4.5
5
­1
2
2.5
3
3.5
4
4.5
5
Jak widać a przykładzie program automatycznie dobiera przedział wartości funkcji (od minimalnej
39
do maksymalnej osiąganej przez dana funkcję w wybranym przedziale). Jeśli jednak chcemy
osiągnąć efekt „zoomu” należy uściślić oba przedziały.
Funkcja użyta w poleceniu powinna być wcześniej zdefiniowana jednak możliwe jest wypisanie
matematycznej formuły (gdy przykładowo wiemy, że nie będziemy w przyszłości korzystać z danej
funkcji):
>> fplot(@(x)sin(x)+cos(x)-1,[2 10])
0.5
0
­0.5
­1
­1.5
­2
­2.5
2
3
4
5
6
7
8
9
10
40
7. Całkowanie
Matlab oferuje wiele funkcji slużących do całkowania numerycznego. Omówimy dwie z nich –
ode45 – najpopularniejszą i najbardziej uniwersalną funkcję całkującą dostępną w Matlab-ie oraz
funkcję trapz – imlpementującą obliczanie całek metodą trapezów.
Na początek rozważmy prostą funkcję:
y=x 2
Całka nieoznaczona z tej funkcji to oczywiście
1 3
z= x
3
7.1 Funkcja trapz
Zaczniemy od trapz. Funkcję, tak jak większość funkcji programu Matlab możemy wywołać na
wiele sposobów. Szczegółowe informacje i opis funkcji otrzymasz, wpisując help trapz w oknie
Command Window. My będziemy korzystać z wywołania, w którym jako argumenty przekazujemy
wektory wartości X i Y. Obliczanie całki metodą trapezów zilustrowano na poniższym rysunku:
Ilustracja całkowania metodą trapezów
Całkowanie tą metodą polega na przybliżaniu przebiegu funkcji pomiędzy kolejnymi znanymi
punktami liniami prostymi i obliczeniu sumarycznego pola powstałych tym sposobem trapezów.
Funkcja ta przydaje się gdy mamy np. punkty pomiarowe i musimy obliczyć przybliżone pole pod
krzywą utworzoną z tych punktów. Przykład użycia funkcji trapz poniżej:
>>
>>
>>
>>
>>
>>
>>
z1
x1=[0:1:10];
x2=[0:0.1:10];
x3=[0:0.01:10];
y1=x1.^2;
y2=x2.^2;
y3=x3.^2;
z1=trapz(x1,y1)
=
335
>> z2=trapz(x2,y2)
z2 =
333.3500
>> z3=trapz(x3,y3)
z3 =
333.3335
>> 1/3*(10^3)
ans =
333.3333
41
>>
Pierwsze trzy operacje to utworzenie wektorów dla zmiennej niezależnej (x) o róznym
zagęszczeniu punktów w tym samym przedziale. Następnie dla każdego z tych wektorów liczymy
wartości funkcji – y, odpowiadajace wszystkim jego wyrazom i obliczamy całkę przy pomocy
funkcji trapz – jej wartość zapisuejmy w zmiennej z. W ostatniej linii obliczono dokładną wartość
całki z funkcji y=x2 w przedziale 0 – 10. Jak można się było spodziewać – dla coraz większego
zagęszczenia punktów otrzymujemy za pomocą funkcji trapz coraz dokładniejszy wynik.
Obliczmy, wykorzystując funkcję trapz, minimalną ilość ciepła potrzebną do ogrzania 1 kg
naftalenu od temperatury 25 st. C (298.15 K)do 80 st. C (353.15 K) w procesie izobarycznym.
Szukana ilość ciepła będzie równa zmianie entalpii naftalenu, zatem:
T=353.15 K
Q= H =
∫
C p T dT
T=298.15 K
Pokażemy dwa sposoby rozwiązania tego zadania – gdy dysponujemy tablicą z wartościami ciepła
właściwego naftalenu pod stalym ciśnieniem dla różnych temperatur oraz gdy dysponujemy
korelacją pozwalajacą te wartości obliczać. Zaczniemy od przypadku w którym mamy wartości
ciepła właściwego w różnych temperaturach zebrane w tabeli.
T [K]
Cp
[J/(kg*K]
298,15
1570,10
303,15
1586,02
308,15
1601,93
313,15
1617,85
318,15
1633,76
323,15
1649,68
328,15
1665,59
333,15
1681,51
338,15
1697,42
343,15
1713,34
348,15
1729,25
353,15
1745,17
W pierwszm kroku musimy posiadane informacje na temat ciepła i
temperatury wprowadzić do programu Matlab. W tym celu utworzymy
tablicę i skopiujemy do niej wartości temperatury i ciepła właściwego
sposobem, omówionym w pierwszym rozdziale. Ilustracja na rysunku
poniżej:
Wklejanie tablicy temperatura – ciepło właściwe
Następnie wykonujemy całkowanie przy pomocy funkcji trapz – w ten sposób obliczymy ilość
energii, którą należy dostarczyć.
>> trapz(t_cp(:,1),t_cp(:,2))
ans =
9.1170e+04
>>
Zatem wymagana energia to około 91.17kJ.
Gdy dysponujemy zależnością funkcyjną również możemy użyć funkcji trapz – podobnie jak
wtedy, gdy liczyliśmy przybliżoną wartość całki z funkcji y=x 2. Korelacja na ciepło właściwe pod
42
stałym ciśnieniem dla naftalenu ma postać:
cp
[ ]
J
=621.093.183∗T
kg⋅K
A obliczenia możemy wykonać w następujący sposób:
>> T=[298.15:1:353.15];
>> cp=621.09 + 3.183 * T;
>> trapz(T,cp)
ans =
9.1170e+04
>>
Najpierw tworzymy tablicę z wartościami temperatury, dla których w kolejnej linii liczymy
wartości ciepła właściwego. Następnie korzystamy z funcji trapz aby obliczyć wartość szukanej
całki.
7.2 Funkcja ode45
Najczęściej używaną funkcją służącą do całkowania w Matlab-ie jest funkcja ode45. Ode to rodzina
funkcji całkująchych, w skład której wchodzi wiele funkcji nadających się do rozwiązywania
różnych klas problemów (sztywne układy równań różniczkowych, różna wymagana dokładność
obliczeń). ode45 jest najbardziej uniwersalną funkcją spośród nich. Wszystkie funkcje z rodziny
ode wywołuje się w praktycznie identyczny sposób. Informacje na temat innych funkcji z rodziny
ode znajdziesz wpisując w Command Window help ode45 i podążając za odnośnikami do innych
funkcji z rodziny ode, znajdującymi się pod koniec opisu funkcji ode45.
Funkcje z rodziny ode pozwalają nam uzyskać przebieg całki funkcji, możemy dzięki nim całkować
układy rownań różniczkowych a także wszukiwać punkty, dla których całka osiąga określoną
wartość.
Podstawowy sposób wywołania funkcji ode45 (i innych funkcji z rodziny ode) wygląda
następująco:
[x,y] = ode45(@funkcja_do_scałkowania,[xp xk],yp)
Funkcja zwraca dwa wektory – x i y. Wektor x zawiera wartości zmienej niezależnej a wektor y –
odpowiadające im wartości całki z funkcji funkcja_do_scałkowania w przedziale od xp do xk. Jako
parametr yp przekazujemy wartość funkcji którą całkujemy dla punktu xp.
Obliczenie wartości całki z funkcji
y=x 2
w przedziale 0 – 10 za pomocą funkcji ode45 obejmuje dwa kroki. W pierwszym - tworzymy plik z
naszą funkcją:
function dxdy=f1(x,y)
dxdy=x.^2;
Następnie przechodzimy do Command Window i tam obliczamy wartość całki za pomocą funkcji
43
ode45:
>> [x,y]=ode45(@f1,[0 10],0);
>> y(length(y))
ans =
333.3333
>> x(length(x))
ans =
10
>> x(1)
ans =
0
Jeśli otrzymałeś błąd, to prawdopodobnie dlatego, ze plik z funkcją f1 nie znajduje się w jednym z
katalogów, w których Matlab poszukuje m-plików z funkcjami. Problem ten i jego rozwiązanie
opisano w rozdziale 4.2.
y(length(y)) oznacza odwołanie się do ostatniego elementu wektora y. Analogicznie dla wektora x.
Zauważ, że jako wynik dostaliśmy od razu dość dokładną wartość całki (przynajmniej do 4-go
miejsca po przecinku), ale to samo i to nawet prościej, bo bez poleceń typu y(length(y)) mogliśmy
uzyskać przy pomocy funkcji trapz.
Aby poznać możliwości jakie zyskujemy dzięki funkcji ode45, zacznijmy od prostego przykładu, w
którym rozważymy model cylindrycznego zbiornika przepływowego, przedstawiony na poniższym
rysunku:
Zbiornik przepływowy
Równanie opisujące zmiany ilości cieczy w zbiorniku, przy założeniu że ciecz wpływająca do
zbiornika ma taką samą gęstość jak ciecz wypływająca ze zbiornika, ma postać:
dV
=F in−Fout
dt
Zakładamy, że natężenie strumienia wpływającego do zbiornika jest stałe. Natężenie strumienia,
wypływającego ze zbiornika jest proporcjonalne do pierwiastka kwadratowego wysokości cieczy w
zbiorniku, zatem:
d
 A⋅h
=F in−⋅ h
dt
dh
A =F in −⋅ h
dt
dh F in 
= − ⋅ h
dt
A A
44
Gdzie A to powierzchnia dna zbiornika dana wzorem:
A=
⋅D
4
2
Aby uzyskać zależność wysokości cieczy w zbiorniku od czasu musimy scałkować równanie:
dh F in 
= − ⋅ h
dt
A A
Równanie to jest na tyle proste, że bez problemu daje się scałkować analitycznie ale my użyjemy
do jego rozwiązania funkcji ode45. Dzięki niej otrzymamy zależność wysokości cieczy w zbiorniku
od czasu w przedziale od tp = 0 [s] do tk = 400 [s]. Zakładamy, że w chwili początkowej w
zbiorniku nie było cieczy, czyli:
ht p=0[s ]=0[m]
Tak jak poprzednio najpierw tworzymy m-plik z naszą funkcją obliczającą dh/dt:
function dhdt=wysokosc(t,h)
Fi=0.07; %m^3/s
A=2.5; %m^2
beta=0.08; %m^(5/2)/s
dhdt=(Fi-beta.*sqrt(h))./A;
i zapisujemy go.
Następnie używając funkcji ode45 obliczamy szukaną zależność wysokości od czasu a uzyskane
wartości nanosimy na wykres (funkcją plot):
>> [t,h]=ode45(@wysokosc,[0 400],0);
>> plot(t,h)
Oto uzyskany wykres zmian wysokości cieczy w zbiorniku w czasie.
Wykres zmian poziomu cieczy w zbiorniku
Gdybyśmy chcieli teraz powtórzyć obliczenia dla zbiorników o innych wymiarach, za każdym
razem musielibyśmy edytować plik z funkcją wysokosc. Znacznie wygodniej byłoby gdybyśmy
zwyczajnie przekazywali wymiary zbiornika jako argument dla tej funkcji. Funkcja wyglądała by
wtedy tak:
45
function dhdt=wysokosc2(t,h,Fi,A,beta)
dhdt=(Fi-beta.*sqrt(h))./A;
Aby funkcja ode45 przekazała do funkcji którą ma scałkować dodatkowe parametry należy ją
wywołać w następujący sposób:
[x,y] = ode45(@funkcja_do_scałkowania,[xp xk],yp,[],p1,p2,p3,itd...)
Jak widać na końcu naszego wywołania dodajemy pusty wektor a za nim kolejne parametry
przekazywane do funkcji. W miejsce pustego wektora możemy podać dodatkowe opcje dla funkcji
rozwiązującej nasze równanie – przykład takiej opcji pokażemy później. Całkowanie naszej funkcji
wysokosc2 wygląda tak:
>> [t,h]=ode45(@wysokosc2,[0 400],0,[],0.07,2.5,0.08);
>> plot(t,h)
>>
Powinniśmy otrzymać dokładnie taki sam wykres jak poprzednio. Zapamiętaj, że jako dodatkowy
argument możesz także przekazać uchwyt funkcji. Może się to czasem przydać – szczególnie przy
pisaniu uniwersalnych skryptów w których będziesz chciał mieć możliwość łatwej zmiany na
przykład funkcji obliczających parametry mediów biorących udział w procesie.
7.3 Funkcja ode45 – całkowanie układów równań
Całkowanie układów równań różniczkowych również można wykonać przy pomocy funkcji ode45.
Rozważmy następujący przykład:
W izotermicznym reaktorze zbiornikowym pracującym w sposób okresowy biegną następujące
reakcje elementarne:
1: A  B
2 : B C
3:C  D
Stałe szybkości poszczególnych reakcji w temperaturze procesu wynoszą:
k1 = 3.46 . 10-3 [1/s]
k2 = 6.51 . 10-2 [1/s]
k2 = 1.38 . 10-4 [1/s]
Stężenie A w reaktorze w chwili t=0 wynosi 20 kmol/m3. Należy obliczyć stężenia poszczególnych
składników w zależności od czasu prowadzenia procesu. Zmiany stężenia składników opisuje układ
równań różniczkowych:
d CA
=−k 1⋅C A
dt
d CB
=k 1⋅C A−k 2⋅C B
dt
d CC
=k 2⋅C B −k 3⋅C C
dt
d CD
=k 3⋅C C
dt
46
Stężenie składnika A w chwili 0 wynosiło 20 kmol/m3, natomiast pozostałe składniki nie byly
obecne w mieszaninie reakcyjnej.
Tworzymy plik z funkcją z naszym układem równań:
function dcdt=stezenia(t,c)
k1=3.46e-3; %1/s
k2=6.51e-2; %1/s
k3=1.38e-4; %1/s
dcdt=[-k1*c(1),
k1*c(1)-k2*c(2),
k2*c(2)-k3*c(3),
k3*c(3)];
Należy zwrócić uwagę, że w przypadku całkowania układu rownań, jako argument będący zmienną
zależną (w naszym przypadku c, czyli wektor zawierajacy stężenia składników) funkcja otrzymuje
nie pojedyncza liczbę jak to się działo dotychczas ale tablicę liczb, zawierajacą stężenia
poszczególnych składników w chwili t. W naszym przypadku pierwszy element tej tablicy – c(1) –
odpowiada składnikowi A, drugi (c(2)) – składnikowi B itd. Zauważ, że jako wartość funkcji także
zwracany jest wektor, którego kolejne pola odnoszą się do szybkości zmian stężenia
poszczególnych składników, przy czym kolejność skłądników jest taka, jak w wektorze c.
Wywołanie funkcji ode45 w celu rozwiązania układu rownań różni się tym, że musimy podać
wektor wartości początkowych dla wszystkich zmiennych zależnych (w naszym przypadku –
wartości stężeń wszystkich składników w chwili t=0s, czyli [20 0 0 0]).
>> [t,c]=ode45(@stezenia,[0 500],[20 0 0 0]);
Następnie na wykres nanosimy przebiegi zależności stęzenia od czasu dla poszczególnych
reagentów – po każdej komendzie plot spójrz na wykres, żeby zobaczyć która linia odpowiada
któremu składnikowi.
>>
>>
>>
>>
>>
>>
hold on
plot(t,c(:,1))
plot(t,c(:,2))
plot(t,c(:,3))
plot(t,c(:,4))
7.4 Zdarzenia (Events)
Niekiedy mając dany różniczkowy model jakiegoś zjawiska (np. model zbiornika z cieczą, jak w
jednym z poprzednich podpunktów), chcemy wiedzieć dla jakiej wartości zmiennej niezależnej,
zmienna zależna osiągnie określoną wartość (np. po jakim czasie uzyskamy określony poziom
cieczy w zbiorniku). Możemy w takim wypadku narysować wykres i odczytać z niego interesujacą
nas wartosc z pewną dokładnością, jednak lepiej skorzystać w takiej sytuacji z obecnego w
matlabie mechanizmu zdarzeń. Należy w tym celu najpierw napisać funkcję, która wykryje dla nas
wystąpienie zdarzenia a następnie „poinformować” o jej istnitniu funckję całkującą – w naszym
przypadku ode45.
Rozważymy dwa przykłady – znajdziemy czas, po którym poziom cieczy w zbiorniku z punktu 7.2
47
wyniesie 0.5 metra oraz czasy, po których stopień przereagowania składnika A w przykładzie z
punktu 7.3 wyniesie 0.5, 0.8 i 0.9.
Zacznijmy zatem od zbiornika. Funkcja opisująca szybkość zmian wysokości cieczy w zbiorniku
ma postać:
function dhdt=wysokosc(t,h)
Fi=0.07; %m^3/s
A=2.5; %m^2
beta=0.08; %m^(5/2)/s
dhdt=(Fi-beta.*sqrt(h))./A;
Musimy teraz stworzyć dodatkową funkcję, która będzie odpowiedzialna za wykrycie wystąpienia
zdarzenia – w naszym przypadku będzie to moment, w którym poziom cieczy w zbiorniku wyniesie
0.5 metra.
function [wartosc, koniec, kierunek]=ev_05m(t,h)
wartosc = h-0.5;
koniec=0;
kierunek=0;
Funkcja musi zwracać trzy argumenty – pierwszy to wartość. Matlab przyjmuje, ze zdarzenie
nastąpiło wtedy, kiedy argument wartosc jest równy zero – dlatego właśnie od wysokości
odejmujemy wysokość która nas interesuje.
Kolejny argument określa, czy po wystąpieniu zdarzenia matlab ma przerwac liczenie całki (wtedy
zmiennej koniec nadajemy wartość 1) czy ma kontynuować obliczanie całki- wtedy tak jak w tym
przykładzie zmiennej nadajemy wartość 0. Zmienna kierunek pozwala dodatkowo określić czy
interesuje nas zdarzenie występujące tylko wtedy, gdy funkcja jest rosnąca (wtedy jej pochodna jest
dodatnia a my musimy nadać zmiennej kierunek wartość 1), malejąca (-1) lub czy jest to nam
obojętne (wtedy tak, jak w naszym przypadku zmiennej kierunek przypisujemy wartość 0).
Ostatnim krokiem przed wywołaniem funkcji całkującej z wykorzystaniem zdarzenia jest
utworzenie specjalnego zbioru dodatkowych opcji dla funkcji ode45, przy pomocy którego
przekażemy informację o interesującym nas zdarzeniu:
>> opt=odeset('Events',@ev_05m);
odeset tworzy taki właśnie zbiór opcji. Wszystkie poza tymi, które wymienimy w wywołaniu
funkcji (w tym przypadku jest to opcja Events), otrzymują wartości domyślne. Jako kolejny
argument przekazujemy uchwyt naszej funkcji która ma służyć do wykrycia zdarzenia. Wpisując w
Command Window help odeset dowiesz się jakie inne opcje możesz przekazywać do funkcji
całkującej.
Następnie wykonujemy całkowanie:
>> [t,h,t_05m,h_05m]=ode45(@wysokosc,[0 400],0,opt);
t_05m i h_05m to zmienne, w których znajdą się odpowiednio czas, w którym wystąpiło zdarzenie i
wysokość dla której wykryto wystąpienie zdarzenia (w naszym przypadku h_05m powinno być
rowne 0.5). Spróbuj teraz wykonać polecenie:
>> plot(t,h,'-',t_05m,h_05m,'o')
48
Aby zobaczyć gdzie na wykresie znajduje się znaleziony przy pomocy mechanizmu zdarzeń punkt.
Teraz spróbuj samodzielnie zmodyfikować zdarzenie tak, żeby otrzymać czas, po którym poziom
cieczy w zbiorniku wyniesie 0.65 m (powinienneś otrzymać wynik 88.7118 s).
Aby lepiej oswoić się z mechanizmem zdarzeń rozważymy jeszcze jeden przykład – znajdziemy
czasy, dla których stopień przereagowania skladnika A w przykładzie z rozdziału 7.3 wyniesie 0.5,
0.8 i 0.9. Oczwiście skorzystamy z napisanej wcześniej funkcji opisującej zmiany stężeń
składników w czasie:
function dcdt=stezenia(t,c)
k1=3.46e-3; %1/s
k2=6.51e-2; %1/s
k3=1.38e-4; %1/s
dcdt=[-k1*c(1),
k1*c(1)-k2*c(2),
k2*c(2)-k3*c(3),
k3*c(3)];
Pisząc funkcję wykrywającą zdarzenia, musimy pamiętać że w wektorze c mamy stężenia a nie
stopień przereagowania. Musimy zatem przeliczyć stopeiń przereagowania na odpowiadające mu
stężenie, zatem:
c 0−c
=
c0
stąd:
c=c0⋅1−
Stężenie początkowe substratu a wynosiło 20 kmol/m3, zatem :
kmol
kmol
⋅1−0.5=10 3
3
m
m
kmol
kmol
c 08=20 3 ⋅1−0.8=4 3
m
m
kmol
kmol
c 09=20 3 ⋅1−0.9=2 3
m
m
c 05=20
Funkcja wykrywająca zdarzenia będzie więc miała postać:
function [wartosc, koniec, kierunek]=evnt(t,c)
wartosc = [c(1)-10; c(1)-4; c(1)-2];
koniec=[0;0;0];
kierunek=[0;0;0];
Następnie tworzymy strukturę z opcjami dla funkcji ode45, do której przekazujemy informacje o
naszej funkcji:
>> opt=odeset('Events',@evnt);
Oraz całkujemy:
>> [t,c,te,ce]=ode45(@stezenia,[0 1000],[20 0 0 0],opt);
>> te
49
te =
200.3315
465.1555
665.4871
>> ce
ce =
10.0000
4.0000
2.0000
0.5613
0.2244
0.1123
9.3058
15.1773
16.8434
0.1329
0.5983
1.0444
W wektorze ce znajdują się stężenia wszystkich związków w reaktorze w chwili wystąpienia
zdarzenia (osiągnięcia zadanego stężenia składnika A) a w odpowiadających im wierszach wektora
te czasy, po których osiągane są szukane stopnie przereagowania.
50

Podobne dokumenty