lefse tkp4100 forord innledning - folk.ntnu.nofolk.ntnu.no/audunfor/4....

65
1 Lefse_TKP4100 Dette er en forkorting av den opprinnelige Lefse fra Jan Aarseth og angir pensum i Matlab i TKP4100. Det som er skrevet i en annen farge enn svart er ikke pensum men likevel beholdt da det kan være av interesse. Det henvises også til eksempler lagt ut på it’s learning. IKP, 14 april 2009, Hallvard Svendsen FORORD Denne lefsa er ikke ment som en lærebok, men gir en kortfattet innføring i de mest brukte kommandoer og konstruksjoner i Matlabdelen av faget TKT4140, basert på eksempler. Lefsa er oppdatert til versjon 7.7 av Matlab, men de fleste eksemplene kan kjøres med eldre versjoner. Storparten av programmene i denne lefsa ligger i mappa "Mlefse" under mappa "Disketten" som finnes på fagets hjemmeside. Konstruksjonsteknikk, NTNU, januar 2009 , Jan B. Aarseth INNLEDNING MATLAB (MATrix LABoratory) er et interaktiv program som er laget spesielt for tekniske og vitenskapelige beregninger. Den første utgava ble skrevet av Cleve Moler i 1977, hovedsakelig for undervisningsformål. I 1984 dannet Cleve Moler og Jack Little selskapet MathWorks som ble starten på Matlab som et kommersielt program. Programmet har siden utviklet seg sterkt med blant annet et eget programmeringspråk, sterk grafikk og objektprogrammering. I tillegg fåes spesialskrevne moduler innen en rekke fagområder (Toolboxes) Det finnes mye litteratur om Matlab og her skal vi bare nevne noen få. [1] Bård T. Fallan & Steinar Line : Introduksjon til Matlab. Tilleggshefte til Innføring i Informasjonsteknologi Tapir, 2. utgave 2003 [2] L.F Shampine et al. : Solving ODEs with MATLAB Cambridge Univ. Press 2003 [3] D. Hanselman et al. : Mastering Matlab 7 Pearson/Prentice Hall 2005 [4] Higham & Higham : Matlab Guide SIAM, 2. utgave 2005 [5] S. J. Chapman : MATLAB Programming for Engineers Thomson, 4. utgave 2008 [6] Cleve Moler : Numerical computing with MATLAB Kan lastes ned fra www.mathworks.com/moler/ Referansene [2], [4], [5] og [6] inneholder Matlabprogrammer som kan lastes ned. For liste over bøker som bruker/omhandler Matlab : www.mathworks.com/support/books

Upload: others

Post on 01-Nov-2019

2 views

Category:

Documents


0 download

TRANSCRIPT

1

Lefse_TKP4100 Dette er en forkorting av den opprinnelige Lefse fra Jan Aarseth og angir pensum i Matlab i TKP4100. Det som er skrevet i en annen farge enn svart er ikke pensum men likevel beholdt da det kan være av interesse. Det henvises også til eksempler lagt ut på it’s learning. IKP, 14 april 2009, Hallvard Svendsen FORORD Denne lefsa er ikke ment som en lærebok, men gir en kortfattet innføring i de mest brukte kommandoer og konstruksjoner i Matlabdelen av faget TKT4140, basert på eksempler. Lefsa er oppdatert til versjon 7.7 av Matlab, men de fleste eksemplene kan kjøres med eldre versjoner. Storparten av programmene i denne lefsa ligger i mappa "Mlefse" under mappa "Disketten" som finnes på fagets hjemmeside. Konstruksjonsteknikk, NTNU, januar 2009 , Jan B. Aarseth INNLEDNING MATLAB (MATrix LABoratory) er et interaktiv program som er laget spesielt for tekniske og vitenskapelige beregninger. Den første utgava ble skrevet av Cleve Moler i 1977, hovedsakelig for undervisningsformål. I 1984 dannet Cleve Moler og Jack Little selskapet MathWorks som ble starten på Matlab som et kommersielt program. Programmet har siden utviklet seg sterkt med blant annet et eget programmeringspråk, sterk grafikk og objektprogrammering. I tillegg fåes spesialskrevne moduler innen en rekke fagområder (Toolboxes) Det finnes mye litteratur om Matlab og her skal vi bare nevne noen få. [1] Bård T. Fallan & Steinar Line : Introduksjon til Matlab. Tilleggshefte til Innføring i Informasjonsteknologi Tapir, 2. utgave 2003 [2] L.F Shampine et al. : Solving ODEs with MATLAB Cambridge Univ. Press 2003 [3] D. Hanselman et al. : Mastering Matlab 7 Pearson/Prentice Hall 2005 [4] Higham & Higham : Matlab Guide SIAM, 2. utgave 2005 [5] S. J. Chapman : MATLAB Programming for Engineers Thomson, 4. utgave 2008 [6] Cleve Moler : Numerical computing with MATLAB Kan lastes ned fra www.mathworks.com/moler/ Referansene [2], [4], [5] og [6] inneholder Matlabprogrammer som kan lastes ned. For liste over bøker som bruker/omhandler Matlab : www.mathworks.com/support/books

2

HJELPESYSTEM Det er etter hvert blitt et omfattende hjelpesystem i Matlab. Skriv doc i kommandovinduet for å starte hjelpesystemet. (Eventuelt trykk på ? eller help i menylinja). Legg merke til at det finnes en rekke manualer som også kan skrives ut om nødvendig. Legg spesielt merke til Getting started with Matlab som er en ren lærebok. Dersom du vet direkte hva du ønsker, kan du skrive doc etterfulgt av ønsket, f.eks. doc sin dersom du ønsker detaljer om sinusfunksjonen. VARIABLE Navn på en variabel må begynne med en bokstav, fulgt av en vilkårlig rekke av bokstaver, tall og understrekningsymbolet (_). Mellomrom er ikke tillatt. Bare de 63 første tegnene er signifikante. (Burde være tilstrekkelig). Merk at Matlab skiller mellom store og små bokstaver slik at f. eks. Pi og pi er to forskjellige variabler. Spesielle symboler [ ] Ved definisjon av matriser ( ) Indekser ' ' (To apostrofer). Markerer en streng , (Komma): Skiller indekser eller matriseelementer ; (Semikolon): 1. Hindrer utskrift i kommandovinduet 2 . Skiller linjer i matriser 3. Skiller programsetninger på en linje % Markerer begynnelsen på en kommentar-setning eller format-streng : Kolonoperator. Liste og matrise-generator + Addisjon – Subtraksjon * Multiplikasjon .* Elementvis multiplikasjon / (Høyre) divisjon ./ Elementvis (høyre) divisjon \ Venstre divisjon ^ Eksponentsiering .^ Elementvis eksponentsiering ' (Enkel apostrof) : Transponering ... Tre prikker etter hverandre angir fortsettelse på neste linje. Noen predefinerte variable pi 3.141592... i Imaginær enhet, 1− j Imaginær enhet, 1− eps Relativ nøyaktighet, 52 162 2.22 10− −≈ ⋅ realmin Minste flyttall, 1022 3082 2.23 10− −≈ ⋅ realmax Største flyttall. 1023 308(2 eps) 2 1.8 10− ⋅ ≈ ⋅

3

Inf Uendelig, eks 1/0 NaN Ikke-et-tall, eks 0/0 Disse variable er ikke beskyttet og kan redefineres. Får tilbake sine opprinnelige verdier ved å bruke clear. Eksempel : » pi

ans =

3.1416

» pi = 3.0

pi =

3

» clear pi

» pi

ans =

3.1416

Det er normalt ikke noen god ide å redefinere pi, mens i og j derimot brukes ofte som indekser slik at det kan bli nødvendig å omdefinere disse. Generelt bør en forsøke å unngå redefinering. Beskytta variable (Keywords) Disse finnes ved å bruke kommandoen iskeyword. >> iskeyword 'classdef' 'parfor' 'continue' 'persistent' 'else' 'return' 'elseif' 'spmd' 'end' 'switch' 'for' 'try' 'function' 'while' 'global' 'if' 'otherwise' >> FILNAVN (PROGRAMNAVN) Dersom du f.eks. lagrer en fil med navnet MinFil under Windows, blir navnet internt lagret som MINFIL selv om det ikke vises. Og dette gjelder uansett skrivemåten: mInfIL -> MINFIL. Matlab brukte tidligere samme konvensjon, men fra og med versjon 7.0 er filnavn og programnavn som lagres via Matlab avhengig av skrivemåten : Skiller mellom store og små bokstaver. Konvensjonen for filnavn(programnavn) følger nå reglene for variable : Filnavn må begynne med en bokstav, fulgt av en vilkårlig rekke av bokstaver, tall og understrekningsymbolet (_). Mellomrom er ikke tillatt. Bare de 63 første tegnene er signifikante. (Windows tillater 256).

4

Det enkleste er da at bokstavene i filnavnet velges små. I noen tilfeller kan det være lurt å starte filnavnet med en stor bokstav for å hindre forveksling med en av Matlabs egne filer (kommandoer) da disse alltid skrives med små bokstaver. Unngå de norske bokstavene æ, ø og å selv om de er tillatte i de nyeste versjonene av Matlab. FILKOMMANDOER Når vi er i kommando-vinduet, finnes det en rekke kommandoer vi kan bruke til å gi liste over filer, hoppe fra en mappe til en annen osv. Alle disse operasjonene kan selvfølgelig gjøres i Windows, men i enkelte tilfeller er det raskere å utføre dem som kommandoer istedenfor å bruke musa. Mange av disse kommandoene har ekvivalente kommandoer hentet fra det underliggende operativsystemet. Ved å starte kommandolinja med et utropstegn, antar Matlab at det som følger er en operativsystemkommando. Brukergrensesnittet i de siste versjonene av Matlab er blitt forbedret slik av mange av kommandoene ikke er nødvendige lenger. Tar likevel med noen få. (Skriv doc general for liste over alle fil-kommandoer) Liste over noen fil-kommandoer : what Gir en liste over M-filer i den mappa du er i. which Finner en mappe som inneholder en M-fil som ligger på søkestien. lookfor Finner alle funksjoner i alle mapper på søkestien som kan ha forbindelse med et søkeord. dir Gir liste over filer og mapper i den mappa du er i. cd Brukes til å hoppe fra en mappe til en annen. copyfile Kopierer innholdet av en fil til en annen. Dersom den andre fila ikke eksistere, blir den opprettet. Flytter også filer fra en mappe til en annen. movefile Flytter eller døper om en fil. delete Sletter filer. mkdir Lag en ny mappe. Merk : En prikk er en forkortelse for navnet til den mappa du er i, mens to prikker er en forkortelse for den overliggende mappa (parent directory). Dersom du skriver cd .. hopper du derfor opp til den overliggende mappa. Vi nevnte ovenfor at dersom du setter et utropstegn foran en kommando, oppfattes dette som kall av en systemkommando. Se forskjellen på dir og !dir. Den første er en Matlab-kommando mens den siste er en Windows-kommando. Du kan døpe om en fil med navn minfil.m til dinfil.m ved kommandoen movefile minfil.m dinfil.m. Dette kan du også gjøre ved å bruke Windows-kommandoen ren: !ren minfil.m dinfil.m . Også : !copy fila.m filb.m istedenfor copyfile fila.m filb.m

Dersom du er interessert i andre Windows-kommandoer : Trykk F1 på skrivebordet og skriv command-line-reference i søkeboksen.

5

RASKT BLIKK PÅ MATLAB Dette avsnittet gir en rask gjennomgang av Matlab hovedsakelig brukt som kalkulator. Når du starter Matlab, kommer du inn i kommandovinduet. Normalt vil en rekke andre vinduer også være åpne. Tegnet >> er en kommandoprompt og du kan begynne å gi kommandoer. Med å utføre en kommando, menes å skrive noe etter >> og trykke på enter-knappen. Utfør 1.23456 + 2.3 . Skjermen viser da følgende : >> 1.23456 + 2.3

ans =

3.5346

»

Vi har fått svaret med 4 desimaler. Svaret er lagret i en variabel ans som er forhåndsdefinert i Matlab. Når du bruker Matlab, blir det avsatt et område i RAM som kalles arbeidsområdet (workspace). For å finne ut hva som finnes i arbeidsområdet, kan du utføre kommandoen whos som gir dette resultatet : Name Size Bytes Class ans 1x1 8 double array

Grand total is 1 elements using 8 bytes

(Dersom du har vinduet Workspace åpent, vil du se dette direkte) Vi ser at det er avsatt plass til en variabel med navn ans med plassbehov 8 bytes. Merk at variable i Matlab oppfattes som matriser slik at en skalar er en 1 1-matrise.× Innholdet i arbeidsområdet fjernes med kommandoen clear. En enkelt variabel x fjernes ved clear x. Eks : Utfør a = 1. Utfør deretter kommandoene whos, clear a og whos tilslutt for å kontrollere innholdet i arbeidsområdet. Anta at vi ønsker flere desimaler. Utfør doc format. La oss skrive ut pi med forskjellige format. >> format short

