《MATLAB基礎與編程入門》課件第4章_第1頁
《MATLAB基礎與編程入門》課件第4章_第2頁
《MATLAB基礎與編程入門》課件第4章_第3頁
《MATLAB基礎與編程入門》課件第4章_第4頁
《MATLAB基礎與編程入門》課件第4章_第5頁
已閱讀5頁,還剩147頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第四章MATLAB編程基礎4.1概述4.2腳本文件4.3流程控制4.4函數文件4.5M文件調試4.6M文件性能分析4.7本章小結4.1概述MATLAB提供了完整的編寫應用程序的能力,這種能力通過一種被稱為M語言的高級語言來實現。這種編程語言是一種解釋性語言,利用該語言編寫的代碼僅能被MATLAB接受,被MATLAB解釋、執(zhí)行。其實,一個M語言文件就是由若干MATLAB的命令組合在一起構成的,這些命令都是在前面章節(jié)中介紹的合法的MATLAB命令。和C語言類似,M語言文件都是標準的純文本格式的文件,其文件的擴展名為.m。

使用M文件最直接的好處就是可以將一組MATLAB命令組合起來,通過一個簡單的指令就可以執(zhí)行這些命令。這些命令可以完成某些MATLAB的操作,也可以實現某個具體的算法。其實,MATLAB產品族中包含的工具箱就是由世界上在相應專業(yè)領域內的頂尖高手,利用M語言開發(fā)的算法函數文件集合。讀者也可以結合自己工作的需要,為自己的MATLAB開發(fā)具體的算法和工具箱。

MATLAB的函數主要有兩類,一類被稱為內建(Build-in)函數,這類函數是由MATLAB的內核提供的,能夠完成基本的運算,例如三角函數、矩陣運算的函數等。另外一類函數就是利用高級語言開發(fā)的函數文件,這里的函數文件既包括用C語言開發(fā)的MEX函數文件,又包含了M函數文件。有關MEX函數文件的內容已經超出了本書的內容,將在《MATLAB外部編程接口》一書中詳細講述。

如前所述,MATLAB的M語言文件是純文本格式的文件,利用任何一種純文本編輯器都可以編寫相應的文件,例如Windows平臺下的記事本、UltraEdit等軟件,或者Unix平臺下的Emacs軟件等。同樣,為了方便編輯M文件,MATLAB也提供了一個編輯器,叫作meditor,它也是系統(tǒng)默認的M文件編輯器。運行meditor的方法非常簡單,在MATLAB命令行窗口中鍵入下面的指令就可以打開meditor:

>>edit

這時MATLAB將啟動meditor,然后創(chuàng)建一個未命名的空白文件,如圖4-1所示。圖4-1meditor的運行界面

這時用戶就可以直接在編輯器中鍵入MATLAB指令,開發(fā)M語言文件了。此外,運行meditor還可以通過“File”菜單中“New”子菜單下的“M-File”命令來實現,或者直接單擊MATLAB用戶界面工具欄上的新建按鈕完成同樣的工作。

M語言文件可以分為兩類,其中一類是腳本文件,另外一類叫作函數文件。本章將分別介紹這兩類文件的編寫方法。4.2腳本文件

腳本文件是最簡單的一種M語言文件,在本章前面章節(jié)的例子中都使用了腳本文件。所謂腳本文件,就是由一系列的MATLAB指令和命令組成的純文本格式的M文件,執(zhí)行腳本文件時,文件中的指令或者命令按照出現在腳本文件中的順序依次執(zhí)行。腳本文件沒有輸入參數,也沒有輸出參數,執(zhí)行起來就像早期的DOS操作系統(tǒng)的批處理文件一樣,而腳本文件處理的數據或者變量必須在MATLAB的公共工作空間中。[例子4-1]

腳本文件示例。001 %注釋行002 %M腳本文件示例003 %"flowerpetal"004 %以下為代碼行005 %計算006 theta=-pi:0.01:pi;007 rho(1,:)=2*sin(5*theta).^2;008 rho(2,:)=cos(10*theta).^3;009 rho(3,:)=sin(theta).^2;010 rho(4,:)=5*cos(3.5*theta).^3;011 fork=1:4012 %圖形輸出013 subplot(2,2,k)014 polar(theta,rho(k,:))015 end016 disp('程序運行結束!')在MATLAB命令行中運行該腳本文件:>>script_example程序運行結束!圖4-2例子4-1腳本文件的運行結果

仔細察看例子4-1的腳本文件,在腳本文件中,主要由注釋行和代碼行組成。M文件的注釋行需要使用%定義符,在%之后的所有文本都認為是注釋文本,不過,M文件的注釋定義符僅能影響一行代碼,類似于C++語言中的“//”。然而在M語言中,沒有類似C語言的注釋定義符“/*”和“*/”,所以無法一次定義多行注釋。給程序添加適當的注釋是良好的編程習慣,希望讀者能夠在日常編程中多多使用。

腳本文件中的代碼行都是一些簡單的MATLAB指令或者命令,這些命令可以用來完成相應的計算處理數據、繪制圖形結果的操作,也可以在腳本文件中調用其他的函數完成復雜的數學運算,在例子4-1中就完成了這些工作。另外,在MATLAB中還有一些指令用來處理程序和用戶之間的交互,在表4-1中進行了總結。表4-1腳本文件中常用的MATLAB指令MATLAB一般使用腳本文件作為某種批處理文件,其中,有兩個批處理文件經常被MATLAB自動調用,這兩個腳本文件分別為startup.m和finish.m。

startup.m文件在MATLAB啟動時自動被執(zhí)行,用戶可以自己創(chuàng)建并定義編寫該文件,例如在文件中添加物理常量的定義、系統(tǒng)變量的設置或者MATLAB搜索路徑的設置。當用戶安裝MATLAB之后,在<MATLABROOT>\toolbox\local路徑下有一個M文件,名為Starupsav.m,該文件可以看作是startup.m文件的模板,可以修改該文件,然后將其以文件名startup.m的形式保存在<MATLABROOT>\toolbox\local路徑下。

