Cvičení v matlabu

Týden 6

Řetězce

Řetězce neboli pole znaků, (anglicky character arrays nebo strings) jsou v podstatě vektory, které obsahují znaky anglické abecedy. Nedoporučuje se používat české znaky obsahující háčky nebo čárky, protože bývá problém s jejich správným zobrazováním.

Vytváření řetězců

Pro vytvoření řetězce slouží apostrofy, do kterých se vepíše obsah řetězce (například 'ahoj' nebo 'Toto je nejaky dlouhy text.'), přičemž takto vytvořený řetězec můžeme uložit do proměnné:
>> s1 = 'nejaky text';
>> nazev = 'Vypocetni technika 2'

Ve workspace se řetězec objeví jako proměnná typu char array (doposud jsme znali jen čísla - double array).

Poznámka: řetězce lze ukládat i do matic, ale je nutné, aby všechny řádky (= řetězce) měly stejnou délku! Doplňuje se většinou mezerami, tedy:
>> jmena=['Ivan '; 'Jana '; 'Ludva'; 'Eva '; 'Pepa '];

Výpis řetězců

Pokud máme řetězec uložený v nějaké proměnné, můžeme jej vypsat úplně stejným způsobem jako obsah kterékoli číselné proměnné, tedy zadáním jména proměnné (například >> s1).

Existují také funkce, které vypisují zadaný řetězec, a to funkce disp(p1), která má jeden parametr (je označen jako p1). Parametrem může být text nebo název proměnné:
>> disp('ahoj')
>> disp(s1)

a funkce error(p1), jejímž parametrem je chybové hlášení (vypisuje se červeně). Tato funkce navíc ukončuje provádění aktuálního příkazu (proto se používá uvnitř funkcí a skriptů).

Poznámka: práce s řetězci
Jelikož je řetězec vektor složený ze znaků, můžeme s ním pracovat znak po znaku. Jinou možností je využít knihovních funkcí MATLABu, které nabízejí porovnávání řetězců (např. funkce strcmp), převod na velká nebo malá písmena (upper a lower), konverze řetězců na čísla a naopak (např. str2num a num2str),... Více se můžete dozvědět z nápovědy k jednotlivým funkcím - jejich přehled získáte příkazem >> help strfun.



Podmíněný příkaz (větvení)

Občas potřebujeme, aby se určité příkazy vykonaly jen a pouze v případě, kdy je splněna nějaká podmínka. Bylo by tedy dobré znát nějaký příkaz, který umožňuje podmínku vyhodnotit (otestovat), a podle její pravdivosti pak vykoná (nebo nevykoná) zadanou množinu příkazů. V MATLABu máme k dispozici příkaz if. Jeho základní syntaxe je:

if podmínka
   příkazy
end

Příkaz začíná klíčovým slovem if, za nímž následuje podmínka - to je libovolný výraz s logickou hodnotou 0 nebo 1 (většinou se v podmínkách používají relační nebo binární logické operátory). Uvnitř ifu jsou jakékoli příkazy, které se mají provádět v případě splnění podmínky. Protože příkazů uvnitř ifu může být více, tak za posledním z nich musíme uvést klíčové slovo end, které označuje konec celého příkazu.

Činnost příkazu if: nejprve se testuje podmínka (tj. vypočítá se hodnota výrazu) a v případě, že podmínka platí (je pravdivá; tj. výraz má logickou hodnotu 1, neboli je nenulový), jsou provedeny příkazy uvnitř ifu. V opačném případě, kdy podmínka neplatí (není splněna, tj. výraz má logickou hodnotu 0, tj.je nulový), příkazy uvnitř ifu jsou ignorovány a pokračuje se až za koncem příkazu if (pokud jsou za ním nějaké další příkazy). Činnost příkazu demonstruje vývojový diagram:

if podmínka
   příkazy
end