>> pi

ans =

3.1416

>> format long

>> pi

ans =

3.141592653589793

>> format short e

>> pi

ans = 3.1416e+000

6

Dersom du ikke ber om noe annet, regner Matlab med 15-16 siffers nøyaktighet uavhengig av hvilket format du velger. Prøv selv de andre formatene. Merk at disse formatene gjelder for utskrift i kommando-vinduet. Vi har mer fleksible muligheter som vi skal bruke senere (Se avsnittet Formattert uskrift). Vi går tilbake til 4 desimaler ved å utføre format som er en forkortelse for format short.

Når du opererer i kommandovinduet, har du adgang til en primitiv editor. (doc cedit gir en liste over alle mulighetene). Merk at tegnet ^ står for Ctrl-tasten). De fleste kommandoene er knyttet til taster på tastaturet og er derfor innlysende. Dersom du vil ha tilbake en kommando som du har brukt tidligere, kan du trykke på ↑ - tasten. (Trykk flere ganger dersom du ikke finner den du ønsker med en gang. Dersom dette ikke virker, må du først utføre kommandoen cedit on). Dessuten kan du bruke de vanlige Windows-kommandoene Ctrl-C (kopier), Ctrl-V (lim inn) og Ctrl-X (slett). Du kan blanke skjermen ved å utføre kommandoen clc. Vi kan selvfølgelig knytte navn til de enkelte uttrykkene. >> a = sin(1)

a = 0.8415

>> b = cos(1)

b = 0.5403

>> c = a + b

c =

1.3818

Vi kan også skrive dette på en linje ved : a = sin(1) ; b = cos(1); c ;

Legg merke til at nå får vi ingen utskrift. Semikolon brukes til å hindre utskrift. Dette er viktig for å hindre utskrift av mellomregning vi ikke er interessert i. Dessuten brukes semikolon til å skille uttrykk på samme linje. Strenger Strenger er en samling med tegn mellom to apostrofer. Eks. : Utfør str = 'Dette er en streng' Strengvariable brukes helst ved programmering og ofte ved innlesning, utskrift og plotting. Vi kan sette sammen strenger ved kommandoen strcat. Eksempel : str1 = 'Dette er' og str2 = ' en streng'. Kommandoen strcat(str1,str2) gir Dette er en streng.

7

Du kan transformere strengen til et tall ved x = double(str) >> double('ABC')

ans =

65 66 67

>>

Hvert tegn får nå den verdien den har i den såkalte ASCII-tabellen. Går tilbake til en streng ved str = char(x). Utfør a = '3.141592'. Dette er en streng , ikke en tilnærmelse til pi. a kan konverteres til et tall >> eval(a)

ans =

3.1416

>>

Kontroller dette ved å utføre whos.Det finnes mange flere strengfunksjoner enn dem vi har brukt ovenfor. Skriv doc og og du får opp Help Navigator. Skriv string i Index-boksen. Komplekse tall Matlab opererer direkte på komplekse tall uten at det er nødvendig å erklære dem som komplekse slik som du f. eks. må gjøre i Fortran. Komplekse tall kan dannes på en rekke måter. i og j brukes som den komplekse enheten 1− . Eksempler : >> z1 = 2 + i*3; z2 = 3 -i*4;

>> z1

z1 =

2.0000 + 3.0000i

>> z2

z2 =

3.0000 - 4.0000i

>>

Kan også skrive : >> z1 = 2 + 3i ; z2 = 3 - 4j;

>> z1

z1 =

2.0000 + 3.0000i

>> z2

z2 =

3.0000 - 4.0000i

Når du utelater multiplikasjonstegnet *, må i eller j settes etter tallet: i4 vil f. eks. ellers tolkes som en variabel. Kan også bruke kommandoen complex : >> z1 = complex(2,3)

z1 = 2.0000 + 3.0000i

8

Noen beregninger :

>> z1 + z2

ans =

5.0000 - 1.0000i

>> z1*z2

ans =

18.0000 + 1.0000i

>> z1/z2

ans =

-0.2400 + 0.6800i

>> sqrt(z1)

ans =

1.6741 + 0.8960i

>>

>> abs(z1)

ans =

3.6056

>>

Noen spesielle komplekse funksjoner : (Skriv doc elfun) abs absolutt verdi

angle fasevinkel

complex danner komplekse tall

conj kompleks konjungert

imag imaginærdel

real realdel

Vi har de vanlige sammenhengene mellom den kartesiske skrivemåten og den polare :

2 2 , arctan( / )

cos , sin

iz x i y r e

r x y y x

x r y r

θ

θθ θ

= + ⋅ = ⋅

= + == ⋅ = ⋅

Eksempel : >> z = 3 - 4i

z = 3.0000 - 4.0000i

>> r = abs(z)

r = 5

>> theta = atan(imag(z)/real(z))

theta = -0.9273

>> x = r*cos(theta)

x = 3.0000

>> y = r*sin(theta)

y = -4.0000

9

Bruk av innebygde matematiske funksjoner. Du finner en liste over de vanlige matematiske funksjonene ved kommandoen doc elfun. Prøv endel av funksjonene, også de mer ukjente. Bruk doc for å finne den nøyaktige syntaksen. >> exp(1) ans =

2.7183

Du kan også bruke utskriftskommandoen disp : >> disp(sin(pi/2))

1

>> tan(pi/2)

ans =

1.6331e+016

>> atan(1)

ans =

0.7854

Det er lurt å bruke atan2 istedenfor atan når du har gitt et uttrykk på formen arctan(y/x) fordi atan2 finner den rette kvadranten. >> y = 1; x = -1;

>> atan(y/x)

ans =

-0.7854

>> atan2(y,x)

ans =

2.3562

Som nevnt tidligere, operer Matlab direkte på komplekse tall. Noen funksjoner som realpow, reallog, realsqrt og nthroot er begrenset til reelle tall. >> sqrt(-1)

ans = 0 + 1.0000i

>> realsqrt(-1)

??? Error using ==> realsqrt

Realsqrt produced complex result.

Gjør også oppmerksom på funksjonene exp(x)-1 og log1p = log(1+x) for verdier av x nær 0 >> format long

>> log(1 + 1.0e-10)

ans = 1.000000082690371e-010

>> log1p(1.0e-10)

ans = 9.999999999500001e-011

10

I mange tilfeller har vi bruk for raskt å plotte funksjoner. Dette gjøres greit med kommandoene ezplot og fplot. (Mer detaljer med doc fplot og doc ezplot). ezplot direkte plotter funksjonen i intervallet 2 2xπ π− ≤ ≤ . Utfør f.eks. >> ezplot(@sin) (eller ezplot('sin(x)') ) >> grid

>>

Det blir nå åpnet et eget figur-vindu. Null-punkter er lettere å plukke ut ved å legge på et nett med kommandoen grid. Eksempel på mer avansert plotting med plot finnes i avsnittet Plotting. La oss se på mer "eksotiske" funksjoner. Disse finnes med doc specfun . Vi ønsker å plotte funksjonen 0( )J x for 0 10x≤ ≤ der 0 ( )J x er en Besselfunksjon av 1. orden og nullte slag. Fra lista finner vi besselj som ifølge beskrivelsen er en Besselfunksjon av første slag. (Dersom du på forhånd visste at dette var en Besselfunksjon, kan du skrive doc bessel ). For å få flere detaljer, skriver vi doc besselj. Ifølge beskrivelsen får vi en Besselfunksjon av 1. slag og orden ν med argument x ved å bruke besselj(nu,x).

Vi utfører derfor følgende: >> fplot('besselj(0,x)', [0 10]) >> grid on

>>

Fra figuren finner vi nullpunkter rundt x = 2.4 , 5.5 og 8.6.

0 1 2 3 4 5 6 7 8 9 10-0.5

0

0.5

1

Vi vil nå bestemme disse nullpunktene nøyaktig ved å bruke Matlabfunksjonen fzero. (doc fzero). Det første nullpunktet finner vi ved å utføre: >> fzero('besselj(0,x)',2.4)

ans =

2.4048

>>

(Dersom vi bruker format long får vi 2.40482555769577) Finn også de to andre nullpunktene. (Mer bruk av fzero er gitt side 44).

11

Når vi først er i gang, kan vi også beregne noen bestemte integral. La oss integrere sin(x) fra 0 til 90º der svaret er 1 . Skriv doc og og du får opp Help Navigator. Skriv integration i Index-boksen. Fra lista velger vi quad. Utfra beskrivelsen, utfører vi : >> quad(@sin,0,pi/2)

ans =

1.0000

>>