與startup.m文件相對應的是finish.m文件,該文件在MATLAB退出時自動執(zhí)行,用戶可以自己創(chuàng)建并定義編寫該文件,例如在文件中添加保存數據等指令,這樣可以將每次退出前的工作結果進行保留。同樣,在<MATLABROOT>\toolbox\local路徑下有兩個文件,分別為finishsav.m和finishdlg.m,這兩個文件可以用來作為finish.m文件的模板,相關的具體內容介紹請讀者自己察看相應的文件和幫助文檔。4.3流程控制4.3.1選擇結構如前所述,當人們判斷某一條件是否滿足,根據判斷的結果來選擇不同的解決問題的方法時,就需要使用選擇結構。和C語言類似,MATLAB的條件判斷可以使用if語句或者switch語句。1.if語句if語句的基本語法結構有三種,分別如下:(1)if(關系運算表達式) MATLAB語句end

這種形式的選擇結構表示,當關系運算表達式計算的結果為邏輯真的時候,執(zhí)行MATLAB語句,這里的MATLAB語句可以是一個MATLAB表達式,也可以是多個MATLAB表達式。在MATLAB語句的結尾處,必須有關鍵字end。if(關系運算表達式) MATLAB語句Aelse MATLAB語句Bend

這種選擇結構表示,當關系運算表達式的計算結果為邏輯真的時候,執(zhí)行MATLAB語句A,否則執(zhí)行MATLAB語句B,在語句B的結尾必須具有關鍵字end。if(關系運算表達式a) MATLAB語句Aelseif(關系運算表達式b) MATLAB語句Belse(關系運算表達式c)

end

這種選擇結構可以判斷多條關系運算表達式的計算結果,然后按照執(zhí)行的邏輯關系執(zhí)行相應的語句。讀者可以根據類似的C語言知識或者前面兩種選擇結構的介紹判斷這種結構的執(zhí)行方式?!璠例子4-2]if語句的使用——if_examp.m。讀者通過本例子將同時了解meditor的基本使用方法。打開meditor,然后鍵入下面的指令:001 clearall002003 I=1;004 J=2;005006 ifI==J007 A(I,J)=2;008 elseifabs(I-J)==1009 A(I,J)=?1;010 else011 A(I,J)=0;012 end

注意:在鍵入程序時,不要將行號(001~012)也敲進去,在這里設置行號的主要目的是為了便于講解和分析程序。在MATLAB的M語言編輯器中進行文本編輯時,編輯器的最左側就是當前文件的行號,如圖4-3所示。

圖4-3編輯M語言時左側的文件行號

細心的讀者可能已經發(fā)現,在M語言編輯器的最右側的一欄中有一些特殊色彩的標識,默認情況下(如圖4-1)該標識(方塊)為綠色,而在圖4-3所示的編輯器中是桔黃色,同時在相應的代碼下會有桔黃色的波浪線,這是新版MATLAB中M語言編輯器針對正在編輯的M文件進行分析的結果,表示當前的代碼可能存在一些潛在的錯誤,把鼠標放置在桔黃色的方塊或者橫線上,可獲取相應的警告信息。如果單擊桔黃色橫線,則M語言編輯器光標會自動跳轉到出現問題的代碼處,如圖4-4所示。

圖4-4顯示的警告信息

運行例子4-2的方法和效果如下:>>if_exampA=0-1

例子4-2代碼的核心是006~012行的部分,這部分展示了if-elseif-else-end語句組合的使用方法。請讀者仔細察看,并且通過修改程序003和004行中對I和J的賦值來察看整個語句的執(zhí)行情況。和C語言類似,if-elseif-else的語句結構也可以嵌套地使用,也就是可以存在這樣的語句結構:if(關系表達式a) if(關系表達式b)MATLAB語句A elseMATLAB語句B endelse if(關系表達式c)MATLAB語句C elseMATLAB語句D endend注意:在使用嵌套的選擇結構時,需要小心if語句和end關鍵字的配對。[例子4-3]

嵌套使用的if結構——if_examp2.m。001 clearall002 003 if1004 disp('Is1')005 else006 disp('Not1')007 end008009 I=1;010 ifI011 ifI<2012 disp('Iisbiggerthan0butlessthan2')013 end014 else015 ifI>-2016 dis('Iislessthan0butbiggerthan-2')017 end018 end該程序的運行方法和效果如下:>>if_examp2Is1Iisbiggerthan0butlessthan2

在例子4-3中,主要說明了嵌套的if結構和在關系表達式中使用常量的方法。在代碼的003行,if語句的關系表達式為常數1,這個時候if語句將始終認為非零值為邏輯真,所以,程序執(zhí)行了004行的代碼。同樣,在程序的009行,if語句的關系表達式為變量I,若I的數值為非零值,則if語句判斷其為邏輯真,所以,代碼的016行只有在I為0時,才可能被執(zhí)行。2.switch語句另外一種構成選擇結構的關鍵字就是switch。在處理實際問題的時候,往往要處理多個分支,這時如果使用if-else語句處理多分支結構往往使程序變得十分冗長,從而降低了程序的可讀性。switch語句就可以用于處理這種多分支的選擇,它的基本語法結構如下:switch(表達式) case常量表達式a:語句A case常量表達式b:語句B

case常量表達式m:語句M otherwise常量表達式n:語句Nend…

在switch語句之后的表達式可以是一個數值類型表達式或者是一個數值類型的變量,當這個表達式的值同case后面的某一個常量表達式相等時,則執(zhí)行該case后面的常量表達式后面的語句。注意:

