MATLAB Ohjelmointi Timo Mäkelä
MATLAB – Ohjelmointi
2
SISÄLTÖ: 1. YLEISTÄ....................................................................................................................................4 1.1 M-TIEDOSTOT.........................................................................................................................4 1.2 SYÖTTÖ JA TULOSTUS............................................................................................................5 2. FUNKTIOT................................................................................................................................9 2.1 FUNKTION RAKENNE..............................................................................................................9 2.2 ALIFUNKTIOT JA YKSITYISET FUNKTIOT..............................................................................12 2.3 FUNKTION MUUTTUJAT........................................................................................................12 2.4 ANONYYMI FUNKTIO............................................................................................................14 3. OHJAUSLAUSEET................................................................................................................16 3.1 TOISTOLAUSEET...................................................................................................................16 3.1.1 for-lause........................................................................................................................16 3.1.2 while-lause....................................................................................................................21 3.2 EHTOLAUSEET......................................................................................................................23 3.2.1 if-lause..........................................................................................................................23 3.2.2 switch-lause..................................................................................................................29 3.2.3 try-lause........................................................................................................................33 3.3 KESKEYTYSLAUSEET............................................................................................................34 4. DIFFERENSSIYHTÄLÖT.....................................................................................................36 4.1 TEORIAA...............................................................................................................................36 4.1.1 Differenssiyhtälö..........................................................................................................36 4.1.2 Differenssiyhtälöryhmä................................................................................................38 4.2 NUMEERINEN RATKAISEMINEN............................................................................................40 4.2.1 Differenssiyhtälö..........................................................................................................40 4.2.2 Differenssiyhtälöryhmä................................................................................................42 5. FUNKTION PARAMETREISTA..........................................................................................45 5.1 KAHVAT JA FUNKTIOPARAMETRIT.......................................................................................45 5.2 SOVELLUS – HAARUKOINTIMENETELMÄ..............................................................................45 5.3 VAIHTELEVA MÄÄRÄ ARGUMENTTEJA.................................................................................47 6. REKURSIIVINEN FUNKTIO...............................................................................................51 7. SOVELLUKSIA......................................................................................................................53 7.1 FUNKTION MAKSIMOINTI......................................................................................................53 7.2 FUNKTIOSARJOJEN PIIRTÄMINEN..........................................................................................55 7.3 TRIGONOMETRINEN FOURIER-SARJA....................................................................................59 7.4 LENTORATA HEITTOLIIKKEESSÄ...........................................................................................64 8. HIIREN KÄYTTÖ GRAFIIKKAIKKUNASSA..................................................................69 9. TIETOTYYPPEJÄ..................................................................................................................71 9.1 MERKKIJONOT......................................................................................................................71 9.1.1 Muunnoskomentoja.......................................................................................................71 9.1.2 Vertailukomentoja........................................................................................................74 9.1.3 Käsittely- ja testauskomentoja......................................................................................75
MATLAB – Ohjelmointi
3
9.1.4 Evaluointikomentoja.....................................................................................................78 9.1.5 Merkkijonon kirjoittaminen..........................................................................................79 9.1.6 Merkkijonosta lukeminen..............................................................................................81 9.2 SOLUTAULUKOT...................................................................................................................82 9.3 TIETUEET..............................................................................................................................86 10. TIEDOSTOT..........................................................................................................................90 10.1 TIEDOSTON AVAAMINEN....................................................................................................90 10.2 TIEDOSTON SULKEMINEN...................................................................................................91 10.3 BINÄÄRITIEDOSTON KÄSITTELY.........................................................................................91 10.4 TEKSTITIEDOSTON KÄSITTELY...........................................................................................94 10.5 KOMENTOIKKUNAN MUUTTUJIEN TALLENTAMINEN..........................................................96 10.6 EXCEL-TIEDOSTOJEN KÄSITTELY........................................................................................98
MATLAB – Ohjelmointi
4
1. YLEISTÄ 1.1
M-tiedostot
MATLABin tehokas käyttö on mahdollista vasta, kun osaa ohjelmoida MATLABilla. MATLABissa on korkean tason ohjelmointikieli, jolla ohjelmia tehdään. Ohjelmointi MATLABilla on helpompaa kuin varsinaisilla ohjelmointikielillä. Omat ohjelmat laajentavat MATLABin käskyjä. Usein toistuvat komentosarjat kannattaa tehdä ohjelmiksi. Seuraavassa esitellään MATLAB-ohjelmoinnin alkeita. Vaikka tässä lähdetäänkin perusteista, omaksumista helpottaa se, että lukija on hiukan perillä ohjelmoinnista. Ohjelmat ovat m-tiedostoja. Nimitys tulee siitä, että niiden tarkenteena on .m. M-tiedostot voivat olla skriptejä tai funktioita. Nämä eroavat seuraavasti: Skripti on vain jono komentoja, joita käytetään automatisoimaan laskentaa. Skriptin muuttujat ovat yleisiä komentoikkunan muuttujia. Skriptin komentojen tulos tulostuu komentoikkunaan, ellei komentoja päätetä puolipisteellä. Funktio on ohjelma, jonka liittyminen ulkomaailmaan tapahtuu sisäänmeno- ja ulostuloparametrien kautta1. Funktion muuttujat ovat funktion sisäisiä muuttujia, joten ne eivät sotkeudu komentoikkunan muuttujiin. Funktiota voidaan käyttää laajentamaan MATLABin ominaisuuksia. M-tiedostoja on käsitelty kirjassa Matematiikkaa MATLABilla luvussa 5. Tässä kirjassa keskitytään ohjelmien eli funktioiden tekemiseen. M-tiedostoja ajetaan komentorivillä aivan samoin kuin muitakin MATLABin komentoja. Skripti ajetaan kirjoittamalla m-tiedoston nimi ilman tarkennetta .m. Funktio ajetaan kirjoittamalla funktion nimi ja antamalla suluissa oleville kutsuparametreille arvot. M-tiedosto voidaan luoda editorilla. Editorin voi käynnistää komennolla edit (tai edit TiedostonNimi) tai HOME-valikoston painikkeilla
Editori tuntee MATLABin syntaksin. Editorissa voi olla auki useita tiedostoja. Jos useampi tiedosto on auki, on editori-ikkunan vasemmassa ylänurkassa välilehdet, josta voi klikkaamalla vaihtaa tiedostoa. M-tiedoston sisällön voi tulostaa komentoikkunaan komennolla type tiedoston_nimi. Tiedostonimen tarkenteen .m voi tiedoston nimestä jättää pois. Oletushakemistossa olevien tiedostojen nimet saa näytölle komennolla what. ESIMERKKI. Seuraavassa on toteutettu Lissajous’n käyrien piirto skriptinä ja funktiona. Tee ohjelmat editorilla ja tallenna tiedostoihin. Tyhjennä MATLABin työtila Workspace komennolla clear ennen skriptin ja funktion ajoa. Mitä eroa on työtilassa ajojen jälkeen?
1
Funktiossa voi tietenkin olla myös luku- ja tulostuskäskyjä.
MATLAB – Ohjelmointi
5
Skripti: Tallenna skripti tiedostoon lissajous.m. Voit ajaa skriptin käskyllä lissajous. Sulje ensin grafiikkaikkuna. Anna komento ja paina viisi kertaa Enteriä. Näytölle tulostuu viisi erilaista Lissajous’n käyrää. % Lissajous'n-käyriä t = 0:0.01:2*pi; for k = 1:5 plot(cos(k*t),sin((k+1)*t)) pause end
Funktio: Tallenna funktio tiedostoon lissa.m. Funktio voidaan ajaa esim. komennolla lissa(10,15). Kokeile tätä! Sulje ensin grafiikkaikkuna. Anna komento ja paina Enteriä, kunnes uusia kuvia ei tule. Näytölle tulostuu erilaisia Lissajous’n käyriä. Funktiossa on kaksi kutsuparametria, joille kutsussa annetaan arvot. Kokeile erilaisia arvoja. Huomaa, että tämä funktio ei palauta mitään arvoa. function lissa(m,n) % Lissajous'n-käyriä funktiona t = 0:0.01:2*pi; for k = m:n plot(cos(k*t),sin((k+1)*t)) pause end
Molemmissa m-tiedostoissa esiintyvää for-silmukkaa käsitellään tarkemmin myöhemmin. Komento pause aiheuttaa sen, että ohjelma jää odottamaan jonkin painikkeen painamista.
1.2
Syöttö ja tulostus
Normaalisti funktio välittää tietoa ympäristön kanssa parametrien välityksellä. MATLABissa on kuitenkin tavanomaisten ohjelmointikielten tyyppisiä syöttö- ja tulostuskäskyjä, joista joitakin esitetään seuraavassa. Kirjoittamalla muuttujan nimi tulostetaan näytölle muuttujan nimi ja arvo. Komennolla disp(A) tulostetaan pelkästään muuttujan A arvo. Jos on A on merkkijono1 tulostetaan merkkijonon sisältävä teksti. >> A = [1 2;3 4]; >> A A =
1 3
2 4
>> disp(A) 1
Merkkijono on yksinkertaisten lainausmerkkien sisällä oleva teksti.
MATLAB – Ohjelmointi 1 3
6
2 4
>> disp('Tässä on merkkijono') Tässä on merkkijono
Näppäimistöltä luetaan reaalilukuja ja matriiseja komennolla a = input(kehote), missä kehote on merkkijono. Tällöin näytölle tulostuu merkkijono kehote ja muuttujaan a tallennetaan käyttäjän syöttämä arvo. Jos käyttäjä ei syötä mitään, vaan painaa vain Enteriä, niin muuttujaan a tallentuu tyhjä matriisi. Jos komento päätetään puolipisteellä, ei tulosta esitetä näytöllä. Merkkijonoon kehote saadaan rivinvaihto aikaiseksi merkeillä \n. Syötetty arvo voi sisältää lausekkeita ja työtilassa olevia muuttujia. >> x = input('Anna x: ') Anna x: 1.7 x =
1.7000
>> x = input('Anna x: ') Anna x: 2*x+5 x =
8.4000
>> A = input('Anna uusi matriisi.\nMatriisi? ') Anna uusi matriisi. Matriisi? [1 3; 4 7] A =
1 4
3 7
>> mxn = input('Anna matriisin kertaluku: ') Anna matriisin kertaluku: size(A) mxn =
2
2
Silmukkarakenteessa syötön loppumista voi testata komennolla isempty: >> A=input('Anna matriisi:') Anna matriisi: A =
[]
>> isempty(A) ans = 1
Komennolla str = input(kehote, ’s’) luettu arvo tallennetaan muuttujaan str merkkijonona.
MATLAB – Ohjelmointi
7
>> valinta = input('Jatketaanko (y/n)? ','s') Jatketaanko (y/n)? y valinta = y
ESIMERKKI. Seuraavassa on yksinkertainen kyselevä ohjelma funktion kuvaajan piirtämiseksi. function plotfun disp('Piirretään funktion f(x) kuvaaja välillä [a,b]'); fun = input('Anna funktio :','s'); vali = input('Anna väli [a,b]: '); clf; ezplot(fun,vali);
Ohjelman ajo tapahtuu seuraavasti: >> plotfun Piirretään funktion f(x) kuvaaja välillä [a,b] Anna funktio :x*sin(1/x) Anna väli [a,b]: [-1,1]
Piirtoikkunaan tulee funktion kuvaaja.
TEHTÄVIÄ 1. Tee ohjelma, joka kysyy lämpötilaa Celsius-asteina ja tulostaa sen Fahrenheit-asteina. Käytä laskennassa kaavaa F =1,8⋅C32 . 2. Tee ohjelma, joka laskee katkaistun ympyräkartion tilavuuden V πh 2 V= (r 1 +r 2 r 2 +r 22 ) , 3
MATLAB – Ohjelmointi missä h on ympyräkartion korkeus r 1 on pohjaympyrän säde r 2 on kansiympyrän säde. Ohjelma kysyy syöttöarvot käyttäjältä ja tulostaa tilavuuden näytölle.
8
MATLAB – Ohjelmointi
9
2. FUNKTIOT 2.1
Funktion rakenne
Funktio koostuu seuraavista osista: 1. Funktion esittelyrivi. Tämä on ohjelman ensimmäinen rivi, joka kertoo MATLABille, että m-tiedosto sisältää funktion. Tällä rivillä esitellään funktion nimi sisäänmenoparametrit ulostuloparametrit Funktion esittelyrivi on muotoa function out_param = funktion_nimi(in_param), missä in_param sisältää funktion sisäänmeno- eli kutsuparametrit. Ne kirjoitetaan pilkulla erotettuna. Jos sisäänmenoparametreja ei ole voidaan sulut jättää pois. out_param ilmoittaa ulostuloparametrit. Niitä voi olla o ei yhtään: jätetään kokonaan pois tai kirjoitetaan [ ]. o yksi: kirjoitetaan ulostuloparametrin nimi o useampi: kirjoitetaan ulostuloparametrien nimet pilkulla erotettuna hakasulkuihin 2. H1-rivi. Tämä on kommenttirivi, joka on ohjelman toinen rivi. Rivi alkaa %-merkillä. MATLAB tulostaa H1-rivin, kun help-komento kohdistetaan hakemistoon. Tämän osan voi jättää pois. 3. Help-teksti. Nämä ovat kommenttirivejä, jotka alkavat riviltä kolme. Help-teksti päättyy tyhjään riviin tai komentoriviin. MATLAB tulostaa H1-rivin ja help-tekstin, kun help-komento kohdistetaan tiettyyn funktioon. Tämän osan voi jättää pois. 4. Funktion runko. Tämä osa sisältää funktion varsinaisen ohjelmakoodin antaa arvon mahdollisille ulostulo-parametreille. Funktiota muodostettaessa on käytettävä taulukko-operaatioita (.*, .^, ./), jos sisäänmenoparametri voi olla vektori tai matriisi. 5. Kommentit. Kommentit alkavat %-merkillä ja päättyvät rivin lopussa. Kommentteja voi sijoittaa minne tahansa ohjelmassa. Osat 1, 2, 3 ja 4 on oltava ohjelmassa tässä järjestyksessä. Osat 1 ja 4 ovat pakollisia. ESIMERKKEJÄ funktion esittelyrivistä: function lissa(m,n) function A = heron(a,b,c) function [x,y,x] = sphe2car(rho,theta,phi)
MATLAB – Ohjelmointi
10
ESIMERKKI. Määritellään funktio heron(a,b,c), jolla on kolme parametria: function A = heron(a,b,c) % HERON Kolmion pinta-ala % heron(a,b,c) laskee kolmion pinta-alan, kun kolmion sivujen % pituudet ovat a, b, c. p = (a+b+c)/2; % Kolmion piirin puolikas A = sqrt(p*(p-a)*(p-b)*(p-c));
Tallennetaan funktio hakemistoon work. Kohdistetaan help-komento nykyiseen hakemistoon: >> help work … HERON Kolmion pinta-ala …
Kohdistetaan help-komento funktioon: >> help heron HERON Kolmion pinta-ala heron(a,b,c) laskee kolmion pinta-alan, kun kolmion sivujen pituudet ovat a, b, c.
Funktioita käytetään seuraavasti: >> heron(3,4,5) ans = 6
Funktion nimen muodostaminen noudattaa samoja sääntöjä kuin muuttujan nimen muodostaminen: nimen on alettava kirjaimella ja se voi sisältää kirjaimia (ei kuitenkaan ääkkösiä), numeroita ja alaviivoja. Nimen 63 ensimmäistä merkkiä otetaan huomioon. Isot ja pienet kirjaimet ovat eri kirjaimia. Funktion nimenä ei voi olla MATLABin avainsana, kuten if tai end. Myöskään MATLABin funktioiden nimiä ei ole hyvä käyttää omien funktioiden niminä, sillä se voi johtaa yllättäviin virheisiin. Funktio on syytä tallentaa samannimiseen m-tiedostoon, muuten voi tulla vaikeasti havaittavia virheitä. Siis funktio fun tallennetaan tiedostoon fun.m. Funktio ajetaan kirjoittamalla funktion nimi ja sulkuihin funktion sisäänmenoparametrien arvot. Tarkemmin: funktion function [y1,y2, ...] = funktion_nimi(x1,x2,...) ajo komennolla funktion_nimi(a1,a2,...) palauttaa ensimmäisen ulostuloparametrin y1 arvon muuttujaan ans. b1 = funktion_nimi(a1,a2,...) palauttaa ensimmäisen ulostuloparametrin y1 arvon ja tallentaa sen muuttujaan b1.
MATLAB – Ohjelmointi
11
[b1,b2,...] = funktion_nimi(a1,a2,...) palauttaa ulostuloparametrien arvot ja tallentaa ne muuttujiin b1,b2,.... ESIMERKKI. Tehdään funktio, jonka sisäänmenoparametrina on vektori ja ulostuloparametreina vektorin suurin ja pienin arvo. Funktio: function [ymin,ymax,ymean] = minmax(vect) ymin = min(vect); ymax = max(vect); ymean = mean(vect);
Funktion ajo: >> v=rand(1,100); >> minmax(v) ans = 0.0046 >> [y1,y2]=minmax(v) y1 = 0.0046 y2 = 0.9961 >> [y1,y2,y3]=minmax(v) y1 = 0.0046 y2 = 0.9961 y3 = 0.4675
TEHTÄVIÄ 1. Tee ohjelma, jonka sisäänmenoparametrina on lämpötila Celsius-asteina ja ulostuloparametrina on lämpötila Fahrenheit-asteina. Käytä laskennassa kaavaa F =1,8⋅C +32 . 2. Tee ohjelma, jonka sisäänmenoparametreina on kaksi reaalilukua ja ulostuloparametreina reaalilukujen summa ja tulo. 3. Tee ohjelma, joka laskee ympyrän
A 1= α π r 2 360
•
sektorin pinta-alan
•
segmentin pinta-alan A2 =
missä • r on ympyrän säde •
a on keskuskulma asteina.
r2 α π−sin α 2 180
(
)
MATLAB – Ohjelmointi
12
Ohjelman sisäänmenoparametreina on luvut r ja ja ulostuloparametreina A1 ja A2 . 4. Tee ohjelma, joka tulostaa taulukon Celsius- ja Fahrenheit-asteiden vastaavuuksista. Syöttötietoina annetaan Celsiusasteiden alaraja, yläraja ja taulukointiväli. Käytä laskennassa kaavaa F =1,8⋅C +32 .
2.2
Alifunktiot ja yksityiset funktiot
M-tiedosto voi sisältä useita funktioita. Tiedoston ensimmäinen funktio on pääfunktio (primary function), muut funktiot ovat alifunktiota (subfunction). Vain pääfunktio ja muut samassa m-tiedostossa olevat alifunktiot voivat kutsua alifunktiota. Jokainen alifunktio alkaa määrittelyrivillä ja sisältää koodin normaaliin tapaan. Alifunktiot voivat olla missä järjestyksessä tahansa. Yksityinen funktio (private function) on funktio, joka sijaitsee alihakemistossa private. Vain private-hakemiston äiti-hakemistossa olevat funktiot voivat kutsua yksityistä funktiota. Alifunktioita ja yksityisiä funktioita käyttäen voidaan luoda tietystä ohjelmasta paikallinen versio. Tämä johtuu siitä, että MATLABissa funktion tai muuttujan nimen selvittäminen tehdään seuraavassa järjestyksessä: Tarkistetaan 1. onko kyseessä muuttuja. 2. onko kyseessä kutsuvan funktion alifunktio. 3. onko kyseessä onko kyseessä kutsuvaan funktioon liittyvä yksityinen funktio. 4. onko kyseessä jokin funktio MATLABin hakupolussa. Hakupolussa ensimmäinen kohdattu nimi valitaan. Jos on useita samannimisiä funktioita, valitaan yo. järjestyksessä ensimmäinen.
2.3
Funktion muuttujat
Funktion muuttujista voidaan todeta seuraavaa: Muuttujan nimi alkaa kirjaimella. Muuttujassa voi olla korkeintaan 63 merkkiä. Muuttujia ei tarvitse esitellä. Sijoituskäsky luo muuttujan tai muuttaa muuttujan arvon. Funktion muuttujat ovat lokaaleja eli funktion sisäisiä. Niitä ei voi käyttää funktion ulkopuolella. Poikkeuksena ovat globaalit muuttujat ja pysyvät muuttujat. Globaali muuttuja on sellainen muuttuja, jonka arvo on käytettävissä ja muutettavissa kaikissa niissä funktioissa, joissa muuttuja on määritelty globaaliksi. Jos globaalia muuttujaa halutaan käyttää komentoikkunassa, on se sielläkin määriteltävä globaaliksi. Globaalit muuttujat suositellaan määriteltäväksi funktion alussa ennen niiden käyttöä. Komennolla global x y z määritellään muuttujat x, y, z globaaleiksi. Pysyvä muuttuja on sellainen lokaali muuttuja, jonka arvo säilyy seuraavaan funktion kutsuun asti. Komennolla persistent x y z
MATLAB – Ohjelmointi
13
määritellään muuttujat x, y, z pysyviksi. Pysyvää muuttujaa voi käyttää vain funktion sisällä. Pysyvät muuttujat on määriteltävä funktion alussa ennen niiden käyttöä. ESIMERKKI. Tehdään funktio, joka tallennetaan tiedostoon herong.m. Huomaa, että funktiossa ei ole kutsuparametreja. function A = herong() % HERON Kolmion pinta-ala % HERON() laskee kolmion pinta-alan, kun kolmion sivujen % pituudet ovat a, b, c % muuttujat a, b, c ovat globaaleja. global a b c p = (a+b+c)/2; % Kolmion piirin puolikas A = sqrt(p*(p-a)*(p-b)*(p-c));
Annetaan komentoikkunassa globaalimäärittely >> global a b c
Annetaan muuttujille arvot >> a = 3; b = 4; c = 5;
Ajetaan funktio >> herong ans = 6
Muutetaan a:n arvo: >> a = 5 a = 5
Ajetaan funktio >> herong ans = 9.1652
Kuten yo. funktiosta nähdään, parametrien välitys globaalien muuttujien välityksellä ei ole kovinkaan havainnollista. Tämä saattaa johtaa vaikeasti havaittaviin virheisiin. Siksi globaalien muuttujien käyttö on syytä rajoittaa vain erikoistilanteisiin. Globaalit muuttujat suositellaan kirjoitettaviksi isoilla kirjaimilla. Tällöin virheellinen käyttö ehkä pienenee.
TEHTÄVIÄ
MATLAB – Ohjelmointi
14
1. Ketjupyörästön ketjun pituuden L määrittäminen. Syöttötietoina annetaan ketjupyörien säteet R ja r sekä ketjupyörien keskipisteiden etäisyys c. Ketjun pituus L lasketaan käyttäen seuraavia kaavoja L=2 t+ b1+ b2 , missä t=√ c 2−(R−r )2 (180+ 2 α) π R b1 = 180 (180−2 α)π r b 2= 180 Edellä kulman a yksikkö on aste ja se määräytyy ehdosta R−r sin α= . c Tee ohjelma, jolla voit määrittää ketjun pituuden.
2.4
Anonyymi funktio
Yksinkertainen funktio voidaan määritellä komentorivillä anonyyminä funktiona komennolla fkahva = @(arglist) lauseke Komennossa arglist sisältää funktion argumentit pilkulla erotettuina lauseke on funktion määräävä lauseke. Komento luo funktiokahvan (ks. seuraava luku) fkahva. Funktion kutsu on muotoa fkahva(arglist) ESIMERKKI. Toteutetaan funktio f (x)=x 3 anonyyminä funktiona. Annetaan funktiolla nimi kuutio. >> kuutio=@(x) x^3 kuutio = @(x) x^3 >> kuutio(2) ans = 8
Toteutetaan funktio f ( x , y)=x 2 + y 2 anonyyminä funktiona. Annetaan funktiolle nimi sqr >> sqr=@(x,y) x^2+y^2 sqr = @(x,y) x^2+y^2 >> sqr(2,-3) ans = 13
MATLAB – Ohjelmointi
15
Toteutetaan vektoriarvoinen funktio f (t)=(cos(t) , sin(t )) anonyyminä funktiona. Annetaan funktiolle nimi cir. >> cir=@(t) [sin(t),cos(t)] cir = @(t)[sin(t),cos(t)] >> cir(0.5) ans = 0.4794
0.8776
TEHTÄVIÄ 1. Määrittele komentorivillä seuraavat anonyymit funktiot 2 a) f ( x)=x + x +1 . Funktion on toimittava alkioittain myös vektorilla. d ( x , y )=|x− y| b) Testaa funktioiden toiminta. 2. Toteuta seuraavat funktiot anonyymeinä funktioina.
a) b) c)
−0,1 x
sin( x) . Laske funktion arvo pisteessä x=1,3 . f ( x , y)=√sin 2 x +0,3 cos2 y . Laske funktion arvo pisteessä x=−3 , y=5 . t f (t)=(5 cos t , 3 sin t , π ) . Laske funktion arvo pisteessä x=π . f ( x)=e
MATLAB – Ohjelmointi
16
3. OHJAUSLAUSEET Ohjauslauseita käyttäen voidaan rakentaa monipuolisia ohjelmia. MATLABissa on toteutettu kaikki modernien ohjelmointikielten ohjauslauseet.
3.1
Toistolauseet
Toistolauseita käytettäessä palataan tietyn ehdon vallitessa yhä uudelleen toistamaan jo aikaisemmin suoritettuja toimenpiteitä. Näin muodostuu ohjelmaan silmukka. Koska matriisien taulukko-operaatiot ovat huomattavasti nopeampia suorittaa kuin toistolause, on aina syytä tarkistaa, voidaanko toistolause korvata matriisien taulukko-operaatioilla. 3.1.1 for-lause For-lauseessa toistetaan käskyjä ennalta määrätty määrä. For-lauseen muoto on for k = alku:askel:loppu lauseita end Oletusarvona on askeleen arvo 1. askel voi olla myös negatiivinen. Lauseen toiminta on seuraava: Silmukkamuuttuja k saa kaikki arvot arvosta alku arvoon loppu askeleella askel: alku, alku+askel, alku+2*askel, …, (loppu)1. Kullakin muuttujan k arvolla suoritetaan lauseet lauseita. ESIMERKKI. Muodosta seuraava tridiagonaalinen matriisi:
[ ] 7 1 0 0 0
1 7 1 0 0
0 1 7 1 0
0 0 1 7 1
0 0 0 1 7
Annetaan seuraavat komennot >> A = 3*eye(5) A = 3 0 0 3 0 0 0 0 0 0
0 0 3 0 0
0 0 0 3 0
0 0 0 0 3
>> for k = 1:4 A(k,k+1)=1; A(k+1,k)=1; end >> A 1
Viimeinen arvo on yhtä suuri kuin loppu, jos loppu on askeleen monikerran päässä muuttujasta alku.
MATLAB – Ohjelmointi A =
3 1 0 0 0
1 3 1 0 0
0 1 3 1 0
0 0 1 3 1
17
0 0 0 1 3
Komentoa diag (ks. help) käyttäen matriisi voidaan muodostaa lyhyemminkin: >> 3*eye(5)+diag(ones(1,4),1)+diag(ones(1,4),-1)
ESIMERKKI. Taulukoidaan funktion y=sin x arvot välillä [0, 2 ] käyttäen askelta 0,4 Toteutus for-lauseella: >> xx = []; yy = [];
% Alustetaan vektorit
>> for x = 0:0.4:2*pi xx = [xx x]; yy = [yy sin(x)]; end >> [xx;yy]' ans = 0 0.4000 0.8000 1.2000 1.6000 2.0000 2.4000 2.8000 3.2000 3.6000 4.0000 4.4000 4.8000 5.2000 5.6000 6.0000
0 0.3894 0.7174 0.9320 0.9996 0.9093 0.6755 0.3350 -0.0584 -0.4425 -0.7568 -0.9516 -0.9962 -0.8835 -0.6313 -0.2794
Nopeampi ja suositeltava tapa: >> x = 0:0.4:2*pi; >> [x;sin(x)]'
Yleisemmin for-lause voidaan esittää seuraavasti: for k = lauseke lauseita end
MATLAB – Ohjelmointi
18
Tässä lausekkeen lauseke sarakkeet tallennetaan yksi kerrallaan silmukkamuuttujaan k. Kullakin muuttujan k arvolla suoritetaan lauseet lauseita. Jos A on mn-matriisi, niin lause for v = A lauseita end tarkoittaa samaa kuin lause for j = 1:n v = A(:,j) lauseita end ESIMERKKI. Kokeillaan >> A=randi(10,2,5) A = 3 4
5 3
9 2
3 2
3 5
>> for v=A disp(v) end 3 4 5 3 9 2 3 2 3 5
ESIMERKKI. Matriisille A komento sum(A) antaa tulokseksi vaakavektorin, jonka alkiot koostuvat matriisin A sarakkeiden summista. Toteutetaan tämä for-lausetta käyttäen. Tapa 1: Tehdään ensin editorilla funktio vect_sum, joka laskee vektorin alkioiden summan. function sum = vect_sum(x) % VECT_SUM Vektorin alkioiden summa sum = 0;
% Alustetaan muuttuja nollaksi
MATLAB – Ohjelmointi for i = 1:length(x) sum = sum + x(i); end;
19
% Muuttujaan sum kerätään summa.
Sen jälkeen tehdään editorilla funktio matr_sum, joka toteuttaa komennon sum. function sar_sum = matr_sum(A) % matr_sum Matriisin rivivektorien summa sar_sum = []; for v = A sar_sum = [sar_sum vect_sum(v)]; end;
% Huomaa laskentatapa!
Tapa 2: Lasketaan suoraan matriisin rivivektorinen summa: function sum = matr_sum1(a) % MATR_SUM1 Matriisin rivivektorien summa sum = 0; for v = A' sum = sum + v; end; sum = sum';
% Alustetaan nollaksi % Lasketaan rivivektorien summat % Ulostuloparametri rivivektorina
Ohjelmia tehtäessä testaus aina tärkeä. Testataan ohjelmat satunnaismatriisilla. >> A= rand(10,5); >> sum(A) ans = 5.7468 4.9347
4.0812
5.4151
4.0064
>> matr_sum(A) ans = 5.7468 4.9347
4.0812
5.4151
4.0064
>> matr_sum1(A) ans = 5.7468 4.9347
4.0812
5.4151
4.0064
Käyttämällä MATLABin taulukko-operaattoreita, voidaan usein välttää for-lauseen käyttö ja suorittaa komennot nopeammin. ESIMERKKI. Lasketaan summa n
1
k k 1
2
1
1 1 1 1 2 4 9 16 n
eri tavoilla. Tehdään toteutukset funktioilla. Tapa 1: for-lauseen käyttö. Tavallisia ohjelmointikieliä käytettäessä toteutus on tämän tapainen function s = summa1(n) % SUMMA1 Lukujonon summan laskenta % for-lauseella
MATLAB – Ohjelmointi s=0; for k=1:n s=s+1/k^2; end
20
% Muuttujan alustus
Tapa 2: Taulukko-operaattoreiden käyttö. Mitään silmukkaa ei tarvita! function s = summa2(n) % SUMMA Lukujonon summan laskenta % taulukko-operaatioilla. k = 1:n; s = sum(1./k.^2);
Testataan toteutusten nopeuksia. Mitataan aika komentoparilla tic-toc. >> tic; summa1(10000000),toc ans = 1.6449 Elapsed time is 0.531663 seconds. >> tic; summa2(10000000),toc ans = 1.6449 Elapsed time is 0.278203 seconds.
Havaitaan, että tapa 2 on noin kaksi kertaa nopeampi 1 kuin tapa 1. Tapa 2 on myös elegantimpana suositeltava. ESIMERKKI. Satunnaiskombinaatio ja lotto. Tehdään ohjelma, joka muodostaa k-vektorin, jonka alkiot ovat satunnaisesti eri kokonaislukuja väliltä 1 .. n. Ohjelmassa komento randi muodostaa satunnaislukuja ja setdiff muodostaa joukkoerotuksen. Näitä asioita on käsitelty kirjan Matematiikkaa MATLABilla luvuissa 3.3 ja 15.3. function v = sat_kombi(n,k) % sat_kombi(n,k) satunnaiskombinaatio. % Ohjelma muodostaa k-vektorin, jonka alkiot ovat % satunnaisesti eri kokonaislukuja väliltä 1 .. n % Input-parametrit: % n - kokonaislukujen joukon yläraja % k - vektorin koko % Oltava k<=n % Output-parametri: % v -- satunnaiskombinaatiovektori rng('shuffle'); luvut = 1:n; v = zeros(1,k);
% Satunnaislukugen. alustus
for i = 1:k ind=randi(n+1-i); v(i) = luvut(ind); luvut = setdiff(luvut,luvut(ind)); 1
Käytetty aika riippuu prosessorin kuormituksesta, joten yhden ajon tulos ei ole luotettava.
MATLAB – Ohjelmointi
21
end
Ohjelmaa käyttäen voidaan arpoa lottorivejä seuraavasti: >> sat_kombi(39,7) ans = 5 13 37
3
18
28
36
Ohjelmaa sat_kombi käyttäen voidaan tehdä ohjelma, joka arpoo satunnaisesti 6 lottoriviä, joissa esiintyvät ainakin kertaalleen kaikki luvut 1..39. Ohjelman ulostuloparamatri on matriisi, jonka riveillä on arvotut lottorivit. function rivit = lottorivit6() % Lottorivien arvonta % Output-parametri: % rivi -- Matriisi, jonka riveillä ovat arvotut lottorivit. luvut=sat_kombi(39,39); K=sat_kombi(35,3); luvut(40:42)=luvut(K); rivit = reshape(luvut,7,6)';
Ohjelman ajo: >> A=lottorivit6 A = 14 12 11 15 31 6 21 1 18 10 39 36 26 8 17 38 20 29
19 7 24 4 32 30
23 34 2 5 13 12
37 28 35 33 9 2
27 3 22 16 25 14
TEHTÄVIÄ 1. Tee ohjelma, joka laskee n:n ensimmäisen kokonaisluvun neliöiden summan. 2. Tee ohjelma, joka lukee lukuja näppäimistöltä ja tulostaa lukujen keskiarvon. Luettavien lukujen määrä annetaan ennen lukujen syöttöä. 3.1.2 while-lause while-lauseen muoto on seuraava: while ehto lauseita
MATLAB – Ohjelmointi
22
end Lauseen toiminta on seuraava: Lauseita lauseita toistetaan niin kauan kuin toistoehto ehto on tosi eli muuttujan ehto reaaliosa on eri suuri kuin nolla. Toistoehto ehto tarkistetaan ennen lauseen suoritusta. Jos toistoehto on epätosi (0) ensimmäisellä kerralla, lausetta ei suoriteta kertaakaan. ESIMERKKI. Selvitetään mistä k:n arvosta lähtien 2−k ≤eps . >> k = 1; >> while 2^(-k)>eps k=k+1; end >> k k =
52
Tarkistus >> eps ans = 2.2204e-016 >> 2^(-k) ans = 2.2204e-016 >> 2^(-k+1) ans = 4.4409e-016
While-lausetta käyttäen voidaan testata syötön oikeellisuutta ja syötön lopetusta: ESIMERKKI. Tehdään ohjelma, joka laskee harmonisen lukujonon summia. Ohjelma kysyy käyttäjältä kokonaisluvun n arvon ja tulostaa summan. Summien laskenta lopetetaan syöttämällä luku nolla. function harmoninen % Harmonisen lukujonon summan laskenta. disp('Harmonisen lukujonon summan laskenta'); n = 1; while(n~=0) n = input('Anna termien lukumäärä (lopetus = 0): '); s=sum(1./(1:n)); disp(s); end
MATLAB – Ohjelmointi
23
Ohjelman ajo on seuraavanlaista: >> harmoninen Harmonisen lukujonon summan laskenta Anna termien lukumäärä (lopetus = 0): 100 5.1874 Anna termien lukumäärä (lopetus = 0): 1000 7.4855 Anna termien lukumäärä (lopetus = 0): 0 0
TEHTÄVIÄ 1. Tee ohjelma, joka lukee näppäimistöltä positiivisia lukuja ja tulostaa lukujen 1 • aritmeettisen keskiarvon ¯x a = ( x 1+ x 2+⋯+ x n) n • •
geometrisen keskiarvon ¯x g= n√ x 1 x 2⋯ x n n harmonisen keskiarvon ¯x h= 1 1 1 + +⋯+ x1 x2 xn
Lukujen syöttö lopetetaan syöttämällä negatiivinen luku tai nolla.
3.2
Ehtolauseet
Ehtolauseessa ohjelman osa sisältää valinnan vaihtoehtoisten ohjelmahaarojen välillä. Valinta perustuu usein muuttujan arvojen vertailuun tai muuttujan ja vakion väliseen vertailuun. 3.2.1 if-lause if-lauseen muoto on seuraava: if ehto 1 lauseita 1 elseif ehto 2 lauseita 2 … elseif ehto n lauseita n else lauseita end
MATLAB – Ohjelmointi
24
Lauseen toiminta on seuraava: Jos ehto 1 on tosi, niin suoritetaan lauseita 1, muuten jos ehto 2 on tosi, niin suoritetaan lauseita 2 jne…, muuten suoritetaan lauseita. Rakenteesta voi puuttua elseif- ja else-osat, joten yksinkertaisimmillaan if-lause on if ehto lauseita end Jos if-lauseen ehto ei ole skalaari, on kaikkien ehtolausekkeen alkioiden oltava nollasta eroavia. Esimerkiksi matriisille X lause if X lauseita end on yhtäpitävä lauseen if all(X(:)) lauseita end kanssa. ESIMERKKI. Tarkastellaan funktion
{
x+1, kun x≤−1 f (x )= x2 −1, kun −1< x≤2 −x +5, kun x >2 esittämistä ja kuvaajan piirtämistä MATLABissa. Funktio voidaan määritellä seuraavana m-funktiona: function y = fun(x)
MATLAB – Ohjelmointi
25
if x <= -1 y = x+1; elseif x <=2 y = x^2-1; else y = -x+5; end
Lasketaan yksittäisiä arvoja >> fun(-3),fun(0),fun(3) ans = -2 ans = -1 ans = 2
Vektorille arvot ovat >> fun([-3,0,3]) ans = 8 5 2
Nämä ovat väärin. If-lauseen ehdoissa verrataan koko vektoria. Ehdot x <= -1 ja x <= 2 eivät päde kaikille vektorin alkiolle, joten päädytään else-osaan. Vektorin alkiot siis lasketaan lausekkeella y = -x+5. Tämä on väärin. M-funktiossa fun ei siis saa käyttää vektoriargumenttia. Jos halutaan piirtää tämän funktion kuvaaja on käytettävä for-lausetta. Määritetään piirtoväli: >> x=-3:0.01:4; >> y = []; >> for t = x y = [y fun(t)]; end >> plot(x,y)
MATLAB – Ohjelmointi
26
Hankaluudet johtuvat if-lauseen käytöstä. Tätä ei tarvitakaan, vaan funktio voidaan määritellä seuraavasti (ks. Matematiikka MATLABilla luku 16.1) function y = gun(x) y = (x<=-1).*(x+1)+((x>-1)&(x<=2)).*(x.^2-1)+(x>2).*(-x+5);
Tällöin vektoriargumentilla laskenta onnistuu >> gun([-3,0,3]) ans = -2 -1 2
ja piirto voidaan suorittaa komennolla >> plot(x,gun(x))
ESIMERKKI. Arvauspeli. Ohjelma arpoo kokonaisluvun tietyltä väliltä. Käyttäjän on arvattava tämä kokonaisluku. Jos käyttäjä vastaa väärin, ilmoittaa ohjelma, onko luku liian suuri vai liian pieni ja antaa käyttäjälle uuden vastausmahdollisuuden. Ohjelma päättyy kun käyttäjä on antanut oikean luvun. Ohjelma on seuraava. Tallenna ohjelma tiedostoon ArvaaLuku.m. function ArvaaLuku() M = 100; rng('shuffle'); luku = randi(M); disp('Arvaa kokonaisluku väliltä'); disp([1,M]); arvaus = input('Arvaus: '); load laughter; while (arvaus ~= luku) sound(y,Fs); if arvaus > luku disp('Luku liian suuri'); else disp('Luku liian pieni'); end; arvaus = input('Arvaus: '); end; disp('Oikein') load handel; sound(y,Fs)
Ohjelmassa on käytetty seuraavia komentoja: load tiedosto: Ladataan muuttujat tiedostosta tiedosto. sound(y,Fs): Soitetaan vektorissa y oleva signaali.
MATLAB – Ohjelmointi
27
ESIMERKKI. Lottorivien tarkistus. Tehdään ohjelma1, jolla voi tarkistaa lottorivien oikeiden numeroiden lukumäärän. function lottotarkistus(rivit, lottonumerot,lisanumerot) % Lottorivin tarkistus. % Input-parametrit % rivit -- Matriisi, jonka riveillä ovat lottorivit % lottonumerot -- Oikea lottorivi vektorina % lisanumerot -- Lisänumerot vektorina [m,n]=size(rivit); for i = 1:m k = length(intersect(rivit(i,:),lottonumerot)); fprintf('rivi %d: %d oikein\n',i,k); if k == 6 if length(intersect(rivit(i,:),lisanumerot)) > 0 fprintf('rivi %d: 6 + lisänumero oikein\n',i); end end end
Ohjelman ajo (lottorivimatriisi on muodostettu luvussa 3.1.1 tehdyllä ohjelmalla lottorivit6. >> A=lottorivit6 A = 12 15 24 17 35 16
33 7 4 1 29 32
36 6 11 10 2 14
23 26 30 19 8 37
27 18 22 38 25 26
13 34 3 9 28 12
39 5 31 20 21 33
>> lottotarkistus(A,[3,11,17,19,29,31,37],[33,1]) rivi 1: 0 oikein rivi 2: 0 oikein rivi 3: 3 oikein rivi 4: 2 oikein rivi 5: 1 oikein rivi 6: 1 oikein
ESIMERKKI. Polynomien yhteenlasku MATLABissa polynomi esitetään rivivektorina, joka sisältää polynomin kertoimet alenevien potenssien mukaan järjestettynä (ks. kirja Matematiikkaa MATLABilla luku 17.2). Esim. polynomi 3
p(x)=2 x −2 x+5 esitetään muodossa >> p = [2 0 -2 5];
Polynomien yhteenlasku suoritetaan siten, että samojen potenssien kertoimet lasketaan yhteen. Esimerkiksi 1
Ohjelmassa käytetään kirjoituskäskyä fprintf, joka esitellään luvussa 10.4
MATLAB – Ohjelmointi
28
(2 x3−2 x +5)+(3 x2 +6 x−2)=2 x3 +3 x 2+ 4 x +3 Tämä ei kuitenkaan onnistu suoraan MATLAB-esityksessä, sillä eo. yhteenlaskua vastaa yhteenlasku >> [2, 0, -2, 5] + [3, 6, -2] ??? Error using ==> + Matrix dimensions must agree.
Ennen yhteenlaskua on vaakavektorien pituudet tehtävä samoiksi lisäämällä mahdollisesti nollia toisen vektorin eteen. >> [2, 0, -2, 5] + [0, 3, 6, -2] ans = 2 3 4 3
Tehdään ohjelma, jolla voidaan suorittaa polynomien yhteenlaskua. Ohjelman on lisäksi poistettava mahdolliset alussa olevat nollat tulosvektorista. Tallennetaan ohjelma tiedostoon polyplus.m function p = polyplus(a,b) % POLYPLUS polynomien yhteenlasku % polyplus(a,b) laskee polynomien a ja b summan. na = length(a); nb = length(b); % Lasketaan polynomien summa: if na > nb p = a + [zeros(1,na-nb),b]; elseif nb > na p = [zeros(1,nb-na),a] + b ; else p = a + b; end % Poistetaan mahdolliset alkunollat: while p(1) == 0 p(1) = []; end
Kokeillaan ohjelmaa: >> polyplus([2, 0, -2, 5],[3, 6, -2]) ans = 2 3 4 3 >> polyplus(2,[-1,1,-3]) ans = -1 1 -1 >> polyplus([4 1 2 3],[-4 -1,1,-3]) ans = 3 0
TEHTÄVIÄ
MATLAB – Ohjelmointi
29
1. Muuta esimerkkiä Arvauspeli (ohjelma ArvaaLuku.m) seuraavasti: Ohjelma pyytää käyttäjää antamaan positiivisen kokonaisluvun, joka on arvattavan luvun suurin arvo. Ohjelma testaa, että annettu luku on positiivinen, jos ei niin ohjelma pyytää lukua uudestaan. 2. Tee ohjelma, joka kysyy käyttäjältä kappalemäärän ja yksikköhinnan. Ohjelma tulostaa tavaraerän hinnan. Alennus määräytyy hinnan perusteella seuraavasti: • jos hinta on yli 100 €, niin alennus on 2% • jos hinta on yli 200 €, niin alennus on 5% • jos hinta on yli 500 €, niin alennus on 10% 3. Tee ohjelma joka lukee Cooperin testin tuloksen (12 min aikana juostu matka miehille 3039 v.) ja tulostaa seuraavan tekstin: • jos matka < 1530, tulostetaan "Erittäin heikko kunto". • jos 1530 £ matka < 1840, tulostetaan "Heikko kunto". • jos 1840 £ matka < 2240, tulostetaan "Välttävä kunto". • jos 2240 £ matka < 2640, tulostetaan "Hyvä kunto". • jos matka ³ 2640, tulostetaan "Erinomainen kunto" 4. Tee ohjelma, joka laskee ns. painoindeksin I. Painoindeksi I määräytyy seuraavasti: m I 2, s missä m on paino kiloina s on pituus metreinä. Ohjelma on tulostettava painoindeksin arvo ja lisäksi seuraava kommentti: • jos I 20, "alipaino" • jos 20 I 25 , "normaalipaino" • jos 25 I 30 , "lievä ylipaino" • jos 30< I ≤35 , "huomattava ylipaino" • jos 35< I ≤40 , ”vaikea ylipaino” • jos I > 40 , "sairaalloinen lihavuus". 3.2.2 switch-lause switch-lauseen muoto on seuraava: switch lauseke case arvo 1 lauseita 1 case arvo 2 lauseita 2 … case arvo n lauseita n
MATLAB – Ohjelmointi
30
otherwise lauseita end Yllä lauseke on skalaari- tai merkkijonolauseke. Lauseen toiminta on seuraava: Lausekkeen lauseke arvo lasketaan ja lausekkeen arvoa verrataan case-osassa määriteltyjen vakiolausekkeiden arvoihin. Vertailu suoritetaan järjestyksessä lähtien arvosta arvo 1. Mikäli lausekkeen lauseke arvo on sama kuin case-osan vakiolausekkeen arvo, ohjelman suoritus siirtyy kyseiseen case-osaan. Vain tässä case-osassa olevat lauseet suoritetaan. Sen jälkeen poistutaan switch-lauseesta. otherwise-osa ei ole pakollinen. Jos lausekkeen lauseke arvo ei vastaa minkään case-osan arvoa, niin ohjelman suoritus siirtyy otherwise-osaan, jos rakenteessa on otherwise-osa switch-lausetta seuraavaan lauseeseen, jos otherwise-osaa ei ole. Perusmuodossaan switch-lauseen toiminta on siten sama kuin seuraavaan if-lauseen toiminta: if lauseke == arvo 1 lauseita 1 elseif lauseke == arvo 2 lauseita 2 … elseif lauseke == arvo n lauseita n else lauseita end case-osassa vertailu tarkoittaa seuraavaa testiä: luvuille: lauseke == arvo merkkijonoille1: strcmp(lauseke, arvo) yhden arvon sijasta voidaan verrata moneen arvoon laittamalla arvot aaltosulkujen sisään eli muodostamalla solutaulukko case {a1, a2, a3, …} lauseita
1
Komento käsitellään myöhemmin merkkijonojen yhteydessä.
MATLAB – Ohjelmointi
31
switch-rakenne ei vuoda läpi: vain ensimmäistä case-arvoa vastaavat lauseet suoritetaan ja sen jälkeen poistutaan rakenteesta. ESIMERKKI. Tehdään funktio, joka ilmoittaa onko arpakuution tulos pariton vai parillinen. Tallennetaan seuraava funktio tiedostoon arpakuutio.m: function arpakuutio(tulos) switch tulos case {1, 3, 5} disp('pariton') case {2, 4, 6} disp('parillinen') otherwise disp('väärä luku') end
Ajetaan ohjelmaa: >> arpakuutio(2) parillinen >> arpakuutio(7) väärä luku >> arpakuutio(1) pariton
ESIMERKKI. Tehdään ohjelma, joka tulostaa arpoo satunnaisia veikkausrivejä. function veikkaus rng('shuffle'); rivi = randi(3,13,1); for k=1:13 switch(rivi(k)) case 1 disp('1') case 2 disp('x') case 3 disp('2') end if mod(k,3)==0 disp(' '); end end
% Alustetaan satunnaislukugener. % Arvotaan rivi
% Tulostetaan tyhjä rivi
Ohjelman ajo tuottaa seuraavanlaisen tuloksen: >> veikkaus x 1 2 1
MATLAB – Ohjelmointi
32
1 x 1 2 2 x 1 2
ESIMERKKI. Satunnaiskävely xy-tasossa. Satunnaiskävelyssä lähdetään liikkeelle origosta ja liikutaan joka askeleella satunnaisesti yksi yksikkö joko vaakasuuntaan oikealle tai vasemmalle tai pystysuuntaan ylös tai alas (neljä vaihtoehtoa). Toteutetaan satunnaiskävely funktiona, jonka sisäänmenoparametrina on askeleiden lukumäärä. function xykavely(n) x = zeros(1,n+1); y = zeros(1,n+1); for k = 1:n suunta = randi(4); switch suunta case 1 x(k+1)=x(k)+1; y(k+1)=y(k); case 2 x(k+1)=x(k)-1; y(k+1)=y(k); case 3 y(k+1)=y(k)+1; x(k+1)=x(k); case 4 y(k+1)=y(k)-1; x(k+1)=x(k); end end plot(x,y,'o-'); hold on plot(x(1),y(1),'r*',x(n+1),y(n+1),'r+') hold off
Ohjelman ajo >> xykavely(100)
% Käydyt pisteet % Alku- ja loppupisteet
MATLAB – Ohjelmointi
33
TEHTÄVIÄ 1. Satunnaiskävely xy-tasossa tietylle etäisyydelle. Muunna esimerkkiä satunnaislukukävelystä siten, että satunnaiskävely päättyy, kun ollaan annetulla etäisyydellä origosta. Toteuta satunnaiskävely funktiona, jonka sisäänmenoparametrina on etäisyys origosta. Ohjelma piirtää kuvan reitistä. Ohjelma ulostuloparametri on askeleiden lukumäärä. 2. Tee ohjelma, joka lukee ensin kaksi reaalilukua ja sitten yhden kokonaisluvun. Luetun kokonaisluvun perusteella tekee seuraavaa: • jos luku on 1, lasketaan reaalilukujen summa • jos luku on 2, lasketaan reaalilukujen erotus • jos luku on 3, lasketaan reaalilukujen tulo • jos luku on 4, lasketaan reaalilukujen osamäärä • jos luku on jokin muu, tulostetaan virheilmoitus. 3.2.3 try-lause try-lauseen muoto on seuraava: try lauseita 1 catch lauseita 2 end Lauseen toiminta on seuraava:
MATLAB – Ohjelmointi
34
Normaalisti suoritetaan sanojen try ja catch välissä olevat lauseet. Jos tapahtuu virhe, jätetään loput lauseet suorittamatta ja siirrytään suorittamaan sanojen catch ja end välissä olevat lauseet. Komennolla lasterr saadaan selville virheen aiheuttaja. ESIMERKKI. Tehdään seuraava skripti ja tallennetaan se m-tiedostoon kokeïlu.m try
X = A+B catch disp('Kertaluvut eivät samoja') end
Työskennellään komentoikkunassa. >> lasterror('reset')
% Alustetaan virheilmoitus perustilaan
>> A=[1,2];B=[4,5];
% OK
>> kokeilu X = 5 7 >> A=[1,2,3];B=[4,5];
% Virheellinen
>> kokeilu Kertaluvut eivät samoja >> lasterr ans = Error using + Matrix dimensions must agree.
3.3
Keskeytyslauseet
Keskeytyslauseilla voidaan keskeyttää rakenteen lauseiden suoritus: voidaan tulla rakenteesta pois tai jättää osa rakenteen lauseista suorittamatta. Toistolauseissa for ja while voidaan käyttää seuraavia keskeytyslauseita: break: siirrytään toistolausetta seuraavaan lauseeseen. continue: pysytään toistolauseessa, mutta jätetään continue-lauseen jälkeiset ohjelmasilmukan lauseet suorittamatta. Funktiosta voidaan poistua return-komennolla. Normaalisti funktiosta poistutaan, kun viimeinen funktion lause on suoritettu. return-lause mahdollistaa poistumisen myös muuten. Ohjelman suoritus voidaan pysäyttää seuraavasti: pause: pysäyttää funktion suorituksen. Suoritus jatkuu, kun jotain näppäintä painetaan. pause(n): pysäyttää ohjelman suorituksen n:n sekunnin ajaksi. ESIMERKKI. pause-komento on kätevä grafiikan esityksessä. Sulje grafiikka-ikkuna. Tee editorilla seuraava skripti ja aja se.
MATLAB – Ohjelmointi
35
t = linspace(0,2*pi,1000); for u = 1:2:20 plot(cos(t).^u,sin(t).^u); axis equal hold on pause(2) end hold off
Saat kahden sekunnin välein käyriä samaan kuvaan.
MATLAB – Ohjelmointi
36
4. DIFFERENSSIYHTÄLÖT 4.1
Teoriaa
4.1.1 Differenssiyhtälö Lukujono x on jono lukuja, jotka on indeksoitu kokonaisluvuilla. Indeksijoukko voi olla kaikki kokonaisluvut tai kokonaislukujen osaväli. Lukujonon indeksiä k vastaavaa alkiota merkitään x k tai x k . Usein koko lukujonoa merkitään lyhyesti x k . Kertalukua n oleva differenssiyhtälö on muotoa F k , x k , x k 1 , , x k n−1 , x k n=0 oleva yhtälö. Seuraavassa tarkastellaan vain sellaisia yhtälöitä, joissa x k n voidaan ratkaista, jolloin yhtälö voidaan esittää muodossa x k n= f k , x k , x k1 , , x kn−1 (1) Jos indeksijoukon alaraja on nolla, on lukujono x k differenssiyhtälön ratkaisu, jos se toteuttaa differenssiyhtälön kaikilla k =0,1 ,2 , . Jos arvoille x 0 , x1 , , x n−1 on annettu mielivaltaiset arvot, voidaan yhtälöstä (1) rekursiivisesti laskea ratkaisun arvot indeksistä n eteenpäin. Siten differenssiyhtälön alkuarvoprobleemalla, jossa on määritettävä se ratkaisu, joka toteuttaa alkuehdot x 0= x1 , x1 =x 2 , , x n−1 =x n on yksikäsitteinen ratkaisu. ESIMERKKI. Eräs pöllölaji lisääntyy 2% vuodessa. Jos x k on pöllöjen määrä k:n vuoden päästä, niin x k 1=x k 0,02 x k =1,02 x k . Lukujono x k toteuttaa siis seuraavan differenssiyhtälön ( k≥0) x k 1=1,02 x k . Jotta x 1 olisi määritelty on tiedettävä x 0 eli pöllöjen määrä alkuhetkellä. Tässä tapauksessa on helppo määrittää yleinen kaava, jolla x k voidaan laskea. ESIMERKKI. Differentiaaliyhtälön diskretointi Analogiset prosessit mallinnetaan usein differentiaaliyhtälöiden avulla. Tällaiset mallit on diskretoitava, kun niitä halutaan käsitellä diskreetillä järjestelmällä. Kun differentiaaliyhtälö diskretoidaan, siitä syntyy differenssiyhtälö. Tarkastellaan esimerkkinä differentiaaliyhtälöä dy +a y= f (t ) . dt Tässä esiintyvä tuntematon funktio y diskretoidaan käyttäen diskretointiaskelta D seuraavasti: Määritellään lukujono y k seuraavasti:
y k = y( k Δ) Derivaatta voidaan diskretoida erotusosamäärällä
MATLAB – Ohjelmointi
37
dy ( k Δ) y (k Δ+ Δ)− y ( k Δ) y k +1− y k ≈ = Δ Δ dt Päädytään seuraavaan differentiaaliyhtälön diskretointiin1:
y k+1− y k , Δ +a y k = f k missä
f k = f (k Δ) Tästä saadaan sieventämällä differenssiyhtälö
y k +1 +(a Δ−1) y k =Δ f k ESIMERKKI. Fibonaccin2 luvut Fibonaccin luvut määritellään seuraavasti: ensimmäinen luku on 1 toinen luku on 1 sen jälkeen luku on kahden edellisen summa. Luvut liittyvät seuraavaan ongelmaan, jota Fibonacci tutki vuoden 1200 tienoilla: Hedelmällinen jänispari sijoitetaan aitaukseen. Kuinka monta jänisparia on vuoden lopussa, jos jänisten lisääntyminen noudattaa seuraavia sääntöjä: Hedelmällinen jänispari tuottaa uuden jänisparin jokaisen kuukauden lopussa. Uusi pari tulee hedelmälliseksi yhdessä kuukaudessa Yksikään jänis ei kuole. Jos k:tta Fibonaccin lukua merkitään f k :lla, niin tämä voidaan ilmaista seuraavasti: f 1=1 f 2=1 f k = f k−1 f k−2
k ≥3
Tässä on kyseessä differenssiyhtälö, jossa on kaksi alkuehtoa. Fibonacci-luvut on määrätty rekursiivisesti: luku on lausuttu edellisten lukujen avulla. Differenssiyhtälö voidaan kirjoittaa myös muotoon f k 2= f k 1 f k k ≥1 Muuttamalla indeksointia voidaan alkuarvoprobleema lausua muodossa f 0=1 f 1=1 f k 2= f k 1 f k
k ≥0 .
1
Tämä johtaa Eulerin menetelmään Leonardo Fibonacci (n. 1180-1240), Leonardo Pisalainen, oli italialainen matemaatikko, jota voidaan pitää Euroopan ensimmäisenä matemaatikkona. Hän sai koulutuksensa Pohjois-Afrikassa. Fibonacci toi Eurooppaan arabialaiset numerot ja niihin liittyvän positiojärjestelmään perustuvan laskutavan. 2
MATLAB – Ohjelmointi
38
4.1.2 Differenssiyhtälöryhmä 1. kertaluvun differenssiyhtälöryhmä on muotoa1
{
x 1 k 1= f 1 k , x1 k , x 2 k , x n k x 2 k 1= f 2 k , x 1 k , x 2 k , x n k ⋯ x n k 1= f n k , x 1 k , x 2 k , x n k
missä x 1 k , x 2 k , , x n k ovat tuntemattomia ratkaistavia lukujonoja. Differenssiyhtälöryhmän ratkaisu koostuu sellaisista lukujonoista, jotka toteuttavat differenssiyhtälöryhmän kaikilla2 k =0,1 ,2 , . Differenssiyhtälöryhmän alkuarvoprobleemassa on löydettävä se ratkaisu, joka indeksin arvolla 0 toteuttaa alkuehdon
{
x1 0= x 1 x 2 0= x 2 ⋯ x n 0= x n
missä x 1 , x 2 , , x n ovat annettuja lukuja. Alkuarvoprobleemalla on yksikäsitteinen ratkaisu, sillä alkuarvoista lähtien voidaan rekursiivisesti laskea ratkaisun arvot indeksien arvoilla 1, 2, 3, … Differenssiyhtälöryhmä voidaan esittää vektorimuodossa x k 1= f k , x k , missä x k on n-vektori ja f on funktio, jonka arvona on n-vektori. Alkuehto on tällöin muotoa x 0=x 0 , missä x 0 on annettu n-vektori. ESIMERKKI. Differenssiyhtälöryhmän alkuarvoprobleeman x (k )−2 y ( k ) x(0)=3 , { {xy((kk+1)=− +1)=−3 x (k )−2 y ( k ) y (0)=2 ratkaisuja voidaan laskea rekursiivisesti: (0)−2 y (0)=−3−2⋅2=−7 {x(1)=−x y(1)=−3 x(0)−2 y(0)=−3⋅3−2⋅2=−13 (1)−2 y (1)=−(−7)−2⋅(−13)=33 {xy(2)=−x (2)=−3 x (1)−2 y (1)=−3⋅(−7)−2⋅(−13)=47 … Ratkaisu voidaan esittää yleisesti muodossa 1 2
Tässä lukujonon alkioita merkitään x(k) Indeksijoukon alaraja on tässä nolla.
MATLAB – Ohjelmointi
39
{
x ( k )=2⋅4 k (−1)k +1 y ( k )=3⋅4 k (−1)k −1
Kertalukua n oleva differenssiyhtälö
xk + n=f (k , xk , xk + 1 , … , xk + n− 1) voidaan muuntaa 1. kertaluvun differenssiyhtälöryhmäksi seuraavasti: Määritellään n lukujonoa
(1)
{ {
y1 (k)=xk y2 (k)=xk + 1 ⋮ yn (k)=xk + n− 1
Suoraan laskemalla todetaan, että nämä lukujonot toteuttavat differenssiyhtälöryhmän y1 (k+1)= y2 (k) y2 (k+1)= y3 (k) ⋮ yn (k+1)=f (k , y1 (k), y2 (k), … , yn (k))
Tämä ryhmä on differenssiyhtälöä (1) vastaava normaaliryhmä. Lukujono x k = y 1 ( k ) on differenssiyhtälön (1) ratkaisu, y 1 ( k ) , y 2 ( k ) ,…, y n ( k ) on vastaavan normaaliryhmän ratkaisu. Jos differenssiyhtälöön (2) liittyy alkuehto
x0= x^ 1 , x 1=^x2 ,… , xn−1= ^xn niin vastaavan normaaliryhmän alkuehto on
{
y1 (0)= x^2 y2 (0)= x^2 ⋮ yn (0)= x^n
ESIMERKKI. Muunnetaan differenssiyhtälö x k +3 −5 x k +2 + x k +1−2 x k =k +2 , x 0 =−1, x 1=2, x 2=4 normaaliryhmäksi. Ratkaistaan ensin x k +3 : x k +3=5 x k+ 2−x k+1 +2 x k + k + 2 Määritellään kolme lukujonoa y1 (k)=xk y2 (k)=xk + 1 y3 (k)=xk + 2 Tällöin
{
jos
ja
vain
jos
MATLAB – Ohjelmointi
{ { {
40
y 1 ( k +1)= x k +1= y 2 ( k ) y 2 ( k +1)= x k +2 = y 3 (k ) y 3 ( k +1)= x k +3=5 x k +2 − x k +1 +2 x k + k + 2=5 y 3 ( k )− y 2 (k )+2 y1 (k )+ k +2
josta saadaan normaaliryhmä y 1 ( k +1)= y 2 ( k ) y 2 ( k +1)= y 3 ( k ) y 3 ( k +1)=5 y 3 ( k )− y 2 (k )+ 2 y1 ( k )+ k + 2 Alkuehdot ovat y 1 (0)=x 0 =−1 y 2 (0)= x 1=2 y 3 (0)= x 2=4
4.2
Numeerinen ratkaiseminen
4.2.1 Differenssiyhtälö Differenssiyhtälön alkuarvoprobleema voidaan ratkaista rekursiivisesti käyttäen esitystä x k +n = f ( k , x k , x k +1 ,… , x k+ n−1 ) . Seuraavassa on esitetty funktio deqsolve, joka toteuttaa tämän: function y = deqsolve(fun,x0,n) % DEQSOLVE Differenssiyhtälön ratkaiseminen % y = deqsolve(fun,x0,n) % Sisäänmenoparametrit: % - fun kahva funktioon y = fun(k,x), joka määrittää differenssiyhtälön % - x0 alkuehdot vektorina [x0, x1, ...] % - n indeksi, johon asti ratkaisuja lasketaan. % Ulostuloparametri: % - ratkaisu vaakavektorina. y = x0; x = x0; for k =0:(n-length(x0)) y1 = fun(k,x); y = [y, y1]; x = [x(2:end),y1]; end
Funktion deqsolve kutsuparametrina oleva kahva funktioon fun määrittelee differenssiyhtälön. Funktion fun esittely on seuraava: function y = fun(k, x), missä k on skalaari x on vektori, joka sisältää arvot [ x k , x k+1 ,… , x k +n−1 ] y on skalaari, joka sisältää lausekkeen f ( k , x k , x k+1 ,… , x k +n−1) arvon. Komento
MATLAB – Ohjelmointi
41
deqsolve(fun,x0,n) ratkaisee differenssiyhtälön välillä 0… n. ESIMERKKI. Määritetään Fibonaccin lukujono arvoja. Fibonaccin lukujono on differenssiyhtälön alkuarvoprobleeman f k +2= f k+1 + f k , f 0=1 , f 1=1 ratkaisu. Differenssiyhtälön määrittelee seuraava m-funktio: function y = defun(k,x) y =x(1)+x(2);
Lasketaan 11 ensimmäistä Fibonaccin lukua: >> deqsolve(@defun,[1,1],10) ans = 1 1 2 3 5
8
13
21
34
55
89
Tuhannes Fibonaccin luku on (indeksointi alkaa 0:sta) >> y = deqsolve(@defun,[1,1],0:999); >> y(999) ans = 2.6864e+208
ESIMERKKI. Ratkaistaan differenssiyhtälö 1 , x 0=1, x 1=2 . 6 x k+2 +6 x k+1−x k = k +1 Ratkaistaan x k+2 : 1 1 . x k+2=−x k+1 + x k + 6 6(k +1) Differenssiyhtälön määrittelee seuraava m-funktio: function y = defun1(k,x) y =-x(2)+1/6*x(1)+1/(6*(k+1));
Määritetään ratkaisu indeksin arvoilla 0…20 ja piirretään kuvaaja. >> y = deqsolve(@defun1,[1,2],20); >> plot(0:20,y,'-o') >> grid
MATLAB – Ohjelmointi
42
Ratkaisujonon 7 ensimmäistä lukua ovat >> y(1:7) ans = 1.0000
2.0000
-1.6667
2.0833
-2.3056
2.6944
-3.0454
4.2.2 Differenssiyhtälöryhmä 1. kertaluvun differenssiyhtälöryhmän alkuarvoprobleema voidaan ratkaista rekursiivisesti käyttäen vektoriesitystä x k 1= f k , x k , Seuraavassa on esitetty funktio dessolve, joka toteuttaa tämän: function y = dessolve(fun,x0,n) % DESSOLVE Differenssiyhtälöryhmän ratkaiseminen % y = dessolve(fun,x0,n) % Sisäänmenoparametrit: % - fun kahva funktioon y = fun(k,x), joka määrittää differenssiyhtälön % - x0 alkuehto vektorina % - n indeksi, johon asti ratkaisuja lasketaan. % Ulostuloparametri: % - ratkaisu matriisina, jonka k:s sarake sisältää ratkaisun indeksin % arvolla k. a = size(x0); if a(1) == 1 x = x0'; else x = x0; end y = x; for k = 0:n-1 x = fun(k,x); y = [y, x]; end
Komento
% x pystyvektori
MATLAB – Ohjelmointi
43
dessolve(fun,x0,n) ratkaisee differenssiyhtälöryhmän välillä 0… n. ESIMERKKI. Ratkaistaan luvun 4.2.1 Esimerkin differenssiyhtälöryhmä x (k )−2 y ( k ) x(0)=3 , { {xy((kk+1)=− +1)=−3 x (k )−2 y ( k ) y (0)=2 Differenssiyhtälön määrittelee seuraava m-funktio: function y=desfun(k,x) y = [-x(1)-2*x(2);-3*x(1)-2*x(2)];
Lasketaan ratkaisu indeksin arvoilla 0…5:. >> dessolve(@desfun,[3;2],5) ans = 3 2
-7 -13
33 47
-127 -193
513 767
-2047 -3073
Siis
{
x (1)=−7 , y (1)=−13
{
x (2)=33 y (2)=47
ESIMERKKI. Ratkaistaan luvun 4.1.2 toisen esimerkin differenssiyhtälö x k +3 −5 x k +2 + x k +1−2 x k =k +2 , x 0 =−1, x 1=2, x 2=4 käyttäen ohjelmia deqsolve1 ja dessolve deqsolve: Ratkaistaan x k +3 : x k +3=5 x k+ 2−x k+1 +2 x k + k + 2 M-funktio: function y = de1fun(k,x) y =5*x(3)-x(2)+2*x(1)+k+2;
Komento >> deqsolve(@de1fun,[-1,2,4],5) ans = -1 2 4 18 93
dessolve: Vastaava normaaliryhmä on
1
Tämä ohjelma on tehty edellisessä luvussa.
459
MATLAB – Ohjelmointi
{
44
y 1 ( k +1)= y 2 ( k ) y 2 ( k +1)= y 3 ( k ) y 3 ( k +1)=5 y 3 ( k )− y 2 (k )+ 2 y1 ( k )+ k + 2
M-funktio: function y=de2fun(k,x) y = [x(2);x(3);5*x(3)-x(2)+2*x(1)+k+2];
Komento >> dessolve(@de2fun,[-1,2,4],5) ans = -1 2 4 2 4 18 4 18 93
18 93 459
93 459 2243
459 2243 10948
Havaitaan, että normaaliryhmän ratkaisumatriisin ensimmäinen rivi on differenssiyhtälön ratkaisu.
MATLAB – Ohjelmointi
45
5. FUNKTION PARAMETREISTA 5.1
Kahvat ja funktioparametrit
Funktio fun(x) kahva (handle) on @fun. Anonyymin funktion nimi, on sen kahva. Funktion fun(x) arvo voidaan kahvaa käyttäen laskea seuraavasti: kahva = @fun kahva(x) Voidaan käyttää myös komentoa feval feval(@fun, x) ESIMERKKI. Funktio sin(x) on MATLABin sisäänrakennettu funktio. Lasketaan sinin arvo eri tavoilla >> sin(0.5) ans = 0.4794
% Normaalisti
>> s=@sin; >> s(0.5) ans = 0.4794
% Kahvan nimeä käyttäen
>> feval(@sin,0.5) ans = 0.4794
% feval-komentoa käyttäen
Funktiossa voi olla kutsuparametreina kahvoja. Tämä mahdollistaa funktioiden välittämisen kutsussa funktioon. Funktio välitetään muodossa @fun, jos funktio on MATLABin funktio tai funktio sijaitsee tiedostossa fun.m. fun, jos funktio on aiemmin määritelty anonyymina funktiona @(arglist) lauseke, jos funktio määritellään anonyymina funktiona kutsussa.
5.2
Sovellus – Haarukointimenetelmä
On määritettävä yhtälön f x =0 välillä [a , b] olevan juuren likiarvo, kun tiedetään, että funktion arvot välin päätepisteissä f a ja f b ovat erimerkkiset. Jos f on jatkuva funktio, niin Bolzanon lauseen mukaan yhtälöllä on ainakin yksi juuri tällä välillä. Haarukointimenetelmässä juuren likiarvo määritetään muodostamalla juurta kohti suppeneva likiarvojen jono x 1 , x 2 , x3 , seuraavasti: ab Valitaan ensimmäiseksi likiarvoksi x 1 välin [a , b] keskipiste x 1= . Jos 2 f x 1 =0 , on juuri löydetty, muuten f x 1 on erimerkkinen kuin f a tai f b , jolloin alkuperäisen välin toisella puolikkaalla on juuri. Valitaan tämän puolikkaan keskipiste uudeksi likiarvoksi x 2 ja jatketaan samaan malliin.
MATLAB – Ohjelmointi
46
Likiarvojen muodostaminen lopetetaan, kun on päästy haluttuun tarkkuuteen. Viimeinen likiarvo x n valitaan juuren likiarvoksi. Tällöin virhe on pienempi kuin ∣x n −x n−1∣ . Toteutetaan tämä seuraavana m-funktiona. Toteutetaan tämä seuraavana MATLAB-funktiona. function y = bisection1(fun,a,b) %BISECTION1 Funktion 0-kohdan määrittäminen haarukointimenetelmällä %Input-parametrit: %fun -- kahva funktioon %a, b -- välin päätepisteet, joissa funktiolla erimerkkiset arvot %Output-parametrit: %y -- juuren likiarvo fa = fun(a); fb = fun(b); if fa*fb > 0 disp('Välin päätepisteessä samanmerkkiset arvot'); y=[]; elseif fa == 0 y = a; elseif fb == 0 y = b; else while abs(a-b) > 1e-6 %Likiarvon tarkkuus 1e-6 y = (a+b)/2; fy = fun(y); if fy*fa <0 b = y; fb = fy; elseif fy*fb < 0 a = y; fa = fy; else break; %fy=0, juuri löydettiin end end end
Kokeillaan ohjelmaa. Määritetään yhtälön1 2
ln x= x −7 x10 välillä [4, 7] oleva juuri. Muodostetaan funktio f x =ln x− x 2 −7 x10 ,
jonka 0-kohta on määrättävä. Määritellään funktio anonyyminä funktiona: >> f = @(x) log(x)-(x.^2-7*x+10);
Funktiolla on erimerkkiset arvot välin päätepisteissä: >> f(4),f(7) ans = 3.3863 1
Yhden tuntemattoman yhtälöiden numeerista ratkaisemista on käsitelty kirjan Matematiikkaa MATLABilla luvussa 6.1
MATLAB – Ohjelmointi
47
ans = -8.0541
Määritetään juuren likiarvo kahdella eri tavalla. Anonyymiä funktiota käyttäen: >> bisection1(f,4,7) ans = 5.4881
M-funktiota käyttäen: m-tiedosto fun.m: function y = fun(x) y = log(x)-(x.^2-7*x+10);
komento: >> bisection1(@fun,4,7) ans = 5.4881
Tarkistetaan funktion arvo >> fun(ans) ans = 1.4089e-06
Juuren likiarvo on siis 5,4881. MATLAB-komennolla fzero saadaan sama tulos: >> fzero(f,[4,7]) ans = 5.4881
5.3
Vaihteleva määrä argumentteja
MATLABissa funktioita voidaan kutsua vaihtelevalla määrällä sisäänmeno- ja ulostuloparametreja. Funktiokutsussa olevien parametrien määrä saadaan funktion sisällä selville komennoilla nargin: input-parametrien lukumäärä nargout: output-parametrien lukumäärä ESIMERKKI. Haarukointimenetelmä (jatkoa) Muutetaan edellisen luvun ohjelmaa, siten että siinä on valinnaisena input-parametrian toleranssi ja valinnaisena output-parametrina funktion arvo nollakohdassa: function [y,fy] = bisection2(fun,a,b,tol) %BISECTION2 Funktion 0-kohdan määrittäminen haarukointimenetelmällä %Input-parametrit: %fun -- kahva funktioon %a, b -- välin päätepisteet, joissa funktiolla erimerkkiset arvot
MATLAB – Ohjelmointi
48
%tol -- toleranssi (valinnainen argumentti); oletustoleranssi 1e-6. %Output-parametrit: %y -- juuren likiarvo %fy -- funktion arvo nollakohdan likiarvossa if nargin == 3 tol = 1e-6; else if tol < 0 disp('tol > 0'); y=[]; fy=[]; return end end
%Oletustoleranssi
fa = fun(a); fb = fun(b); if fa*fb > 0 disp('Välin päätepisteessä samanmerkkiset arvot'); y=[]; fy=[]; elseif fa == 0 y = a; fy = 0; elseif fb == 0 y = b; fy = 0; else while abs(a-b) > tol %Likiarvon tarkkuus tol y = (a+b)/2; fy = fun(y); if fy*fa <0 b = y; fb = fy; elseif fy*fb < 0 a = y; fa = fy; else break; %fy=0, juuri löydettiin end end end
Käytetään1 ohjelmaa neljällä input-parametrilla, toleranssi on 1e-2 ja kahdella output-parametrilla: >> [y,arvo] = bisection2(f,4,7,1e-2) y = 5.4824 arvo = 0.0216
Käytetään funktiota kolmella input-parametrilla (oletustoleranssi on 1e-6) ja kahdella output-parametrilla: >> [y,arvo] = bisection2(f,4,7) y = 5.4881 arvo = 1
Anonyymi funktio f on määritelty edellisessä luvussa.
MATLAB – Ohjelmointi
49
1.4089e-006
Huomaa toleranssin vaikutus. Seuraavassa on vain yksi output: >> bisection2(f,4,7) ans = 5.4881
Vaihteleva määrä input- ja output-parametreja voidaan välittää funktioon käyttämällä muuttujia varargin syötteisiin varargout ulostuloihin. Nämä ovat solutaulukkoja1, sillä MATLABin pakkaa input-parametrit solutaulukoksi. Output-parametrit on ohjelmassa muutettava solutaulukoksi. ESIMERKKI. Tehdään funktio, joka kerää annetuista rivivektoreista koordinaatit. function [varargout] = collect(varargin) X = []; for i = 1:length(varargin) X = [X; varargin{i}]; end for i = 1:length(varargin{1}) varargout{i} = X(:,i)'; end
Ohjelman toiminta selvinnee seuraavasta ajoesimerkistä Kolme output-muuttujaa: kerätään kaikki koordinaatit >> [a,b,c] = collect([1 2, 4],[2 -3,5], [0, 4, 5], [5 9 -2]) a = 1 2 0 5 b = 2 -3 4 9 c = 4 5 5 -2
Kaksi ulostulo-muuttujaa: kerätään kaksi ensimmäistä koordinaattia >> [a,b] = collect([1 2, 4],[2 -3,5], [0, 4, 5], [5 9 -2]) a = 1 2 0 5 b = 2 -3 4 9
Kerätään vain ensimmäinen koordinaatti: >> collect([1 2, 4],[2 -3,5], [0, 4, 5], [5 9 -2]) ans = 1 2 0 5
1
Solutaulukkoja käsitellään tarkemmin myöhemmin.
MATLAB – Ohjelmointi
50
ESIMERKKI. Tehdään funktio, jonka syötteenä on mielivaltainen määrä samanpituisia vektoreita. Tulosteena saadaan vektoreiden koordinaattien keskiarvot ja keskihajonnat. function [varargout] = stat(varargin) X = []; for i = 1:length(varargin) X = [X; varargin{i}]; end varargout{1} = mean(X); varargout{2} = std(X);
Ajoesimerkki: >> [keskiarvo, hajonta] = stat([1 2, 4],[2 -3,5], [0, 4, 5], [5 9 -2]) keskiarvo = 2 3 3 hajonta = 2.1602 4.9666 3.3665
Pelkät keskiarvot saadaan seuraavasti: >> stat([1 2, 4],[2 -3,5], [0, 4, 5], [5 9 -2]) ans = 2
3
3
Jos funktiossa käytetään sekä tavallisia parametreja että varargin- ja varargout-parametreja on tavallisten parametrien oltava ensin.
MATLAB – Ohjelmointi
51
6. REKURSIIVINEN FUNKTIO MATLABissa voidaan käyttää rekursiivisia funktioita eli sellaisia funktioita, jotka kutsuvat itseään. Rekursiivisen funktion tekemisessä on huolehdittava siitä, että funktiossa on joku muuttuva ehto, joka pysäyttää rekursion jossain vaiheessa. Rekursiivinen funktio voidaan aina myös toteuttaa iteratiivisena funktiona, jossa rekursio toteutetaan iteraatiolla eli ohjelmasilmukalla. Koska rekursio joka kutsukerta tallentaa funktion muuttujat ja kutsutiedot tietokoneen muistiin, on iteraatio useimmiten nopeampi kuin rekursio. Tutkitaan tätä seuraavassa esimerkissä. ESIMERKKI. Tsebyshevin polynomit. Tsebyshevin polynomit T n x määritellään rekursiokaavalla T 0 ( x)=1 T 1 x =x T n x=2 x T n−1 x−T n−2 x , kun n1 Tehdään funktio Tsebyshevin polynomien laskemiseksi. Funktiossa käytetään luvun 3.2.1 esimerkissä tehtyä funktiota polyplus. Polynomit esitetään vaakavektoreina1. Iteratiivinen toteutus: function tn = tseby_it(n) % TSEBYSHEV Tsebyshevin polynomit -- iteratiivinen toteutus % tsebyshev(n) laskee n:nnen asteen Tsebyshevin polynomin x = [1 0]; t0 = 1; t1 = x; if n < 0 disp('n >=0'); elseif n == 0 tn = t0; elseif n == 1 tn = x; else for i = 2:n tn = polyplus(2*conv(x,t1),-t0); t0 = t1; t1 = tn; end end
Rekursiivinen toteutus: function tn = tseby_rek(n) % TSEBYSHEV Tsebyshevin polynomit -- rekursiivinen toteutus % tsebyshev(n) laskee n:nnen asteen Tsebyshevin polynomin x = [1 0]; if n < 0 disp('n >= 0'); elseif n == 0 tn = 1; elseif n == 1 1
Polynomeja on käsitelty kirjan Matematiikkaa MATLABilla luvussa 17.2
MATLAB – Ohjelmointi
52
tn = x;
else end
tn = polyplus(2*conv(x,tseby_rek(n-1)),-tseby_rek(n-2));
Lasketaan 8. asteen Tsebyshevin polynomi: >> tseby_it(8) ans = 128 0 -256
0
160
0
-32
0
1
>> tseby_rek(8) ans = 128 0 -256
0
160
0
-32
0
1
Siis 8
6
4
2
T 8 (x)=128 x −256 x +160 x −32 x +1 Mitataan laskentaan kulunut aika käyttämällä tic-toc komentoparia:
tic käynnistää kellon
toc pysäyttää kellon ja tulostaa komentojen suorittamiseen käytetyn ajan sekunteina. Lasketaan T 20( x ) , jotta saataisiin ero paremmin esille; kertoimia ei tulosteta. >> tic;tseby_it(20);toc Elapsed time is 0.001353 seconds. >> tic;tseby_rek(20);toc Elapsed time is 0.473235 seconds.
Siis iteraatio on huomattavasti nopeampi.
MATLAB – Ohjelmointi
53
7. SOVELLUKSIA 7.1
Funktion maksimointi
Tarkastellaan suljetulla välillä [a , b] määritellyn jatkuvan funktion f x lokaalin maksimikohdan ja maksimiarvon määrittämistä Tällainen lokaali maksimikohta voi olla välin päätepiste 1 tai välin sisäpiste. Viisipistemenetelmässä valitaan väliltä [a , b] tasavälisesti 5 pistettä (päätepisteet ja kolme sisäpistettä). Lasketaan funktion arvot näissä pisteissä ja otetaan niistä suurin arvo ja vastaava piste (jos kaikki arvot ovat yhtä suuria, otetaan sisäpiste). Tämän pisteen ympäristössä on lokaali maksimikohta, joten sen ympäristössä suoritetaan sama menettely. Tätä jatketaan kunnes lokaali maksimikohta on löydetty halutulla tarkkuudella. Menetelmän yksityiskohdat selviävät seuraavasta ohjelmasta. function [ymax,xmax] = maximum(fun,a,b,tol) % Funktion lokaalin maksimikohdan määrittäminen 5-pistemenetelmällä % Input-parametrit: % fun -- funktio % a, b -- välin päätepist, joiden välissä funkt. on lok. maks.kohta % tol -- toleranssi (valinnainen argumentti); oletustoleranssi 1e-6. % Output-parametrit: % ymax -- lokaali maksimiarvo % xmax -- lokaali maksimikohta if nargin == 3 tol = 1e-6; else if tol < 0 disp('tol <0') ymax=[]; xmax=[]; return end end delta = (b-a)/5; pisteet=linspace(a,b,5); arvot=[]; for x=pisteet arvot = [arvot,fun(x)]; end eka = 1; while (delta > tol)|eka eka=0; delta = delta/2; [ymax,k]=max(arvot); xmax=pisteet(k); if k==1 k=2; elseif k==5 k=4; end 1
Tarkastellaan funktion arvoja vain ko. välillä.
% Oletustoleranssi
MATLAB – Ohjelmointi pisteet(1)=pisteet(k-1); pisteet(3)=pisteet(k); pisteet(5)=pisteet(k+1); pisteet(2)=pisteet(k)-delta; pisteet(4)=pisteet(k)+delta;
end
arvot(1)=arvot(k-1); arvot(3)=arvot(k); arvot(5)=arvot(k+1); arvot(2)=fun(pisteet(2)); arvot(4)=fun(pisteet(4));
Kokeillaan ohjelmaa. Tarkastellaan funktion 1 f ( x )= 1+|x sin x| suurimman arvon määrittämistä. Määritellään funktio >> f=@(x) 1./(1+abs(x.*sin(x)));
ja piirretään kuvaaja >> x=0:0.01:12; >> plot(x,f(x))
Määritetään lokaali maksimi välillä [1,6] : >> [ymax,xmax]=maximum(f,1,6) ymax = 0.5430 xmax = 1
Eräs lokaali maksimi on siis välin vasemmassa päätepisteessä. Määritetään lokaali maksimi välillä [2,6] : >> [ymax,xmax]=maximum(f,2,6) ymax = 1.0000 xmax =
54
MATLAB – Ohjelmointi
55
3.1416
Eräs lokaali maksimi on siis välin sisäpisteessä ja arvo 1.
7.2
Funktiosarjojen piirtäminen
Tarkastellaan funktioiden approksimointia Taylorin polynomeilla ja Fourier-sarjojen osasummilla. Approksimaation arvo tietyssä pisteissä voidaan usein määrittää funktiota sum ja vektorointia käyttäen. Piirtoa varten funktion arvojen taulukko voidaan muodostaa for-lauseella. Tarkastellaan asiaa esimerkkien avulla. ESIMERKKI 1. Taylorin polynomi Kosini voidaan esittää Taylorin sarjana cos x =1−
x2 x4 x6 + − +⋯ , 2! 4! 6!
eli ∞
cos x =∑ (−1)k k=0
x2 k , (2k)!
jolloin n
cos x≈ ∑ (−1) k k =0
x2k , (2k)!
kun n on suuri. Tutkitaan tätä asiaa arvolla n=5 . Otetaan piirtoväliksi [−10, 10] . Seuraava skripti piirtää Taylorin polynomin ja kosinifunktion. xx=-10:0.01:10; k=0:5;
% Piirtoväli % n = 5
y=[]; for x=xx y=[y,sum((-1).^k.*x.^(2*k)./factorial(2*k))]; end plot(xx,y) hold; plot(xx,cos(xx)) ylim([-2,2]) hold;
% Piirretään Taylorin polynomi % Piirretään kosinifunktio
MATLAB – Ohjelmointi
56
Approksimaatio on hyvä välillä [−3, 3] . Kun n=10 , on approksimaatio hyvä laajemmalla välillä [−7, 7] .
ESIMERKKI 2. Trigonometrinen Fourier-sarja Kuvan
jaksollisen kanttiaallon Fourier-sarja on 1 2 2 2 f (t)= + π sin π t+ sin 3 π t+ sin 5 π t+⋯ 2 3π 5π eli 1 ∞ 2 f (t)= + ∑ sin (2 k +1) π t , 2 k=0 ( 2 k +1)π jolloin n
1 2 f (t)≈ + ∑ sin(2 k +1) π t , 2 k=0 ( 2 k + 1)π
MATLAB – Ohjelmointi
57
kun n on suuri. Tutkitaan tätä asiaa arvolla n=10 . Otetaan piirtoväliksi [−4, 4] . Seuraava skripti piirtää Fourier-sarja-approksimaation tt=-4:0.001:4; k=0:10;
% Piirtoväli % n=10
y=[]; for t=tt y=[y,1/2+sum(2./((2*k+1)*pi).*sin((2*k+1)*pi*t))]; end plot(tt,y)
Kanttiaalto voidaan piirtää seuraavalla skriptillä. Tällaista piirtoa on käsitelty kirjan Matematiikkaa MATLABilla luvussa 16.2. Siellä on myös esitelty jaksollisen jatkon muodostava funktio jj. hold; v = jj(tt,0,2); plot(tt, v<=1) hold;
ESIMERKKI 3. Funktion piirtäminen spektristä Jos jaksollisen funktion amplitudispektri on r k ja vaihespektri ϕk mamuodossa annettu Fourier-sarja on
(k ≥0) , niin vaihekul-
∞
f (t)=±r 0 +2 ∑ r k cos ( k ω t+ϕ k ) , k =1
missä ω on peruskulmataajuus. Kaavassa on + merkki, jos ϕ0=0 ja – merkki, jos ϕ0=π . Olkoon peruskulmataajuus ω=300 , amplitudispektri r 0=70 , r 1=95 , r 2=75 , r 3=53 , r 4 =26 , r 5=9,8 , r 6=7,5 , r 7=6,2 ja vaihespektri ϕ0=0
ϕ1=−0,16 , ϕ2=2,6 , ϕ3=−0,89 , ϕ4 =1,74 , ϕ5=−2,51 ,
ϕ6=−0,86 , ϕ7=1,27
MATLAB – Ohjelmointi
58
Piirretään funktio seuraavalla skriptillä: r0=70; r = [95, 75, 53, 26, 9.8, 7.5, 6.2]; %Amplitudit phi = [-0.16, 2.6, -0.89, 1.74, -2.51, -0.86, 1.27]; %Vaihekulmat omega = 300; %Peruskulmataajuuus k = 1:7; %Kertoimet tt = 0:0.0001:0.05; %Aikaväli y =[]; for t=tt y = [y, r0+2*sum(r.*cos(k*omega*t+phi))]; end plot(tt,y) grid
Funktion kuvaaja on seuraavanlainen:
TEHTÄVIÄ 1. Funktion arkustangentti Taylorin sarja on ∞ x 3 x5 x 7 x 2 k+1 + − +⋯=∑ (−1)k , 3 5 7 2 k +1 k=0 kun |x|≤1 . Jos |x|≤1 , on siis
arctan x=x− n
arctan x≈∑ (−1)k k=0
k 2 k +1 , 2 k +1
kun n on suuri Tutki tätä asiaa arvolla n=3 . Piirrä sekä arkustangentin että Taylorin polynomin kuvaajat välillä [−1,2; 1.2] . Tee tehtävä skriptiä käyttäen. Millä välillä approksimaatio on hyvä? Kokeile suurempi muuttujan n arvoja. Millä välillä approksimaatio voi maksimissaan toimia? 2. Erään jaksollinen funktion Fourier-sarja on
MATLAB – Ohjelmointi
59
k−1
2 ∞ (−1) f (t)= π ∑ k
sin( k π t )
k=1
Selvitä piirtämällä Fourier-sarjan osasummia välillä [−3, 3] minkä jaksollisen funktion Fourier-sarja on kyseessä. 3. Jaksollisen funktion spektristä tiedetään: • peruskulmataajuus: ω=2 π , • amplitudispektri (nollasta eroavat termit): r 0=1 , r 1=4 , r 2=2,5 , r 4 =1 , r 5=0,7 Vaihespektri: ϕ0=0 ϕ1=0,78 , ϕ2=1,57 , ϕ4 =−1,12 , ϕ5=−2,02 , Piirrä funktion kuvaaja välillä [0, 4] . 4. Jaksollisen funktion sinimuotoinen spektri koostuu amplitudeista A k ja vaihesiirtokulmista ϕk , joita käyttäen funktio esitetään muodossa •
∞
f (t)= A0 + ∑ A k sin (2 k π f t+ ϕk ) , k=1
missä f on funktion perusjakso. Olkoon funktion • perustaajuus: f =50 , • amplitudit (nollasta eroavat termit): A 0=0 , A 1=100 , A 3=77 , A 5=51 , A 7=25 , A 9=9.6 , A 11=7.6 , A 13=6,5 , •
Vaihesiirtokulmat (asteissa) ϕ1=−9 ϕ3=151 , ϕ5=−51 , ϕ7=100 , ϕ9=−138 ,
ϕ11=−50 , ϕ13=72 Piirrä funktio välillä [0 ; 0,04 ] . Ohjeita: • • •
7.3
π Vaihesiirtokulmien muunnos radiaaneiksi suoritetaan kertomalla luvulla 180 Käytä piirrossa riittävän pientä askelpituutta Käytä hyväksi sitä,, että positiiviset indeksit ovat parittomia lukuja.
Trigonometrinen Fourier-sarja
Jaksollinen funktio f, jonka on jakso T, voidaan esittää trigonometrisena Fourier-sarjana ∞ a f (t )= 0 + ∑ (a k cos k ω t +b k sin k ω t ) , 2 k =1 missä 2π T on kulmataajuus ja kertoimet lasketaan integraaleina ω=
MATLAB – Ohjelmointi 2 a k= T
bk =
2 T
60
t 0 +T
∫
f (t )cos k ω t dt
(k = 0, 1, 2, …)
f (t )sin k ω t dt
(k = 1, 2, 3, …).
t0
t 0 +T
∫ t0
Toteutetaan tämä MATLABilla. Seuraava ohjelma laskee Fourier-sarjan kertoimet. Ohjelma sisältää kaksi alifunktiota ja m-tiedoston sisäisiä globaaleja muuttujia. function [a,b,w] = four_trig(fun,T1,T2,n) % FOUR_TRIG Trignometrisen funktion Fourier-sarjan kertoimien laskenta. % [a,b,w] = four_trig(fun,T1,T2,n) % Sisäänmenoparametrit: % - fun kahva funktioon % - T1 funktion fun perusjakson alaraja % - T2 funktion fun perusjakson yläraja % - n kokokaisluku, joka ilmoittaa laskettavien Fourier-kertoimien % lukumäärän % Ulostuloparametrit: % - a kosinikertoimet rivivektorina [a0, a1, a2, ...] % - b sinikertoimet rivivektorina [0 b1, b2, ...] % - w jaksoa on vastaava kulmataajuus. global w k f T = T2-T1; w = 2*pi/T; f = fun; a=[]; b=[]; for k=0:n a = [a 2/T*integral(@fun_cos,T1,T2)]; b = [b 2/T*integral(@fun_sin,T1,T2)]; end
function y = fun_cos(t) global w k f y = f(t).*cos(k*w*t);
% Alifunktio
function y = fun_sin(t) global w k f y = f(t).*sin(k*w*t);
% Alifunktio
Fourier-sarjan approksimaation arvoja voidaan laskea seuraavalla ohjelmalla: function y = four_trig_arvo(a,b,w,t) % FOUR_TRIG_ARVO Fourier-sarjan määräämän funktio arvon laskenta % y = four_trig_arvo(a,b,w,t) % Sisäänmenoparametrit: % - a rivivektori, joka sisältää kosinikertoimet % - b rivivektori, joka sisältää sinikertoimet % - w jaksoa vastaava kulmataajuus % - t ajanhetki n = length(a); y = a(1)/2;
MATLAB – Ohjelmointi
61
for k=2:n y = y + a(k)*cos((k-1)*w*t)+b(k)*sin((k-1)*w*t); end
ESIMERKKI. Pulssijonon Fourier-sarja. Käyttäen kirjassa Matematiikkaa MATLABilla luvussa 16 esitettyä tekniikkaa muodostetaan pulssijono (funktio jj on esitelty kirjan luvussa 16.2). Tässä on käytetty anonyymejä funktioita. >> f=@(t) (t>=0)&(t<=2); >> g=@(t) f(jj(t,0,3));
Piirretään kuva pulssijonosta >> t=-7:0.001:7; >> plot(t,g(t)) >> ylim([-0.3,1.3])
Määritetään Fourier-sarjan 20 ensimmäistä kerrointa1. >> [a,b,w]=four_trig(g,0,3,20);
Tulostetaan alku näkyviin. >> w w =
2.0944
>> [a(1:6);b(1:6)] ans = 1.3333 -0.2757 0 0.4775
0.1378 0.2387
-0.0000 0.0000
-0.0689 0.1194
0.0551 0.0955
Tämä mukaan Fourier-sarjan alku on 1.3333 f (t)= −0,2757 cos (2,0944 t)+0,477 sin (2,0944 t)+ 2 +0,1378 cos (2⋅2,0944 t)+0,2387 sin(2⋅2,0944 t)+ ⋯ Piirretään saatu Fourier-sarjan approksimaatio samaan kuvaan kuin pulssijono. >> hold on 1
Komennon integraalin laskentaohjelma antaa varoituksia, mutta ei välitetä niistä.
MATLAB – Ohjelmointi
62
>> y=four_trig_arvo(a,b,w,t); >> plot(t,y) >> hold off
TEHTÄVIÄ 1. Jaksollinen reaaliarvoisen funktio f, jonka on jakso T, voidaan esittää eksponenttimuotoisena Fourier-sarjana ∞
f (t)=
∑
k=−∞
c k ei k ω t ,
missä ω=
2π T
ja 1 ck = T
t 0 +T
∫
f (t) e−i k ω t dt .
t0
Fourier-sarjan kertoimille pätee c−k =̄c k . Tee ohjelmat, joilla voidaan laskea Fourier-sarjan kertoimet ja laskea Fourier-sarjan approksimaation arvoja. 2. Määritä funktion f t =∣sin t∣ trigonometrinen Fourier-sarja. Piirrä kuva signaalista ja Fourier-sarja-approksimaatiosta. 3. Määritä kuvan funktion trigonometrinen Fourier-sarja. Piirrä kuva signaalista ja Fouriersarja-approksimaatiosta. Kokeile Fourier-sarjan kertoimien määrän vaikutusta tulokseen. a)
MATLAB – Ohjelmointi
63
b)
c)
4. Määritä kuvan funktion trigonometrinen Fourier-sarja. Piirrä kuva signaalista ja Fouriersarja-approksimaatiosta. Kokeile Fourier-sarjan kertoimien määrän vaikutusta tulokseen. a)
b)
MATLAB – Ohjelmointi
7.4
64
Lentorata heittoliikkeessä
Jatketaan kirjan1 Matematiikkaa MATLABilla luvussa 19.3.2 käsiteltyä kappaleen lentoradan tarkastelua heittoliikkeessä, kun ilmanvastus otetaan huomioon. Jos tuulen vaikutusta ei oteta huomioon, tapahtuu liike pystysuorassa tasossa. Asetetaan tähän tasoon xy-koordinaatisto siten, että x-akseli on vaakasuunnassa, y-akseli pystysuoraan ylös ja kappaleen lähtöpiste koordinaatiston origossa. Oletetaan, että ilmanvastus on suoraan verrannollinen nopeuden suuruuden neliöön. Ilmanvastus on liikesuunnan vastainen voima. Jos kappaleen nopeus on v , on ilmanvastus2 F i =−D∥v∥v , missä kerroin D=
C A . 2
Tässä
on ilman tiheys
A on kappaleen liikesuuntaa vastaan kohtisuoran pinnan poikkileikkauksen ala
C on vastuskerroin, joka riippuu kappaleen muodosta.
[]
x Kirjan luvussa 19.3.2 on johdettu differentiaaliyhtälöryhmä, jonka kappaleen sijainti x = y toteuttaa. Kyseessä on toisen kertaluvun differentiaaliyhtälöryhmä
{
x ' ' =−
D m
x ' 2 y ' 2 x '
y ' ' =−g−
D m
x ' 2 y ' 2 y '
jonka alkuehdot ovat
{
x 0=0 , y 0=0
{
x ' 0=v 0 cos . y ' 0=v 0 sin
Differentiaaliyhtälöryhmässä m on kappaleen massa. Määrittelemällä funktiot
{
z 1= x z 2 =x ' z 3= y z4= y '
voidaan differentiaaliyhtälö muuntaa 1. kertaluvun differentiaaliyhtälöryhmäksi (ks. kirjan luku 19.3.2)
1 2
Tässä luvussa kirja tarkoittaa tätä kirjaa. Merkintä ∥v∥ tarkoittaa vektorin v normia.
MATLAB – Ohjelmointi
{
65
z 1 ' =z 2 z 2 ' =−
D z z 2 z 2 m 2 2 4
z 3 ' =z 4 z 4 ' =−g −
D z 4 z 22 z 24 m
jonka alkuehdot ovat
{
z 1 0=0 z 2 0=v 0 cos z 3 0=0 z 4 0=v 0 sin
Tarkastellaan samaa tapausta kuin kirjan luvussa 19.3.2 eli baseballin lentorataa. Kerroin D lasketaan seuraavia arvoja käyttäen: = 1,2 kg/m3 2 A=π r , missä r = 0,0366 m C = 0,5 Baseballin massa on m = 0,145 kg. Käytetään yksiköitä m, kg, s. Lasketaan kerroin D. Määritellään muuttuja D globaaliksi.
>> global D >> rho=1.2; A=pi*0.0366^2; C=0.5; >> D=rho*C*A/2 D = 0.0013
Ratkaistaan differentiaaliyhtälö numeerisesti. Differentiaaliyhtälön määräävä m-funktio on function y=lento(t,z) global D m=0.145; g=9.81; y=[0;0;0;0]; y(1)=z(2); y(2)=-D/m*z(2)*sqrt(z(2)^2+z(4)^2); y(3)=z(4); y(4)=-g-D/m*z(4)*sqrt(z(2)^2+z(4)^2);
Koska differentiaaliyhtälön ratkaisuvälin loppupiste on se ajan t arvo, jolla kappaleen korkeus on nolla y=0 ⇔ z 3=0 , on lopetusehdon määräävä tapahtumafunktio m-funktiona function [arvo, toiminta, suunta] = lop(t,z) arvo = z(3);
MATLAB – Ohjelmointi
66
toiminta = 1; suunta = -1;
Kirjan Matematiikkaa MATLABilla luvussa 19.3.2 on ratkaistu lentorata, kun kappaleen lähtönopeus on 50 m/s ja lähtökulma 35. Tulokseksi saatiin, että kappaleen lentoaika on 4,53 s ja heiton pituus on 106,30 m. Pyritään selvittämään, mikä lähtökulman on oltava, jotta kappale lentäisi mahdollisimman pitkälle1. Oletetaan, että lähtönopeus on 50 m/s. Muodostetaan funktio, joka määrittää heiton pituuden lähtönopeuden ja lähtökulman funktiona: function y=heiton_pituus(v0,alfa) % Input-parametrit: % v0: lähtönopeus (m/s) % alfa: lähtökulma asteina % Output-parametrit: % y = lennon pituus (m) z0=[0;v0*cosd(alfa);0;v0*sind(alfa)]; [t, z, te, ze, ie] = ode45(@lento, [0, 10], z0, odeset('Events',@lop)); y=ze(1);
Kokeillaan funktion toimintaa: Tarkistetaan luvussa 19.3.2 laskettu tulos: >> heiton_pituus(50,35) ans = 106.3024
Piirretään lennon pituus lähtökulman funktiona, kun lähtönopeus on 50 m/s. Lasketaan lentoradan pituus, kun lähtökulma on välillä 1 … 90 : >> y=[]; >> kulma=1:90; >> for k=kulma y=[y, heiton_pituus(50,k)]; end
Esitetään kuva xy-koordinaatistossa >> plot(kulma,y) >> grid
1
Kirjan Matematiikkaa MATLABilla luvussa 19.3.3 on tarkasteltu vastaavaa asiaa, kun ilmanvastusta ei oteta huomioon.
MATLAB – Ohjelmointi
67
ja napakoordinaateissa >> polar(kulma*pi/180,y)
Kuvista zoomailemalla nähdään, että lennon pituus on suurimmillaan, kun lähtökulma on n 38,5 0,5. Tarkempi tulos saadaan piirtämällä kuva pienemmällä askelvälillä.
MATLAB – Ohjelmointi
68
Vielä parempi tulos saadaan maksimoimalla numeerisesti heiton pituus. Käytetään minimointifunktiota1 fminbnd. Määritellään ensin minimoitava funktio: >> f=@(x) -heiton_pituus(50,x);
ja sitten funktion f minimikohta, joka on muuttujan x funktion heiton_pituus(50,x) maksimikohta: >> [x,arvo]=fminbnd(f,0,90) x = 38.4122 arvo = -106.8545 >> -arvo ans = 106.8545
Siis lennon pituus on suurimmillaan, kun lähtökulma on 38,4 ja tällöin lennon pituus on 106,85 m.
1
Katso kirja Matematiikkaa MATLABilla luku 6.2.
MATLAB – Ohjelmointi
69
8. HIIREN KÄYTTÖ GRAFIIKKAIKKUNASSA Tässä luvussa tarkastellaan hiiren käyttöä grafiikkaikkunassa. Seuraavassa taulukossa on esitetty joitain komentoja. Komento
Toiminto
[x,y] = ginput
Lukee hiiren painallusten koordinaatit grafiikkaikkunasta. Koordinaatit tallennetaan vaakavektoreihin x ja y. Lukeminen lopetetaan Enterin painalluksella.
[x,y] = ginput(n)
Lukee n:n hiiren painalluksen koordinaatit grafiikkaikkunasta. Voidaan keskeyttää Enterin painalluksella.
[x,y,t] = ginput(…)
Palauttaa lisäksi vektorin t, jolla on seuraavat arvot: 1. 1, jos on painettu hiiren vasenta painiketta 2. 2, jos on painettu hiiren keskimmäistä painiketta 3. 3 jos on painettu hiiren oikeaa painiketta 4. näppäimen ASCII-koodin, jos on painettu näppäintä.
waitforbuttonpress
Odotetaan, kunnes aktiivisessa grafiikkaikkunassa on painettu hiiren painiketta tai näppäintä. Funktio palauttaa arvon 0, jos on painettu hiiren painiketta 1, jos on painettu näppäimistöä.
zoom on
Zoomaus 2-ulotteisessa kuvassa: Suurentaminen hiiren vasemmalla näppäimellä Vaihtoehtoja hiiren oikealla näppäimellä Alue voidaan myös valita hiirellä vetämällä. Zoomaus pois päältä.
zoom off
ESIMERKKI. Tallenna seuraava skripti tiedostoon monikulmio.m. Skripti piirtää monikulmion, jonka kärjet annetaan hiirellä osoittamalla. Skripti tulostaa myös monikulmion pinta-alan. Tutki skriptin toimintaa. Skriptissä komento polyarea määrittää monikulmion pinta-alan ja funktio num2str muuttaa luvun merkkijonoksi. % Monikulmion piirtäminen n = figure;
% Uusi grafiikkaikkuna
disp('MONIKULMION PIIRTO') disp('Osoita monikulmion käret painamalla hiiren vasenta näppäintä') disp('Lopeta painamalla hiiren oikeaa näppäintä') axis([-10 10 -10 10]); hold on; [x1,y1,t] = ginput(1); plot(x1,y1,'o'); xx = x1; yy = y1; while t ~= 3 [x,y,t] = ginput(1); if t ~= 3 plot(x,y,'o'); end xx = [xx x]; yy = [yy y];
% Luetaan ens. koordinaatit % Merkitään tämä pallolla % Tallennetaan koordinaatit
% Ei piirr. oik. näpp. painallusta
MATLAB – Ohjelmointi
70
end xx(end) = x1; yy(end) = y1; plot(xx,yy);
% Viim. koord. on ens. koordinaatti
A = polyarea(xx,yy); title(['Pinta-ala = ' num2str(A)]); disp('Klikkaa kuva, kun olet valmis.') waitforbuttonpress; delete(n);
TEHTÄVIÄ 1. Tutki zoomauksen toimintaa poistamalla Esimerkin skriptistä kolme viimeistä komentoa ja korvaa ne komennolla zoom on.
MATLAB – Ohjelmointi
71
9. TIETOTYYPPEJÄ 9.1
Merkkijonot
Merkkijono on vaakavektori, jonka alkiot ovat merkkejä. Sisäisesti merkit tallennetaan ASCIIkoodeina. Merkkijono esitetään ympäröimällä merkit yksinkertaisilla lainausmerkeillä. ESIMERKKI. Tallennetaan merkkijono muuttujaan nimi >> nimi = 'Albert Einstein' nimi = Albert Einstein
Muuttuja nimi on vaakavektori, jossa on 15 alkiota. >> size(nimi) ans = 1 15
Merkkijonon alkioihin voidaan viitata kuten vektorin alkioihin. >> nimi(8) ans = E >> nimi(1:6) ans = Albert
Merkkijonoja voidaan asettaa peräkkäin matriisien tapaan: >> ammatti = 'fyysikko'; >> [nimi,', ',ammatti] ans = Albert Einstein, fyysikko
Merkkijonoihin liittyy paljon erilaisia käsittelykomentoja. Seuraavissa luvuissa esitellään joitain niistä. 9.1.1 Muunnoskomentoja Seuraava taulukko sisältää merkkijonojen muunnoskomentoja.
MATLAB – Ohjelmointi Komento
Toiminto
double(str)
Merkkijonon str merkkien ASCII-koodit vektorina.
char(x)
Kokonaislukuvektorin x alkioita vastaavat ASCII-merkit.
num2str(A)
Muuntaa lukumatriisin A merkkijonoksi.
num2str(A,format)
Muuntaa lukumatriisin A merkkijonoksi käyttäen muotoilua format1.
int2str(n)
Muuntaa kokonaisluvun n merkkijonoksi.
str2num(str)
Muuntaa merkkijonon str luvuksi.
lower(str)
Muuntaa kirjaimet pieniksi kirjaimiksi
upper(str)
Muuntaa kirjaimet isoiksi kirjaimiksi
strcat(str1,str2, …)
Asettaa merkkijonot str1, str2, … peräkkäin. Poistaa merkkijonojen lopussa olevat blankot.
strrep(str1,str2,str3)
Korvaa kaikki merkkijonon str2 esiintymät merkkijonossa str1 merkkijonolla str3.
bin2dec(str)
Muuntaa merkkijonon str sisältämän binääriluvun desimaaliluvuksi.
dec2bin(n)
Muuntaa ei-negatiivisen kokonaisluvun binääriluvuksi, joka esitetään merkkijonona.
hex2dec(str)
Muuntaa merkkijonon str sisältämän heksadesimaaliluvun desimaaliluvuksi.
dec2hex(n)
Muuntaa ei-negatiivisen kokonaisluvun heksadesimaaliluvuksi, joka esitetään merkkijonona.
ESIMERKKEJÄ. >> x = double('abc') x = 97 98 99
%Merkkijonon merkkien ASCII-koodit
>> char(x) ans = abc
%Muunnetaan takaisin merkkijonoksi
>> x = '123.45' x = 123.45
%Luku merkkijonona
>> 1/x ??? Error using ==> mrdivide Matrix dimensions must agree. >> x = str2num(x) x = 123.4500 >> 1/x ans = 0.0081
%Muunnetaan luvuksi %Nyt voidaan laskea.
>> nimi = 'Albert Einstein'; 1
72
format samanlainen kuin sprintf-komennossa, joka esitellään myöhemmin.
MATLAB – Ohjelmointi
73
>> upper(nimi) ans = ALBERT EINSTEIN >> strcat(nimi,', ','fyysikko') ans = Albert Einstein,fyysikko
%Peräkkäinasettelu %välilyönti pilkun perästä poistuu!
>> nimi1 = strrep(nimi,'e','E') nimi1 = AlbErt EinstEin >> x = dec2bin(51) x = 110011
%Muunnetaan binääriluvuksi
>> x+1 ans = 50
%Tulos on merkkijono. %Sillä ei kannata laskea
50
>> double(x) ans = 49 49
49
48
49
48
50
49
50
%Edellinen lisäsi taulukon %alkioihin luvun 1
49
>> char(x+1) ans = 221122 >> x = bin2dec(x) x = 51
%Muunnetaan desimaaliluvuksi
>> x+1 ans = 52
%Tulos luku!
ESIMERKKI. Tulostetaan ASCII-merkit väliltä 30…127. >> for i = 30:10:127 disp([num2str(i,'%03d'),': ',char(i:i+9)]) end 030: - !"#$%&' 040: ()*+,-./01 050: 23456789:; 060: <=>?@ABCDE 070: FGHIJKLMNO 080: PQRSTUVWXY 090: Z[\]^_`abc 100: defghijklm 110: nopqrstuvw 120: xyz{|}~
Alkupään ja loppupään merkit eivät tulostuneet. Oikeastaan tulostettiin merkkiin 129 asti.
MATLAB – Ohjelmointi
74
ESIMERKKI. Seuraava ohjelma muuntaa syötettyjen rivien merkkien järjestyksen käänteiseksi. Syöttö päätetään tyhjällä merkkijonolla. function kaanto a = ' '; while length(a) ~= 0 a = input('Anna Merkkijono: ','s'); disp(a(end:-1:1)); end
Ohjelman ajo: >> kaanto Anna Merkkijono: 13817jejiru95 59urijej71831 Anna Merkkijono: >>
TEHTÄVIÄ 1. Tee ohjelma, joka lukee näppäimistöltä merkkijonoja ja tulostaa merkkijonojen merkkien ASCII-koodit. Lukemisen päättää tyhjä merkkijono. 2. Tee ohjelma, joka lukee merkkijonoja näppäimistöltä ja muuntaa merkkijonon kirjaimet isoiksi kirjaimiksi. Lukemisen päättää tyhjä merkkijono. 9.1.2 Vertailukomentoja Merkkijonojen vertailuun on seuraavia komentoja: Komento strcmp(str1, str2)
Toiminto Merkkijonojen vertailu. Arvo on looginen luku 1, jos samat, muuten looginen luku 0.
strcmpi(str1,str2)
Merkkijonojen vertailu. Muuten sama kuin strcmp, mutta ei erottele isoja ja pieniä kirjaimia.
strncmp(str1,str2,n)
Merkkijonojen vertailu. Arvo on looginen luku 1, jos n ensimmäistä merkkiä samoja, muuten looginen luku 0.
strncmpi(str1,str2,n)
Merkkijonojen vertailu. Muuten sama kuin strcnmpi, mutta ei erottele isoja ja pieniä kirjaimia.
strfind(str1,str2)
Merkkijonojen etsintä. Etsii merkkijonoa str2 merkkijonosta str1. Palauttaa vektorin, joka sisältää merkkijonojen str2 aloituskohdat.
ESIMERKKI. >> nimi = 'Albert Einstein'; nimi1='AlbErt EinstEin'; >> strcmp(nimi,nimi1) ans =
MATLAB – Ohjelmointi
75
0 >> strcmpi(nimi,nimi1) ans = 1 >> strncmp(nimi,nimi1,3) ans = 1 >> strncmp(nimi,nimi1,4) ans = 0 >> strfind(lower(nimi),'ei') ans = 8 13
ESIMERKKI. Tehdään ohjelma, joka lukee lukuja näppäimistöltä ja tulostaa luettujen lukujen keskiarvon. Lukujen lukeminen päätetään kirjaimella s tai S. function y = keskiarvo % KESKIARVO Lukujen keskiarvon laskenta. % Luvut syötetään näppäimistöltä. Syötön lopetus s tai S. disp('Lukujen keskiarvojen laskenta\nSyötön lopetusmerkki: s') luvut = []; jatka = 1; while jatka x = input('Anna luku: ','s'); if strncmpi('s',x,1) jatka = 0; else x = str2num(x); luvut = [luvut, x]; end; end; y = mean(luvut);
9.1.3 Käsittely- ja testauskomentoja Merkkijonojen käsittelyyn ja testaukseen on seuraavia komentoja:
MATLAB – Ohjelmointi
76
Komento
Toiminto
blanks(n)
Luo blankoista koostuva merkkijono, jonka pituus n
deblank(str)
Merkkijonosta poistetaan loppublankot.
ischar(s)
Arvo looginen 1, jos s on merkkijono, muuten arvo looginen 0.
isspace(str)
str:n pituinen vektori, jonka alkio on looginen 1, jos vastaava str:n alkio on blankko, tabulaattori tai rivin vaihto, muuten alkio on looginen 0.
strtok(str)
Palauttaa merkkijonossa str esiintyvän ensimmäisen sanan (token), joka päättyy blankkoon tai tabulaattoriin tai rivinvaihtoon. Alun tyhjät merkit poistetaan.
ESIMERKKEJÄ. >> ischar('abc') ans = 1 >> ischar(123) ans = 0
Etsitään merkkijonosta välilyönnit >> koe = ' a b c' koe = a b c >> isspace(koe) ans = 1 0
1
0
1
0
Merkkijonosta poistetaan välilyönnit seuraavasti: >> koe(~isspace(koe)) ans = abc
% Looginen indeksointi
Komennon strtok laajennettu muoto on [token, rem] = strtok(str,delimiter). Tämä etsii ensimmäisen sanan, joka on ennen rajoitinta delimiter. Sana tallennetaan muuttujaan token. Muuttujaan rem tallennetaan loppu merkkijonosta str. ESIMERKKI. Luetellaan merkkijonon >> viikko = 'ma, ti, ke, to, pe, la, su' viikko = ma, ti, ke, to, pe, la, su
sanat. Sanoja erottaa pilkut. Poistetaan myös välilyönnit sanoista. Toteutetaan tämä seuraavana skriptinä:
MATLAB – Ohjelmointi
77
rem = viikko; while ~isempty(rem) [token,rem] = strtok(rem,','); token = token(~isspace(token)); disp(token) end
Skriptin ajo tuottaa seuraavan tuloksen: ma ti ke to pe la su
Komento isstrprop(str, ‘kategoria’) palauttaa loogisen vektorin, jonka koko on sama kuin merkkijonon str. Vektorin alkiot ovat loogisia lukuja 1 tai 0 riippuen siitä, mihin kategoriaan ko. kohdalla oleva merkkijonon str merkki kuuluu. Kategorioita ovat mm.
alpha: kirjain
alphanum: kirjain tai numero
digit: numero
lower: pieni kirjain
upper: iso kirjain
print: tulostuva merkki
ESIMERKKI. >> aika = 'Kello on 14:22' aika = Kello on 14:22 >> a=isstrprop(aika,'alpha') a = 1 1 1 1 1 0
1
1
0
0
0
0
0
0
0
0
0
1
1
0
1
1
>> aika(a) ans = Kelloon >> a=isstrprop(aika,'digit') a = 0 0 0 0 0 0 >> aika(a) ans =
MATLAB – Ohjelmointi
78
1422
TEHTÄVIÄ 1. Tee ohjelma, joka lukee merkkijonoja näppäimistöltä ja poistaa vokaalit. Lukemisen päättää tyhjä merkkijono. 9.1.4 Evaluointikomentoja Seuraava taulukko sisältää merkkijonojen laskentaan liittyviä komentoja. Komento
Toiminto
eval(str)
Suorittaa merkkijonon str sisältämän komennon.
vectorize(f)
Muodostaa merkkijonona annetusta matemaattisesta lausekkeesta vektoroidun version: laittaa pisteen . operaattoreiden *, /, ^ eteen.
ESIMERKKEJÄ. >> str = '5+6' str = 5+6 >> eval(str) ans = 11
Lauseke merkkijonona: >> f = '3*x^2*y^2-x*y+1' f = 3*x^2*y^2-x*y+1
Vektoroidaan lauseke. >> g=vectorize(f) g = 3.*x.^2.*y.^2-x.*y+1
Lasketaan vektoroidun lausekkeen arvo. >> x = [1 2 3]; y = [0 2 4]; >> eval(g) ans = 1 45 421
MATLAB – Ohjelmointi
79
9.1.5 Merkkijonon kirjoittaminen Merkkijono s kirjoitetaan komennolla s = sprintf(format, A,...), missä A, … ovat matriiseja joiden sisältö kirjoitetaan. format on muotoilun sisältävä merkkijono. Muotoilu format on samanlainen kuin C-kielessä. Se voi sisältää kentänmäärittelyjä, jotka alkavat %-merkillä. Formaatin k:s kentänmäärittely määrää, minkä muotoisena k:s argumentti tulostuu. Muut kuin kentänmäärittelyissä olevat merkit tulostuvat sellaisenaan. Tämä mahdollistaa selittävien tekstien sijoittamisen lukujen yms. tulosteiden ympärille. Kentänmäärittelyn muoto on seuraava (kulmasulkeissa olevat ovat valinnaisia): %<.tarkkuus>tyyppi, jossa etumerkit –
tuloste sijoittuu kentän vasempaan laitaan (oletusarvo: oikea laita).
+ numeerinen tuloste alkaa aina etumerkillä. 0 täytteenä käytetään nollia eikä välilyöntejä. minimileveys Minimileveys määrää tulostettavan kentän vähimmäisleveyden. Jos tulosteessa on minimileveyttä vähemmän merkkejä, käytetään täytemerkkinä välilyöntiä. tarkkuus Desimaalilukuja tulostettaessa tarkkuus kertoo desimaalipisteen jälkeen tulostettavien desimaalien lukumäärän. Merkkijonoa tulostettaessa tarkkuus kertoo tulostettavien merkkien enimmäismäärän. tyyppi c yksittäinen merkki s merkkijono d kokonaisluku tai desimaaliluku e eksponenttiesitysmuoto f kiinteä määrä desimaaleja g tiiviimpi muodoista e ja f Tulostuksen muotoilussa voidaan käyttää myös erikoismerkkejä, joita ovat: \b backspace \f sivunvaihto \n rivinvaihto \r vaunun palautus \t horisontaalinen tabulointi Lisäksi voidaan tulostaa muita merkkejä:
MATLAB – Ohjelmointi %% \\ \"
80
prosenttimerkki kenoviiva heittomerkki
Komento sprintf eroaa vastaavasta C-kielen komennosta print() siten, että se on vektoroitu: formaatissa pyöritään silmukkana kunnes kaikki matriisien alkiot on tulostettu. Matriisien alkiot käydään sarakkeittain läpi. ESIMERKKEJÄ. >> sprintf('%f',pi) ans = 3.141593 >> sprintf('%0.2f',pi) ans = 3.14 >> p = 10^10*pi; >> sprintf('%f %e ans = 31415926535.897930
%g', p, p, p) 3.141593e+010
3.14159e+010
Rivinvaihtomerkin \n käyttö: >> sprintf('luku pii: %0.7f\nluku e ans = luku pii: 3.1415927 luku e : 2.7182818
: %0.7f',pi,exp(1))
Formaatissa pyöritään silmukkana kunnes kaikki alkiot on tulostettu. >> A = rand(1,7) A = 0.4057 0.9355 >> sprintf('%f ans = 0.405706 0.916904 0.893650 0.352868
0.9169
0.4103
%f\n',A)
0.935470 0.410270 0.057891
Matriisin alkiot käydään läpi sarakkeittain. >> A = rand(3,4) A = 0.8132 0.2028 0.0099 0.1987 0.1389 0.6038 >> sprintf('%f %f ans = 0.813166 0.009861 0.202765 0.198722 0.272188 0.198814 0.746786 0.445096
0.2722 0.1988 0.0153 %f\n',A) 0.138891 0.603792 0.015274 0.931815
0.7468 0.4451 0.9318
0.8936
0.0579
0.3529
MATLAB – Ohjelmointi
81
9.1.6 Merkkijonosta lukeminen Formatoitu lukeminen merkkijonosta s suoritetaan komennolla [A, määrä] = sscanf(s, format, koko) missä A on matriisi, johon data luetaan määrä on valinnainen parametri, joka kertoo luetun data määrän. format on muotoilu, joka on samanlainen kuin C-kielessä. koko on valinnainen parametri, joka ilmoittaa luettavan data määrän. Jos parametria ei ole, niin luetaan merkkijonon loppuun asti. koko n
Merkitys Luetaan n alkiota sarakevektoriin.
inf
Luetaan merkkijonon loppuun asti.
[m, n]
Luetaan alkiot mn-matriisin sarakkeittain. Jos alkioita ei riittävästi asetetaan loput alkiot nolliksi.
Komento sscanf eroaa vastaavasta C-kielen komennosta scanf() siten, että se on vektoroitu: formaatissa pyöritään silmukkana kunnes merkkijono s on käyty läpi tai argumentin koko määrä dataa on luettu. Formaatti sisältää kentänmäärittelyjä, jotka alkavat %-merkillä. Kentänmäärittelyn muoto on seuraava (kulmasulkeissa olevat ovat valinnaisia): %<*>tyyppi *
Muotoilu tehdään, mutta tulosta ei sijoiteta mihinkään ts. kenttä ohittuu.
maksimileveys Määrää luettavan kentän enimmäisleveyden. tyyppi c s d, i e, f, g
yksittäinen merkki (myös tyhjä väli) merkkijono (ei tyhjää väliä) kokonaisluku desimaalilukuja
Merkkijonoa tutkittaessa sscanf hyppää automaattisesti tyhjän välin yli, jos muotoilun tyyppi on muu kuin %c. ESIMERKKEJÄ. >> A=sscanf('43.6 67.98','%f %f')
MATLAB – Ohjelmointi
82
A = 43.6000 67.9800 >> A=sscanf('43.6 ... 67.98','%f
%f')
A = 43.6000 >> A=sscanf('43.6 ... 67.98','%f %*s %f') A = 43.6000 67.9800
9.2
Solutaulukot
Solutaulukko on taulukko, jonka alkiot voivat olla eri tyyppiä esim. matriiseja, lukuja, merkkijonoja ... Solutaulukon alkioita sanotaan soluiksi. Solutaulukko eroaa matriisista siinä, että matriisin alkiot ovat kaikki samaa tyyppiä, lukuja. Solutaulukon voi luoda aaltosulkuja {, } käyttäen samaan tapaan kuin matriisi luodaan hakasulkuja käyttäen. Merkintä { } tarkoittaa tyhjää solutaulukkoa. syöttämällä arvot yksittäisiin soluihin. Solujen indeksoinnissa käytetään aaltosulkuja. Jos samanniminen matriisi on olemassa, on matriisi ensin tyhjennettävä esim. clear-komennolla. Tyhjä mn-solutaulukko C luodaan komennolla C = cell(m,n). Komento C = cell(n) on sama kuin komento C = cell(n,n). ESIMERKKEJÄ. Luodaan solutaulukko F aaltosulkuja käyttäen: >> F = {'Einstein','Albert',[1879,1955];'Newton','Isaac',[1642,1727]} F = 'Einstein' 'Albert' [1x2 double] 'Newton' 'Isaac' [1x2 double]
Luodaan solutaulukko M syöttämällä: >> >> >> >> >> >>
M{1,1} M{1,2} M{1,3} M{2,1} M{2,2} M{2,3}
>> M M =
='Eukleides'; = '?'; = [-325,-265]; = 'Pythagoras'; = '?'; = [-569,-475];
MATLAB – Ohjelmointi 'Eukleides' 'Pythagoras'
'?' '?'
83
[1x2 double] [1x2 double]
Yksittäiseen soluun viitataan aaltosulkujen sisällä olevilla indekseillä: >> F{1,3} ans = 1879
1955
Tämä on vektori, jonka alkioihin viitataan vektori-indeksillä >> F{1,3}(1) ans = 1879
Solutaulukkoja voidaan asettaa peräkkäin hakasulkuja käyttäen. Menetelmä on sama kuin matriiseilla. >> T = [F;M] T = 'Einstein' 'Newton' 'Eukleides' 'Pythagoras'
'Albert' 'Isaac' '?' '?'
[1x2 [1x2 [1x2 [1x2
double] double] double] double]
Solutaulukon osiin voi viitata kuten matriisien osiin käyttäen sulkuja tai aaltosulkuja. Solutaulukon koko sisältö voidaan tulostaa näytölle komennolla celldisp(C). ESIMERKKI. >> celldisp(T(1:2,[1,3])) ans{1,1} = Einstein
%tai T{1:2,[1,3]}
ans{2,1} = Newton ans{1,2} = 1879
1955
ans{2,2} = 1642
1727
Solutaulukosta C poistetaan i:s rivi komennolla C(i,:) = [ ] j:s sarake komennolla C(:,j) = [ ] Komento on siis sama kuin matriiseilla. Poistetaan solutaulukosta T toinen sarake:
MATLAB – Ohjelmointi
84
>> T(:,2)=[] T =
'Einstein' 'Newton' 'Eukleides' 'Pythagoras'
[1x2 [1x2 [1x2 [1x2
double] double] double] double]
Funktioon voidaan välittää vaihteleva määrä sisäänmeno- ja ulostulo-argumentteja käyttämällä muuttujia1 varargin syötteisiin (sisäänmenoihin) varargout ulostuloihin. Nämä ovat solutaulukkoja. Tämä mahdollistaa erityyppiset muuttujat argumentteina. Komento C = num2cell(A) muuntaa matriisin A solutaulukoksi C. Muunnos tapahtuu alkioittain. Tuloksena on samaa kertalukua oleva solutaulukko. Komennon muoto
num2cell(A, 1) asettaa sarakkeet erillisiin soluihin num2cell(A, 2) asettaa rivit erillisiin soluihin
ESIMERKKI. >> A = rand(2,3) A = 0.4057 0.9169 0.9355 0.4103 >> C = num2cell(A) C = [0.4057] [0.9169] [0.9355] [0.4103]
0.8936 0.0579
[0.8936] [0.0579]
>> C = num2cell(A,1) C = [2x1 double] [2x1 double] >> celldisp(C) C{1} = 0.4057 0.9355 C{2} = 0.9169 0.4103 C{3} = 0.8936 0.0579 >> C = num2cell(A,2) C = [1x3 double] [1x3 double]
1
Katso luku 5.3.
[2x1 double]
MATLAB – Ohjelmointi >> celldisp(C) C{1} = 0.4057 0.9169 C{2} = 0.9355 0.4103
85
0.8936 0.0579
Solutaulukon C muuntaminen lukutaulukoksi tapahtuu A = cell2mat(C). Tässä solutaulukon C alkioiden dimensioiden on oltava yhteensopivia. ESIMERKKI. >> A = rand(3,7) A =
0.8998 0.8216 0.6449
0.8180 0.6602 0.3420
0.2897 0.3412 0.5341
0.7271 0.3093 0.8385
0.5681 0.3704 0.7027
0.5466 0.4449 0.6946
0.6213 0.7948 0.9568
>> C = num2cell(A,1) C = Columns 1 through 5 [3x1 double] double]
[3x1 double]
[3x1 double]
[3x1 double]
[3x1
Columns 6 through 7 [3x1 double]
[3x1 double]
>> B = cell2mat(C) B = 0.8998 0.8216 0.6449
0.8180 0.6602 0.3420
0.2897 0.3412 0.5341
0.7271 0.3093 0.8385
0.5681 0.3704 0.7027
0.5466 0.4449 0.6946
0.6213 0.7948 0.9568
0.5681 0.3704 0.7027
0.5466 0.4449 0.6946
0.6213 0.7948 0.9568
Tämä voidaan toteuttaa myös for-silmukkaa käyttäen: >> [m,n] = size(C); >> D = []; >> for i = 1:n D = [D C{i}]; end >> D D =
0.8998 0.8216 0.6449
0.8180 0.6602 0.3420
0.2897 0.3412 0.5341
0.7271 0.3093 0.8385
MATLAB – Ohjelmointi
9.3
86
Tietueet
Tietue on joukko loogisesti yhteenkuuluvia tietoja, jotka voivat olla keskenään erityyppisiä. Näitä tietueeseen kuuluvia tietoja sanotaan kentiksi. Tietueet auttavat hallitsemaan monimutkaisia asiakokonaisuuksia ja tekevät ohjelmista helppolukuisempia. Tietue voidaan luoda kahdella eri tavalla: sijoituskäskyllä antamalla arvot yksittäisille kentille. Tietueen kenttiin viitataan siten, että kirjoitetaan tietueen nimi, piste ja kentän nimi. struct-komennolla muodossa s = struct('kenttä1',arvot1,'kenttä2',arvot2,...), joka luo tietueen kenttineen ja antaa kentille arvot. Arvot voivat olla yksittäisiä arvoja tai samankokoisia solutaulukoita. Tyhjä tietue annetuilla kentän nimillä luodaan komennolla s = struct('kenttä1',{ },'kenttä2',{ },...). Tietueen kentän nimen on alettava kirjaimella. ESIMERKKI. Luodaan sijoituskäskyllä tietue henkilo, jossa on kolme: kenttää nimi, ammatti, elinaika. >> henkilo.nimi = 'Einstein Albert'; >> henkilo.ammatti = 'fyysikko'; >> henkilo.elinaika = [1879,1955];
Saatiin 11-taulukko, jonka sisältö voidaan tulostaa kirjoittamalla tietueen nimi: >> henkilo henkilo = nimi: 'Einstein Albert' ammatti: 'fyysikko' elinaika: [1879 1955]
Laajennetaan taulukkoa laittamalla indeksi tietueen nimen perään: >> henkilo(2).nimi = 'Newton Isaac'; >> henkilo(2).ammatti = 'fyysikko'; >> henkilo(2).elinaika = [1642,1727];
Nyt taulukon koko on 12 ja tietueen nimen kirjoittamisen tuloksena saadaan kuvaus tietueen rakenteesta: >> henkilo henkilo = 1x2 struct array with fields: nimi ammatti elinaika
Yksittäinen tietue saadaan tulostettua käyttämällä indeksointia:
MATLAB – Ohjelmointi
87
>> henkilo(2) ans = nimi: 'Newton Isaac' ammatti: 'fyysikko' elinaika: [1642 1727]
Tietueen kenttien ei tarvitse olla kooltaan yhtä suuria. >> henkilo(3).nimi = 'Eukleides'; >> henkilo(3).ammatti = 'matemaatikko'; >> henkilo(3).elinaika = -300;
ESIMERKKI. Luodaan struct-komennolla tietue mittaus, jossa on kaksi kenttää: pituus ja paino. Seuraava komento luo yhden tietueen. >> mittaus = struct('pituus',185,'paino',87) mittaus = pituus: 185 paino: 87
Seuraava komento luo taulukon, jossa on neljä alkiota. >> mittaus = struct('pituus',{185,156,172,179},'paino',{87,65,68,81}) mittaus = 1x4 struct array with fields: pituus paino
Tulostetaan näistä toinen alkio. >> mittaus(2) ans = pituus: 156 paino: 68
Tietueista muodostetun taulukon osiin voi viitata kuten matriisin osiin. Kentän mahdollisiin alkioihin viitataan käyttäen asiaan kuuluvaa indeksointia. ESIMERKKI. (jatkoa) >> uus_henkilo = henkilo(1:2) uus_henkilo = 1x2 struct array with fields: nimi ammatti elinaika >> uus_henkilo(1) ans = nimi: 'Einstein Albert'
MATLAB – Ohjelmointi
88
ammatti: 'fyysikko' elinaika: [1879 1955]
Tulostetaan muuttujan henkilo(1) kentät nimi ja elinaika sekä vektorin elinaika ensimmäinen alkio. >> henkilo(1).nimi ans = Einstein Albert >> henkilo(1).elinaika ans = 1879 1955 >> henkilo(1).elinaika(1) ans = 1879
Taulukkomuotoisen tietueen kenttiin voidaan viitata kerralla. >> mittaus.pituus ans = 185 ans = 156 ans = 172 ans = 179 >> pituudet = [mittaus.pituus] pituudet = 185 156 172 179
Taulukon jokaiseen tietueeseen voidaan lisätä kenttä lisäämällä kenttä yhteen tietueeseen. Muiden tietueiden vastaava kenttä sisältää tyhjän matriisin. >> mittaus(1).nimi = 'TM' mittaus = 1x4 struct array with fields: pituus paino nimi
Seuraavaan taulukkoon on koottu tietueiden käsittelyyn liittyviä komentoja.
MATLAB – Ohjelmointi
89
Komento
Toiminto
fieldnames(s)
Tietueen s kenttien nimet solutaulukkona.
rmfield(s,’kenttä’)
Tietyn kentän poistaminen tietueesta.
struct2cell(s)
Muuntaa tietueen s solutaulukoksi. Jos s on mn-taulukko, jossa on p kenttää, niin tuloksena on pmn-solutaulukko.
isstruct(s)
Arvo on tosi (looginen 1), jos s on tietue, muuten arvo epätosi (looginen 0).
isfield(s, ’kenttä’)
Arvo on tosi (looginen 1), jos kenttä on tietueen s kenttä.
ESIMERKKI. (jatkoa) >> fieldnames(mittaus) ans = 'pituus' 'paino' 'nimi' >> arvot = rmfield(mittaus,'nimi') arvot = 1x4 struct array with fields: pituus paino >> struct2cell(arvot) ans(:,:,1) = [185] [ 89] ans(:,:,2) = [156] [ 65] ans(:,:,3) = [172] [ 68] ans(:,:,4) = [179] [ 81]
MATLAB – Ohjelmointi
10.
90
TIEDOSTOT
Tiedostot ovat tietokoneen pysyväismuistissa sijaitsevia tietovarastoja, joissa ohjelmia ja niiden tarvitsemaa tietoa voidaan säilöä. Koska tiedostot ovat tietojen säilytyspaikkoja, niiden käsittelemiseen riittää varsin niukka toimenpidevalikoima. Tiedoston käsittely voidaan jakaa seuraaviin vaiheisiin: 1. Tiedoston avaaminen komennolla fopen. 2. Tiedoston käsittely a. Luetaan
binääridataa komennolla fread
merkkijonoja riveittäin komennoilla fgetl tai fgets
muotoiltua ASCII-dataa komennolla fscanf b. Kirjoitetaan
binääridataa komennolla fwrite
muotoiltua ASCII-dataa komennolla fprintf
3. Tiedoston sulkeminen komennolla fclose. Seuraavassa esitellään lähemmin näiden komentojen toimintaa. Lisäksi esitellään tiedoston käsittelykohdan muuttamista.
10.1 Tiedoston avaaminen Tiedosto avataan komennolla fopen, jonka on muotoa fid = fopen(’tiedosto’, ’käsittelytapa’). Parametri käsittelytapa ilmoittaa tiedoston käsittelytavan, joita ovat mm.
r
w uuden tiedoston avaaminen vain kirjoittamista varten
vanhan tiedoston avaaminen vain lukemista varten (oletusarvo)
r+ tiedoston avaaminen sekä lukemista että kirjoittamista varten Komento palauttaa tiedoston tunnistimen fid, joka on kokonaisluku. Tällä on seuraava merkitys:
Jos tiedoston avaus onnistuu, niin fid on ei-negatiivinen kokonaisluku, jolla tiedosto tunnistetaan ohjelmassa. Tiedoston tunnistin fid ilmaisee, mihin tiedostoon kulloinenkin käsittely kohdistuu.
Jos tiedoston avaus ei onnistu, niin fid = –1. Lisäksi valinnaiseen toiseen ulostulomuuttujaan tulee virheilmoitus. Aina kun tiedosto avataan, on syytä testata tunnistimen fid arvo. ESIMERKKI. Seuraava ohjelmakoodi sisältää silmukan, jossa pysytään, kunnes lukukelpoisen tiedoston nimi on annettu. fid = -1;
MATLAB – Ohjelmointi
91
while fid < 0 tiedosto = input('Anna tiedosto: ','s'); [fid, ilmoitus] = fopen(tiedosto,'r'); if fid == -1 disp(ilmoitus); end; end;
Tallennetaan ohjelmakoodi tiedostoon avaus.m ja ajetaan se. Tulokseksi saadaan >> avaus Anna tiedosto: avaus No such file or directory Anna tiedosto: avaus.m
Komento tempdir palauttaa tilapäisten tiedostojen hakemiston nimen tempname palauttaa tilapäisen tiedoston nimen. Ohjelman mahdollisesti käyttämä tilapäistiedosto voidaan avata komennolla fid = fopen(tempname,’w’);
10.2 Tiedoston sulkeminen Tiedosto, jonka tunnistin on fid suljetaan funktiolla fclose: status = fclose(fid); Kaikki tiedostot1 suljetaan komennolla status = fclose(‘all’); Komennot palauttavat arvon –1, jos toiminnossa tapahtui virhe, muuten arvon 0. Tiedosto on aina hyvä sulkea itse, vaikka kaikki avoimet tiedostot suljetaankin automaattisesti, kun MATLAB lopetetaan. ESIMERKKI. (jatkoa) Suljetaan edellisen esimerkin tiedosto. >> fclose(fid) ans = 0
10.3 Binääritiedoston käsittely Binääritiedostossa tiedot on tallennettu tietokoneen sisäisessä esitysmuodossa tavujonoina. Binääritiedostoon kirjoitettu ja siitä luettu tieto siirtyy sellaisenaan ilman muunnoksia. Seuraavassa fid tarkoittaa aina tiedoston tunnistinta. 1
Paitsi standard input, output ja error.
MATLAB – Ohjelmointi
92
Binääritiedostoon kirjoitetaan komennolla määrä = fwrite(fid, A, tarkkuus), missä A on matriisi, jonka alkiot kirjoitetaan sarakkeittain tarkkuus on merkkijono, joka ilmoittaa luettavan tiedon formaatin. Seuraava taulukko sisältää joitain yleisesti käytettyjä tarkkuuksia. tarkkuus ’char’
Merkitys merkki (8 bittiä eli 1 tavu)
’short’
kokonaisluku (16 bittiä eli 2 tavua)
’int’
kokonaisluku (32 bittiä eli 4 tavua)
’long’
kokonaisluku (32 tai 64 bittiä)
’float’
desimaaliluku (32 bittiä eli 4 tavua)
’double’
desinaaliluku (64 bittiä eli 8 tavua)
Oletusarvoisesti luvut tallennetaan muodossa ’double’. määrä on valinnainen parametri, joka kertoo kirjoitettujen alkioiden määrän. Binääritiedostosta luetaan komennolla [A, määrä] = fread(fid, koko, tarkkuus), missä A on matriisi, johon data luetaan määrä on valinnainen parametri, joka kertoo luetun data määrän. koko on valinnainen parametri, joka ilmoittaa luettavan data määrän. Jos parametria ei ole, niin luetaan tiedoston loppuun asti. koko
Merkitys
n
Luetaan n alkiota sarakevektoriin.
inf
Luetaan tiedoston loppuun
[m, n]
Luetaan alkiot mn-matriisin sarakkeittain. Jos alkioita ei riittävästi asetetaan loput alkiot nolliksi.
tarkkuus on merkkijono, joka ilmoittaa luettavan tiedon formaatin kuten komennossa fwrite. ESIMERKKI. Luodaan satunnaismatriisi. >> A = rand(2,5) A = 0.9501 0.6068 0.2311 0.4860
0.8913 0.7621
0.4565 0.0185
0.8214 0.4447
MATLAB – Ohjelmointi
93
Avataan uusi binääritiedosto, tallennetaan matriisi A tiedostoon ja suljetaan tiedosto. >> tied = fopen('bindata.bin','w') tied = 4 >> count = fwrite(tied,A,'double') count = 10 >> status = fclose(tied) status = 0
Avataan edellä muodostettu binääritiedosto, luetaan data matriisiin B ja suljetaan tiedosto. >> id = fopen('bindata.bin','r') id = 3 >> B = fread(id,[2,5],'double') B = 0.9501 0.6068 0.8913 0.2311 0.4860 0.7621
0.4565 0.0185
0.8214 0.4447
>> status = fclose(id) status = 0
Tarkistetaan matriisien A ja B yhtäsuuruus >> A==B ans = 1 1
1 1
1 1
1 1
1 1
Siis matriisit A ja B ovat samoja. Avoinna olevaan tiedostoon liittyy käsittelykohta, joka kertoo mihin kohtaan seuraava luku- tai kirjoitusoperaatio suoritetaan. Käsittelykohta ilmoitetaan tavujen määränä tiedoston alusta. Jokainen luku- ja kirjoitusoperaatio siirtää käsittelykohtaa datan koon verran eteenpäin. Käsittelykohtaan liittyviä komentoja on esitetty seuraavassa taulukossa Komento feof(fid)
Toiminto Testaa tiedoston loppumista: arvo 1, jos tiedoston loppu, muuten arvo 0.
frewind(fid)
Käsittelykohta palautetaan tiedoston alkuun.
ftell(fid)
Antaa tiedoston käsittelykohdan.
Laajemmin käsittelykohdan voi määrätä komennolla status = fseek(fid, offset, origin),
MATLAB – Ohjelmointi
94
jossa offset ilmoittaa siirtymän origin on siirtymän lähtökohta, joka sallitut arvot ovat o ’bof’ tai -1: tiedoston alku (beginning of file) o ’cof’ tai 0: nykyinen käsittelykohta (current position of file) o ’eof’ tai 1: tiedoston loppu (end of file) status kertoo toiminnon onnistumisen: 0, jos toiminto onnistui, –1, jos epäonnistui
10.4 Tekstitiedoston käsittely Tekstitiedosto on jono merkkejä. Tekstitiedosto sisältää rivejä, jotka päättyvät rivivaihtomerkkiin. Tekstitiedostoon kirjoitetut merkit usein koodataan ASCII-koodilla, joten kirjoitettaessa tai luettaessa tehdään muunnoksia esitysmuodosta toiseen. Komennolla line = fgetl(fid) luetaan yksi rivi tiedostosta. Jos tiedosto on loppu, niin komento palauttaa arvon –1. Luettu rivi ei sisällä rivinvaihtomerkkiä. Komento fgets on muuten samanlainen, mutta luettu rivi sisältää rivinvaihtomerkin. Formatoitu lukeminen tekstitiedostosta suoritetaan komennolla [A, määrä] = fscanf(fid, format, koko) missä A on matriisi, johon data luetaan määrä on valinnainen parametri, joka kertoo luetun data määrän. format on muotoilu, joka on samanlainen kuin komennossa1 sscanf. koko on valinnainen parametri, joka ilmoittaa luettavan data määrän. Jos parametria ei ole, niin luetaan tiedoston loppuun asti. Muuttujan koko sallitut arvot ovat samat kuin komennossa fread tai sscanf. Formatoitu kirjoittaminen tiedostoon suoritetaan komennolla määrä = fprintf(fid, format, A,...), jossa A, … ovat matriiseja joiden sisältö kirjoitetaan. format on muotoilu, joka on samanlainen kuin komennossa2 sprintf. määrä ilmoittaa kirjoitettujen tavujen määrän. Jos fid jätetään pois, kirjoitetaan näytölle. ESIMERKKI. Seuraava skripti tulostaa käyttäjän antaman tiedoston näytölle lisäten siihen rivinumerot.
1 2
Katso luku 9.1.6 Katso luku 9.1.5
MATLAB – Ohjelmointi
95
fid = -1; while fid < 0 tiedosto = input('Anna tiedosto: ','s'); fid = fopen(tiedosto,'r'); end; i = 1; while feof(fid) == 0 rivi = fgetl(fid); fprintf('%3d: %s\n',i,rivi); i = i + 1; end; fclose(fid);
%rivivaihto merkki \n
Tallennetaan skripti tiedostoon file_nro.m ja ajetaan se. >> file_nro Anna tiedosto: file_nro Anna tiedosto: file_nro.m 1: fid = -1; 2: while fid < 0 3: tiedosto = input('Anna tiedosto: ','s'); 4: fid = fopen(tiedosto,'r'); 5: end; 6: 7: i = 1; 8: while feof(fid) == 0 9: rivi = fgetl(fid); 10: fprintf('%3d: %s\n',i,rivi); %rivivaihto merkki \n 11: i = i + 1; 12: end; 13: fclose(fid);
ESIMERKKI. Seuraava ohjelma, joka kopioi tekstitiedoston toiseksi tekstitiedostoksi. Ohjelmaa voidaan ajaa komennoilla kopio tai kopio('kopiotava_tied') kopio('kopiotava_tied','uusi_tied'). Argumenttien vaihteleva määrä on toteutettu luvussa 5.3 esitetyllä tekniikalla.
function kopio(varargin) n = nargin; if n>0 fid1=fopen(varargin{1},'r'); else fid1 = -1; end while fid1 < 0 tiedosto = input('Anna kopioitava tiedosto: ','s'); fid1 = fopen(tiedosto,'r'); end; if n==2 fid2=fopen(varargin{2},'w'); else
tai
MATLAB – Ohjelmointi end
96
fid2 = -1;
while fid2 < 0 tiedosto = input('Anna uusi tiedosto: ','s'); fid2 = fopen(tiedosto,'w'); end; while feof(fid1) == 0 rivi = fgetl(fid1); fprintf(fid2,'%s\n',rivi); end;
%rivivaihto merkki \n
fclose(fid1); fclose(fid2);
Seuraavassa on ohjelman ajoesimerkkejä. Kopioitava tiedosto on kopio.m. >> kopio Anna kopioitava tiedosto: kopio.m Anna uusi tiedosto: kopio1.m >> kopio('kopio.m') Anna uusi tiedosto: kopio2.m >> kopio('kopio.m','kopio3.m')
TEHTÄVIÄ 1. Muunna esimerkin kopio-ohjelmaa siten, että kopiossa pienet kirjaimet on muutettu isoiksi kirjaimiksi. 2. Muunna tehtävän 1 ohjelmaa siten, että kopioon tulee rivinumerot.
10.5 Komentoikkunan muuttujien tallentaminen Komento save tiedosto muuttuja1 muuttuja2 tallentaa komentoikkunan muuttujat muuttuja1, muuttuja2, … binäärimuodossa työhakemiston tiedostoon tiedosto. Komennon muoto save tiedosto tallentaa kaikki työpöydän muuttujat tiedostoon tiedosto. save tallentaa kaikki työpöydän muuttujat oletustiedostoon matlab.mat. Komennon muoto save tiedosto ’-append’ lisää muuttujat olemassa olevaan tiedostoon tiedosto. Komennolla load tiedosto muuttuja1 muuttuja2 … luetaan muuttujien arvot tiedostosta tiedosto. Komennon muoto
MATLAB – Ohjelmointi
97
load tiedosto lukee kaikki tiedoston tiedosto muuttujat. load lukee kaikki oletustiedoston matlab.mat muuttujat. ESIMERKKI. >> clear >> A = rand(2,2); B = rand(1,3); S = 'Merkkijono'; >> who Your variables are: A B S >> save Saving to: matlab.mat >> clear >> who >> load Loading from: matlab.mat >> who Your variables are: A B S >> save testi A B >> clear >> who >> load testi >> who Your variables are: A B
Työpöydällä annetut komennot voidaan tallentaa tekstitiedostoon diary käyttäen komentoa diary. Komentojen tallentaminen aloitetaan komennolla diary. Uusi diary-komento lopettaa talletamisen, seuraava diary-komento jatkaa tallennusta jne. Komennolla get(0,’Diary’) saadaan selville tallennuksen tilan (on/off). Komennot voidaan tallentaa tiettyyn tiedostoon komennolla diary tiedosto. Komento diary off lopettaa tallennuksen ja komento diary on jatkaa tallennusta aikaisempaan tiedostoon. Muodostunutta tekstitiedostoa voidaan tarkastella tekstinkäsittelyohjelmassa.
MATLAB – Ohjelmointi
98
ESIMERKKI. >> diary
% Aloitetaan tallennus
>> A = rand(2,2) A = 0.6154 0.9218 0.7919 0.7382 >> A^(-1) ans = -2.6776 2.8724
3.3435 -2.2322
>> get(0,'Diary') ans = on
% Tarkistetaan tila
>> diary
% Lopetetaan tallennus
>> get(0,'Diary') ans = off >> det(A) ans = -0.2757
% Tämä komento ei tallennu
>> diary
% Jatketaan tallenusta
>> svd(A) ans = 1.5390 0.1791 >> diary
% Lopetetaan tallennus
Voit tarkastella tiedostoa diary aukaisemalla sen MATLABin editoriin kaksoisklikkaamalla tai aukaisemalla sen jollain tekstinkäsittelyohjelmalla.
TEHTÄVIÄ 1. Kokeile diary-komentoa. Tallenna komennot nimeämääsi tiedostoon. Avaa muodostunut tiedosto tekstinkäsittelyohjelmalla.
10.6 Excel-tiedostojen käsittely Matriisi A voidaan tallentaa Excel-taulukkona työhakemiston tiedostoon tiedosto komennolla xlswrite(tiedosto, A) Komennon muoto xlswrite(tiedosto, A, alue)
MATLAB – Ohjelmointi
99
tallentaa matriisin A osan Exel-taulukon alueeseen alue. Jos Excel-taulukko on olemassa, niin komento jättää ne solut ennalleen, joiden kohdalle ei kirjoiteta mitään. Komento A = xlsread(tiedosto) lukee Excel-tiedoston tiedosto ja tallentaa numeerisen datan matriisiin A. Komennon muoto A = xlsread(tiedosto, alue) lukee alueen alue määräämän osan matriisiin A. Yllä • tiedosto annetaan merkkijonona • alue annetaan merkkijonona Excel-muodossa, esim. 'B2:D5'. Lukukomennon muoto [A, txt, raw] = xlsread(...) lukee • numeerisen datan matriisiin A • tekstikentät solutaulukkoon txt • sekä numeerisen datan että tekstikentät solutaulukkoon raw. HUOMAUTUS. Luettavan Excel-taulukon on hyvä olla MATLABin Nykyisessä hakemistossa. Tällöin tiedostonimeen ei tarvitse laittaa hakemistopolkua. Tiedosto voidaan siirtää Nykyiseen hakemistoon vetämällä se hiirellä MATLABin Nykyinen hakemisto -ikkunaan (Current Folder). Vastaavasti tiedosto voidaan siirtää Nykyisestä hakemistosta muualla vetämällä se hiirellä MATLABin Nykyinen hakemisto -ikkunasta haluttuun paikkaan. Jos Ctrl-näppäin on painettuna luodaan kopio. ESIMERKKI 1. Kirjoittaminen Määritellään matriisi >> A=randi(10,3,5) A = 4 1 5 7 8 10 2 6 7
Komento
7 9 9
>> xlswrite('excel1',A)
tekee Excel-taulukon
6 2 3
MATLAB – Ohjelmointi
100
Komento >> xlswrite('excel2',A,'B2:C3')
tekee Excel-taulukon
ESIMERKKI 2. Lukeminen Työhakemiston tiedostossa ExcelRead.xlsx on seuraava Excel-taulukko
Luetaan taulukon numeeriset arvo matriisiin A: >> A=xlsread('ExcelRead.xlsx') A = 0.3000 0.0480 1.6370 0.7500 0.0480 4.2700 1.1000 0.0480 6.4100 2.5000 0.4800 12.7200 3.0000 0.4800 15.2800
0.0347 0.1054 0.1482 0.2744 0.3256
Luetaan taulukon ensimmäisen sarakkeen numeeriset arvo vektoriin x: >> x=xlsread('ExcelRead.xlsx','A1:A6') x = 0.3000
MATLAB – Ohjelmointi
101
0.7500 1.1000 2.5000 3.0000
Kokeillaan vielä monipuolisempaan lukemista: >> [A,txt,raw]=xlsread('ExcelRead.xlsx') A =
0.3000 0.7500 1.1000 2.5000 3.0000
0.0480 0.0480 0.0480 0.4800 0.4800
1.6370 4.2700 6.4100 12.7200 15.2800
0.0347 0.1054 0.1482 0.2744 0.3256
txt = 'I / mA'
'ΔI / mA'
'U / V'
raw = 'I / mA' [0.3000] [0.7500] [1.1000] [2.5000] [ 3]
'ΔI / mA' [ 0.0480] [ 0.0480] [ 0.0480] [ 0.4800] [ 0.4800]
'U / V' [ 1.6370] [ 4.2700] [ 6.4100] [12.7200] [15.2800]
'ΔU / V' 'ΔU / V' [0.0347] [0.1054] [0.1482] [0.2744] [0.3256]
Muuttujat txt ja raw ovat solutaulukkoja1. Seuraavassa on tulostettu niiden joitain alkioita: >> txt{3} ans = U / V >> raw{2,3} ans = 1.6370
MATLABin Nykyisessä hakemistossa oleva Excel-taulukko voidaan lukea MATLABiin myös kaksoisklikkaamalla sitä MATLABin Nykyinen hakemisto -ikkunassa (Current Folder). Tällöin aukeaa tuonti-ikkuna, jota käyttäen halutut tiedot voidaan lukea MATLABiin. Luettavan datan muoto ilmoitetaan ikkunan yläosassa. Ikkunassa voi hiirellä valita luettavan datan. Luettavalle datalle annetaan nimi data-alueen yläpuolella olevaan kohtaan. ESIMERKKI 3. Luetaan osa edellisen esimerkin Excel-taulukosta ExcelRead.xlsx. Kuvassa on tehty valinnat Numeric Matrix, osoitettu luettava data hiirellä ja annettu matriisille nimi Aosa.
1
Katso luku 9.2.
MATLAB – Ohjelmointi
102
TEHTÄVIÄ 1. Muodosta MATLABilla satunnaisluvuista koostuva 45-matriisi. Tallenna matriisi Exceltaulukoksi ja avaa se Excelillä. Huom. Voit siirtää Excel-taulukon haluamaasi paikkaan hiirellä vetämällä. 2. Tee Excelillä seuraava taulukko
Tallenna taulukko tiedostoon ja siirrä se MATLABin Nykyiseen hakemistoon. Lue sen numeeriset arvot MATLABiin seuraavilla tavoilla: a) MATLABin komennolla. b) Kaksoisklikkaamalla tiedostoa Nykyinen hakemisto -ikkunassa. Anna luetulle datalle nimi AA ja tulosta se näytölle MATLABissa.