Kan også skrive quad('sin',0,pi/2

Bruk av editor ved programmering. Velg file i menyen, deretter new og velg M-file. Du er nå klar til å skrive et program med den innebygde editoren. Skriv inn programmet som er gitt nedenfor : %=== Program poly2 ===

% Finner de reelle røttene av ligningen Ax^2+Bx + C

a = input('Les koeffisient A: ');

b = input('Les koeffisient B: ');

c = input('Les koeffisient C: ');

d = b^2 - 4*a*c;

if d > 0 % To reelle røtter

x1 = (-b + sqrt(d))/(2*a);

x2 = (-b - sqrt(d))/(2*a);

fprintf('x1 = %f\n',x1)

fprintf('x2 = %f\n',x2)

elseif d == 0 % En reell rot

x1 = -b/(2*a);

fprintf('x1 = x2 = %f\n',x1)

else % Imaginære røtter

fprintf(' === Ingen reelle røtter ===\n')

end

Når programmet er skrevet, må det lagres. Velg Save As på fil-menyen og lagr det under navnet poly2. Matlab legger automatisk til endelsen m. Etter at programmet er lagret, kan det eksekveres i kommandovinduet ved å utføre poly2. Du kan teste det på følgende eksempler :

2

2

2

5 6 0

4 4 0

2 5 0

x x

x x

x x

+ + =+ + =+ + =

12

Litt om feilfinning i program Svært ofte vil det være feil i et program første gangen det brukes. Feilskrift er typisk. Dette fører til syntaksfeil som blir oppdaget av Matlab. Feil bruk av språket generelt fører også til syntaksfeil. I begynnelsen kan det ofte være vanskelig å finne ut hva Matlab mener når den påpeker feil, men det kommer med litt øvelse. Når syntaksen er i orden, kommer de logiske feilene : Programmet gjør ikke det du ønsker. I praksis betyr dette at du må be programmet skrive ut mellomregning som du normalt ikke er interessert i. I programmet ovenfor kan du f.eks. skrive ut størrelsen d ved å fjerne semikolonet etter den linja der d er definert. Husk at du kan finne slutt-verdiene av de størrelsene som er beregnet i programmet ved å utføre de aktuelle variable i kommandovinduet. I noen tilfeller ønsker du å teste ut en del av programmet fordi du vet at resten ikke funker. En vanlig teknikk er å sette kommentartegn (%) foran de linjene du ikke vil ha utført. (Velg "Text" fra menyen) Vanligvis er programmene små, slik at du greier deg med prosedyrene ovenfor. Ved mer kompliserte program, kan du bruke Matlabs "Debugger" som du finner informasjon om ved å utføre doc og skriv debug i Index-boksen i Help Navigator. Merk også Debug i Matlabs menylinje. Det er også mulig å få tips til å forbedre programmet når du er inne i editoren. Velg Tools i menylinja og velg deretter M-Lint og Show M-lint Report.

13

MATRISER OG VEKTORER Skriver inn en 3 3× matrise. Semikolon angir slutt på hver matriselinje. » A = [1 2 3; 4 5 6; 7 8 9] A =

1 2 3

4 5 6

7 8 9 Linjevektor : » a = [10 11 12] a =

10 11 12

Kolonnevektor : » b = [13; 14 ;15] b =

13

14

15

Får en kolonnevektor ved å transponere en linjevektor : » a'

ans =

10

11

12

Får en linjevektor ved å transponere en kolonnevektor : » b'

ans =

13 14 15

Ved å transponere A bytter vi om linjer og kolonner » A = A'

A =

1 4 7

2 5 8

3 6 9

14

Velger ut den første kolonna i A : » a = A(:,1)

a =

1

2

3

Velger ut den første linja i A » b = A(1,:)

b =

1 4 7

Velger det siste elementet i den første kolonna i A: » A(end,1)

ans =

3

Velger det siste elementet i den tredje kolonna i A: » A(end,3)

ans =

9

» b = b'

b =

1

4

7

Lager en ny B-matrise ved å sette sammen to kolonnevektorer : » B = [a b]

B =

1 1

2 4

3 7

Lager en ny C matrise ved å sette sammen de to matrisene A og B » C = [A B]

C =

1 4 7 1 1

2 5 8 2 4

3 6 9 3 7

Finner antall elementer i vektoren b: » length(b)

ans = 3

15

Finner dimensjonene av matrisa C: » size(C)

ans =

3 5

Lager en linjevektor av elementene 2,3,4 i første linje av C: » d = C(1,2:4)

d = 4 7 1

Lager en kolonne-vektor av elementene 1,2 i første kolonne av C: » d = C(1:2,1)

d =

1

2

Setter d lik siste kolonne i C: » d = C(:,3)

d =

7

8

9

Adderer et element til begynnelsen og slutten av d . Merk at Matlab øker dimensjonene dynamisk: » d = [0;d;0]

d =

0

7

8

9

0

Merk at vi kan addere en skalar direkte til en vektor selv om dette strengt tatt ikke er en tillatt vektor-operasjon » b = d +1

b =

1

8

9

10

1

16

Vi har også tomme matriser. Disse markeres med [] (to hakeparenteser). Kan f.eks brukes til å fjerne en kolonne eller linje fra en matrise. »A A =

1 4 7

2 5 8

3 6 9

» A(:,3) = []

A =

1 4

2 5

3 6

AUTOMATISK GENERERING AV VEKTORER OG MATRISER. Kan bruke kolonnotasjon i:j:k der i = startverdi, j = inkrement og k = sluttverdi. Dersom inkrementet utelates, antas inkrement = 1 Nå brukes vanlige parenteser eller kan helt utelate parenteser for linjevektorer . » a = (1:5)

a =

1 2 3 4 5

» a = (1 :0.5 : 3)

a =

1.0000 1.5000 2.0000 2.5000 3.0000

» a = 1:0.1:1.5

a =

1.0000 1.1000 1.2000 1.3000 1.4000 1.5000

» b = 7:-1:1

b =

7 6 5 4 3 2 1

Får kolonnevektorer ved å transponere. Kan også bruke linspace: » d = linspace(1,2,4)

d =

1.0000 1.3333 1.6667 2.0000

Syntaks : linspace (venstre endepunkt, høyre endepunkt, antall punkt) Dette betyr at linspace genererer n ekvidistante punkt der d(1) = a og d(n) = b . Dersom antall punkt utelates, velges 100. (Se også logspace).

17

Her er et eksempel på bruk av indeksvektor. (Merk at a blir en kolonnevektor fordi vi har brukt a = zeros(5,1) ovenfor). Om indeksvektoren er kolonne- eller linjevektor betyr ikke noe i dette tilfellet. » j = 1:5

j =

1 2 3 4 5

» a(j) = j*0.1

a =

0.1000

0.2000

0.3000

0.4000

0.5000

Indeksvektorer brukes også til såkalt indirekte addressering. »a = a';

» v(1) = 1; v(2) = 5; v(3) = 2;

» v

v = 1 5 2

» b = a(v)

b = 0.1000 0.5000 0.2000

Standardmatriser og vektorer De følgende kommandoene brukes ofte til å initialisere vektorer og matriser » a = zeros(5,1)

a =

0

0

0

0

0

» b = ones(1,5) b =

1 1 1 1 1

» D = eye(3)

D =

1 0 0

0 1 0

0 0 1

18

Funksjonen rand lager matriser(vektorer) av vilkårlige tall uniformt fordelt mellom 0 og 1. >> rand(3)

ans =

0.8147 0.9134 0.2785

0.9058 0.6324 0.5469

0.1270 0.0975 0.9575

>> rand(1,5)

ans =

0.9649 0.1576 0.9706 0.9572 0.4854

>> a=1:3

a =

1 2 3

>> diag(a)

ans =

1 0 0

0 2 0

0 0 3

>>

Elementvise operasjoner Vi ønsker ofte å beregne utrykk som 1 1 2 2[ ] n nx y x y x y⋅ =x y og

1 1 2 2/ [ / / / ]n nx y x y x y=x y o.l.. direkte. Dette gjøres ved å bruke elementvise operatorer . * , . / og .^ >> x = 1:5

x = 1 2 3 4 5

>> y = x.*x

y = 1 4 9 16 25

>> y./x

ans = 1 2 3 4 5

>> z = y.^2

z = 1 16 81 256 625

>> x.^3./y

ans = 1 2 3 4 5

Et typisk eksempel: Skal plotte funksjonen sin(12 )x xy e ⋅=

x = linspace(0,2*pi);

y = exp(sqrt(x).*sin(12*x));

plot(x,y);

(Se figur side 62 sammen med bruk av fplot)

19

Her er flere måter å beregne skalarproduktet på : >> sum(x.*x)

ans =

55

>> x*x'

ans =

55

>> dot(x,x)

ans =

55

>> Sortering >> c=[2 3 6 4 5 1]

c =

2 3 6 4 5 1

>> cs = sort(c)

cs =

1 2 3 4 5 6

Funksjonen sort sorterer i stigende størrelse. Ved bruk av parameteren descend går sorteringen i motsatt retning. >> cs = sort(c,'descend') cs =

6 5 4 3 2 1

Skriv doc sort får flere opplysninger. Matrisefunksjonene find, max og min >> a = -3:3

a =

-3 -2 -1 0 1 2 3

La oss finne de verdiene av a som har absoluttverdi > 1. Vi gjør det først i to steg :

>> b = find(abs(a) > 1)

b =

1 2 6 7

>> c = a(b)

c = -3 -2 2 3

b inneholder indeksene av a med elementer der absoluttverdien > 1. Deretter bruker vi b som argument i a. Nedenfor har vi gjort dette i ett steg. >> a(find(abs(a) > 1))

ans = -3 -2 2 3

20

Skriv doc find for flere opplysninger. I mange tilfeller har vi bruk for de største og minste verdiene av en matrise. Til dette bruker vi funksjonene max og min. Genererer en vektor med 5 vilkårlige tall (uniform fordeling) og finner den største: >> v = rand(1,5)

v =

0.8147 0.9058 0.1270 0.9134 0.6324

>> max(v)

ans =

0.9134

>> [mv,k] = max(v)

mv =

0.9134

k =

4 Vi ser at funksjonen max kan kalles på to måter : Det første kallet gir bare den største verdien, mens det andre også gir plasseringen. Tilsvarende for min. La oss også se på en matrise. >> A = rand(3)

A =

0.0975 0.9575 0.9706

0.2785 0.9649 0.9572

0.5469 0.1576 0.4854

>> max(A)

ans =

0.5469 0.9649 0.9706

Vi ser at max nå finner maksverdien av hver kolonne. Dersom vi ønsker å finne maksverdien for hele matrisa A, kan vi skrive : >> max(max(A))

ans =

0.9706

>>

Et alternativ : >> max(A(:))

ans =

0.9706

Ved å skrive A(:), betraktes matrisa A som en vektor.

21

Løsning av ligningsystem Vi skal løse systemet ⋅ =A x b . Symbolsk kan løsningen skrives ⋅-1x = A b . I Matlab kan dette gjøres ved å utføre x = inv(A)*b der b er en kolonnevektor, men dette er ineffektivt. Løsning av ligningsystemet i Matlab skrives x = A\b . Operatoren \ kalles venstre divisjon (heller mot matrisa som skal «divideres» på ); symbolsk kan -1A oppfattes som divisjon. Merk at b/A ikke er definert. Derimot kan vi beregne b'/A der b'/A = b'*inv(A). (Husk at nå er b' en linjevektor) Eksempel 1 » A = [-3 3/2 0; 3/4 -9/4 5/4; 0 5/6 -19/9]

A =

-3.0000 1.5000 0

0.7500 -2.2500 1.2500

0 0.8333 -2.1111

» b = [1/2 1 3/2]'

b =

0.5000

1.0000

1.5000

» x = A\b

x =

-0.8952

-1.4571

-1.2857

» format rat

» x

x =

-94/105

-51/35

-9/7

Da matriseelementene her er rasjonale tall, kan vi få løsningen på pen brøkform. Dette gjøres ved å forandre utskriftsformatet for kommando-vinduet fra format til format rat. Går deretter tilbake til format short (Se doc format) » format

22

Eksempel 2 A =

0.4096 0.1234 0.3678 0.2943

0.2246 0.3872 0.4015 0.1129

0.3645 0.1920 0.3728 0.0643

0.1784 0.4002 0.2786 0.3927

b =

0.4043

0.1550

0.4240

-0.2557

>> x = A\b

x =

-0.0061

-1.5556

2.0315

-0.5043 KORT OM ANDRE DATASTRUKTURER Cellematriser (Cell Arrays) Cellematriser er spesielle Matlab-matriser der elementene er celler. Hver celle i en cellematrise kan inneholde hvilken som helst datatype som f.eks. numeriske matriser, strenger osv. Cellematriser kan lages ved tilordning-setninger eller ved preallokering med bruk av funksjonen cell. Det er to måter å tilordne data til de enkelte cellene : Innholdsindeksering og celleindeksering. La oss lage en 2 2× cellematrise på disse to måtene. 1. Innholdsindeksering >> a{1,1}=[1 2;3 4];

>> a{1,2} = 'Dette er en streng';

>> a{2,1} = [1 + i; 5 + 3*i];

>> a{2,2} = [];

Legg merke til krøllparentesene! Dersom du skriver ut a på vanlig måte, ser det sånn ut : >> a a =

[2x2 double] 'Dette er en streng'

[2x1 double] []

Ønsker du detaljert oversikt over innholdet, bruker du funksjonen celldisp. >> celldisp(a);

a{1,1} =

23

1 2

3 4

a{2,1} =

1.0000 + 1.0000i

5.0000 + 3.0000i

a{1,2} =

Dette er en streng

a{2,2} =

[]

1. Celleindeksering Nå plasserer vi krøllparenteser rundt dataene som skal lagres i cella. >> a(1,1)={[1 2;3 4]};

>> a(1,2) = {'Dette er en streng'};

>> a(2,1) = {[1 + i; 5 + 3*i]};

>> a{2,2} = {[]};

Resultatet blir som ovenfor.

Innholdet i de enkelte cellene kan aksesseres ved : >> a{1,1}

ans =

1 2

3 4

>> a{2,1}

ans =

1.0000 + 1.0000i

5.0000 + 3.0000i

>> Dersom vi ønsker å få tak i element(2,1) i matrisa som er lagret i celle (1,1): >> a{1,1}(1,2)

ans =

2

>>

Vi kommer ikke til å bruke cellematriser i noen utstrekning i dette kurset, men Matlab bruker dem en del i sine program. To funksjoner som genererer en cellematrise(vektor) er varargin og varargout. varargin kan brukes i argumentlista i funksjoner for å generere et vilkårlig antall inn-argumenter. Tilsvarende brukes varargout til å generere et vilkårlig antall ut-argumenter. Se programmet rkn i mappa "Kap1" under mappa "Disketten" for et eksempel på bruk av varargin.

24

Strukturer (Structure Arrays) En vanlig matrise har et navn for hele matrisa, mens de individuelle elementene kan finnes ved å angi indekser. Alle elementene må være av samme type. Det samme gjelder for en cellematrise, men her kan de individuelle elementene være av forskjellige typer. En struktur derimot, er en datatype der hvert individuelle element har et navn. De individuelle elementene kalles felt (fields) og hvert felt kan være av forskjellig type. En struktur kan lages ved tilordning eller ved bruk av funksjonen struct. Eksempel : >> person.navn = 'Hans Hansen';

>> person.adresse = 'Hans Blomsgate 200';

>> person.by = 'Byen';

>> person.land = 'Norge';

>> person

person =

navn: 'Hans Hansen'

adress: 'Hans Blomsgate 200'

by: 'Byen'

land: 'Norge'

>> Vi har her laget en struktur med navn person. Dersom vi ønsker å legge til flere navn under person, kan vi gjøre dette som følger : >> person(2).navn = 'Ole Olsen';

>> person(2).adresse = 'Markegata 200'; Innholdet av person(2) finnes direkte :

>> person(2)

ans =

navn: 'Ole Olsen'

adresse: 'Markegata 200'

by: []

land: []

Den første personen vi opprettet, er nå blitt person(1) : >> person(1)

ans =

navn: 'Hans Hansen'

adresse: 'Hans Blomsgate 200'

by: 'Byen'

land: 'Norge'

>>

25

Vi kan aksessere de enkelte feltene i strukturen. Eksempel : >> person(1).adresse

ans =

Hans Blomsgate 200

>> person(2).land

ans = []

Et annet eksempel : >> firekant.bredde = 4;

>> firekant.hoyde = 10;

>> firekant.senter = [0 0];

>> firekant.rotert = pi/4;

>> firekant

firekant =

rotert: 0.7854

bredde: 4

hoyde: 10

senter: [0 0]

Det finnes en rekke kommandoer for å trekke ut opplysninger samt for manipulering av strukturer. F.eks : >> fieldnames(firekant)

ans =

'rotert'

'bredde'

'hoyde'

'senter'

>>