MATLAB的switch和C語言的switch語句結構不同。在C語言中,每一個case后面的語句中必須包含類似break語句的流程控制語句,否則程序會依次執(zhí)行符合條件的case語句后面的每一個case分支。但是在MATLAB中就不必如此,程序僅僅執(zhí)行符合條件的case分支。例子4-4switch結構使用示例——switch_examp.m。001 clearall002 003 algorithm=input('Enteranalgorithminquotes(ode23,ode15s,etc:)');004 005 switchalgorithm006 case'ode23'007 str='2nd/3rdorder';008 case{'ode15s','ode23s'}009 str='stiffsystem';010 otherwise011 str='otheralgorithm';012 end013 disp(str);該文件的運行方法和效果如下:>>switch_exampEnteranalgorithminquotes(ode23,ode15s,etc:)'ode23'2nd/3rdorder>>switch_exampEnteranalgorithminquotes(ode23,ode15s,etc:)'ode4'otheralgorithm

例子4-3中需要用戶在執(zhí)行程序的過程中輸入一個字符串,switch語句根據用戶的輸入判斷執(zhí)行相應的case分支。若沒有符合條件的case分支,則switch執(zhí)行otherwise后面的語句。若switch結構中沒有定義otherwise及其相應的代碼,則程序不會進行任何操作,而是直接退出switch結構。提示:在處理以字符串變量或者常量參與的關系判斷操作時,使用switch結構要比if-else結構效率高一些。由于MATLAB的switch結構沒有C語言的fall-through特性,所以,如果需要針對多個條件而使用同一個case分支的時候,需要使用元胞數組與之配合,參見例子4-4。[例子4-5]switch結構使用示例——switch_examp2.m。001 clearall002003 var=input('InputaNumer:');004 switchvar005 case1006 disp('1')007 case{2,3,4}008 disp('2or3or4')009 case5010 disp('5')011 otherwise012 disp('somethingelse')013 end例子4-5運行的方法和效果如下:>>switch_examp2InputaNumer:11>>switch_examp2InputaNumer:32or3or4>>switch_examp2InputaNumer:7somethingelse

例子4-5代碼的核心部分為007行,這里使用元胞數組增加判斷條件的個數,當輸入的數字為2、3或者4時,switch結構將使用同一個case分支進行判斷、計算。注意:從代碼的完整性和可靠性角度出發(fā),在使用switch語句時,一定要包含otherwise分支,這是一種良好的編程習慣。4.3.2循環(huán)結構在解決很多問題的時候需要使用循環(huán)結構,例如求解數列的和或者進行某種迭代法求解數值方程時,都需要循環(huán)結構配合完成計算。在MATLAB中,包含兩種循環(huán)結構,一種是循環(huán)次數不確定的while循環(huán),而另一種是循環(huán)次數確定的for循環(huán)。

1.while循環(huán)結構while語句可以用來實現“當”型的循環(huán)結構,它的一般形式如下:while(表達式)MATLAB語句end

當表達式為真時,循環(huán)將執(zhí)行由語句構成的循環(huán)體,其特點是先判斷循環(huán)條件,如果循環(huán)條件成立,即表達式運算結果為“真”,再執(zhí)行循環(huán)體。循環(huán)體執(zhí)行的語句可以是一句也可以是多句,在MATLAB語句之后必須使用關鍵字end作為整個循環(huán)結構的結束。另外,在循環(huán)過程中一定要能夠改變關系表達式或者布爾類型變量的值,或者使用其他方法來跳出循環(huán),否則會陷入死循環(huán)(無法正常退出的循環(huán)叫作死循環(huán))。例子4-6

使用while語句求解 。001 i=1;002 sum=0;003 while(i<=1000)004 sum=sum+i;005 i=i+1;006 end007 str=['計算結果為:',num2str(sum)];008 disp(str)

例子4-6的運行結果為

>>while_example

計算結果為:500500

例子4-6的002~006行使用了while循環(huán)結構,在循環(huán)結構中進行了累加的操作。需要注意的是,在MATLAB中沒有類似C語言的++或者+=等運算操作符,因此在進行諸如累加或者遞減的運算時,不得不給出完整的表達式。另外,例子4-6求數列和的算法的運算效率很低,在MATLAB中不要使用這樣的結構完成類似的運算,而需要采用向量化的計算。

注意:

while循環(huán)結構的關系表達式可以是某個數據變量或者常量,這時,將按照非零值為邏輯真進行相應的操作。另外,在進行上述操作時,若數據變量為空矩陣,則while語句將空矩陣作為邏輯假處理,也就是說,在whileAMATLAB語句S1end結構中,若A為空矩陣,則MATLAB語句S1永遠不會被執(zhí)行。

2.for循環(huán)結構使用for語句構成循環(huán)是最靈活、簡便的方法,不過,使用for語句循環(huán)需要預先知道循環(huán)體執(zhí)行的次數,所以這種循環(huán)一般叫作確定循環(huán)。在MATLAB中for循環(huán)的基本結構如下:forindex=start:increment:end MATLAB語句end其中,index的取值取決于start和end的值,一般地,這里通常使用等差的數列向量,參見例子4-7。例子4-7

使用for語句求解 。001 sum=0;002 fori=1:1000003 sum=sum+i;004 end 005 str=['計算結果為:',num2str(sum)];006 disp(str)例子4-7運行的結果為>>for_example計算結果為:500500

在例子4-7中,002行的代碼使用了確定次數的for循環(huán)結構,循環(huán)次數使用行向量進行控制,而且索引值i按照默認的數值1進行遞增。在for循環(huán)語句中,不僅可以使用行向量進行循環(huán)迭代的處理,也可以使用矩陣作為循環(huán)次數的控制變量,這時循環(huán)的索引值將直接使用矩陣的每一列,循環(huán)的次數為矩陣的列數,參見例子4-8。例子4-8for循環(huán)示例。001 A=rand(3,4);002003 fori=A004 sum=mean(i)005 end例子4-8運行的結果為:>>for_matricessum=0.2728sum=0.6649sum=0.4275sum=0.5220

