MATLAB-opas, m-tiedostot, ohjelmointi
Päivitys: 20.8.2019
Oppaan etusivu
Ohjelmointisivun sisällys
plot | subplot |
ex+cosx
ex+cosx
M-tiedostot, skriptit ja funktiot
Avataan MATLAB-editori (New m-file) ja kirjoitetaan seuraavat
komennot:
pisteet=[10 11 15 3 29 7 0 9 30 2 1 8 20 22 5 9 23 24];
jarjestyksessa=sort(pisteet)
keskiarvo=sum(pisteet)/length(pisteet) % tai mean(pisteet)
hajonta=std(pisteet)
Talletetaan tiedostoon tentti.m.
MATLAB-istunnossa suoritetaan komento tentti.
Näin käy:
>> tentti
pisteet =
Columns 1 through 14
10 11 15 3 29 7 0 9 30 2 1 8 20 22
Columns 15 through 18
5 9 23 24
jarjestyksessa =
Columns 1 through 14
0 1 2 3 5 7 8 9 9 10 11 15 20 22
Columns 15 through 18
23 24 29 30
keskiarvo =
12.6667
hajonta =
9.7075
Tulos on sama kuin jos komennot olisi kirjoitettu Matlab-istuntoon.
Matlab-työn dokumentointi (publish)
(Seuraava tekstikappale leikattiin mini/tutoriaalista)
Usein tällaista skriptitiedostoa käsitellään pääohjelman tavoin. Se sisältää
funktiokutsuja, joko Matlab:n tai omiin funktioihin.
Työstä saa html-dokumentin kuvineen ja sisällysluetteloineen klikkaamalla
Matlab-editorin FILE-valikon valintaa publish. (Tapahtuu sitten,
kun Matlab-tulkin havaitsemat virheet on korjattu.)
Selitykset m-tiedostoissa sijoitetaan %-merkin taakse. Kappalejako saadaan
aikaan %%-alulla, samalla syntyy sisällysluettelo. KÄTEVÄÄ, käytä ihmeessä
hyväksi harjoitustöissä ym.
Kokeile: Kirjoita ja aja yllä oleva tai jokin muu. Tulos on alihakemistossa html (Vau!)
Funktio-m-tiedostot
MATLAB on funktionaalinen kieli. Ohjelmointi tarkoittaa omien
funktioiden kirjoittamista tällä kielellä.
Funktiot kirjoitetaan tekstitiedostoon, ns. m-tiedostoon.
Lisäksi on versiosta 5.3 lähtien tullut mahdolliseksi määritellä lyhyitä
"kertakäyttöluonteisia" funktioita suoraan komentotilassa. Käsittelemme
ensin lyhyesti näitä (pitkästi niitä ei voikaan käsitellä).
Versiosta 7 lähtien Matlabissa on ns. funktio-osoittimet, "function handles".
Se tekee merkkijonona annetuista funktiomäärittelyistä ja feval-
käytöstä vanhanaikaista ja tehotonta kamaa. Pidetään ne tässä vielä mukana,
mutta kaikissa uusissa esimerkeissä käytetään yksinomaan
tätä uutta osoitintapaa.
(Oppaan rakenne hiukan hypähtelee, kun Matlabiin tulee uusia ominaisuuksia.)
Komentorivifunktiot, "inline"-määrittelyt
Jos haluaisimme määritellä vaikkapa funktion
f(x)=e-x2,
voisimme toimia näin:
>> f=inline('exp(-x.^2)','x')
f =
Inline function:
f(x) = exp(-x.^2)
MATLAB tuntee nyt funktion f
, ja voimme kutsua sitä tähän
tapaan:
>> y=f(-1:0.2:1)
y =
Columns 1 through 7
0.3679 0.5273 0.6977 0.8521 0.9608 1.0000 0.9608
Columns 8 through 11
0.8521 0.6977 0.5273 0.3679
Huomaa taas piste funktion määrittelyssä potenssin yhteydessä,
sen ansiosta funktiomme toimii samoin kuin muutkin
MATLABin matemaattiset funktiot, eli palauttaa syöteargumentin kokoisen
matriisin "pisteittäin" laskettuja funktion arvoja.
(Skalaarifunktio) Kts ...
Funktio-osoittimen avulla sama tehdään näin:
**
>> f=@(x) exp(-x.^2) % Lue: f = "at x: exp(-x.^2)"
f =
@(x)exp(-x.^2)
>> f(-1:0.2:1)
ans =
Columns 1 through 8
0.3679 0.5273 0.6977 0.8521 0.9608 1.0000 0.9608 0.8521
Columns 9 through 11
0.6977 0.5273 0.3679
**
Funktiomäärittely tällä tyylillä on itse asiassa aivan sama kuin vaikkapa
Maplessa: f:=x->exp(-x^2);, eli määritellään funktio, joka
argumentilla x saa arvon exp(-x2) .
Usean muuttujan funktio määriteltäisiin näin:
**
>> g=@(x,y,a,b) a*x.^2 + b*y.^2
g =
@(x,y,a,b)a*x.^2+b*y.^2
>> g(1,0,2,3)
ans =
2
**
Funktio-osoittimen eräs hienous on, että voidaan näppärästi määritellä
parametreista riippuvia funktioita. Edellisessä esimerkissä voitaisiin ajatella a ja b parametreiksi. Meillä voisi olla käytössämme Matlab-funktio "ratkaise"
, joka kutsuu kahden muuttujan funktiota (muiden argumenttien ohella). Tällöin voitaisiin toimia tähän tapaan:
**
>> a=1; b=2;
>> g=@(x,y) a*x.^2 + b*y.^2
g =
@(x,y)a*x.^2+b*y.^2
>> g(2,3)
ans =
22
>> ratkaise(g,...)
>> a=-1; b=0; % Muutetaan parametreja.
>> g=@(x,y) a*x.^2 + b*y.^2 % Huom! funktiomääritys on uusittava näillä.
g =
@(x,y)a*x.^2+b*y.^2
>> g(2,3)
ans =
-4
>> ratkaise(g,...)
**
Palaa katsomaan tätä vaikkapa sitten, kun käsitellään
diffyhtälöratkaisijoita.
M-tiedostot
Jokaisen vakavasti MATLABilla työskentelevän on syytä tutustua
m-tiedostoihin ja ottaa ne aktiiviseen käyttöön.
Jos yllä oleva funktio kirjoitettaisiin m-tiedostosyntaksilla, se
kirjoitettaisin tiedostoon f.m
ja koodi olisi:
function y=f(x)
% Kutsu y=f(x) tuottaa samanmuotoisen matriisin kuin x.
% Tulos y koostuu funktion exp(-x.^2) arvoista x:n alkioissa.
y=exp(-x.^2);
Jotta MATLAB löytäisi tiedoston f.m
, sen on oltava matlabpolun
path varrella. Helpointa lienee käyttää addpath-
komentoa.
Huomaa, että tiedoston nimi on ratkaiseva. Suositus: Käytä
aina samaa tiedoston nimeä kuin sen määrittelemä funktion nimi.
Ongelmaksi voi muodostua, että polun varrella saattaa olla monta
f.m
-nimistä tiedostoa. Kannattaa varmistaa which-komennolla,
missä hakemistossa olevaa f.m
-funktiota MATLAB soveltaa.
Yleensä kannattaa käyttää hieman "eksoottisempia" funktionnimiä kuin f.
On hyvä tietää, missä järjestyksessä MATLAB hakee sille annettuja symboleja.
Kun MATLABille kirjoitetaan nimi, esimerkiksi foo
,
MATLAB-tulkki toimii seuraavassa järjestyksessä:
- Tarkistaa onko
foo
muuttuja
- Tarkistaa onko
foo
sisäänrakennettu funktio
- Etsii nykyhakemistosta
foo.mex
tai
foo.m
-nimistä tiedostoa.
- Etsii MATLABin hakupolun osoittamista hakemistoista
em. tiedostoja. Katso komento
path
.
MEX-tiedostot liittyvät käyttäjän tekemiin C- tai fortran-kielisiin
aliohjelmiin. Käsittelemme niitä myöhemmin.
M-tiedostot: skriptejä tai funktioita
Mikä tahansa tekstitiedosto tiedosto.m
, joka sisältää
MATLAB-komentoja, on m-tiedosto. Jos m-tiedosto on MATLAB-polun
varrella, ja kirjoitamme sen nimen, niin sen sisältämät komennot
tulevat suoritetuiksi. Kyseessä on komentotiedosto eli skripti.
Esimerkiksi MATLABin mukana tulevat demot ovat tällaisia skriptejä.
Jos M-tiedoston ensimmäinen rivi alkaa sanalla
function
on kyseessä funktion määrittely. Funktio eroaa
skriptistä siinä, että funktiolle voi antaa parametreja ja
funktionmäärittelyn sisällä olevat muuttujanmäärittelyt ja suoritetut
laskutoimitukset ovat lokaaleja ts. ne eivät näy
varsinaisessa MATLAB-työtilassa. Suuri osa MATLABin mukana tulevista
funktiosta on toteutettu M-tiedostoina ja niiden sisältö on siten
vapaasti tutkittavissa (esimerkiksi MATLAB-komennon
type
avulla).
Lisää esimerkkejä M-funktiosta
Edellä oli jo esillä funktiotiedosto f.m
.
Otamme joukon erilaisia esimerkkejä.
Ajatellaanpa, että haluaisimme laskea annettujen lukujen keskiarvon.
Luvut olisi sopivaa tallettaa
vektoriin x
. Keskiarvo saataisiin yksinkertaisesti lausekkeella
sum(x)/length(x)
. Kokeillaan vaikka näin:
>> x=1:10
x =
1 2 3 4 5 6 7 8 9 10
>> sum(x)/length(x)
ans =
5.5000
Voimme haluta kirjoittaa funktion, jolle annetaan argumentiksi datavektori
x
ja joka palauttaa vektorin alkioiden keskiarvon.
Kirjoitamme tiedostoon keskiarvo.m
seuraavan koodin (Matlabin omalla
editorilla tai millä tahansa muulla tekstieditorilla.)
function y = keskiarvo1(x)
% Funktio palauttaa syötevektorin x alkioiden keskiarvon.
%
y = sum(x)/length(x);
Funktio tulee sijoittaa hakemistoon, joka on Matlab-polun varrella.
Ellei näin ole tehty, pitää ennen funktion kutsua antaa sopiva
addpath-komento.
Esimerkiksi
>> help keskiarvo1
Funktio palauttaa syötevektorin x alkioiden keskiarvon.
>> addpath /home/apiola/matlab/opas/marko/matopas/mfiles
>> keskiarvo1([1,2,3])
ans =
2
>> ka=keskiarvo1(1:10)
ka =
5.5000
Esimerkki havainnollistaa seuraavia periaatteita:
- Otsikkorivin jälkeisten kommenttirivien teksti tulostuu help-
komennolla (kätevää).
- Otsikkorivillä esiintyy muuttujan nimi (tässä y). Funktion koodissa
viimeksi tälle muuttujalle sijoitettu arvo palautetaan funktion arvona.
- Koodissa on syytä lopettaa kaikki sijoituslauseet puolipisteeseen,
muussa tapauksessa funktion kutsu aiheuttaa ylimääräisiä, usein hämmentäviä
tulostuksia. (Testausvaiheessa ne voivat olla hyödyksi.)
Jos haluaisimme sallia myös datan antamisen matriisina, ja haluaisimme sen
toimivan samaan tyyliin kuin funktiot sum, min, max, ...
, voisimme
täydentää koodia näin:
function y = keskiarvo2(x)
% keskiarvo(x) palauttaa
% - x:n alkioiden keskiarvon, jos x on vektori.
% - x:n sarakkeiden keskiarvojen muodostaman vektorin, jos x on matriisi.
%
[m,n] = size(x);
if m == 1 % Vaakavektorin (1 x n-matriisin) tapauksessa komponenttien
m = n; % lukumäärä on n, muuten m .
end
y = sum(x)/m;
Laajemmassa oppaassamme puhumme "vektorifunktioista".
Nämä toimivat juuri funktioiden sum, min, max, ...
tavoin, eli palauttavat vektoriargumentilla skalaarituloksen ja
matriisiargumentilla operoivat sarakkeittain.
Jos haluaisimme laskea matriisin A
kaikkien alkioiden keskiarvon,
olisi
kutsu: keskiarvo2(keskiarvo2(A))
tai keskiarvo2(A(:))
.
Toinen ajattelutapa olisi kirjoittaa funtio, joka palauttaa aina kaikkien
alkioiden keskiarvon. Se olisi yksinkertaisempaa:
function y = keskiarvo3(x)
% Funktio palauttaa syötteenä annetun vektorin tai matriisin x
% kaikkien alkioiden keskiarvon.
%
x=x(:); % Jos x on matriisi, se "jonoutetaan" pitkäksi vektoriksi.
% (Vektoriargumenttia jonoutus ei haittaa.)
y = sum(x)/length(x);
Käyttötarkoituksesta riippuu, kummanlainen funktio on tarkoituksenmukaisempi.
Tärkeää on kirjoittaa alkukommentteihin, mitkä ovat funktion
toimintaperiaatteet.
Useita tulosarvoja
Toisinaan on kätevää, kirjoittaa funktio, joka palauttaa useamman tulosarvon.
Tässä esimerkki, joka palauttaa sekä keskiarvon että keskihajonnan.
Kirjoitetaan funktio nyt pelkästään vektoriargumentille.
function [ka,haj] = tilasto1(x)
% Palautetaan keskiarvo ja keskihajonta.
% x - vektori
% esim: [karvo,kh]=tilasto1(1:10)
n = length(x);
ka = sum(x)/n;
haj = sqrt(sum((x - ka).^2)/n);
Kutsuesimerkki:
>> [karvo,kh]=tilasto1(1:10)
karvo =
5.5000
kh =
2.8723
Jos tällaista funktiota kutsutaan yhdellä paluumuuttujan nimellä, palautetaan
ensimmäinen, tässä tapauksessa keskiarvo.
Funktiomäärittelyn sisällä on käytettävissä hyödylliset muuttujat
nargin
ja nargout
, jotka ilmaisevat
funktion kutsussa esiintyvien syöte- tai tulosargumenttien lukumäärän.
Esimerkki nargin:n käytöstä
** Ota ensin ohjausrakenteet ja lisää esimerkkejä, kehittele nargin-nargout-asiat esimerkkien täydentämiseen**
Tyypillinen käyttötapa on sellainen, jossa halutaan antaa osalle argumenteista
jokin oletusarvo. Tällaisia ovat usein esimerkiksi toleranssit, iteraatioiden
maksimimäärä, piirtodatapisteiden lukumäärä, ym.
Otetaan esimerkiksi neliöjuuren
√a
laskeminen Newtonin menetelmällä.
Iteraatiokaava on
xk+1=12(xk+axk).
Koodissa esiintyy while-ohjausrakenne.
Iteratiivista algoritmia ei voi "vektoroida", joten ohjausrakenteen
käyttö ei ole vältettävissä.
function x=itersqrt(a,tol,maxiter)
% Palautetaan iteraatiovektori, joka suppenee kohti sqrt(a):ta.
% Oletustoleranssi = eps.
% Oletusarvo maksimaaliselle iteraatiomäärälle = 50.
if nargin < 3, maxiter=50; end
if nargin < 2, tol=eps; end
x(1)=a;
k=1;
suhtero=inf; % Näppärä tapa alustaa
while(suhtero > tol)
x(k+1)=(x(k)+a./x(k))/2;
k=k+1;
suhtero=abs((x(k)-x(k-1)))/x(k-1);
if k > maxiter
error(['Ei suppene ',num2str(maxiter),':lla iteraatiolla'])
end
end
Kutsuesimerkkejä:
>> format long
>> itersqrt(2)
ans =
Columns 1 through 4
2.00000000000000 1.50000000000000 1.41666666666667 1.41421568627451
Columns 5 through 7
1.41421356237469 1.41421356237309 1.41421356237309
>> x=itersqrt(20,.0001,6)
??? Error using ==> itersqrt
Ei suppene 6:lla iteraatiolla
>> x=itersqrt(20,.0001,7)
x =
Columns 1 through 4
20.00000000000000 10.50000000000000 6.20238095238095 4.71347454528837
Columns 5 through 7
4.47831444547438 4.47214021706570 4.47213595500161
Esimerkki nargout:n käytöstä
Kuten edellä todettiin, tulosargumenttien lukumäärän testaaminen ei
"peruskäytössä" ole useinkaan tarpeen.
Erityisen hyödyllistä se on esimerkiksi kahden tulosargumentin tapauksessa,
jossa pelkästään toisen
tuloksen pyytäminen on tavallista, ja toisen laskeminen on raskasta.
Hyvä esimerkki tällaisesta on MATLAB:n funktio eig.
Se on ns. "builtin-function" ja sen koodi ei ole luettavissa.
Periaatteessa toteutus voisi olla seuraavanlainen:
** Huono esimerkki, oikeasti ominaisvektorit lasketaan ensin **
function [OA,OV]=eig(A)
% Lasketaan ominaisarvot ja pyydettäessä myös ominaisvektorit.
% Kutsut: lambda=eig(A); [lambda,V]=eig(A);
%
OA=laskeominaisarvot(A);
if nargout == 2, OV=laskeominaisvektorit(A); end
Ohjausrakenteet
MATLAB sisältää muista ohjelmointikielistä tutut
ohjausrakenteet,
kuten
for
ja
while
loopit sekä
if .. else
lauseen.
Edellä näimme jo esimerkkejä while- ja if-rakenteista.
Kenties tavallisin on for-lause, jota demonstroimme heti.
Muistutamme ensin, että ohjausrakenteita harkittaessa on syytä muistaa
vektoriajattelu. Monet
asiat voidaan hoitaa suoraan vektorioperaatioilla ilman
ohjausrakenteita. Tietenkään tämä ei ole aina mahdollista, kuten
iteraatiivisissa algoritmeissa. (Vrt. edellä oleva neliöjuuri-iteraatio.)
Seuraava toimii, mutta edustaa "vääräoppista" skalaariajattelua,
joka tekee koodista sekä tarpeettoman mutkikasta että tehotonta.
Esimerkki toimikoon tässä for-rakenteen opetustarkoituksessa.
t=0:.01:200;
for i=1:length(t);
y(i) = sin(t(i));
end
Oikeaoppinen tapa tehdä sama suoraan vektorioperaationa on yksinkertaisesti:
t = 0:.01:200;
y = sin(t);
tai suoraan
y = sin(0:.01:200);
Tällaisella vektorilla (pituus = 20001) näkyy hyvin selkeä ero
suoritusajassa.
Tehtävä:
Tee pieni vertaileva tutkielma edellä olevan for-silmukan ja oikeaoppisen
vektorioperaation välillä. Sen saat tic,toc
-yhdistelmällä:
>> tic % Kello käyntiin
>> komento1
>> komento2
>> ...
>> toc % Kellon pysäytys
Esimerkki "oikeaoppisesta" for-silmukasta
Lasketaan vektoreita for-silmukassa (vaikka Gaussin eliminaatio)
Funktion välittäminen argumenttina
Monissa tilanteissa on tarpeellista välittää jokin funktio argumenttina
toiselle funktiolle. Esimerkin tästä näimme
Funktion fplot yhteydessä.
Numeerinen integrointi, nollakohta, minimi
Oman funktion tekeminen on välttämätöntä mm. yllä mainituissa
tehtävissä. Otetaan esimerkiksi numeerinen integrointi, johon
MATLAB:ssa on funktiot
quad
ja
quad8
.
Kokeile esim.
>> quad('g',0,5); % Oletustoleranssi
>> format long
>> quad('g',0,5,0.000000001); % Käyttäjän vaatima toleranssi
Muita otsikossa olevia (ja olemattomiakin) "funktiofunktioita":
>> help funfun
Tämä on hiukan vanhentunut lista
Function functions - nonlinear numerical methods.
ode23 - Solve differential equations, low order method.
ode23p - Solve and plot solutions.
ode45 - Solve differential equations, high order method.
quad - Numerically evaluate integral, low order method.
quad8 - Numerically evaluate integral, high order method.
fmin - Minimize function of one variable.
fmins - Minimize function of several variables.
fzero - Find zero of function of one variable.
fplot - Plot function.
See also The Optimization Toolbox, which has a comprehensive
set of function functions for optimizing and minimizing functions.
Tutki helpin avulla ja testaa.
Ulkoisten ohjelmien käyttö
MATLABista käsin voidaan kutsua käyttäjän kirjoittamia C- tai
fortran aliohjelmia. Nämä näkyvät MATLAB-istunnossa tavallisina
MATLAB-funktioina. Näin voidaan lisätä huomattavasti käytettävissä
olevien funktioiden määrää. Ulkoisia ohjelmia käytetään MEX-tiedostojen avulla.
Tiedostovälitteinen datan siirto ulkoiseen ohjelmaan
Yksinkertaisin tapa käyttää ulkoista ohjelmaa perustuu parametrien
ja datan välitykseen tiedostojen avulla. Olkoon meillä ohjelma
myprog
, joka luettuaan datan määrätyn nimisestä tiedostosta,
käsittelee sitä ja lopuksi kirjoittaa tulokset toiseen
tiedostoon. Välittävä MATLAB-funktio voisi olla vaikka seuraavanlainen
function y=myprog(x)
save indata.dat x -ascii
!run myprog
load outdata.dat
y=outdata;
MATLAB-funktioilla save
ja
load
talletetaan ja luetaan ASCII-muodossa olevaa dataa. Huutomerkki
!
komentorivin alussa luo käyttöjärjestelmän aliprosessin,
jossa annettu ohjelma suoritetaan. Katso myös esimerkkinä vaikka
print.m
-funktion toteutusta.
Kehittyneempi tapa omien ohjelmien käyttöön on tehdä MEX-tiedostoja, so. ohjelmia joihin
on suoraan linkitetty oma aliohjelma ja jotka dynaamisesti ladataan
muistiin ja joissa parametrit välitetään MATLABin sisäisesti.
[Edellinen]
[Seuraava]
[Alkusivu]