Vi kommer ikke til å bruke strukturer noen utstrekning i dette kurset, men Matlab bruker dem en del i sine program. For oss er dette mest aktuelt i forbindelse med løsning av ordinære diff. ligninger(ODE). En måte å bruke en ODE-løser for startverdiproblem på er : sol = solver(odefun,[t0 tf], y0 ..). solver er f. eks. ode45. (Skriv doc ode45) sol er her en struktur. Også randverdiløserene bvp4c og bvp5c bruker strukturer. F. eks. kalles bvp4c på følgende måte : sol = bvp4c(odefun,bcfun,solinit) (Skriv doc bvp4c) sol og solinit er begge strukturer. Et annet eksempel er ved bruk av kubisk «spline» : pp = spline(x,y) pp er her en struktur (doc spline)

26

PROGRAMMERINGSDEL Til nå har vi sett på bruk av Matlab som kalkulator. De konstruksjonene og kommandoene som følger her, blir vanligvis brukt i program selvom de også kan skrives direkte i kommandovinduet. Programmene skrives med en tekst-editor Den innebygde editoren er vanligvis god nok, da Matlabprogrammene normalt er små. Er det behov for en mer sofistikert editor, finnes TextPad ved NTNU. Programmene blir lagt i filer med endelse m. Kalles derfor M–filer. Eks. : Prog.m Har to typer M-filer: Skript M–filer, også kalt kommando-filer, samt funksjons M–filer som starter med ordet function. Mange av eksemplene her er så korte at de kan skrives direkte i kommandovinduet. PROGRAMOPPSETT La oss se på de programoppsettene som vi bruker i dette kurset, før vi går mer detaljert tilverks. Oppsett 1

% prog1

.

.

kommandoer

.

Det enkleste oppsettet er å skrive kommandoene ved bruk av editoren og deretter lagre dem i en fil, her kalt prog1. Fila får da navnet prog1.m. Programmet utføres ved å skrive prog1 i kommandovinduet. Merk at verdiene av alle variable du har brukt, blir lagret i arbeidsområdet. Dette forenkler eventuell feilfinning. Oppsett 2

% prog2

.

.

kommandoer

.

y = func1(2.0).

27

.

.

function y = func1(x)

y = x^2

I oppsett 2 bruker prog2 en funksjon med navn func1. Funksjonen func1 legges i en fil med navn func1.m . Bruk samme navn på fila som funksjonen. Dette oppsettet minner om standardoppsettet for andre programmeringspråk som f. eks. Fortran. I Fortran ville vi si at prog2 er hovedprogrammet, mens func1 er et subprogram. Merk at igjen vil de variable som brukes i prog2 bevares i arbeidsområdet. Når vi bruker funksjoner, lages det et eget arbeidsområde for hver funksjon. Når funksjonen er utført, slettes innholdet i dette området,unntatt variable som er definert som global eller persistent. Merk at vi ikke kan legge en funksjon inn i en kommando-fil, slik som vi f. eks. kan i Fortran. Kommunikasjonen mellom prog2 og func1 skjer ved parameter-overføring eller ved bruk av globale variable (Se avsnittet Bruker-definerte funksjoner) Oppsett 3

.

.

kommandoer

.

y = func1(2.0).

function prog3

function y = func1(x)

y = x^2;

Her har vi rett og slett puttet funksjonen func1 inn i prog2 og forandret prog2 til en funksjon med navnet prog3 som legges i en fil med navnet prog3.m. Husk at vi ikke kan legge funksjoner inn i kommandofiler. Oppsettet utføres ved å skrive prog3 i kommandovinduet. Fordelen med dette oppsettet er at vi slipper med en fil. Bakdelen er at verdiene av alle variable, unntatt variable som er definert som global eller persistent, slettes så snart funksjonen er utført. (Vanskeliggjør feilfinning) Kommunikasjonen mellom variable i prog3 og func1 skjer fremdeles ved

28

parameteroverføring eller ved bruk av globale variable (Se avsnittet Bruker-definerte funksjoner) Oppsett 4

.

.

kommandoer

.y = func1(2.0)

.

function prog4

function y = func1(x)y = x^2;

end

end

Dette oppsettet er likt oppsett 3 bortsett fra at vi her har avsluttet begge funksjonene med kommandoen end. Vi sier at vi bruker "nøstede funksjoner". Alle variable som er gitt i funksjonen prog4, er tilgjengelige i func1, slik at vi får en mer direkte kommunikasjon mellom funksjonene. (Se avsnittet Bruker-definerte funksjoner for flere detaljer) LOGISKE UTTRYKK OG VARIABLE Opprinnelig kunne en ikke angi at en variabel var logisk i Matlab, men genererte dem ved bruk av sammenligningsoperatorer. Eksempel : >> a = 3>2

a =

1

>> b = 2>3

b =

0

>>

a og b er her logiske variable med verdiene 1 eller 0 der sant = 1 og usant = 0. >> whos Name Size Bytes Class Attributes a 1x1 1 logical

b 1x1 1 logical Legg merke til at en logisk variabel bruker bare en byte, så selv om den har verdien 0 eller 1, er disse verdiene forskjellig fra en vanlig 0 eller 1.

29

Det kan utføres aritmetiske operasjoner med logiske variable, men de blir da konvertert til vanlige 8-bytes tall. >> c = a + b

c =

1

>> d = 2*a

d =

2

>> whos

Name Size Bytes Class Attributes

c 1x1 8 double

d 1x1 8 double

>>

Fra og med versjon 6.5 kan vi direkte angi logiske variable ved å bruke true og false som vist nedenfor : >> a = true

a =

1

>> b = false

b =

0

>> Sammenligningsoperatorer (Skriv doc ops) < mindre enn <= mindre eller lik == lik >= større eller lik > større enn ~= ikke lik (ulik, forskjellig) Når a og b er tall, blir a == b, a > b , a ~= b eksempler på logiske uttrykk. Logiske operatorer (Skriv doc ops) & både og (and) (Også &&) | enten eller (or) (Også ||) xor eksklusiv eller(exclusive or) ~ negasjon (not) I tillegg har vi any og all Operatorene && og || kan brukes når operandene er skalarer. Dette sparerer noe tid, men er sjelden bryet verdt.

30

La a og b være to logiske uttrykk og sett sant = 1 og usant = 0 Sannhetstabellen nedenfor viser verdiene ved bruk av operatorene.

and or xor not

a b a&b a|b xor(a,b) ~a

0 0 0 0 0 1

0 1 0 1 1 1

1 0 0 1 1 0

1 1 1 1 0 0

Eksempler a =1, b =2, c = 3 , d = 4 » y = (a<=1)| (c>a) y =1

» y = ( a > 1)& (d >b)

y =

0

» y = ( a == 1)& (d ~=b)

y =

1

» y = xor(( a == 1) , (d ~=b))

y =

0

Ovenfor har vi brukt operatorene på skalarer, men de virker like godt på matriser. >> c = 1:5

c =

1 2 3 4 5

>> d = [0 2 5 6 4]

d =

0 2 5 6 4

>> f = c > d

f =

1 0 0 0 1

>>

Resultatet viser at første og siste element i c er større enn i d. f kalles en logisk vektor.

31

Et annet eksempel. Genererer 100 vilkårlige tall fra en uniform fordeling mellom 0 og 1: >> d = rand(1,100); Vi kan finne hvor mange som er større enn 0.5 på denne måten : >> n = sum(d > 0.5)

n = 46

>>

Betingelsen d > 0.5 genererer en logisk vektor der 1 angir verdiene >0.5. Ved å summere disse ett-tallene finner vi antallet. De logiske uttrykkene brukes naturlig ved forgreininger og løkker. Forgreininger Kommandoer: if, else, elseif og switch Variant 1 if logisk uttrykk setninger end

Setninger utføres bare dersom det logiske uttrykket = sant. Variant 2 if logisk utrykk setninger1 else

setninger2 end

setninger1 utføres dersom det logiske uttrykket = sant ellers utføres setninger2. Variant 3 if logisk utrykk1 setninger1 elseif logisk uttrykk2 setninger2 else setninger3 end

setninger1 utføres bare dersom logisk uttrykk1 = sant. setninger1 og 2 blir da ikke utført. Dersom logisk uttrykk1 = usant utføres bare setninger2 dersom logisk uttrykk2 =

32

sant. Dersom både logisk uttrykk1 og 2 = usant utføres setninger3 (og bare da). Ved bruk av sammenligningsoperatorer kan de variable være vektorer og matriser. La x og y være vektorer med n komponenter. Da vil if x < y bare være sant dersom i ix < y , i = 1,2, .. n . Tilsvarende for matriser. Et eksempel der vi kan bruke konstruksjonen fra variant 3. Anta at vi skal regne om tallkarakterer til bokstavkarakterer og følgende relasjoner er gitt :

[100 90] , (89 80] , (79 60]

(59 50] , (49 40] , < 40 (stryk)

A B C

D E F

− ⇒ − ⇒ − ⇒− ⇒ − ⇒ ⇒

Som Matlab-kode : if (tallk >= 90)

disp ('Karakter er A');

elseif (tallk >= 80)

disp ('Karakter er B');

elseif (tallk >= 60)

disp ('Karakter er C');

elseif (tallk >= 50)

disp ('Karakter er D');

elseif (tallk >= 40)

disp ('Karakter er E');

else

disp ('Karakter er F (stryk)');

end

Merk at parentesen rundt f.eks (tallk >= 90) ikke behøves. Det forutsettes at vi på forhånd har verifisert at alle verdiene er gyldige. Et enkelt eksempel på bruken av kommandoen switch. ukedag = input('Les nummer av ukedag : '); switch ukedag case {1} disp('mandag'); case {2} disp('tirsdag'); case {3} disp('onsdag'); case {4} disp('torsdag'); case {5} disp('fredag'); case {6} disp('lørdag'); case {7} disp('søndag'); otherwise error('Ikke noen ukedag !') end

33

Iterasjonsløkker Matlab har to kommandoer, for og while, for gjentatt utførelse av setninger. Den generelle syntaksen for en for- løkke er : for variabel = uttrykk setninger end variabel er navnet på løkke-variabelen. Eksempel >> for k = [1 2.5 3 4.5]

x= k^2

end

x = 1

x = 6.2500

x = 9

x = 20.2500

>>

Her er uttrykk en vektor slik at løkkevariabelen k forløpende går gjennom verdiene i vektoren. Det vanligste er at uttrykk tilordner en startverdi, en inkrement-verdi og en sluttverdi til løkke-variabelen. Inkrementet kan være både positivt og negativt eller kan utelates. I det siste tilfellet antas 1 som inkrement-verdi. Vanligvis brukes kolonnotasjonen til å definere løkke-variabelen. Vi kan ha flere løkker inne i hverandre : for variabel1 = uttrykk1 setninger1 for variabel2 = uttrykk2 setninger2 end

end

Eksempel » A = zeros(4);

» for k = 1:3

A(k,k) = 4;

A(k,k+1) = 1;

A(k+1,k) = 1;

end

» A(4,4) = 4;

» A

A = 4 1 0 0

1 4 1 0

34

0 1 4 1

0 0 1 4

Kommandoen while utfører setninger så lenge et logisk uttrykk er sant. Den generelle syntaksen for en while-løkke er : while logisk uttrykk setninger end

setninger blir ikke utført dersom det logiske uttrykket er usant. Også her kan vi ha flere løkker inne i hverandre. Merk at både for og while tester på den første linja i løkka. Dersom vi ønsker å hoppe ut av løkkene andre steder, kan det gjøres ved å bruke kommandoen break. Merk at break bare gir uthopp fra den innerste løkka dersom det er flere løkker. Dersom break brukes utenfor for og while-løkker, stoppes eksekveringen av resten av programmet. Dette kan være nyttig ved feilfinning. Nedenfor er noen typiske varianter på bruken av for og while i iterasjonsløkker. Som eksempel ser vi på en iterasjonsprosess der vi skal finne kvadratrota x av et tall der c x c= . Matematisk er dette ekvivalent med å finne nullpunktet av funksjonen ( ) 0f x = der 2( )f x x c= − . Ved bruk av Newton-Raphsons metode får vi følgende iterasjonsprosess :

112, 0,1,... , m m m m m

m

mc

x x x x xx+ =

⎛ ⎞= + Δ Δ = −⎜ ⎟

⎝ ⎠

For å starte iterasjonsprosessen, må vi tippe en startverdi 0x . Dessuten må vi ha et stoppkriterium. For å være spesifikk, velger vi 20c = ; vi skal finne

20x = . Velger startverdi 0 5x = . Variant 1 % program variant1

itmax = 10; epsi = 1.0e-5; x = 5.0;

c = 20.0;

it = 0;

while true

it = it + 1;

if it > itmax

disp('*** Max. no. of iterations ***');

break

end

dx = (c/x - x)*0.5

x = x + dx

if abs(dx) < epsi

break

end

35

end

dx =-0.5000 x = 4.5000