例子4-8盡管只有短短的幾行,但是在003行使用了一個矩陣作為循環(huán)的索引值,于是,循環(huán)結果就分別計算矩陣的每一列元素的均值。和其他高級語言類似,MATLAB的循環(huán)結構也可以進行嵌套使用,使用嵌套的循環(huán)需要注意for關鍵字和end關鍵字之間的配對使用,請讀者根據高級語言的一般特性來推斷其運行的方式,這里就不再贅述了。4.3.3break語句和continue語句在循環(huán)結構中還有兩條語句會影響程序的流程,這就是break語句和continue語句,這兩條語句的基本功能如下:●當break語句使用在循環(huán)體中的時候,其作用是能夠在執(zhí)行循環(huán)體的時候強迫終止循環(huán),即控制程序的流程,使其提前退出循環(huán),它的使用方法是

break;●continue語句出現在循環(huán)體中的時候,其作用是能夠中斷本次的循環(huán)體運行,將程序的流程跳轉到判斷循環(huán)條件的語句處,繼續(xù)下一次的循環(huán),它的使用方法是

continue;[例子4-9]break語句示例——break_example.m。001 i=0;002 j=0;003 k=0;004 fori=1:2005 forj=1:2006 fork=1:2007 if(k==2)008 disp('退出循環(huán)');009 break;010 end011 str=sprintf('I=%d,J=%d,K=%d',i,j,k);012 disp(str);013 end014 end015 end016 disp('程序運行結束');例子4-9的運行結果如下:>>break_exampleI=1,J=1,K=1Exittheloop!I=1,J=2,K=1Exittheloop!I=2,J=1,K=1Exittheloop!I=2,J=2,K=1Exittheloop!Endtheprogram!break語句的作用是退出當前的循環(huán)結構運行,所以在例子4-8中,位于最內層循環(huán)的break語句執(zhí)行的結果是退出了最內層的循環(huán)k,位于外層的循環(huán)i和j還是都運行完畢了。[例子4-10]continue語句示例。001 i=0;002 fori=1:6003 if(i>3)004 continue005 else006 str=sprintf('I=%d',i);007 disp(str);008 end009 end010 str=sprintf('循環(huán)結束I=%d',i);011 disp(str);例子4-10的運行結果如下:>>continue_exampleI=1I=2I=3循環(huán)結束I=6continue語句的作用在例子4-9中得到了充分說明,該語句終止當前的循環(huán),然后繼續(xù)下一次循環(huán)運算,直到所有的循環(huán)迭代運算結束為止。4.3.4提高運算性能

M語言和其他的高級語言不同,由于采用了解釋型語言,所以M語言的執(zhí)行效率肯定低于編譯型語言(例如C語言)。然而,隨著MATLAB版本的不斷升級,再加之合理利用MATLAB向量運算等特點可以較大幅度地提高M語言代碼的執(zhí)行效率。在本小節(jié)結合一些具體的例子來講述M語言編程以及MATLAB軟件本身在提高程序執(zhí)行效率方面的一些特性。

1.向量化運算首先,希望讀者牢記這樣一點,MATLAB最初的目的是提供便利的矩陣數據操作能力。所以在大多數的應用程序中,不要使用循環(huán)結構操作矩陣的元素,應直接使用矩陣元素的索引或者矩陣運算的函數,這樣做不僅能夠提高代碼的執(zhí)行效率,而且還能夠提高程序的可讀性,這就是所謂的向量化的運算,也就是說,盡量將使用while循環(huán)或者for循環(huán)的語句結構轉換成等價的向量或者矩陣運算,以提高程序的運算速度,參見例子4-11。[例子4-11]

向量化運算——array_vs_loops.m。001 Mass=rand(5,10000);002 Length=rand(5,10000);003 Width=rand(5,10000);004 Height=rand(5,10000);005 006 [rows,cols]=size(Mass);007 008 disp([char(10),'使用數組運算:'])009 tic010 Density=Mass./(Length.*Width.*Height);011 toc012013 disp([char(10),'使用循環(huán)結構:'])014 tic;015 forI=1:rows016 forJ=1:cols017 Density(I)=Mass(I,J)/(Length(I,J)*Width(I,J)*Height(I,J));018 end019 end020 toc

例子4-11比較了循環(huán)結構和數組運算的執(zhí)行效率,分別使用數組運算010行和循環(huán)結構015~019行完成了同樣的工作。程序的運行結果如下:>>array_vs_loops

UseArray:Elapsedtimeis0.002907seconds.

UseLoop:Elapsedtimeis0.007055seconds.

2.預分配存儲空間另外一種能夠提高運算效率的方法就是進行內存變量存儲空間的預分配,首先察看例子4-12。

[例子4-12]內存預分配的例子——pre_allocate.m。001 disp([char(10),'使用內存預分配:'])002 pre_allo=zeros(10000,1);003 tic;004 forI=1:10000005 pre_allo(I)=rand(1);006 end007 toc008 009 disp([char(10),'不使用內存預分配:'])010 tic;011 forJ=1:10000012 not_pre_allo(J)=rand(1);013 end014 toc例子4-12的執(zhí)行結果如下:>>pre_allocate

Preallocation:Elapsedtimeis0.024410seconds.

Non-Preallocation:Elapsedtimeis0.223652seconds.

上面兩種不同的運算唯一的區(qū)別就是程序的002行,執(zhí)行這行語句之后,MATLAB自動分配了10000個連續(xù)的內存空間用于存儲數據,MATLAB將一次創(chuàng)建足夠的存儲空間,然后依次賦值。而后者not_pre_allo變量沒有進行相應的操作,所以帶來了兩次運算結果的不同。那么在不使用內存預分配的運算中MATLAB進行什么操作呢?當I=1時,MATLAB將使用一小塊長度為一個單元大小的內存保存一位隨機數。當I=2時,MATLAB尋找一塊兩單元大小的內存區(qū),一個單元放第一個隨機數,第二個放另外一個隨機數。

……

