Matlab M檔案 方煒 台大生機系
Matlab 底稿(Script) 副檔名為m的檔案 包含 MATLAB各種指令 在MATLAB指令視窗直接輸入檔名,即逐一執行檔案內的指令
M檔案的顯示 在目前目錄下有一個M檔案“script01.m”,可用 type 指令顯示其內容: Matlab M檔案的顯示 在目前目錄下有一個M檔案“script01.m”,可用 type 指令顯示其內容: >> type script01.m clear all % 清除所有變數 x = [1 4 -2 3 -1 -5]; for i = 1:length(x), if x(i)>0, fprintf('x(%g) = %g is positive\n', i, x(i)); else fprintf('x(%g) = %g is negative or zero\n', i, x(i)); end
M檔案的執行 欲執行 script01.m, 在指令視窗下輸入 script01 即可 >> script01 Matlab M檔案的執行 欲執行 script01.m, 在指令視窗下輸入 script01 即可 >> script01 x(1) = 1 is positive x(2) = 4 is positive x(3) = -2 is negative or zero x(4) = 3 is positive x(5) = -1 is negative or zero x(6) = -5 is negative or zero
M檔案的執行效應 執行程式底稿,相當於直接在指令視窗下下達 script01.m 裡的每一列指令 Matlab M檔案的執行效應 執行程式底稿,相當於直接在指令視窗下下達 script01.m 裡的每一列指令 所產生的變數也都存放在 MATLAB 的基本工作空間(Base Workspace),可驗證如下: >> whos Name Size Bytes Class i 1x1 8 double array x 1x6 48 double array Grand total is 7 elements using 56 bytes
Matlab 提示 可在函數中呼叫一程式底稿 產生的變數會放在該函數的工作空間中
底稿的優缺點 優點 缺點 適用於簡單但重複性高的程式碼 產生的變數保留在基本工作空間中 Matlab 底稿的優缺點 優點 適用於簡單但重複性高的程式碼 產生的變數保留在基本工作空間中 變數檢視及除錯容易 缺點 不支援輸入及輸出引數(Input/Output Arguments) 變數互相覆蓋而造成程式錯誤
Matlab M 檔案編輯器 (I) M 檔案是文字檔 可以用各種文字編輯器修改 儲存時,需以文字模式儲存 MATLAB在 Windows 及 Mac 平台上,提供了內建的「M 檔案編輯器」(M-File Editor) 點選指令視窗的 file/open 下拉式選單,開啟 M 檔案編輯器 或在指令視窗直接鍵入「edit filename.m」或「open filename.m」
M 檔案編輯器 (II) 開啟 Script01.m,可輸入 即可開啟 M 檔案編輯器: >> edit script01.m Matlab M 檔案編輯器 (II) 開啟 Script01.m,可輸入 >> edit script01.m 即可開啟 M 檔案編輯器:
Matlab 提示 M 檔案編輯器以不同的顏色顯示註解、關鍵字、字串、及一般程式碼 M 檔案編輯器也是一個除錯器(Debugger)
函數 (function) 函數 也是 M 檔案的一種 可接受輸入變數,並將結果送至輸出變數 運算過程產生的變數都存放在函數本身的工作空間 Matlab 函數 (function) 函數 也是 M 檔案的一種 可接受輸入變數,並將結果送至輸出變數 運算過程產生的變數都存放在函數本身的工作空間 不會和 MATLAB 基本工作空間的變數相互覆蓋 函數適用於大型程式碼 使程式碼模組化(Modularized)並易於維護與改進
函數顯示及內容 func1.m 可算出一向量的平均值 用 type 指令顯示其內容: Matlab 函數顯示及內容 func1.m 可算出一向量的平均值 用 type 指令顯示其內容: >> type func1.m function average = func1(vector) average = sum(vector)/length(vector); % 計算平均值 第一列為函數定義列(Function Definition Line) 定義函數名稱(func1,最好和檔案的檔名相同) 輸入引數(vector) 輸出引數(average) function為關鍵字 第二列為函數主體(Function Body) 規範函數運算過程,並指定輸出引數的值
呼叫函數 呼叫此函數,可輸入: >> vec = [1 5 3]; >> ave = func1(vec) Matlab 呼叫函數 呼叫此函數,可輸入: >> vec = [1 5 3]; >> ave = func1(vec) ave = 3
函數線上輔助說明 (I) 加上函數「線上輔助說明」(On-line Help) 在函數定義列下直接加入註解 Matlab 函數線上輔助說明 (I) 加上函數「線上輔助說明」(On-line Help) 在函數定義列下直接加入註解 >> type func2.m function average = func(vector) % FUNC2 A simple function with a single help line. % % Usage of this function: % output = func2(input) % "output" is the average of the input vector "input". average = sum(vector)/length(vector); % 計算平均值
函數線上輔助說明 (II) 函數定義列之後的連續註解(以「%」開頭),即為函數的線上輔助說明 Matlab 函數線上輔助說明 (II) 函數定義列之後的連續註解(以「%」開頭),即為函數的線上輔助說明 輸入「help 函數主檔名」,即可看到這些輔助說明 >> help func2 FUNC2 A simple function with a single help line. Usage of this function: output = func2(input) "output" is the average of the input vector "input".
H1輔助說明 函數線上輔助說明,最重要的就是第一列 使用lookfor keyword查詢 MATLAB 指令 又稱為「H1 輔助說明」(H1 Help) 使用lookfor keyword查詢 MATLAB 指令 對所給的關鍵字和搜尋路徑上所有函數的「H1 輔助說明」一一比對 >> lookfor 'help line' FUNC2 A simple function with a single help line.
Matlab 提示 安裝很多工具箱,或搜尋路徑很長時,lookfor指令的執行時間可能會較長
函數的目錄 (I) 使MATLAB 在任何目錄內,均可執行某目錄內的函數 將和某應用相關的函數,存放於一子目錄內 將此目錄加入搜尋路徑 加入路徑 => 使用 addpath 指令 移除路徑 => 使用 rmpath指令
函數的目錄 (II) 建立目錄的線上輔助說明 在此目錄下加入特定檔案 Contents.m 此檔案只能包含輔助說明文字 每列均需以「%」開頭 Matlab 函數的目錄 (II) 建立目錄的線上輔助說明 在此目錄下加入特定檔案 Contents.m 此檔案只能包含輔助說明文字 每列均需以「%」開頭 輸入「help 目錄名稱」時,顯示在「目錄名稱」下 Contents.m 的輔助說明
函數命名的限制 函數名稱和變數名稱有相同的限制 函數名稱和檔案名稱不同 Matlab 函數命名的限制 函數名稱和變數名稱有相同的限制 只接受前 31 個字母(MATLAB 5.x)或前 63 個字母(MATLAB 6.x 和 7.x) 以英文字母作為開頭 函數名稱和檔案名稱不同 仍可依檔案名稱呼叫檔案 函數名稱將被忽略
函數的輸入和輸出 一個函數可以有多輸入及輸出 func3.m 可接受兩個輸入並產生兩個輸出 func3.m 的呼叫方式 Matlab 函數的輸入和輸出 一個函數可以有多輸入及輸出 func3.m 可接受兩個輸入並產生兩個輸出 >> type func3.m function [ave1, ave2] = func3(vector1, vector2); ave1 = sum(vector1)/length(vector1); ave2 = sum(vector2)/length(vector2); func3.m 的呼叫方式 >> [a, b] = func3([1 2 3], [4 5 6 7 8]) a = 2 b = 6
Examples of Function Definition Lines One input, one output: function [area_square] = square(side) 2. Brackets are optional for one input, one output: function area_square = square(side) 3. Two inputs, one output: function [volume_box] = box(height,width,length) 4. One input, two outputs: function [area_circle,circumf] = circle(radius) 5. No named output: function sqplot(side)
輸出入變數的個數 (I) 決定函數實際輸入輸出變數的個數 使用內建變數 nargin 及 nargout 主要功能 Matlab 輸出入變數的個數 (I) 決定函數實際輸入輸出變數的個數 使用內建變數 nargin 及 nargout 主要功能 設定未被指定之輸入引數的預設值 避免計算未被用到的輸出引數,以節省計算時間
輸出入變數的個數 (II) 上述函數 func3.m 可改寫成 func4.m >> type func4.m Matlab 輸出入變數的個數 (II) 上述函數 func3.m 可改寫成 func4.m >> type func4.m function [ave1, ave2] = func4(vector1, vector2) if nargin == 1, % 只有一個輸入變數 ave1 = sum(vector1)/length(vector1); end if nargout == 2, % 有兩個輸出變數 ave2 = sum(vector2)/length(vector2);
輸出入變數的個數 (III) func4.m 可以接受一個或兩個輸入變數: MATLAB 函數亦可傳送不定數目的輸入引數和輸出引數 >> [a, b] = func4([1 2 3], [4 5 6 7 8]) a = 2 b = 6 >> c = func4([1 3 5 7 9]) c = 5 MATLAB 函數亦可傳送不定數目的輸入引數和輸出引數
提示 從外表來看,MATLAB 函數的變數傳遞方法是 “Call by Value” 實際運作上 函數的工作空間中,所有的輸入變數均是父工作空間(Parent Workspace)的一份拷貝 在函數中更改這些輸入變數,並不會影響原先父工作空間的變數 實際運作上 若輸入變數未被修改,MATLAB 採用“Call by Reference” 否則,則採用“Call by Value”
次函數與私有化目錄 一個 M 檔案可以包含一個以上的函數 主函數與次函數的位置 一個主函數(Primary Function) Matlab 次函數與私有化目錄 一個 M 檔案可以包含一個以上的函數 一個主函數(Primary Function) 其他則為次函數(Subfunctions) 次函數只能被同檔案中的函數(主函數或次函數)呼叫,但不可被不同檔案的其他函數呼叫 主函數與次函數的位置 主函數必需出現在最上方 其後接上任意數目的次函數 次函數的次序並無任何限制
主函數與次函數
mystats.m function [avg,med]=mystats(u) n=length(u); avg=mean(u,n); med=median(u,n); function a=mean(v,n) a=sum(v)/n; function m=median(v,n) w=sort(v); if rem(n,2)==1 m=w((n+1)/2); else m=(w(n/2)+w(n/2+1))/2; end
主函數與次函數 func5.m 包含一個主函數及一個次函數 呼叫此函數 >> type func5.m Matlab 主函數與次函數 func5.m 包含一個主函數及一個次函數 >> type func5.m function out = func5(x) recip = reciproc(x); out = sum(recip); % Definition for subfunctions function output = reciproc(input) %計算倒數向量 output = 1./input; 呼叫此函數 >> func5([1 2 3]) ans = 1.8333
函數呼叫 1. As a character string identifying the appropriate function M-file, which is function y = fun1(x) y = x.^2-4; The function may be called as follows, to compute the zero over the range 0 £ x £ 3: >>[x, value] = fzero(’fun1’,[0, 3]) 第2名 (continued …)
函數呼叫 第1名 2. As a function handle to an existing function M-file: >>[x, value] = fzero(@fun1,[0, 3]) 3. As an “inline” function object: >>fun1 = ’x.^2-4’; >>fun_inline = inline(fun1); >>[x, value] = fzero(fun_inline,[0, 3]) (continued …)
函數呼叫 4. As a string expression: >>fun1 = ’x.^2-4’; >>[x, value] = fzero(fun1,[0, 3]) or as >>[x, value] = fzero(’x.^2-4’,[0, 3])
巢狀函數
Test_nested_1.m function res=test_nested_1 a=1;b=2;x=0;y=9; fprintf(‘Before call to fun1\n’); fprintf(‘a,b,x,y=%2d %2d %2d %2d \n’,a,b,x,y); x=fun1(x); fprintf(‘\nAfter call to fun1\n’); function res=fun1(y) fprintf(‘\nAt start of call to fun1\n’); y=y+5;a=a+1;res=y; fprintf(‘\nAt end of call to fun1\n’); end
Results of Test_nested_1 Before call to fun1 a,b,x,y= 1 2 0 9 At start of call to fun1 a,b,x,y= 1 2 0 0 At end of call to fun1 a,b,x,y= 2 2 0 5 After call to fun1 a,b,x,y= 2 2 5 9 >>
Test_nested_2.m function res=test_nested_1 a=1;b=2;x=0;y=9; fprintf(‘Before call to fun1\n’); fprintf(‘a,b,x,y=%2d %2d %2d %2d \n’,a,b,x,y); x=fun1(x); fprintf(‘\nAfter call to fun1\n’); end function res=fun1(y) fprintf(‘\nAt start of call to fun1\n’); y=y+5;a=a+1;res=y; fprintf(‘\nAt end of call to fun1\n’);
Results of Test_nested_2 Before call to fun1 a,b,x,y= 1 2 0 9 At start of call to fun1 ??? Undefined function or variable "a". Error in ==> test_nested_2>fun1 at 11 fprintf('a,b,x,y=%2d %2d %2d %2d \n',a,b,x,y); Error in ==> test_nested_2 at 5 x=fun1(x);
Test_nested_3.m function res=test_nested_3 global a b x y fprintf('Before call to fun1\n'); fprintf('a,b,x,y=%2d %2d %2d %2d \n',a,b,x,y); x=fun1(x); fprintf('\nAfter call to fun1\n'); end function res=fun1(y) fprintf('\nAt start of call to fun1\n'); y=y+5;a=a+1;res=y; fprintf('\nAt end of call to fun1\n');
Results of Test_nested_3 Before call to fun1 a,b,x,y= 1 2 0 9 Warning: The value of local variables may have been changed to match the globals. Future versions of MATLAB will require that you declare a variable to be global before you use that variable. > In test_nested_3>fun1 at 11 In test_nested_3 at 6 At start of call to fun1 At end of call to fun1 a,b,x,y= 2 2 0 14 After call to fun1 a,b,x,y= 2 2 14 14 >>
私有化目錄 私有化目錄(Private Directory) 在目錄中建立名稱為 private 的私有化目錄 存放與這目錄相關的函數 Matlab 私有化目錄 私有化目錄(Private Directory) 在目錄中建立名稱為 private 的私有化目錄 存放與這目錄相關的函數 目錄 private 之下的函數,只能被其父目錄函數所呼叫,不能被其他目錄的函數來呼叫
函數搜尋次序 從 M 檔案呼叫一個函數時,MATLAB 搜尋函數的次序: MATLAB 找到第一個檔名相符的函數,即會立即取用 檢查此函數是否為次函數 檢查此函數是否為私有化目錄的函數 從系統所設定的搜尋路徑找尋此函數 MATLAB 找到第一個檔名相符的函數,即會立即取用
區域變數與全域變數 區域變數(Local Variables) 每一個函數在運算時,均佔用個別的記憶體 Matlab 區域變數與全域變數 區域變數(Local Variables) 每一個函數在運算時,均佔用個別的記憶體 此工作空間和 MATLAB 的基本工作空間或是其他函數的工作空間是互相獨立的 不同空間的變數是完全獨立,不會相互影響 不同工作空間的變數,稱為「區域變數」(Local Variables)
全域變數的使用 (I) 減少變數的傳遞,可用「全域變數」(Global Variables) 使用全域變數前,需先進行變數宣告 Matlab 全域變數的使用 (I) 減少變數的傳遞,可用「全域變數」(Global Variables) 使用全域變數前,需先進行變數宣告 >> type func6.m function func6 global X % 全域變數宣告 X = X + 2; fprintf('The value of X in "func6" is %g.\n', X);
全域變數的使用 (II) Func6.m沒有輸出和輸入,只宣告全域變數 X,將 X 的值加 2,並印出其值 測試 Matlab 全域變數的使用 (II) Func6.m沒有輸出和輸入,只宣告全域變數 X,將 X 的值加 2,並印出其值 測試 >> global X % 在基本工作空間進行全域變數 x 的宣告 >> X = 2; >> fprintf('The value of X in the base workspace is %g.\n', X); The value of X in the base workspace is 2. >> func6; The value of X in "func6" is 4. The value of X in the base workspace is 4.
全域變數的使用原則 盡量少用全域變數 使用全域變數,請遵循下列兩原則 檢視工作空間的變數,輸入whos global Matlab 全域變數的使用原則 盡量少用全域變數 全域變數使程式的流程不透明,造成程式除錯或維護的困難 使用全域變數,請遵循下列兩原則 使用前一定要宣告 使用全部大寫或較長的變數名稱,以資區別 檢視工作空間的變數,輸入whos global 清除所有工作空間的全域變數 X,需使用 clear global X
程式碼保護:p-code p-code 一般的 M 檔案都是文字檔 所有的 MATLAB 原始程式碼都看得到 讓別人使用您的程式碼,又不想被看到程式碼的內容,使用 pcode 指令將底稿或函數轉成 p-code(即Pseudo-Code) pcode filename.m
p-code的使用 將函數 func5.m 轉成 p-code 檢視func5,以p-code的程式碼為優先 Matlab p-code的使用 將函數 func5.m 轉成 p-code >> pcode func5.m >> dir *.p func5.p 檢視func5,以p-code的程式碼為優先 >> which func5 D:\matlabBook\MATLAB程式設計:入門篇\15-M檔案\func5.p 呼叫 p-code 的函數和一般函數並無不同 >> func5([2 4 8]) ans = 0.8750
p-code提高效率 一函數被呼叫時,MATLAB 會載入並剖析(Parse)此函數 pcode 的作用是將程式碼剖析後的結果儲存 剖析結果存放置在記憶體內 下次再呼叫此函數,可以省下剖析所花的時間 pcode 的作用是將程式碼剖析後的結果儲存 程式碼牽涉到很多 M 檔案時 將程式碼轉成 p-code,節省剖析的時間