dx =-0.0278 x = 4.4722

dx =-8.6266e-005 x = 4.4721

dx =-8.3203e-010 x = 4.4721

Dette er en evighetsløkke da betingelsen while true alltid er oppfylt. Uthopp fra løkka skjer enten når maks. antall iterasjoner er overskredet eller når konvergens er oppnådd. Selv om vi skriver ut verdien av it og dx, er det lurt å gjøre oppmerksom på at maksimalt antall iterasjoner er overskredet. Variant 2 % program variant2

itmax = 10; epsi = 1.0e-5; x = 5.0;

c = 20.0;

for it = 1 : itmax

dx = (c/x - x)*0.5;

x = x + dx;

if abs(dx) < epsi

break

end

end

if it >= itmax

disp('*** Max. no. of iterations ***');

end (Resultat som for variant1 ) Denne løkka som utføres maksimalt itmax ganger, er mer kompakt. Uthopp fra løkka før maks. antall iterasjoner er oppnådd, skjer dersom vi har konvergens. Utskrift om maks. antall iterasjoner ligger nå etter løkka. Variant 3 % Program variant3

itmax = 10; epsi = 1.0e-5; dx = 1.0;

x = 5.0; c = 20.0;

it = 0;

while (it <= itmax) & (abs(dx) > epsi)

it = it + 1;

dx = (c/x - x)*0.5;

x = x + dx;

end

if it > itmax

disp('*** Maks. antall iterasjoner ***')

end

(Resultat som for variant1)

36

Denne løkka utføres bare dersom it <= itmax og samtidig dx > epsi. For at løkka skal utføres minst en gang, må dx ved inngang settes til en verdi større enn epsi. Det skjer ingen uthopp fra løkka. Antall iterasjoner må nå telles dersom vi vil følge iterasjonsprosessen. Utskrift om maks. antall iterasjoner ligger nå som i variant2, etter løkka. Vi har sett at vi kan bruke break til å hoppe ut av en løkke. Dessuten har vi kommandoen continue som brukes til å hoppe til slutten av en løkke. La oss se på et eksempel som bruker både break og continue. På side 2 har vi nevnt størrelsen eps 52 162 2.22 10− −= ≈ ⋅ der eps er det minste tallet slik at 1 + eps >1. Denne størrelsen fås direkte ved : >> eps

ans =

2.2204e-016

eps kan f. eks. beregnes på følgende måte : epsr = 1; for number = 1 : 200 epsr = epsr/2; if (1 + epsr) > 1 continue end epsr = epsr*2; break end disp(epsr)

som gir 2.2204e-016 Vi skal se på noen eksempler på bruk av while som i variant2 og 3 etter vi har sett litt nærmere på funksjoner. BRUKER-DEFINERTE FUNKSJONER Funksjoner programmeres i funksjons M-filer og tilsvarer det som generelt kalles subprogram. Men i Matlab kan funksjoner også brukes som selvstendige program. En funksjon opprettes ved : function [ ut1,ut2,...utn] = fnavn(inn1,inn2,....innk) Linja over definerer en funksjon med navn fnavn. Vi har k inn-parametre og n ut-parametre. Dersom vi bare har en ut-parameter, kan vi utelate hake-parentesene. Vi kan utelate alle inn-parametrene eller alle ut-parametrene eller begge deler. I det siste tilfellet skal = utelates : function fnavn og vi kaller programmet ved å skrive fnavn. Denne siste varianten er brukt i de fleste demo-programmene som følger med Matlab. Når vi kaller programmet, skriver vi :

37

[ ut1,ut2,...utn] = fnavn(inn1,inn2,....innk) Foreløpig bruker vi funksjonen direkte fra kommandovinduet eller sammen med et M-skript. Matlab definerer flere typer funksjoner. Ta en titt på anonyme funksjoner (anonymous functions) i tillegg til dem vi ser på nedenfor. Vi ser på et enkelt eksempel der vi har laget en funksjon som beregner parabelen 2y x= . Funksjonen kan lagres som func.m function y = func(x)

y = x^2;

» y = func(2)

y =

4

x og y kan være vektorer eller matriser, men da må funksjonen skrives slik at den opererer rett på denne typen variable. function y = func(x)

y = x.^2;

» z = [0 : 0.1 : 0.5];

» v = func(z)

v =

0 0.0100 0.0400 0.0900 0.1600 0.2500

Legg merke til at det ikke er noen sammenheng mellom navnene på de variable i definisjonen av funksjonen og navnene som benyttes når den brukes. (Når vi bruker en funksjon, sier vi at vi kaller funksjonen). Men vi må passe på at de er av samme type. Legg også merke til at da x er en linjevektor blir også y en linjevektor. I mange tilfeller er det lurt å initialisere ut-parametrene dersom de er vektorer og matriser. I tilfellet over kan vi f. eks. skrive : function y = func(x)

y = zeros(size(x));

y = x.^2;

Ved å bruke kommandoen size sørger vi for at funksjonen virker for både linje- og kolonne-vektorer. Dersom du redefinerer dine inngangsvariable inne i funksjonen, vil disse bli mellomlagret til funksjonen er utført. (Det blir ikke laget kopi av inngangsdata som ikke redefineres). Matlab bruker her en overførings-metode for parametre som kalles “pass by value”. Dermed blir ikke de opprinnelige verdiene ødelagt. Dette betyr også at du ikke sparer plass ved å redefinere inngangsdata.

38

Merk også at alle lokale variable som defineres i en funksjon, forsvinner når funksjonen er utført. function y = func(x)

y = zeros(size(x));

a = 1;

y = x.^2;

x = 2*x;

» v = func(z)

v = 0 0.0100 0.0400 0.0900 0.1600 0.2500

» z

z = 0 0.1000 0.2000 0.3000 0.4000 0.5000

» a

??? Undefined function or variable 'a'.

Vi ser her at z har fremdeles sin opprinnelige verdi. Den lokale variable a som vi definerte, blir slettet når funksjonen er utført. Vi kan også overføre data ved bruk av kommandoen global. function y = func(x)

y = zeros(size(x));

global P Q;

y = x.^2 + P + Q ;

» global Q P;

» Q = 1; P = 2;

» v = func(z)

v =

3.0000 3.0100 3.0400 3.0900 3.1600 3.2500

Med Q = 1 og P = 2 har vi addert 3 til vektoren v . Merk at rekkefølgen av de globale variable kan være forskjellig i det kallende programmet og det kalte programmet. ( Godt nytt for dem som er vant til Fortran). Flere globale variable skal skilles med mellomrom; ikke komma. global kan brukes til å overføre data mellom M-skript og funksjoner og mellom de enkelte funksjonene. Globale variable gir en effektiv overføring av data. Bakdelen er at vi ved en feiltagelse kan redefinere noen av dem i et program. Denne sideeffekten har aldri vært særlig poulær i data-kretser. Jeg har sett forslag om at globale variable bør skrives med minst 20 store bokstaver og helst avsluttes med dyrets tegn 666. Det gjelder spesielle regler for sletting av globale variable ved bruke av clear. (doc clear). Dersom vi skal overføre to globale variable a og b mellom et M-skript og en funksjon, kan vi skrive i M-skriptet : clear ; clear global a b;

global a b;

Ved å bruke clear global a b fjerner vi først de gamle verdiene av a og b. Dersom vi bare skriver clear global , fjerner vi bare tilgangen til de globale variable i M-skriptet, ikke i funksjonene. Eventuelt kan vi rett og slett skrive

39

clear all. I dette tilfellet fjerner vi alle funksjonene også. I Matlab versjon 7.7 er det innført en ny kommando clearvars. Dersom du skriver clearvars -global, slettes alle globale variable. Vi kommer tilbake til bruken av globale variable senere i avsnittet Overføring av data mellom program. (Oppsummering) I mange tilfeller har vi bruk for å avslutte beregningen og returnere til det kallende programmet før vi ha nådd slutten av funksjonen. Dette gjøres ved å bruke kommandoen return. (Se f.eks. funksjonen CDkule side 9 i kompendiet). Om nødvendig, kan vi avbryte beregningen med kommandoen error. (Flere opplysninger med doc return og doc error) Tradisjonelle subfunksjoner. (Se Oppsett 3 , side 27) Det er mulig å bruke funksjoner inne i funksjoner. Slike funksjoner, kalt subfunksjoner, må ligge helt tilslutt i hovedfunksjonen. function y = func(x)

y = zeros(size(x));

a = f(x);

y = a*x.^2;

%------------------

function fac = f(t)

fac = sum(t);

z = [0 : 0.1 : 0.5];

» v = func(z)

v = 0 0.0150 0.0600 0.1350 0.2400 0.3750

Her er func hovedfunksjonen og f subfunksjonen. Merk at variable i begge funksjonene er uavhengie av hverandre selv om de skulle ha samme navn. Skriv doc function for flere eksempler. Nøstede funksjoner (nested functions). (Se Oppsett 4 , side 28) Disse ble innført fra og med versjon 7.0. La oss først se på et eksempel med tradisjonelle funksjoner. function func1 a = 1; z = func2(2.0) function val = func2(x) val = 2*x*a; Når vi eksekverer denne funksjonen får vi : ??? Undefined function or variable 'a'. Error in ==> func1>func2 at 5 val = 2*x*a;

Dette resultatet er ikke overraskende da variable a ikke er definert i func2. Vi lager nå en ny versjon og eksekverer denne : function func1 a = 1; z = func2(2.0) function val = func2(x)

40

val = 2*x*a; end end >> func1

z = 4

Vi har bare avsluttet begge funksjonene med end og dermed har a blitt tilgjengelig i func2 med verdien 1. Dette er et eksempel på nøstede funksjoner. func1 benevnes primærfunksjonen og func2 er nå innlagt i func1 slik at verdiene av alle variable som er definert i func1 også er blitt tilgjengelige i func2. Dette reiser et spørsmål. Dersom vi nå forandrer verdien av a i func2, vil da verdien av a i func1 forandres ? . La oss prøve: function func1 a = 1; z = func2(2.0) a function val = func2(x) val = 2*x*a; a = 2; end end >> func1

z = 4

a = 2

Svaret er ja. Med andre ord : Det er den samme a i begge programmene slik at effekten blir som å bruke globalmed tradisjonelle subfunksjoner. La oss verifisere dette : function func1 global a; a = 1; z = func2(2.0) a function val = func2(x) global a; val = 2*x*a; a = 2; >> func1

z = 4

a = 2

41

EKSEMPEL PÅ BRUK AV FUNKSJONER Nullpunktsbestemmelse ved bruk av sekantmetoden. Sekantmetoden er beskrevet i avsnitt 2.2 i kompendiet. For oversiktens skyld gjentar vi beskrivelsen her.

0x

1x2x

3x

0( )f x

1( )f x

2( )f x

*x•• •

• •

y

x

Vi skal finne nullpunktet *x (kan være flere) av funksjonen ( )y f x= . Utfører en iterasjonsprosess etter følgende skjema :

1

1

1

, 1,2,...

( )( ) ( )

m m

m mm

m m

x x x m

x xx f x

f x f x

+

= + Δ =

−Δ = − ⋅

−⎡ ⎤⎢ ⎥⎣ ⎦

Figuren viser prosessen for m = 2. Vi har valgt å sette iterasjonsindekset m nede da det ikke er noen fare for kollisjon med andre indekser. For å komme i gang, må vi tippe to verdier 0 1og x x . Prosessen gjentas til et

konvergenskriterium er oppfylt, f.eks. 1 2 eller x x xε εΔ < Δ < ⋅ . Kombineres

gjerne med 1 3( )mf x ε+ < .

La oss bruke sekantmetoden til å finne den reelle rota av tredjegradpolynomet 3 2( ) 4 10f x x x= + − . (Et tredjegradspolynom med reelle koeffisienter har alltid

minst en reell rot). Figuren nedenfor viser polynomet tegnet for [0 , 2]x ∈ .

0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 1.8 2-10

-5

0

5

10

15Funksjonen x3 + 4x2 -10

x

y

42

Vi ser at vi har et nullpunkt i intervallet [1.2 , 1.4] , og på en lommekalkulator med nullpunktsløser finner vi nullpunktet * 1.365200134x = med 10 korrekte siffer. La oss gjenta beregningen med bruk av sekantmetoden og bruker startverdier 0 10 og 2x x= = . I den første versjonen utfører vi iterasjonsprosessen et visst antall ganger uten å spesifisere noe iterasjonkriterium. Dette er ofte lurt når vi begynner på et problem der vi er usikker på iterasjonsforløpet. Programmet sekant1 gir følgende resultat : m dx f(x) x --------------------------------------------------

1 -1.17e+000 1.40e+001 0.8333333333

2 3.75e-001 -6.64e+000 1.2087912088

3 2.11e-001 -2.39e+000 1.4196238401

4 -5.87e-002 9.22e-001 1.3608992155