當I=10000時,MATLAB尋找一塊容納10000單元的內存區(qū)存放以前的9999個隨機數,同時把最新的一個隨機數加入進去。代碼運行的結果造成了存儲空間的浪費,降低了程序的執(zhí)行速度。所以,在編寫M語言程序的時候需要盡量使用內存的預分配,而少使用或者不使用數組內存空間的自動擴充方式。MATLAB針對不同的數據類型有不同的內存預分配函數,見表4-2。表4-2內存預分配函數

表4-2中說明了不同數據類型所要使用的預分配內存函數,其中結構類型的數組需要兩個函數配合使用,利用struct函數構造結構,而使用repmat函數創(chuàng)建數組。對于非雙精度類型的數據,例如整數類型或者單精度類型進行內存的預分配時,需要使用相應的構造函數或者類型轉換函數,例如:

Y=int16(zeros(1:10000));

在上面的表達式中創(chuàng)建了連續(xù)10000個16位整數的存儲空間。如果預先分配的內存空間無法容納數據,則可以通過repmat函數來擴充數組的存儲空間。上述函數的具體使用方法請讀者參閱MATLAB的幫助文檔或者在線幫助。此外,為了提高MATLAB編程性能,還需注意一些要點,見表4-3所示。

表4-3提高MATLAB編程性能的要點

4.4函數文件4.4.1基本結構

M函數文件和腳本文件不同,函數文件不僅有自己特殊的文件格式,不同的函數還分別具有自己的工作空間。同其他高級語言類似,M函數文件也有局部變量和全局變量。讀者首先需要了解的是函數文件的基本結構,參見例子4-13。[例子4-13]

函數文件示例——average.m。001 functiony=average(x)002 %AVERAGE求向量元素的均值003 %語法:004 %Y=average(X)005 %其中,X是向量,Y為計算得到向量元素的均值006 %若輸入參數為非向量則出錯007 008 %代碼行009 [m,n]=size(x);010 %判斷輸入參數是否為向量011 if(~((m==1)|(n==1))|(m==1&n==1))012 %若輸入參數不是向量,則出錯013 error('Inputmustbeavector')014 end015 %計算向量元素的均值016 y=sum(x)/length(x);在MATLAB命令行中,鍵入下面的指令運行例子4-14的代碼:>>z=1:99;>>y=average(z)y=50M語言函數文件具有下面的不同部分:*函數定義行。*在線幫助。*注釋行。*M語言代碼。下面結合例子4-14分別說明這些部分的構成。函數定義行,例子4-14的函數定義行為代碼的001行:

001 functiony=average(x)

這一行代碼中包括關鍵字function、函數輸出參數y、函數的名稱average和函數的輸入參數x。需要讀者注意的是函數的名稱,函數的名稱定義要求必須以字符開頭,后面可以用字符、數字和下劃線的組合構成函數名稱。MATLAB對函數名稱的長度有限定,讀者可以在自己的MATLAB中,通過執(zhí)行namelengthmax函數獲取相應的數值。假設該函數返回的數值為N,若函數的名稱長度超過了N,則MATLAB使用函數名稱的前N個字符作為函數名稱。一般地,推薦將函數名稱使用小寫的英文字符表示,同時保存函數的M文件名稱最好和函數名稱保持一致,若文件名稱和函數名稱不一致,則調用函數的時候需要使用文件名稱而非函數名稱。在新版本的MATLAB中,調用函數或者腳本的時候,調用指令的大小寫必須與函數或者腳本名稱的大小寫完全一致,否則會報告警告信息,例如,在MATLAB命令行窗體中鍵入下面的指令:

>>y=Average(z)Warning:Couldnotfindanexact(case-sensitive)matchfor'Average'.D:\Class\ML01\ch4\average.misacase-insensitivematchandwillbeusedinstead.Youcanimprovetheperformanceofyourcodebyusingexactnamematchesandwethereforerecommendthatyouupdateyourusageaccordingly.Alternatively,youcandisablethiswarningusingwarning('off','MATLAB:dispatcher:InexactMatch').

y= 50

在未來版本中,MATLAB會把這種調用指令大小寫與函數或者腳本不匹配的現象設定為錯誤。

M函數文件的在線幫助為緊隨在函數定義行的注釋行。在例子4-13中,average函數的在線幫助為002~006行的注釋行。若在MATLAB命令行窗體中鍵入下面的指令:>>helpaverageAVERAGE求向量元素的均值語法:

Y=average(X)

其中,X是向量,Y為計算得到向量元素的均值

若輸入參數為非向量則出錯

其中,在線幫助中比較重要而且特殊的是在線幫助的第一行,在MATLAB中將這行注釋稱為H1幫助行,它是在線幫助的第一行,若使用lookfor函數查詢函數時,僅查詢并顯示函數的H1幫助行,例如,在MATLAB命令行中鍵入下面的指令:

>>lookforaverage

在MATLAB的命令窗口中就會出現:

AVERAGE求向量元素的均值

MEANAverageormeanvalue.…

由于H1幫助行的特殊作用,所以在用戶自己定義M函數文件時,一定要編寫相應的H1幫助行,對函數進行簡明、扼要的說明或者解釋。例子4-13的008、010、012、015行代碼分別是程序具體的注釋行,這些注釋行不會顯示在在線幫助中,主要原因就是這些注釋行沒有緊隨在H1幫助行的后面,其中008行的注釋與在線幫助之間有一個空行。其實從008行開始一直到文件的結尾都是M函數文件的代碼行,這些代碼行需要完成具體的算法,實現用戶的具體功能。代碼行就是用戶開發(fā)的算法M語言的實現。4.4.2輸入輸出參數

M語言函數文件的輸入、輸出參數和其他高級語言的輸入、輸出參數不同,在定義這些輸入、輸出參數的時候不需要指出變量的類型,因為MATLAB默認這些參數都使用雙精度類型,這樣可以簡化程序的編寫。而且在定義參數時,也沒有確定輸入參數的維數或者尺寸,也就是說,直接從參數上無法判斷輸入來的是標量、向量還是矩陣,只有通過程序內部的具體代碼來加以判斷。