Poznámky:

  • V případě, že součástí podmínky je matice typu mxn, je podmínka pravdivá jen tehdy, pokud je pravdivá pro všechny prvky této matice.
  • V případě, že v nějaké podmínce použijeme binární logický operátor (& nebo |) a po vyhodnocení prvního argumentu je už zřejmý výsledek (kdy se to může stát?), tak se druhý argument nevyhodnocuje. Tato vlastnost se nazývá zkrácené vyhodnocování.
  • Jednotlivé příkazy if se mohou vnořovat, tj. uvnitř ifu může být další příkaz if.

  • Příklad 1 - chtěli bychom vypsat gratulaci jen v tom případě, kdy žák bude mít jedničku. Vyzkoušíme si to nejprve pro trojku, tedy v Command Window zadáváme:
    >> znamka=3;
    >> if znamka==1
    zprava='Gratuluji! Lepsi to byt nemohlo!'
    end

    Všimněte si:
    - po zadání části příkazu if MATLAB čeká na jeho dokončení (nevypisují se znaky >>)
    - protože proměnná znamka neobsahovala číslo 1, tak podmínka neplatí - proto se proměnná zprava nevytvořila.
    Nevýhoda:
    pokud bychom chtěli vyzkoušet stejný příkaz pro jinou známku, musíme všechno napsat znovu, přičemž první příkaz opravíme na >> znamka=1;. Je vidět, že práce v Command Window se v případě složených příkazů stává neefektivní. Máme sice možnost napsat celý if na jeden řádek (příkazy od sebe musíme oddělit - čárkou nebo středníkem), ale tím si celou situaci znepřehledníme:
    >> znamka=1; if znamka==1; zprava='Gratuluji! Lepsi to byt nemohlo!', end
    Proto se v dnešní lekci naučíme vytvářet skripty (soubory s posloupností příkazů) a funkce (soubory se specifickou strukturou, které mohou zpracovávat vstupní parametry). Následující příklady budou psány tak, jako kdyby se vyskytovaly uvnitř skriptu nebo funkce.


    Příklad 2 - v případě, že proměnná a je menší než pět, vypíšeme zprávu, jinak se nic neprovede:

    if a < 5
       disp('cislo 'a' je mensi nez 5')
    end
    


    Pro případ, kdy potřebujeme provést nějaké příkazy v případě platnosti podmínky, ale jiné příkazy v případě její neplatnosti, můžeme použít větev else:

    if podmínka1
       příkazy1
    else
       příkazy2
    end
    
    Činnost příkazu if-else: nejprve se testuje podmínka - je-li pravdivá, provedou se příkazy1, je-li nepravdivá, provedou se příkazy2. Vždycky se tedy provede jedna skupina příkazů.


    Příklad 3 - v případě, že proměnná a je menší než pět, vypíšeme zprávu " a="" je="" mensi",="" jinak="" se="" vypise="" "a="" vetsi="" nebo="" rovno":

    if a < 5
       disp('cislo 'a' je mensi nez 5')
    else
       disp('cislo 'a' je vetsi nebo rovno 5')
    end
    


    Z příkladu 3 je vidět, že někdy by bylo vhodné v případě neplatnosti podmínky testovat také jiné možnosti. Ke splnění tohoto cíle stačí vnořit další příkaz if do větve else, ale existuje pohodlnější prostředek - rozšířená syntaxe příkazu if:

    if podmínka1
       příkazy1
    elseif podmínka2
       příkazy2
    else
       příkazy3
    end
    
         
    • větev if musí být právě jedna
    • větev elseif nemusí být vůbec, případně jich může být více
    • větev else může být nanejvýš jedna
    Činnost příkazu if obecně: nejprve se testuje pravdivost podmínky1. Pokud platí, provedou se příkazy1 a ostatní větve příkazu jsou ignorovány. Pokud podmínka1 neplatila, začne se testovat podmínka2 - když platí, provedou se příkazy2 a zbylé větve jsou ignorovány; neplatí-li, pokračuje se další větví elseif (je-li ještě nějaká)... V případě, že ani jedna z podmínek neplatila, jsou provedeny příkazy ve větvi else (je-li přítomna).
    Činnost příkazu demonstruje vývojový diagram:
    činnost></center><p></p><p><b>Příklad 4</b><span> </span>- chceme rozhodovat o poloze hodnoty proměnné<span> </span><code>a</code><span> </span>vzhledem k číslu 5:<br></p><pre>if a < 8
   disp('a je mensi nez 5')
elseif a > 8
   disp('a je vetsi nez 5')
elseif a == 8
   disp('a je rovno 5')
else
   error('Nedefinovaná situace!')