5 4.22e-003 -7.14e-002 1.3651166138

6 1.14e-004 -1.87e-003 1.3652302546

7 -2.41e-007 3.98e-006 1.3652300134

8 1.34e-011 -2.21e-010 1.3652300134

Vi ser at vi har fått 10 korrekte siffer etter 7 iterasjoner. Legg merke til at prosessen går langsomt i begynnelsen; prosessen skyter fart først etter 6 iterasjoner. Det gjelder generelt både for Newton-Raphsons metode og sekantmetoden at vi må være nær rota for å få rask konvergens. Listingen av programmet er vist nedenfor. % Program sekant1

clear

x0 = 0.0 ; x1 = 2.0; % Initial values

f0 = func(x0);

mmax = 8;

s1 = '%2.0f % 7.2e % 7.2e %13.10f \n';

disp(' m dx f(x) x ' )

disp('--------------------------------------------------')

for m = 1 : mmax

f1 = func(x1);

dx = - f1*(x1 - x0)/(f1 - f0);

x = x1 + dx;

fprintf(s1,m,dx,f1,x);

x0 = x1;

x1 = x;

f0 = f1;

end

function y = func(x)

y = x^3 + 4*x^2 - 10;

Når vi nå vet at iterasjonsprosessen forløper greit, kan vi legge inn et konvergenskriterium. Dette er gjort i versjonen sekant2 nedenfor. (Se avsnittet Formatert utskrift angående bruk av fprintf og disp)

43

% Program sekant2

x0 = 0.0 ; x1 = 2.0; % Initial values

f0 = func(x0);

itmax = 10; epsi = 1.0e-7; it = 0; dx = 1;

while (abs(dx) >= epsi ) & ( it <= itmax)

it = it + 1;

f1 = func(x1);

dx = - f1*(x1 - x0)/(f1 - f0);

x = x1 + dx;

x0 = x1;

x1 = x;

f0 = f1;

end

if (it > itmax)

disp( '*** Max. no. of iterations ***')

end

fprintf( '\n x = %13.10f \n',x);

FUNKSJON SOM PARAMETER I EN FUNKSJON I mange tilfeller ønsker vi å lage funksjoner som operere på andre funksjoner. F. eks. ønsker vi å ha funksjoner som kan behandle generelle diff. ligninger eller finner nullpunkt av generelle funksjoner, slik at det er tilstrekkelig å kode diff. ligningen eller funksjonen separat uten å måtte gå inn i programmet som utfører selv løsningen. I Matlab kalles slike funksjoner for function function. Skriv doc funfun hvis du vil se lista over slike som finnes i Matlab. Vi skal se på hvordan vi lager våre egne. Eksempel : Nullpunktsløser Anta at vi ønsker å lage en funksjon sekant som finner røtter av vilkårlige funksjoner. I dette tilfellet ønsker vi å bruke navnet på funksjonen som vi skal finne røttene av, som inn-parameter i sekant. Dette får vi til ved å bruke kommandoen feval (function evaluation). Ved å bruke sekant2 som modell, kan sekant skrives som følger : function rot = sekant(fname,x0,x1,itmax,epsi)

f0 = feval(fname,x0);

it = 0; dx = 1;

while (abs(dx) >= epsi ) & ( it <= itmax)

it = it + 1;

f1 = feval(fname,x1);

dx = - f1*(x1 - x0)/(f1 - f0);

x = x1 + dx;

x0 = x1;

x1 = x;

f0 = f1;

end

44

rot = x;

if (it > itmax)

disp( '*** Max. no. of iterations ***')

end

Dersom vi bruker sekant på funksjonen func i det forrige eksemplet,får vi: rot = sekant( @func,x0,x1,itmax,epsi) Legg merke til at istedenfor fname, setter vi inn det virkelige navnet på den funksjonen som vi skal finne rota av. Denne er lagret som en m-fil med navn func.m og må ligge på søkestien. Istedenfor @func, kan vi skrive 'func', altså en streng. Fra og med versjon 6.0 av Matlab, ble @ (krøllnabla) innført som et alternativ og utvidelse til bruken av funksjonsnavnet som en streng. Når du bruker @, genererer du noe som heter "function handle". (Skriv doc function_handle for flere opplysninger). Det må nevnes at sekantmetoden i umodifisert versjon som vist ovenfor, ikke er noen god nullpunktsløser i generelle tilfeller. Det er bedre å bruke Matlabs egen nullpunktsløseren fzero. (Har kalkulatoren din en nullpunktsløser, er dette vanligvis en variant av fzero). La oss bruke fzero på funksjonen ovenfor. Anta først at vi ikke kjenner noe intervall som inneholder nullpunktet, men vi har en anelse om at nullpunktet ligger i nærheten av 1.0 » format long

» x0 = 1.0;

» rot = fzero('func',x0)

rot = 1.36523001341410

fzero kan kalles på en rekke måter(skriv doc fzero). Dersom vi kjenner et intervall som rota ligger i, kan vi spesifisere dette. » x0 = [1.2 1.4];

» rot = fzero('func',x0)

rot = 1.36523001341410

»

Normalt vil den siste varianten være raskere. I begge tilfellene ovenfor har vi funnet rota med full presisjon, noe vi kan tillate oss i dette enkle tilfellet. For mer kompliserte tilfeller kan dette være både tidkrevende og unødvendig. Anta at det er tilstrekkelig med ca. 5 siffers nøyaktighet. » x0 = [1.2 1.4];

» options = optimset('Tolx',1.0e-5);

» rot = fzero('func',x0,options)

rot = 1.36523001552733

»

Vi ser at vi har fått adskillig mer enn 5 korrekte siffer. (Skriv doc optimset for å se den totale lista over opsjoner )

45

Eksempel : Bestemte integral

1a x= 2x 3x 1kx +kx nx1nx b+ =

2y3y

ky1ky +

ny

h

x

y

1y1ny +

La oss lage en rutine som integrerer en funksjon ( )y f x= fra y a= til y b= ved bruk av trapesmetoden. Deler intervallet [a , b] i n deler der hver del har

lengde ( )b a

hn−= . Med 1x a= og 1nx b+ = blir ( 1) , 1,2,.., 1kx a h k k n= + − = + .

Fra figuren ovenfor får vi følgende uttrykk for arealet :

1 1 2 3( ) ( .... )2 n n

hA y y h y y y+= + + + + +

La oss som et eksempel integrere cos(x). Funksjonen trapes1 gjør dette. function intcos = trapes1(a,b,n)

h = (b-a)/n; % Length of interval

s = 0;

for k = 2 : n

x = a + (k-1)*h;

y = cos(x);

s = s + y*h;

end

intcos = s + h*(cos(a) + cos(b))*0.5;

Vi bruker trapes1 til å beregne 0

/422cos( ) 0.707106x dx

π= =∫

» a = 0; b = pi/4; n = 50;

» value = trapes1(a,b,n)

value = 0.7071

Problemet med denne versjonen er selvfølgelig at vi kan bare bruke den til å integrere cosinus-funksjonen. Bruker derfor kommandoen feval som vi brukte i programmet sekant til å sette funksjonsnavnet i parameterlista. Benytter samtidig anledningen til å gjøre trapes1 mer effektiv ved å beregne alle funksjonsverdiene før vi går inn i summasjonsløkka. Bruker dessuten den innebygde kommandoen sum. Den nye versjonen er vist nedenfor.

46

function trapint = trapes2(fname,a,b,n)

h = (b-a)/n; % Length of interval

np = n + 1 ; % Number of knots

x = linspace(a,b,np); % x-values (knots)

y = feval(fname,x); % Function-values at knots

s = h*sum(y(2:end));

trapint = s + h*(y(1) + y(np))*0.5;

fname er navnet på funksjonen som skal integreres. Vi gjentar beregningen som vi gjorde ovenfor : » a = 0; b = pi/4; n = 50;

» value = trapes2(@cos,a,b,n)

value = 0.7071

Kan også direkte skrive value = trapes2(@cos,0,pi/4,50)

La oss deretter bruke trapes2 på funksjonen som vi har brukt under nullpunkts-eksemplene: function y = func(x)

y = x.^3 + 4.*x.^2 - 10;

La oss integrere denne mellom x = 1 og x = 2 der det analytiske resultatet er 37

3.08333...12

= . Legg merke til at trapes2 må ha alle funksjonsverdiene samlet i

en vektor. Derfor må vi nå bruke elementvise operatorer i func. » a = 1.0; b = 2.0; n = 50;

» value = trapes2(@func, a, b, n)

value =

3.0839

Trapesformelen kan også skrives (med variabel delbredde) :

1 11

1( ) ,

2

n

k k k k k kk

A y y h h x x+ +=

= + ⋅ = −∑

Her er Molers “one-liner” for denne formelen : (Se ref. [6]): A = sum(diff(x).*(y(1:end-1) + y(2:end))/2);

Eksemplene ovenfor er ment å vise programmering i Matlab. Når en gitt funksjon skal integreres, velger vi heller å bruke metodene som er innebygget i Matlab, f.eks quadl. Matlab har trapesmetoden i trapz.

47

Overføring av data mellom program. (Oppsummering). Vi har sett at vi kan overføre data mellom M-skript og funksjoner ved parametre i funksjonskallet eller ved bruk av globale variable. Det samme er tilfellet for overføring mellom funksjoner. For funksjoner kan vi i tillegg bruke nøstede funksjoner. Det sikreste er å overføre data via parametre i kallet. I dette tilfellet unngår vi mulige side-effekter som vi kan få ved bruk av globale variable eller ved nøstede funksjoner. Bakdelen er at denne prosessen kan være litt langsom ved overføring av store matriser. Hovedproblemet er at dersom du har bruk for ekstra lagerplass internt i et subprogram, vinner du ingenting på overskrive inngangsparametere da Matlab bruker "pass by value" i dette tilfellet : Det blir laget en kopi av inngangsdataene (Se side 37). I de tilfellene der vi har en funksjon som parameter i en annen funksjon, kan funksjonsparameteren inneholde variable som vi må overføre. I dette tilfellet kan vi bruke funksjonen varargin. (Har nevnt varargin tidligere i avsnittet cellematriser). Bruk av varargin er vist i funksjonen rkn i mappa "Kap1" under mappa "Disketten". Matlab brukte denne teknikken tidligere for alle ODE-løserene samt fzero, men har gått bort fra dette i dokumentasjonen i de siste versjonene av Matlab, selv om teknikken virker fremdeles. Trenden fra MathWorks (de som lager Matlab) er at man skal bruke nøstede funksjoner i steden. Globale variable kan brukes mellom M-skript og funksjoner og funksjoner seg i mellom. Dette gir en effektiv overføring, også for store matriser, men vi må være på vakt for mulige side-effekter ved feilaktig tilordning. Jeg bruker globale variable når jeg kaller Matlabs ODE-løsere samt fzero når funksjonen som skal behandles, inneholder ekstra variable som må overføres. Her sparer du plass ved å skrive over inngangsdata som du ikke lenger behøver. Nøstede funksjoner virker stort sett som teknikken med globale variable. Her blir alle variable i de ytre funksjonene tilgjengelige i de indre. Dette betyr at vi ikke trenger å overføre disse variablene. Bakdelen er at alle blir overført; ikke bare dem vi trenger slik som ved bruk av globale variable. Derfor kan det lett oppstå side-effekter dersom vi ikke er påpasselige. En fordel er at det ikke er nødvendig å slette variable samt at de variable bare er tilgjengelige mellom de nøstede funksjonene. Også her sparer du plass ved å skrive over inngangsdata som du ikke lenger behøver. Det er tydelig at Matlab går i retning av å bruke nøstede funksjoner.

48

FORMATTERT UTSKRIFT Når vi skriver til skjerm, papir eller en annen fil, bruker vi kommandoene disp, fprintf og sprintf. disp og fprintf brukes til utskrift. sprintf lager en utskriftstreng som senere kan skrives ut med disp eller fprintf. Nytting ved overskrift på plott. Syntaks : disp(streng og/eller variable) sprintf ( <Streng med format spesifikasjoner>, <Liste av variable>) Syntaksen for fprintf er som for sprintf, men i tillegg kan det spesifiseres at det skal skrives til en fil. Et format ser ut som følger : % mW.PF Tegnet % angir starten av et format og må alltid være med. m er en markør som kan ha følgende verdier (kan utelates): minus tegn (–) Venstrejusterer tallet. Ellers høyrejustert + Skriv alltid tallets fortegn ( pluss eller minus) 0 Utfyll tallet med ledende nuller isteden for mellomrom W angir antall plasser som er avsatt til tallet. (Kan utelates). P angir antall desimaler etter desimalpunktum (presisjonen). (Kan utelates). F er formatbeskriver.(Må være med). En liste over verdier for F er gitt på neste side.

F Beskrivelse

c Et enkelt tegn

d Heltall med fortegn

e Eksponentform (liten e)