M語言的函數文件不僅可以有一個輸入參數和一個返回值,還可以為M語言函數文件定義多個輸入參數和多個輸出參數,見例子4-14。[例子4-14]

多個輸入、輸出參數的M函數。001 function[avg,stdev,r]=ourstats(x,tol)002 %OURSTATS多輸入輸出參數示例003 %該函數計算處理矩陣,得到相應的均值、004 %標準差和矩陣的秩005 [m,n]=size(x);006 ifm==1007 m=n;008 end009 %Average010 avg=sum(x)/m;011% Sandaddeviation012 stdev=sqrt(sum(x.^2)/m-avg.^2);013 %Rank014 s=svd(x);015 r=sum(s>tol);運行例子4-15,在MATLAB命令行中,鍵入下面的指令:>>A=[123;456]A=123456>>[a,s,r]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000r=2>>ourstats(A,0.1)ans=2.50003.50004.5000>>[a,s]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000>>[a,s,r,q]=ourstats(A,0.1)???Errorusing==>ourstatsToomanyoutputarguments.>>[a,s,r]=ourstats(A,0.1,1)???Errorusing==>ourstatsToomanyinputarguments.>>[a,s,r]=ourstats(A,0.1,q)???Undefinedfunctionorvariable'q'.

例子4-14的M代碼具有兩個輸入參數、三個輸出參數,所以在使用該函數的時候,需要將必要的輸入、輸出參數寫明。注意調用該函數時的語法,將輸出參數依次寫在一個向量中,若輸出參數的個數與函數定義的輸出參數個數不一致,則在例子4-14中,將計算得到的前幾個輸出參數作為返回值,個數等于用戶指定的輸出參數個數。計算的結果依次賦值給不同的變量。4.4.3子函數同一個M函數文件中可以包含多個函數。如果在同一個M函數文件中包含了多個函數,那么將出現在文件中的第一個M函數稱為主函數(primaryfunction),其余的函數稱為子函數(subfunction)。M函數文件的名稱一般與主函數的名稱保持一致,其他函數都必須按照函數的基本結構來書寫,每一個函數的開始都是函數定義行,函數的結尾是另一個函數的定義行的開始或者整個M文件的結尾(最后一個子函數的結尾就是文件結束符)。不過,子函數不像主函數,一般子函數沒有在線幫助,子函數的作用范圍有限,它只能被那些在定義子函數的M文件中定義的函數(包括主函數和其他子函數)調用,不能被其他M文件定義的函數調用。

【例子4-15】子函數應用示例001 function[avg,med]=newstats(u) %主函數002 %NEWSTATS計算均值和中間值003 n=length(u);004 avg=mean(u,n); %調用子函數005 med=median(u,n); %調用子函數006 007 functiona=mean(v,n) %子函數

008 %計算平均值009 a=sum(v)/n;010 011 functionm=median(v,n)%子函數

012 %計算中間值013 w=sort(v);014 ifrem(n,2)==1015 m=w((n+1)/2);016 else017 m=(w(n/2)+w(n/2+1))/2;018 end

運行例子4-15,在MATALB命令行窗口中鍵入下面的指令:>>x=1:11;>>[mean,mid]=newstats(x)mean=

6mid=6

在例子4-15的代碼中,分別在007行和011行定義了兩個子函數mean和median,這兩個子函數分別在主函數的004行和005行被調用。注意,在不同的函數之間傳遞變量是通過函數的參數形式來完成的。子函數的在線幫助也可以通過help指令來訪問,例如可以在MATLAB命令行窗體中鍵入下面的指令,從而查看子函數median的在線幫助:>>helpnewstats>median

計算中間值

4.4.4局部變量和全局變量同C語言類似,在M語言函數中也存在局部變量和全局變量。所謂局部變量,就是那些在M函數內部聲明并使用的變量,這些變量僅能在函數調用執(zhí)行期間被使用,一旦函數結束運行,則這些變量占用的內存空間將自動被釋放,變量的數值也就不存在了。這是由于MATLAB的解釋器在解釋執(zhí)行函數的時候,為不同的函數創(chuàng)建不同的工作空間,函數彼此的工作空間相互獨立,一旦函數執(zhí)行完畢,則函數的工作空間就不存在了。在本章前面的例子中,每個例子的函數內部聲明使用的變量都是局部變量,所以函數執(zhí)行完畢后,MATLAB的基本工作空間中沒有這些變量存在,參見例子

4-16。

【例子4-16】局部變量的示例001 functionlocal002 %LOCAL查看局部變量的例子003 x=rand(2,2);004 y=zeros(2,2);005 z='函數中的變量';006 u={x,y,z};007 disp(z)

008 whos運行例子4-16,在MATLAB命令行窗體中鍵入下面的指令:>>local函數中的變量

NameSizeBytesClassAttributes

u1x3256cellx2x232doubley2x232doublez1x612char運行l(wèi)ocal函數之后,再次運行whos指令:>>whos沒有任何輸出。

通過運行l(wèi)ocal函數可以看到,所有在函數中創(chuàng)建的變量在函數運行結束后就不存在了,也就是說,局部變量的生存周期僅在函數活動期間。與局部變量相對應的就是全局變量。MATLAB將全局變量保存在特殊的工作空間統(tǒng)一維護管理,將變量聲明為全局的方法就是在使用變量前,用關鍵字global聲明,例如聲明全局變量gXY:

>>globalgXY>>whosNameSizeBytesClassAttributes

gXY0x00

doubleglobal需要強調一點,MATLAB管理維護全局變量和局部變量使用了不同的工作空間,所以使用global關鍵字創(chuàng)建全局變量的時候有以下三種情況:

(1)若聲明為全局的變量在當前的工作空間和全局工作空間都不存在,則創(chuàng)建一個新的變量,然后將這個變量賦值為空數組,該變量同時存在于局部工作空間和全局工作空間。

(2)若聲明為全局的變量已經存在于全局工作空間,則不會在全局工作空間創(chuàng)建新的變量,其數值同時賦值給局部工作空間中的變量。