end
</pre><p></p><br><a name=

    M-soubory

    M-soubory slouží k ukládání posloupností příkazů (skripty) nebo k ukládání uživatelských funkcí (funkce).

    Poznámka: M-soubory jsou obyčejné textové soubory, a proto je lze psát i v libovolném textovém editoru. Z důvodu vyššího komfortu (zvýraznění syntaxe, možnost krokování) je však součástí MATLABu také M-editor/Debugger, který se otevírá v samostatném okně po otevření nebo vytvoření M-souboru (skriptu či funkce).

    M-editor

    M-editor/Debugger je spuštěn v samostatném okně po otevření (File--Open) nebo vytvoření (File--New--M-file) M-souboru. Slouží k pohodlné editaci M-souborů. Navíc umožňuje krokovat obsah M-souborů (tj. kontrolovat provádění jejich jednotlivých příkazů).

    M-editor/Debugger
    Obr.1: okno M-editoru

    Skripty

    Skript je posloupnost příkazů uložených do souboru. Každý skript pracuje s proměnnými pracovního prostředí, takže může vytvářet nové nebo mazat či měnit vybrané. Výsledky skriptu tedy zůstávají v pracovním prostředí i po jeho skončení. Skripty samozřejmě mohou volat jiné skripty nebo funkce, vytvářet grafická okna, vypisovat do Command Window,...

    Poznámka: V době psaní skriptu se jeho příkazy samozřejmě neprovádějí - k tomu potřebujeme spustit skript v Command Window (viz Spuštění skriptu).

    Vytvoření skriptu

    1. Nejprve si v MATLABu nastavíme pracovní adresář (na lokálním disku).
    2. Vytvoření nového nebo otevření existujícího skriptu
      M-soubor, který bude obsahovat skript, vytvoříme například pomocí menu File--New--M-file, čímž se také otevře okno M-editoru/Debuggeru. Pokud chceme opravit již existující skript, musíme jej otevřít (například pomocí menu File--Open).
    3. Zápis skriptu
      Do prázdného M-souboru zapíšeme všechny příkazy, které má skript provést - příkazy píšeme stejně jako v Command Window, jen s tím rozdílem, že se po napsání neprovádějí. Takto vytvoříme kód skriptu (posloupnost příkazů).
    4. Uložení skriptu
      Máme-li napsaný kód skriptu, musíme celý M-soubor uložit pod nějakým jménem na disk (do pracovního adresáře). Uložení provedeme pomocí menu File--Save, kde zkontrolujeme pracovní adresář a zadáme jméno skriptu:
      jméno skriptu musí splňovat stejná pravidla jako název proměnné, přestože se jedná o jméno souboru. Je to z toho důvodu, aby MATLAB mohl skript spustit (viz níže). Jméno M-souboru se skriptem tedy může obsahovat POUZE písmena anglické abecedy, podtržítko a číslice (číslicí nesmí začínat)!!!

    Spuštění skriptu

    Spuštění skriptu dává MATLABu pokyn k vykonání jeho příkazů. Před spuštěním musí být skript uložen! Skript můžeme spustit buď

    1. v Command Window - stačí zadat jméno M-souboru bez přípony (>> jméno, tj. skript graf1.m spustíme příkazem >> graf1), anebo
    2. v M-editoru/Debuggeru pomocí menu Debug--Run (klávesa F5).

    Příklad - vytvoříme skript parabola.m, který kreslí graf funkce x2:

    parabola.m
    % GRAF1 - vykresleni paraboly
    x = -3:0.1:3; % vektor hodnot z intervalu [-3;3] s krokem 0,1
    y = x.^2; % zavisle promenna
    plot(x,y) % graf (parabola)
    ...uložíme jej a spustíme příkazem
    >> parabola
    ...pokud je vše v pořádku, objeví se okno s grafem. V opačném případě musíme najít a opravit chybu, uložit soubor a znovu jej spustit.


    Zobrazení obsahu skriptu v Command Window

    Obsah skriptu (M-souboru) vidíme v M-editoru/Debuggeru, ale můžeme jej zobrazit také v Command Window příkazem >> type název, kde název je jméno skriptu (název M-souboru bez přípony).


    Uživatelské funkce

    Máme-li používat jeden určitý postup (algoritmus) pro vícero různých situací (např. pro různé hodnoty proměnných), není zrovna praktické používat skripty, neboť pokaždé musíme opravit hodnoty proměnných ve skriptu, uložit příslušný M-soubor a skript spustit. Řešení nabízejí funkce.

    Funkce jsou M-soubory, které mají přesně definovanou strukturu (viz Vytvoření funkce). Funkce akceptují vstupní parametry, které mohou mít při každém spuštění jinou hodnotu.

    Každá funkce má své vlastní pracovní prostředí, které je odděleno od pracovního prostředí Command Window. Všechny proměnné ve funkci jsou lokální (existují jen po dobu spuštění funkce)! To znamená, že:

    • nemůžeme použít žádné jiné proměnné než ty, které funkci předáváme (pomocí vstupních parametrů), nebo ty, které si funkce sama vytvoří,
    • všechny proměnné (i ty, které obsahují vypočtené výsledky) po skončení funkce zaniknou.
    Naštěstí existuje způsob, kterým funkce může své výsledky předat "ven": výstupní proměnné. Počet vstupních i výstupních parametrů funkce se určuje při jejím vytváření. Pokud funkce nemá žádné vstupní parametry, můžeme její příkazy napsat také jako skript.

    Vytvoření funkce

    1. Nejprve si v MATLABu nastavíme pracovní adresář (na lokálním disku).
    2. Otevření M-souboru
      Funkce je M-soubor, a proto si nejprve musíme otevřít nový soubor: například pomocí menu File--New--M-file. Tím se otevře okno M-editoru/Debuggeru s prázdným souborem.
      Poznámka: pokud chceme nějakou existující funkci opravit, použijeme menu File--Open.
    3. Zápis funkce (struktura M-souboru obsahujícího funkci)
      První řádek obsahuje definici funkce, po něm mohou následovat řádky s nápovědou k funkci (komentáře) a zbytek souboru tvoří příkazy (kód funkce, algoritmus) potřebné k výpočtu výstupů funkce za použití jejích vstupů.
      • Definice funkce

        tvoří první řádek M-souboru. Má tvar:
        function[výstupy]=jmeno_funkce(vstupy)
        ||||
        klíčové slovovýstupy
        funkce
        název
        funkce
        vstupní
        parametry
        funkce
        výstupy:
        • je-li jich víc, oddělují se čárkou
        • je-li jen jeden, závorky nejsou nutné
        • funkce nemusí mít žádný výstup
        jmeno_funkce:
        • název funkce by měl vystihovat její činnost
        • musí splnit pravidla pro název proměnné, jinak se funkci nepodaří spustit!
        • název funkce se nesmí shodovat s žádným názvem její proměnné!
        vstupy:
        • je-li jich víc, oddělují se čárkou
        • funkce nemusí mít žádný vstup (pak se podobá skriptu, ale má své lokální workspace!)

        Příklady definic funkcí:
        function [s]=soucet(a,b) - funkce s jedním výstupem a dvěma vstupy
        function[podil,zbytek]=deleni(delenec,delitel) - funkce se dvěma vstupy i výstupy
        function f=faktorial(n) - funkce s jedním výstupem i vstupem
        function graf(x,y) - funkce bez výstupu, s jedním vstupem

      • Nápověda k funkci

        není povinnou součástí funkce, ale měla by být vytvořena, protože usnadňuje používání dané funkce. Nápověda k funkci začíná druhým řádkem, pokud je tento řádek komentářem. Nápověda k funkci končí jakýmkoli řádkem, který již není komentářem (tj. i třeba prázdným řádkem).
        Pokud je v M-souboru funkce obsažena nápověda, zobrazíme ji příkazem >> help jméno_funkce, stejně jako nápovědu ke knihovním funkcím MATLABu.

        První řádek nápovědy (anglicky zvaný H1 line) by měl obsahovat jméno funkce a vystihovat její činnost, protože je vypisován příkazem >> lookfor slovo (slouží pro výpis všech funkcí obsahujících dané slovo) nebo při výpisu nápovědy k funkcím nějakého adresáře >> help adresář (například >> help C:\temp\matlab).
        Další řádky nápovědy by měly obsahovat popis vstupů a výstupů funkce a také příklad jejího použití (volání).
      • Kód funkce

        (algoritmus; příkazy) začíná hned za nápovědou a obsahuje posloupnost příkazů, pomocí nichž funkce vypočítá své výstupy. Všechny výstupy funkce musí být jejím kódem vytvořeny, jinak je po spuštění funkce ohlášena chyba! Všechny přiřazovací příkazy unvitř funkce by měly být ukončeny středníkem (aby funkce neobtěžovala okolí výpisem pomocných proměnných).
        Poznámky:
        • pro výpis chyby a ukončení funkce lze použít funkci error, jejímž parametrem je text chybového hlášení (např. error('Chyba: mnoho vstupních parametrů!'))
        • kromě vytvoření nápovědy k funkci je vhodné používat také komentáře v kódu funkce (u jednotlivých příkazů), protože až funkci ukážete kolegům nebo ji budete studovat za půl roku, už si nevzpomenete, co znamenal "tenhle divnej řádek"
          "Program bez komentářů je jako velbloud bez hrbů - nedá se na něj dlouho dívat."
        • pro složité problémy je vhodné použít rozklad problému na podproblémy - složitou funkci rozdělíme na několik jednoduchých, které se vzájemně volají


        Příklad 1: funkce, která vypočítá součet dvou čísel:
        function [s]=soucet(a,b)
        % SOUCET - soucet dvou cisel
        % s=soucet(a,b)
        % a,b ... scitance
        % s ... vysledek (soucet)
        % priklad volani: s=soucet(10,-2.5)

        s = a+b;
        Všimněte si:
        - nápověda k funkci obsahuje vše potřebné pro správné použití funkce
        - kód funkce zabere sice jen jediný řádek, ale to k vypočítání výstupu s stačí
        - přiřazovací příkaz uvnitř funkce je ukončen středníkem, aby funkce neobtěžovala okolí svými pomocnými výpočty

        Příklad 2: funkce, která vypočítá délku přepony pravoúhlého trojúhelníku. Funkce obsahuje jen minimální nápovědu:
        function [prep]=prepona(odvesna1,odvesna2)
        % PREPONA - vypocet prepony pravouhleho trojuhelniku
        prep = (odvesna1^2 + odvesna2^2)^(1/2); % pouziti Pythagorovy vety
    4. Uložení funkce
      Napsanou funkci musíme uložit disk jako M-soubor. Použijeme např. menu File--Save, kde:
      • zkontrolujeme pracovní adresář
      • jako název souboru zadáme jméno funkce, protože název M-souboru se musí shodovat s názvem dané funkce, jinak by funkce nešla spustit!

      zatím border=
      Obr. 2: zatím neuložená funkce v M-editoru
      uložená border=
      Obr. 3: uložená funkce v M-editoru

      Všimněte si: po uložení M-souboru zmizí hvězdička za jeho názvem v titulkovém pruhu okna M-editoru/Debuggeru.

    Spuštění funkce

    Pokud jsme vytvořili vlastní funkci, můžeme ji spustit z Command Window (anebo z jiných funkcí či skriptů). Příkaz pro spuštění funkce vypadá obecně takto:
    >> [vystupy]=jmenofce(vstupy), pokud chceme uložit výsledky do nějakých proměnných (na konci lze uvést středník, aby se výsledky nevypisovaly), nebo takto:
    >> jmenofce(vstupy), pokud nechceme výsledky ukládat do proměnných.

    Poznámky:

    • počet vstupních argumentů se musí shodovat s její definicí (výjimkou jsou funkce obsahující nargin)
    • pořadí vstupních argumentů při volání je zavazující - jsou zpracovávány v pořadí daném definicí funkce
    • výstupy z funkce nejsme povinni odebírat (pokud nenapíšeme za voláním funkce středník, první z výstupů se vypíše pomocí ans)
    • pokud odebíráme výstupy funkce, měl by být dodržen jejich počet (funkce obsahující nargout mohou vracet různé výsledky v závislosti na počtu právě odebíraných výstupů)
    • neznáme-li počet vstupů ani výstupů, necháme si zobrazit nápovědu k funkci (>> help jmenofce)
    • pokud je po spuštění funkce hlášena chyba, ověřte:
      - je správně zadáno jméno funkce?
      - souhlasí počet vstupních parametrů?
      - je funkce uložena? (pokud jsme ji opravovali)
      - jsme ve správném pracovním adresáři?
      Poznámka: někdy pomůže k odstranění "divné" chyby smazání všech proměnných i funkcí z pracovního prostředí (>> clear all)
    • pokud není po spuštění funkce hlášena chyba, ale funkce nevrací správné výsledky, musíme krokovat

    Příklady:
    >> s=soucet(7,14);   s odebráním výstupu a bez jeho výpisu
    >> vysledek=soucet(7,14)   s odebráním výstupu i jeho vypsáním
    >> x=7; y=14; soucet(x,y)   bez odebrání výstupu, ale vypsáním výsledku (pomocí ans)
    >> soucet(3.1,8.14)   bez odebrání výstupu, bez vypsání výsledku (v podstatě zbytečná akce)

    Zobrazení nápovědy k funkci

    Pokud chceme vědět, jak funkci spustit nebo jak pracuje (a funkce byla vyvtořena s nápovědou), můžeme použít příkaz >> help jmenofce, kde jmenofce je název M-souboru bez přípony.
    Jinou možností je pak napsat jméno funkce (v Command Window nebo v M-editoru/Debuggeru), označit ho (třeba dvojklikem myši) a pomocí pravého tlačítka myši zobrazit kontextové menu, kde zvolíme položku "Help on selection" (otevře se Help Browser s nápovědou k funkci; tato nápověda vypadá u knihovních funkcí lépe než při použití příkazu help).

    Zobrazení kódu funkce

    Kód funkce (tj. obsah M-souboru) vidíme v M-editoru/Debuggeru, ale můžeme jej zobrazit také v Command Window příkazem >> type jmenofce, kde jmenofce je název funkce (název M-souboru bez přípony).


    Zjišťování počtu skutečných vstupních a výstupních argumentů

    Pokud chceme, aby naše funkce reagovala na různý počet vstupních parametrů, můžeme v jejím kódu použít nargin. Funkce nargin nemá žádné vstupy, ale vrací skutečný počet parametrů, s nimiž byla funkce spuštěna. Pokud tedy někdo zavolá naši funkci s menším počtem vstupních argumentů, můžeme je zpracovat jinak než v případě plného počtu vstupů.
    Pozor: pořadí vstupních parametrů v definici funkce je zavazující (tedy pokud si myslíme, že vynecháme druhý ze čtyř vstupů, funkce to pochopí tak, že jsme vynechali ten čtvrtý!).

    Pro zjištění skutečného počtu výstupních parametrů máme funkci nargout. Pracuje se s ní podobně jako s funkcí nargin.

    Příklad - vylepšíme funkci soucet, aby sama hlásila chybu, když ji někdo zavolá pro méně než dva parametry:

    soucet.m
    function [s]=soucet(a,b)
    % SOUCET - soucet dvou cisel
    % s=soucet(a,b)
    % a,b ... scitance
    % s ... vysledek (soucet)
    % priklad volani: s=soucet(10,-2.5)
    if nargin~=2 % nespravny pocet vstupu?
       error('CHYBA: k vypoctu potrebuji DVA vstupy!') % vypis chyby a konec funkce
    end % konec if
    s = a+b; % vypocet vysledku
    

    Krokování (ladění) funkcí/skriptů

    Pokud jsou ve funkci chyby (např. nedává správné výsledky) a nemůžeme jejich příčinu najít pouhým přečtením jejího kódu, použijeme Debugger ("odvšivovač"), který nám nabízí možnost krokování:

    • v M-editoru nastavíme breakpoint (F12) na nějakém řádku s příkazem
    • spustíme funkci s jejími parametry (z Command window) - v Command Window se objeví K>> a v M-editoru svítí zelená šipka před řádkem, který bude následně zpracován
    • pomocí F10 a F11 v M-editoru krokujeme (spouštíme jednotlivé příkazy) - výsledky kontrolujeme pomocí myši (pohyb nad názvem proměnné, jejíž obsah nás zajímá) nebo pomocí okna Workspace (kde by měl být nastaven Stack pro krokovanou funkci)
    • výsledkem celého snažení je nalezení chyby, její oprava a uložení opravené funkce

    Hesla semestru:

    • Kdo nekrokuje s námi, krokuje proti sobě.
    • Pokud funkce musí fungovat, ale přesto nefunguje, krokuj.
    • Pokud funkce vypadá jako zcela nefunkční, ale přesto funguje, krokuj.

    krokování><br>Obr. 4: krokování funkce</center><br class=