E Eksponentform (stor E)

f Desimaltall

g Kompakt versjon av f eller g

G Som ovenfor, men med stor G

o Oktalt tall (uten fortegn)

s Streng av tegn

u Heltall uten fortegn

x Heksadesimalt tall(små bokstaver)

X Som ovenfor , men med store bokstaver

49

La oss se på et eksempel der vi skriver en tabell over feilfunksjonen erf(x) og den komplementære feilfunksjonen erfc(x) = 1 - erf(x) for 0 2x≤ ≤ x = (0 : 0.25 : 2.0)';

y1 = erf(x);

y2 = erfc(x);

disp(' x erf(x) erfc(x)')

disp(' -----------------------------')

disp([x y1 y2]);

som gir utskrift : x erf(x) erfc(x)

-----------------------------

0 0 1.0000

0.2500 0.2763 0.7237

0.5000 0.5205 0.4795

0.7500 0.7112 0.2888

1.0000 0.8427 0.1573

1.2500 0.9229 0.0771

1.5000 0.9661 0.0339

1.7500 0.9867 0.0133

2.0000 0.9953 0.0047

Legg merke til at x er generert som en kolonnevektor slik at også y1 og y2 blir kolonnevektorer. Deretter bruker vi disp til å lage tabell-overskrift. Ber deretter om utskrift av matrisa [x y1 y2]. Merk at matrisa skrives ut linje for linje slik som vi ønsker. Tallene i tabellen blir utskrevet med den valgte versjonen av kommandoen format. I dette tilfellet er dette short som gir 4 desimaler. Dersom vi hadde valgt format long, ville vi fått utskrift med 14 siffer for alle kolonnene. Vi ser derfor at vi ikke kan velge forskjellig format for de enkelte kolonnene med ensidig bruk av disp. Kombinerer derfor disp med sprintf. x = (0 : 0.25 : 2.0)';

y1 = erf(x);

y2 = erfc(x);

disp(' x erf(x) erfc(x)')

disp(' -------------------------------');