(3)若聲明為全局的變量存在于局部工作空間,而全局工作空間不存在,則系統(tǒng)會提示一個警告信息,同時將局部的變量“挪”到全局工作空間中。

【例子4-17】全局變量的示例在MATLAB命令行窗體中鍵入下面的指令:創(chuàng)建全局變量并賦值:>>globalmyx>>myx=10;變量的信息:>>whosNameSizeBytesClassAttributes

myx1x18double

global清除變量:>>clearmyx查看信息:>>whos當前的工作空間下沒有任何變量,但是在全局工作空間下:>>whosglobalNameSizeBytesClassAttributes

myx1x18double

global在當前工作空間再次創(chuàng)建變量:>>myx=23myx=23變量的信息:>>whosNameSizeBytesClassAttributes

myx1x18double將其修改為全局變量(注意警告信息):>>globalmyxWarning:Thevalueoflocalvariablesmayhavebeenchangedtomatchtheglobals.FutureversionsofMATLABwillrequirethatyoudeclareavariabletobeglobalbeforeyouusethatvariable.看看變量的數值:>>myxmyx=10清除當前的工作空間:>>clear>>whosglobalNameSizeBytesClassAttributes

myx1x18double

global清除所有的內存空間:>>clearall在全局工作空間下沒有任何變量了:>>whosglobal4.4.5函數執(zhí)行規(guī)則到這里,讀者應該能夠創(chuàng)建自己的算法函數,并且能夠執(zhí)行任何M語言函數了。只要在MATLAB的命令行窗口中鍵入函數的名稱,并且提供足夠的輸入/輸出參數就會得到正確的結果。如前文所述,M語言的函數被MATLAB的解釋器解釋執(zhí)行,所以,在本小節(jié)中將簡要討論一下解釋器解釋執(zhí)行程序的問題。

當用戶在MATLAB命令行窗體鍵入一個命令或者執(zhí)行M語言文件中包含的一條語句或者指令時,MATLAB解釋器就負責解析用戶的輸入,并且給出相應的答案。就目前而言,讀者能夠創(chuàng)建變量、創(chuàng)建自定義的函數和腳本文件,并且能夠編寫子函數,在代碼中調用MATLAB的函數文件以及內建函數等。那么,MATLAB解釋器解析命令的優(yōu)先級是怎樣的呢?n

首先判斷輸入的命令是否為變量。n

若不是內存中的變量,判斷輸入的命令是否為MATLAB的內建函數。n

若不是內建函數,則判斷輸入的命令是否為子函數。n

若在同一個路徑下發(fā)現同名的三種類型的文件:MEX文件、P代碼文件和M代碼文件,則優(yōu)先執(zhí)行MEX文件,其次是P代碼文件,最低的優(yōu)先級是M語言文件?!纠?-18】MATLAB命令解析優(yōu)先級在MATLAB命令行窗體中鍵入下面的指令:>>cos='Thisisastring!'cos=Thisisastring!>>cos(4)ans=s>>whichcoscosisavariable.>>clearall>>cos(4)ans=-0.6536>>whichcos

cosisabuilt-infunction.提示:

P代碼文件是從M文件用pcode命令生成的,

它是M文件經過解析之后得到的代碼(P=Parse)。P代碼是經過預編譯的無論何時函數被調用MATLAB都能訪問的現成代碼。因為

P文件是預編譯過的,所以它們的實際內容對用戶而言是不可讀的,而且一般情況下它們比相應的

M文件運行速度快。將M語言函數文件轉變?yōu)镻代碼文件的方法是:

>>pcodefun1fun2…4.5M文件調試4.5.1一般調試過程一般來說,應用程序的錯誤有兩類,一類是語法錯誤,另一類是運行時錯誤。其中,語法錯誤包括了詞法或者文法的錯誤,例如函數名稱的錯誤拼寫等,而運行時錯誤是指那些程序運行過程得到的結果不是用戶需要的情況。不過不論是哪一種錯誤,都必須在開發(fā)的過程中將其找出,并且修正。由于M文件是一種解釋型語言,語法錯誤和運行時錯誤多數都是在運行過程中才能發(fā)現,所以程序的調試往往是在程序無法得到正確結果時進行程序修正的重要手段,特別是在早期版本的MATLAB中,程序調試是修正錯誤的唯一手段。不過,隨著MATLAB版本的不斷升級,發(fā)現定位M語言錯誤的手段也越來越豐富。例如,新版本的MATLAB提供的M語言編輯器能夠在代碼編寫過程中針對其中的語法錯誤進行分析,并且會通過編輯器來提示相應的錯誤信息,這一點在前面例子4-2中已經討論過了,其實這也是一種輔助的代碼調試手段。

另外,從MATLABRelease14即MATLAB7.0開始,如果程序運行過程中出現錯誤,則在MATLAB命令行窗體提示信息中,以超鏈接的方式來顯示出現錯誤的代碼行位置,用戶只要單擊超鏈接,則可以打開M語言編輯器,并且自動定位到出現錯誤的代碼。此外,還可以使用M-LintCode、代碼的單元模式(CellMode)、路徑分析工具(DirectoryAnalysis)等來查找代碼中存在的錯誤。有關M-LintCode、代碼的單元模式(CellMode)、路徑分析工具(DirectoryAnalysis)等內容已經超出了本書的討論范圍,有興趣的讀者可以參閱《MATLAB高級編程》一書。

M語言編輯器既是M語言的文本編輯器,同時也是調試的可視化環(huán)境,在M語言編輯器下Debug菜單中的命令就能夠完成程序調試的所有功能,默認情況下,大部分命令都是用來設置各種斷點,只有設置了斷點的應用程序才能夠進行調試。

在MATLAB中,程序斷點主要分為三類:n

標準斷點。n

條件斷點。n

錯誤斷點。這些斷點的設置都可以通過M語言編輯器下的Debug菜單中相應的菜單命令來創(chuàng)建,如圖4-5所示。