disp(sprintf(' %5.2f %7.4f %12.4e \n',[x y1 y2]'));

x erf(x) erfc(x)

-------------------------------

0.00 0.0000 1.0000e+000

0.25 0.2763 7.2367e-001

0.50 0.5205 4.7950e-001

0.75 0.7112 2.8884e-001

1.00 0.8427 1.5730e-001

1.25 0.9229 7.7100e-002

1.50 0.9661 3.3895e-002

1.75 0.9867 1.3328e-002

2.00 0.9953 4.6777e-003

50

I sprintf har vi nå skrevet en streng som inneholder formatteringskoder. Disse starter som vi vet med %. Strengen avsluttes med \n som betyr ny linje. Hadde vi utelatt \n , ville hele matrisa blitt skrevet på en linje. Legg merke til at vi har transponert matrisa [x y1 y2]. Når vi bruker formatteringskoder, skrives en matrise ut kolonne for kolonne; ikke linje for linje som vi ønsker. Derfor må matrisa transponeres. Dette er ikke nødvendig når vi bare bruker disp, som i det forrige eksemplet. I stedenfor disp og sprintf, kan vi her greie oss med fprintf alene som vist nedenfor. x = (0 : 0.25 : 2.0)';

y1 = erf(x);

y2 = erfc(x);

fprintf(' x erf(x) erfc(x)\n');

fprintf(' -------------------------------\n');

fprintf(' %5.2f %7.4f %12.4e \n',[x y1 y2]');

x erf(x) erfc(x) -------------------------------

0.00 0.0000 1.0000e+000

0.25 0.2763 7.2367e-001

0.50 0.5205 4.7950e-001

0.75 0.7112 2.8884e-001

1.00 0.8427 1.5730e-001

1.25 0.9229 7.7100e-002

1.50 0.9661 3.3895e-002

1.75 0.9867 1.3328e-002

2.00 0.9953 4.6777e-003

sprintf er nyttig når formatteringsstrengene blir lange, samt i forbindelse med tekst på plott. Se programmene nonlinvib og cantlevplot i mappa "Disketten". Igjen gjør vi oppmerksom på at vi sparer plass ved å bruke en løkke for print-setningen. (Se nederst side 52)

51

PLOTTING La oss plotte feilfunksjonene som vi brukte i det forrige eksemplet. » x = 0 : 0.1 : 2;

» y1 = erf(x);

» y2 = erfc(x);

» plot (x,y1,x,y2);

Den første vektoren plottes langs x-aksen mens den andre plottes langs y-aksen. I dette tilfellet har vi plottet to funksjoner i samme plottet. Dette kan vi gjøre fordi begge har samme utstrekning langs både x- og y-aksen. I praksis har vi bruk for å fortelle hva vi har plottet, samt å skille de to funksjonene fra hverandre. Dette gjøres med title og legend samt plottesymboler. 1 % program plot1

2 x = 0 : 0.1 :2;

3 y1 = erf(x);

4 y2 = erfc(x);

5 plot(x,y1,'k',x,y2,'k-.');

6 grid

7 title('Feilfunksjonene erf(x) og erfc(x)','FontWeight','Bold')

8 xlabel('x','FontWeight','Bold')

9 ylabel('erf \rightarrow , erfc\rightarrow','FontWeight','Bold')

10 legend('erf','erfc')

0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 1.8 20

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

52

Forklaring til det meste finnes ved bruk av doc plot, men noen kommentarer kan være nyttige. I linje 5 har vi brukt 'k' og 'k-.'. 'k' brukes for å angi at plottefargen skal være svart. Uten denne vil plottefargen være blå for den første kurva og grønn for den andre. (Spesielt den grønne vises dårlig på en gråtone -printer ). For den andre kurva bruker vi 'k-.' der - . angir strekpunktert linje. I line 6 har vi spesifisert nett. Vi setter overskrifta i linje 7 og angir uthevet skrift. I linje 8 og 9 setter vi tekst på aksene. Legg merke til \rightarrow som ganske riktig blir en høyrepil på figuren. Det finnes en mengde symboler, deriblant de greske bokstavene, som kan brukes på figuren. (Et utvalg er gitt i appendiks). I linje 10 setter vi tegnforklaring til kurvene (legend) der erf(x) har heltrukket linje og erfc(x) har en strekpunktert. Denne boksen kan flyttes rundt på figuren med musa. Dersom du har bruk for å sette annen tekst på figuren, kan denne skrives direkte på figuren. Ovenfor har vi tegnet begge kurvene samtidig ved å plotte dem i den samme plot-setningen. Samme effekten kan vi få ved følgende sekvens : plot(x,y1)

hold on

plot(x,y2)

hold off

Vi bruker denne framgangsmåten dersom det skal plottes mange kurver på samme figur , f. eks. i en iterasjonsprosess. For mange flere detaljer angående tekst : Skriv doc, skriv tex i Search for-boksen og velg Adding Text Annotations ...

0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 1.8 20

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1Feilfunksjonene erf(x) og erfc(x)

x

erf

→ ,

erf

c →

erf erfc

53

Når vi bruker strenger som 'FontWeight', 'FontSize', osv. kan vi få utskrift-strengene mer kompakte med å skrive FW = 'FontWeight', FS = 'FontSize' osv. og deretter bruke FW og FS i utskriftstrengen. I plot1 vil vi da få : FW = 'FontWeight';

title('Feilfunksjonene erf(x) og erfc(x)',FW,'Bold')

xlabel('x',FW,'Bold')

ylabel('erf \rightarrow , erfc\rightarrow',FW,'Bold')

La oss se på et annet eksempel.

k

x(t)

m

Vi har et svingesystem med en frihetsgrad med masse m og fjærkonstant k Bevegelsen beskrives ved ( ) cos( )ex t A tω φ= ⋅ −

med 0 0(0) , (0) (0) x x x v v= = = og egenfrekvensen /e k mω =

Amplituden ( )220 0 / eA x v ω= + og fasevinkelen 0

0

arctane

vx

φω

⎛ ⎞= ⎜ ⎟

⎝ ⎠.

Vi skal plotte ( )x t for 4 - 5 verdisett av 0 0, , og k m x v for en svart- og hvit- printer. Dette er vist i programmet plot2 nedenfor %progam plot2 % For black and white print clear % === Data === k = [16 16 16 8 ]'; % fjærkonstant m = [16 16 16 16 ]'; % mass x0 = [0.2 0.1 0.2 0.2 ]'; % displacement v0 = [0.1 0.1 0.05 0.1 ]'; % velocity % % === Computation === we = sqrt(k./m); % eigenfrequency A = sqrt(x0.^2 + (v0./we).^2); % amplitude phi = atan(v0./(we.*x0)); % phase angle % % === Printing === disp(' k m x0 v0 we A phi'); disp('-------------------------------------------------'); st = '%5.1f %5.1f %6.2f %6.2f %7.4f %7.4f %7.4f \n'; fprintf (st,[k m x0 v0 we A phi]'); % % === Plotting === t = (0.0 : 0.1:10.0); for j = 1:length(k) x(j,:) = A(j)*cos(we(j)*t - phi(j)); end LW = 'LineWidth'; axis([0 10 -0.25 0.25]); hold on

54

plot(t,x(1,:),'k-', LW,1); plot(t,x(2,:),'k--',LW,1); plot(t,x(3,:),'k:', LW,1); plot(t,x(4,:),'k-.',LW,1); hold off grid xlabel('t','FontSize',14); ylabel('x(t)','FontSize',14,'Rotation',0); legend('x1','x2','x3','x4'); shg Programmet gir følgende utskrift og figur : >> plot2

k m x0 v0 we A phi

-------------------------------------------------

16.0 16.0 0.20 0.10 1.0000 0.2236 0.4636

16.0 16.0 0.10 0.10 1.0000 0.1414 0.7854

16.0 16.0 0.20 0.05 1.0000 0.2062 0.2450

8.0 16.0 0.20 0.10 0.7071 0.2449 0.6155

>>

0 1 2 3 4 5 6 7 8 9 10-0.25

-0.2

-0.15

-0.1

-0.05

0

0.05

0.1

0.15

0.2

0.25

t

x(t)

x1

x2x3

x4

55

Nå er det ofte mulig å gjøre samme ting på flere måter i Matlab. Programmet plot2v2 nedenfor gjør det samme som plot2, men er en mer kompakt versjon (Tar bare med plottingsdelen i listingen). %program plotv2 . . % === Plotting === t = (0.0 : 0.1:10.0); for j = 1:length(k) x(j,:) = A(j)*cos(we(j)*t - phi(j)); end colorordermatrix = [0 0 0];% black colour % Line styles linestylematrix = ['- ';'--';': ';'-.']; axes('ColorOrder',colorordermatrix,... 'LineStyleOrder',linestylematrix,'NextPlot','add'); plot(t,x,'LineWidth',1); grid xlabel('t','FontSize',14); ylabel('x(t)','FontSize',14,'Rotation',0); legend('x1','x2','x3','x4'); shg

Vi kan også dele plottevinduet opp i delplot ved å bruke kommandoen subplot. Eksempel : subplot(3,3,k) betyr at plottevinduet skal deles opp i en 3 3× matrise av delvindu og at det neste plottet skal plasseres i delvindu k. Nummereringen av delplottene er som følger :

1 2 34 5 67 8 9

⎡ ⎤ ⎡ ⎤ ⎡ ⎤⎣ ⎦ ⎣ ⎦ ⎣ ⎦⎡ ⎤ ⎡ ⎤ ⎡ ⎤⎣ ⎦ ⎣ ⎦ ⎣ ⎦⎡ ⎤ ⎡ ⎤ ⎡ ⎤⎣ ⎦ ⎣ ⎦ ⎣ ⎦

Programmet plot2 med oppdeling i sub-plot er vist nedenfor i programmet plot2sub. (Tar bare med plottingsdelen i listingen). % === Plotting === t = [0.0 : 0.1:10.0]; for j = 1:length(k) x(j,:) = A(j)*cos(we(j)*t - phi(j)); end for j = 1:5 subplot(2,3,j) plot(t,x(j,:)); xlabel('t'); st =['x',char(48+j)]; ylabel(st,'Rotation',0); grid end shg

56

0 5 10-0.4

-0.2

0

0.2

0.4

t

x1

0 5 10-0.2

-0.1

0

0.1

0.2

t

x2

0 5 10-0.4

-0.2

0

0.2

0.4

t

x3

0 5 10-0.4

-0.2

0

0.2

0.4

t

x4

0 5 10-0.4

-0.2

0

0.2

0.4

t

x5

På side 10 har vi nevnt kommandoen fplot som er grei å bruke i forbindelse med plotting av funksjoner. La oss se på et eksempel der vi kombinerer med bruk av kommandoen subplot. (Tatt fra ref. [4] ) >> subplot(221), fplot('exp(sqrt(x)*sin(12*x))',[0 2*pi])

>> subplot(222), fplot('sin(round(x))',[0 10],'--')

>> subplot(223), fplot('cos(30*x)/x',[0.01 1 -15 20],'-.')

>> subplot(224), fplot('[sin(x),cos(2*x),1/(1+x)]',[0 5*pi -1.5 1.5])

0 5 10 15-1.5

-1

-0.5

0

0.5

1

1.5

0 1 2 3 4 5 60

2

4

6

8

10

12

0 2 4 6 8 10-1

-0.5

0

0.5

1

0.2 0.4 0.6 0.8 1-15

-10

-5

0

5

10

15

20

57

INNLESNING AV DATA (doc iofun) På meny-linja under file finner du import data …. Dette er en såkalt «wizard» som hjelper til med innlesning i mange forskjellig format. Nedenfor vil vi se på noen kommandoer som brukes direkte i programmer. Kommandoen input brukes for interaktiv innlesning. Eksempel : x = input('les x-verdi : ');

Skriver les x-verdi : på skjermen og venter på input fra brukeren. Lesning av matriser til og fra filer (doc load og doc save) 1. Lagring av en variabel. Vi lager først en matrise A som vist nedenfor. > A = [1 2 3; 4 5 6; 7 8 9]

A =

1 2 3

4 5 6

7 8 9

Ønsker å lagre A på fila amatr.txt på tekstform slik at vi kan se på fila med en editor og om nødvendig editere den. Dette kan vi gjøre med følgende kommando :>> save amatr.txt A -ascii Opsjonen -ascii sikrer at innholdet er en tekst-fil. Legg merke til at endelsen .txt er vilkårlig valgt; kunne f.eks.valgt endelsen .dat istedet. Sletter A og leser A inn på nytt fra amatr.txt ved : >> clear A

>> A = load('amatr.txt')

A =

1 2 3

4 5 6

7 8 9

Dersom du bare skriver load amatr.txt, lagres innholdet i en matrise med navn amatr.

Opsjonen -ascii sikrer som nevnt at fila blir lagret på tekst-form, men A blir bare lagret med 8 siffers nøyaktighet. Dersom du ønsker 16 siffers nøyaktighet, blir kommandoen :>> save amatr.txt A -ascii –double

Dersom du ikke har behov for å se på eller redigere innholdet av fila, er det like greit å lagre den på binær form. Du får da også automatisk full nøyaktighet.

58

Skriver da : >> save amatr.mat A Det er ikke nødvendig å bruke endelsen mat, men da Matlab behandler automatisk filer som ender på .mat som binær-filer, er det fornuftig å bruke mat-endelsen. Sletter A og leser A inn på nytt fra amatr.mat ved : >> clear A

>> load amatr.mat

>> A

A = 1 2 3

4 5 6

7 8 9

Merk at load-setningen oppretter matrisa A i dette tilfellet.

1. Lagring av flere variable La oss i tillegg til A-matrisa lage en B-matrise : >> B = [0.1 0.2 0.3;0.4 0.5 0.6;0.7 0.8 0.9]

B =

0.1000 0.2000 0.3000

0.4000 0.5000 0.6000

0.7000 0.8000 0.9000 Lagrer både A- og B-matrisa på en fil abmatr.txt: :>> save abmatr.txt A B –ascii Dersom vi ser på denne fila med en editor, finner vi at begge matrisene er lagret som ventet. Vi ønsker å lese tilbake bare A-matrisa og skriver : > A = load('abmatr.txt')

A =

1.0000 2.0000 3.0000

4.0000 5.0000 6.0000

7.0000 8.0000 9.0000

0.1000 0.2000 0.3000

0.4000 0.5000 0.6000

0.7000 0.8000 0.9000

Vi ser at begge matrisene er nå lagret i A. Det er ikke hjelp i å f.eks skrive : > load abmatr.txt A Dette gir oss en matrise abmatr med samme innhold som A ovenfor. For filer som er lagret med save og ascii-opsjon, blir det ikke holdt rede på de enkelte variable som er lagret. Vi må lese inn hele fila og deretter plukke ut de variable vi ønsker. Dette er i motsetning til binærfiler der det blir holdt rede på de enkelte variable. La oss gjenta eksemplet ovenfor, men nå som binær-fil. save abmatr.mat A B

59

>> clear A B

>> load abmatr.mat

>> A

A =

1 2 3

4 5 6

7 8 9

>> B

B = 0.1000 0.2000 0.3000

0.4000 0.5000 0.6000

0.7000 0.8000 0.9000

>> Vi kan også laste inn bare en av matrisene: >> clear A B

>> load abmatr.mat B

>> B

B = 0.1000 0.2000 0.3000

0.4000 0.5000 0.6000

0.7000 0.8000 0.9000

>> A

??? Undefined function or variable 'A'.

Formattert inn- og utlesning Vi kan også skrive ut matrisa på formatert form dersom dette er ønskelig. Lager først en ny A-matrise : >> A = [1.11 2.22 3.33; 4.44 5.55 6.66; 7.77 8.88 9.99]

A =

1.1100 2.2200 3.3300

4.4400 5.5500 6.6600

7.7700 8.8800 9.9900

Anta at vi nå ønsker å lagre denne matrisa med bare ett siffer bak desimalpunktet. Utfører følgende setninger : fid = fopen('amatr.txt','wt');

fprintf(fid,'%10.1f \n',A);

fclose(fid);

(Bruk doc til å finne ut hva dette betyr) Matrisa A blir nå lagret kolonne for kolonne på fila amatr.txt på det ønskede format som en vektor. Vi kan lese A tilbake med f.eks. load : A = load('amatr.txt')

A =

1.1000

60

4.4000

7.8000

2.2000

5.5000

8.9000

3.3000

6.7000

10.0000

Vi får tilbake A som en 3 3 matrise ved : A =reshape(A,[3,3]) A =

1.1000 2.2000 3.3000

4.4000 5.5000 6.7000

7.8000 8.9000 10.0000

Inn- og utlesningsmulighetene i Matlab er omfattende og vi har bare skrapt litt på overflata. Se for eks. på kommandoene textread og textscan.

61

LOKALISERING AV HENDELSER La oss se på følgende enkle problem: En ball blir kastet loddrett oppover med hastighet 0 20m/sv = . Vi ønsker å finne hvor lang tid det tar før hastigheten v = 0 samt hvor lang tid det tar før ballen igjen er tilbake til utgangsposisjonen y = 0. Samtidig ønsker vi også å finne y og v som funksjon av tiden t. Begivenhetene y = 0 og v = 0 kalles en hendelse. (event). Den analytiske løsningen av dette problemet er innlysende når vi ser bort fra all luftmotstand. Alle ODE-løserene i Matlab er laget slik at spørsmålene ovenfor kan besvares med bare litt ekstra programmering. Problemet ovenfor er et spesialtilfelle av en sprettende ball. Det sistnevnte tilfellet er behandlet i Matlab-programmet ballode.m som ligger i demo-folderen under Matlab. (Prøv det!). Vi har rett og slett kuttet ut alle unødvendige programlinjer i ballode og sitter bare igjen med dem som trengs for å forstå fremgangsmåten. Problemet ovenfor beskrives av følgende diff.ligning :

9.81y = −

Skrevet som et ligningsystem :

(1)(2)

(2)9.81

dyy

dtdy

dt

=

= −

der y(1) er høyden y og y(2) er hastigheten v.

62

For bruk i Matlab kan vi skrive: function dydt = f(t,y)

dydt = zeros(size(y));

dydt(1) = y(2);

dydt(2) = - 9.81;

De to siste linjene kan også skrives : dydt = [y(2); -9.81]; Med funksjonen ovenfor kan vi integrere diff.ligningen, men for å bestemme nullpunktkryssningene trenger vi en funksjon til. Denne ser slik ut :

function [value,isterminal,direction] = events(t,y)

value = y;

isterminal = [1; 0];

direction = [-1; 0];

Navnene på argumentene og funksjonsnavnet kan velges fritt. La oss se på betydningen av argumentene. value er en vektor som inneholder de komponentene av løsningsvektoren som skal testes for null-verdier. I vårt tilfellet gjelder dette begge komponentene dvs.: både høyden y(1) og hastigheten y(2).

isterminal er en vektor som består av bare 0 og 1-enere. (Logisk vektor). 1 betyr at beregningen for den tilhørende komponenten skal stoppes når denne komponenten blir lik null. I vårt tilfelle skal vi stoppe når den første komponenten y(1), høyden, blir lik null. Derimot skal vi ikke stoppe når den andre komponenten y(2), hastigheten, blir lik 0. direction er en vektor som angir om de respektive stoppkomponentene øker eller minker når de stoppes. (Maksimum eller minimum). Mulige verdier er 1, -1 og 0. 1 betyr at komponenten øker , -1 at den minker og 0 at det er uten betydning. I vårt tilfelle minker høyden når ballen er på vei nedover mot nullpunktet. For hastigheten får vi samme verdi før og etter nullpunktet siden integrasjonen ikke stoppes. Vi har da fått to funksjoner som tilsammen tar vare på alle spørsmålene vi stilte. Det som står igjen , er å sette sammen disse to funksjonene som da kalles av ODE-løseren. Vi bruker ode45, men alle løserene har samme grensesnitt. I det kallende programmet har vi følgende setninger : options = odeset('Events', @events)

[t, y, te, ye, ie,] = ode45(@f,tint,y0,options) Den første setningen må være med for å fortelle programmet at vi ønsker å utføre den utvidede beregningen. Når denne opsjonen er satt, får vi tre nye resultat - variable te, ye og ie når vi bruker løseren. La oss se på betydningen av disse nye størrelsene.

63

te : En kolonne-vektor som inneholder tidene for når en hendelse inntreffer. ye : Linjene i ye gir løsningene for tilhørende tider i te. ie : Indeksene i vektoren ie spesifiserer hvilken hendelse som inntraff ved den gitte tiden i te. Det kallende programmet ballv1.m blir som vist nedenfor : function ballv1 % Throws a ball vertically up at t = 0 % with intitial velocity v = 20 m/s. tint = [0 10]; y0 = [0 ; 20]; options = odeset('Events',@events); % --- Compute until y = 0 for a second time [t,y,te,ye,ie] = ode45(@f,tint,y0,options); disp (' te ye(1) ye(2) ie '); disp(' --------------------------------------'); disp([te ye ie]); function dydt = f(t,y) dydt = zeros(size(y)); dydt(1) = y(2); dydt(2) = - 9.81; % ------------------------------------------------- function [value,isterminal,direction] = events(t,y) value = y; isterminal = [1; 0]; direction = [-1; 0]; % -------------------------------------------------

Ved å kjøre dette programmet, får vi følgende utskrift : te ye(1) ye(2) ie

--------------------------------------

2.0387 20.3874 -0.0000 2.0000

4.0775 -0.0000 -20.0000 1.0000

ie = 1 angir at det er en hendelse tilknyttet value(1) som er inntruffet, mens ie = 2 angir en hendelse tilknyttet value(2).Utskrifta sier at etter 2.0387s har ballen nådd sin maksimale høyde på 20.3874 m med hastigheten lik 0. Etter 4.0775s er høyden blitt lik 0 igjen og hastigheten er lik 20 m/s nedover. Anta at vi i tillegg ønsker å vite når ballen er 10m over bakken på vei nedover. Den eneste forandringen i programmet ovenfor er i funksjonen events som kan skrives som vist nedenfor. (Ligger i ballv2.m) function [value,isterminal,direction] = events(t,y)

value = zeros(3,1);

value(1) = y(1);

value(2) = y(2);

value(3) = y(1) - 10.0;

isterminal = [1; 0 ; 0];

direction = [-1; 0 ; -1];

Betingelsen y = 10 er satt i linja value(3) = y(1) - 10.0.

64

Dessuten angir vi retningen som negativ (ballen på vei nedover) ved å sette den tredje komponenten av direction som –1. Ved å kjøre ballv2.m, får vi følgende utskrift : te ye(1) ye(2) ie --------------------------------------

2.0387 20.3874 -0.0000 2.0000

3.4940 10.0000 -14.2759 3.0000

4.0775 -0.0000 -20.0000 1.0000

Utskrifta viser at etter 3.494 s er ballen 10 m over bakken på nedtur.

65

APPENDIKS

Math Symbols

±

×

\leftarrow

\rightarrow

\uparrow

\downarrow

\Leftarrow

\Rightarrow

\Leftrightarrow

\partial

\neq

\geq

\approx

\equiv

\cong

\pm

\nabla

\angle

\in

\subset

\cup

\cap

\perp

\infty

\int

\times

Greek Symbols

αβγδεκλμν

\alpha

\beta

\gamma

\delta

\epsilon

\kappa

\lambda

\mu

\nu

ωφπχψρστυ

\omega

\phi

\pi

\chi

\psi

\rho

\sigma

\tau

\upsilon

ΣΠΛΩΓ

\Sigma

\Pi

\Lambda

\Omega

\Gamma