圖4-5M文件編輯器的Debug菜單

[例子4-19]M文件調試代碼——stats_error.m。001 function[totalsum,average]=stats_error(input_vector)002 %STATS_ERROR-Calculatescumulativetotal&average003 totalsum=sum(input_vector);004 average=ourmean(input_vector);005 006 functiony=ourmean(x)007 %OURMEAN-Calculatesaverage008 [m,n]=size(x);009 ifm==1010 m=n;011 end012 y=sum(input_vector)/m;在MATLAB命令行窗體中嘗試執(zhí)行上面的函數:>>[sumavg]=stats_error(rand(1,50))???Undefinedfunctionorvariable'input_vector'.

Errorin==>stats_error>ourmeanat12y=sum(input_vector)/m;Errorin==>stats_errorat4average=ourmean(input_vector);MATLAB首先提示程序運行有錯誤,并且指出錯誤發(fā)生的地點,單擊Errorin后面的超鏈接(具有下劃線文字的),可以直接在M語言編輯器中打開相應的M代碼文件,并且光標會停留在相應的代碼行。這時,可以嘗試幾種不同的設置斷點的方法,因為這里的示例代碼在執(zhí)行過程中出現了錯誤,可以設置錯誤斷點,也可以直接在出現錯誤的代碼行處設置標準斷點。由于在前面的操作中,已經自動定位到了出現錯誤的代碼行,故選擇設置標準斷點是比較好的選擇。設置標準斷點的方法如下:

在M語言編輯器打開代碼stats_error.m,將光標置于代碼的第12行,然后執(zhí)行Debug菜單下的Set/ClearBreakpoint菜單命令,或者直接使用快捷鍵F12,或者用鼠標直接單擊代碼行左側編輯器上的短橫線,還可以通過M語言編輯器工具欄上的按鈕來設置標準斷點。此時將在出現錯誤的代碼行(也就是代碼的第12行)設置斷點,設置斷點處用紅色的圓點標識,如圖4-6所示。

圖4-6設置斷點

設置好斷點之后,再次在MATLAB命令行中運行函數,這次運行MATLAB不會報告代碼運行錯誤,而是進入到調試狀態(tài):>>[sumavg]=stats_error(rand(1,50))12y=sum(input_vector)/m;K>>進入到調試狀態(tài)后,MATLAB的命令行窗體中會顯示當前斷點的代碼行,并且命令行窗體提示符變成“K>>”,表示當前MATLAB的狀態(tài)為調試狀態(tài)。此時,在M文件編輯器中第12行代碼前有綠色的箭頭,表示當前程序運行在此處中斷,如圖4-7所示。

圖4-7M語言編輯器的調試模式

圖4-8調試程序的按鈕

另外,部分按鈕從編輯狀態(tài)進入調試狀態(tài),如圖4-8所示。

通過M語言編輯器用戶界面中的Stack下拉列表框可以了解當前應用程序使用堆棧的狀態(tài),例如本例子中Stack下拉列表框包含ourmean,stats_error和Base,它們由下至上,分別為調用者和被調用者之間的關系,同時也顯示了當前的工作空間。此時在MATLAB命令行窗體的“K>>”提示符下,可以任意鍵入MATLAB指令進行運算和處理,不過需要注意,此時執(zhí)行指令的MATLAB工作空間就是當前Stack下拉列表框中選擇的那個工作空間,例如,當Stack下拉列表框為ourmean時,在MATLAB命令行窗體下鍵入指令:

K>>whosName SizeBytesClassm 1x18doublearrayn 1x18doublearrayx 1x50400doublearray再來看看調用函數時,MATLAB命令行窗體顯示的錯誤信息:???Undefinedfunctionorvariable'input_vector'.

可以看到,當前的工作空間下沒有變量名input_vector,這也是該程序執(zhí)行出錯的原因,將程序中第12行的input_vector修改成為x就能得到正確的答案了。注意:如果需要修改代碼,一定要退出調試模式。如果不退出調試模式而修改了代碼,在保存代碼時,MATLAB將提示用戶,如圖4-9所示。

圖4-9退出調試模式的警告信息

4.5.2條件斷點所謂條件斷點,就是當代碼執(zhí)行過程中,代碼的某個條件滿足時再進入到調試模式。這種條件斷點對于調試那些循環(huán)結構代碼時非常有效,因為循環(huán)體內的代碼很有可能是在循環(huán)的某個階段才出現錯誤,也就是說,當循環(huán)變量達到某個數值時才出現錯誤。早期版本的MATLAB沒有條件斷點的功能,只能使用標準斷點來進行調試,對于老版本的MATLAB用戶來說,這是非常痛苦的一件事情。

下面使用例4-7的代碼演示設置條件斷點的方法。001 sum=0;002 fori=1:1000003 sum=sum+i;004 end 005 str=['Theresult:',num2str(sum)];006 disp(str)條件斷點其實可以設置在代碼的任意行,只要能夠滿足相應的條件就會中斷當前程序執(zhí)行進入到調試模式,這里將斷點設置在循環(huán)體內,也即是代碼的003行。首先,把光標放置在需要設置斷點的代碼行,然后執(zhí)行M語言編輯器中Debug菜單下的Set/ModifyConditionBreakpoint菜單命令,此時將彈出斷點設置對話框,如圖4-10所示。

圖4-10設置條件斷點

4.5.3錯誤斷點所謂錯誤斷點,就是在程序執(zhí)行過程中,如果出現了錯誤或者警告信息,則自動中斷當前程序執(zhí)行,并且進入到調試模式下。由于這種斷點是在程序執(zhí)行出現錯誤的時候自動實現程序中斷,并且進入調試模式,所以又叫做自動斷點。其實在早期版本的MATLAB中就已經存在自動斷點了,而從MATLABRelease14開始,在這方面進行了增強。設置錯誤斷點,需要執(zhí)行M語言編輯器中Debug菜單下的StopifErrors/Warnings命令,此時將

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論