Scilab 常微分教學

68
中文 Scilab 常微分及差分方程組 Scilab 教學系列 李運璋 (Scilab 中文開發群) 有關 Scilab 請參考: http://www-rocq.inria.fr/scilab/ ADE 中文 Scilab 主網頁 i JJ “ 目錄 II

description

Scilab 常微分教學 (Scilab ODE tutorial in chinese)

Transcript of Scilab 常微分教學

Page 1: Scilab 常微分教學

中文 Scilab

常微分及差分方程組

Scilab教學系列 ∗

李運璋 (Scilab中文開發群)

∗有關 Scilab請參考: http://www-rocq.inria.fr/scilab/或 ADE 中文 Scilab主網頁

i JJ ª目 錄 II

Page 2: Scilab 常微分教學

目 錄

目 錄

序 1

一階常微分方程式組–初值問題 2一階純量微方方程式 . . . . . . . . . . . . . . 5

一階純量微方方程式,使用 C語言 . . . . . . . 6

向量微分程式 . . . . . . . . . . . . . . . . . . 7

矩陣微分方程式 . . . . . . . . . . . . . . . . . 8

跨零條件 . . . . . . . . . . . . . . . . . . . . . 11

隱式微分方程式 . . . . . . . . . . . . . . . . . 14

利用 ode指令求解差分方程組 . . . . . . . . . 17

常微分方程式–邊界值問題 19兩點式邊界值問題 . . . . . . . . . . . . . . . . 22

特徵值問題 . . . . . . . . . . . . . . . . . . . 24

兩個以上解的邊界值問題 . . . . . . . . . . . . 27

多點邊界值問題 . . . . . . . . . . . . . . . . . 29

邊界層問題 . . . . . . . . . . . . . . . . . . . . 30

微分–代數方程式 33

微分–代數方程式,使用 dassl指令 . . . . . . . 34

跨零條件之微分–代數方程式,使用 dasrt指令 . 36

線性微分及差分方程組模擬簡介 38

線性微分系統之時間響應 . . . . . . . . . . . . 39

線性差分系統之時間響應 . . . . . . . . . . . . 40

Scialb指令說明 41

ode-常微分方程組求解 . . . . . . . . . . . . . 42

impl-微分-代數方程式 . . . . . . . . . . . . . . 48

bvodeS-bvode的簡化呼叫版 . . . . . . . . . . . 52

dassl,dasrl -微分-代數方程式 (differential alge-

braic equation) . . . . . . . . . . . . . . . 57

external- Scilab物件,外部函數或程序 . . . . . 64

後記 66

ii JJ ª目 錄 II

Page 3: Scilab 常微分教學

1 序

計算工具對科學教育之重要性,就如同紙筆對文化傳承一樣;欠缺這類輔助工具,就無法面對環境所提出之

挑戰。工程師、研究人員因此而失去成長的機會,久而久之也就以為我們的文化並不擅長處理科學事項,只

能接受現況。

計算工具沒有了自主性,科技也就失去了根本,外來科技文化很容易的將我們的環境變成一個殖民地。但

要改變現況並不容易;因為現況既已行之久遠,那麼環境早已具備反撲任何改變它的企圖心。所以我們認為

引入 Scilab到國內高等教育體系是否能成功,關鍵不僅僅在於理念是否服人,也必須具有持續降低 Scilab學

習成本之實際行動。這樣才能讓新加入的成員很快就具備對抗環境挑戰的實力而能擺脫工具技術上之箝制。

目前針對碩、博士研究生推廣 Scilab會比向大學生介紹它容易許多。學生程度上差異只是一個原因,計算

工具能夠減輕研究生之研究課題壓力才是主因。因此要將 Scilab向下推廣到大學生之間,應讓 Scilab轉成理

工大學生課堂上的輔助學習工具才易成功,而這須要課堂上授課教師願意配合。

所以我們有一系列針對大學理工課堂上所需的 Scilab引介文章,希望填補課堂之學理和計算工具之間的空

白處,讓教師和學生都願意推介 Scilab。計畫中的主題如下:

『常微分及差分方程組』、『非線性聯立方程式、最佳化及最小二乘法』、『線性代數』、『機率、統

計』、『控制』、『訊號處理』、

這一系列文章應能彌補 Scilab線上手冊之不足,使大學生易於接受。也希望能做為下一個階段撰寫高中生

教學文件的參考文章。

1 JJ ª目 錄 II

Page 4: Scilab 常微分教學

一階常微分方程式組--初值問題

2 一階常微分方程式組–初值問題

內容

一階純量微方方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

一階純量微方方程式,使用 C語言 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

向量微分程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

矩陣微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

跨零條件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11

隱式微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14

利用 ode指令求解差分方程組 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

一階常微分方程組通式 一階常微分方程組之初值問題之通式為:

微分方程組

dydt

= f(t,y)

初值條件

y(t0) = y0

2 JJ ª目 錄 II

Page 5: Scilab 常微分教學

一階常微分方程式組–初值問題

其中 y為一 n階向量, f(t,y)為非線性向量方程式,y0 稱為 y在時間 t0 的初始條件。上式微分關係將 y視為時間 t的函數。因此,常微分方程式之初值問題目的是求 y(t)在, t0 ≤ t ≤ T 範圍之解。

Scilab提供 ode指令 (參考 6.1)做為一階常微分方程式組之求解工具,使用者必須提供函數 f(t,y)及初始時間 t0, y之初值 y0以及需要計算出結果之時間點等資料。ode指令最簡單的呼叫格式為:

Y=ode(y0,t0,t,f)

其中 t代表須要計算的時間點所形成的 (行)向量,而 Y為指定時間之輸出結果。因此,如果為 y0為一

n × 1 (列)向量,則 Y為一 n × m之矩陣,其中m為 t向量之維度 (大小)。

高階常微分方程式及一階常微分方程組關係 Scilab提供一階微分方程組計算工具 (ode),但這對高階常微分

方程式之計算應用並不算限制,因為所有 n階微分方程式都可轉寫成等價之一階 n維向量微分關係,例如下

列:

三階常微分方程式

f ′′′(η) +12f(η)f ′′(η) = 0

等價於

3 JJ ª目 錄 II

Page 6: Scilab 常微分教學

一階常微分方程式組–初值問題

一階三維常微分方程組

y′1(η) = y2(η)

y′2(η) = y3(η)

y′3(η) = −12y1(η)y3(η)

因此本節僅介紹一階微分方程組之計算工具。

4 JJ ª目 錄 II

Page 7: Scilab 常微分教學

一階常微分方程式組–初值問題

2.1 一階純量微方方程式

以下列一階純量微方方程式為例,

微分方程組

y = y2 − y sin(t) + cos(t)

初值條件

y(0) = 0

用 Scialb ode指令求解之程序如下:

function ydot=f(t,y) // 1. 提供非線性方程式 f

ydot=y^2-y*sin(t)+cos(t)

endfunction

y0=0;t0=0; // 2. 初始時間及初值

t=0:0.1:%pi; // 3. 設定輸出結果之時間

Y=ode(y0,t0,t,f) // 4. 呼叫 ode 指令

plot(t,Y) // 5. 繪出結果

記算程序中除了定義微分方程式右邊項之非線性函數 f(t, y)及初始時間 t0 = 0,初值 y0 = 0之外,還須告知系統須要輸出結果的時間 (以行向量表示)。此例要求在 t = 0, 0.1, 0.2, · · · , π 各時刻輸出 y 之值以形成輸

出矩陣 Y。輸出矩陣 Y 之列數與 t相同,也就是 Y 的第 i列 Y [:, i]代表 y在時間 t[i]之計算結果。

5 JJ ª目 錄 II

Page 8: Scilab 常微分教學

一階常微分方程式組–初值問題

2.2 一階純量微方方程式,使用 C語言

同樣的問題,也可以使用 C或 Fortran語言提供函數,好處是計算效率大幅提高,以下是 C語言轉撰寫的函

數:

// myode.c 檔, 存在工作目錄

#include <math.h>

void myode(int *n,double *t,double *y,double *ydot)

{

ydot[0]=y[0]*y[0]-y[0]*sin(*t)+cos(*t);

}

// Scilab 指令

// 在 TMPDIR 內編譯出動態連結檔,

// 以及一自動載入程序檔 loader.sce

ilib_for_link('myode','myode.o',[],'c','Makefile','loader.sce');

exec('loader.sce') //執行 loader.sce 以載入動態聯結檔

y0=0;t0=0;t=0:0.1:%pi;

y=ode(y0,t0,t,'myode');

原始檔 myode.c經過 ilib_for_link 指令編譯程動態連結檔,一旦載入系統後 (此例透過自動產生的

loader.sce程序檔)就與 Scilab語言撰寫的函數無異,執行效率卻遠高於 Scilab函數。

有關在 Scilab函數指令中傳遞函數資料以及如何使用 Fortran和 C語言撰寫外部函數請參考 6.5 ,及 ode

(6.1)說明。

6 JJ ª目 錄 II

Page 9: Scilab 常微分教學

一階常微分方程式組–初值問題

2.3 向量微分程式

此例,模擬以下之動態系統

微分方程組

x = Ax(t) + Bu(t)

A =

[1 10 2

], B =

[11

]

初值條件

x(0) =

[10

]

// A 及 u 必須利用串列告知函數原型

function xdot=linear(t,x,A,u)

xdot=A*x+B*u(t) // B 透過全域變數傳遞

endfunction

// omega 透過全域變數傳遞

function ut=u(t) // 輸入函數

ut=sin(omega*t)

endfunction

A= [1 1;0 2];B= [1;1];omega=5;// 線性系統資訊

// 在 t=0.1, 0.2, 0.5 ,1. 提供 x(t) 的時刻

// x0= [1;0] ; 初始值

//最後一參數為串列,提供額外參數 A 及 u 資訊

X=ode([1;0],0,[0.1,0.2,0.5,1],list(linear,A,u))

由於微分函數 linear除了參數 t,x之外,另外接受一函數參數 u(t) = sin(ωt),以模擬一般動態系統之輸入,因此利用外部函數之串列方式 (6.5,6.1)表示。輸出結果X 為2× 4之矩陣,同一列代表同一時刻之輸出。

7 JJ ª目 錄 II

Page 10: Scilab 常微分教學

一階常微分方程式組–初值問題

2.4 矩陣微分方程式

函數 f 可以傳回 p × q矩陣而非向量。使用這種矩陣表示式,代表求解 n = p + q階 ODE方程組:

微分方程組

Y = F(t,Y)

初值條件

Y(0) = Y0

其中Y為一p× q矩陣。初始條件Y0也必須為 p× q矩陣,而 ode 指令之輸出結果為一 p× q(T + 1)之陣列; [Y(t0),Y(t1), ...,Y(tT )]。例如:

8 JJ ª目 錄 II

Page 11: Scilab 常微分教學

一階常微分方程式組–初值問題

Riccati矩陣微分方程式

X = ATX + XA − XT BX + C

初值條件

X(0) = I

Scilab解方程式之指令為:

function Xdot=ric(t,X)// 設定 Riccati 矩陣微分方程式

Xdot=A'*X+X*A-X'*B*X+C

endfunction

A= [1,1;0,2]; B= [1,0;0,1]; C= [1,0;0,1]; // 矩陣係數

t0=0;t=0:0.1:%pi; // 計算時間

X=ode(eye(A),0,t,ric)

輸出結果為矩陣 X 在 32個時刻計算結果橫排成一行,因此為2 × 64之矩陣。

9 JJ ª目 錄 II

Page 12: Scilab 常微分教學

一階常微分方程式組–初值問題

另一例利用矩陣微分方程式之解

矩陣微分方程式

X = AX

A =

[1 10 2

]

初值條件

X(0) = I

求得矩陣之指數, eA,如下:

A= [1,1;0,2];

function xdot=f(t,x) // 設定矩陣微分方程式

xdot=A*x;

endfunction

ode(eye(A),0,1,f) // 使用內定方法

ode("adams",eye(A),0,1,f) // 選用 "adams" 法

計算出之結果可與矩陣函數 eA之 Scilab函數計算結果 expm(A)相比較。

10 JJ ª目 錄 II

Page 13: Scilab 常微分教學

一階常微分方程式組–初值問題

2.5 跨零條件

指令 ode第一個參數若為 "root" ,常微分計算結束時刻是由一組曲面函數g(t,y)=0決定,稱為跨零條件。

微分方程組

dydt

= f(t,y)

初值條件

y(t0) = y0

跨零條件

g(t,y) = 0

任一個跨零條件滿足時ode指令即停止計算,同時傳回滿足跨零條件的曲面資訊。

11 JJ ª目 錄 II

Page 14: Scilab 常微分教學

一階常微分方程式組–初值問題

例如以下問題:

微分方程式及初值條件

y = y,y(0) = 1

跨零條件

g = y − 2 = 0

由 t = 0積分起,直到滿足 y(t) = 2條件為止,因此截止計算時間是動態決定的,以下為 Scilab指令:

deff("[ydot]=f(t,y)","ydot=y") // 動態產生函數 f , 與使用 function ... endfunction 等效

deff("[z]=g(t,y)","z=y-2") // 跨零條件

y0=1;ng=1;

[y,rd]=ode("roots",y0,0,2,f,ng,g) //

跨零條件,可以為一向量組組,例如將 g改為

g(t,y) = y −

2233

則 Scilab指令如下:

//同時設定三個面 y=2,y=2,y=33

deff("[z]=g(t,y)","z=y-[2;2;33]") // 3 階跨零條件

[y,rd]=ode("roots",1,0,2,f,3,g) //

12 JJ ª目 錄 II

Page 15: Scilab 常微分教學

一階常微分方程式組–初值問題

傳回之參數 rd內含截止計算時滿足跨零條件的區面編號資訊,請參考 6.1

13 JJ ª目 錄 II

Page 16: Scilab 常微分教學

一階常微分方程式組–初值問題

2.6 隱式微分方程式

物理上常有之之微分模式中,微分項 y′並無法完全獨立安排至等號左邊,而必須如下式與求解之量 y如下式集結在等號左邊,

隱式微分方程組

A(t,y)y′ = g(t,y)

例如,流體力學中常見的水動力,附加質量 (added mass)項與慣性力項就常混合成一項移到等號左邊。而

代數–微分方程式之組合也可歸於此類。

理論上,這類微分方程式可以在微分方程式等號兩邊各乘上A−1(t,y)即能表為常見之格式,但如此計算效率極差並不值得採用,而且也未必可求得反矩陣。

Scilab針對這類微分方程式,提供 impl指令 (參考 6.2),以方便應用。impl指令常見的呼叫格式為:

y=impl(y0,ydot0,t0,t,res,adda)

其中,res為一向量函數,負責計算 g(t,y) − A(t,y)y′之結果,也就是

r = res(t,y,ydot)=g(t,y)-A(t,y)ydot

而res為一矩陣函數,負責計算A(t,y)和任一同階 (同樣大小)矩陣 p之和,也就是

r = adda(t,y,p)=A(t,y)+p

14 JJ ª目 錄 II

Page 17: Scilab 常微分教學

一階常微分方程式組–初值問題

例如以下指令呼叫impl,

y=impl([1;0;0],[-0.04;0.04;0],0,0.4,'resid','aplusp'); // resid 及 aplusp 為 Fortran 函數

由指令反解,可知輸出結果時刻是在 t = 0.4,而初值 y0,y′0為

y0 =

100

,y′0 =

−0.040.040

函數resid , aplusp定義在檔案routines/default/Ex-impl.f中 (Scilab系統已事先編譯),內容為:

c

c routines/default/Ex-impl.f 檔

c

subroutine resid(neq, t, y, s, r, ires)

c ----------------------------------------

c 此函數計算 r=g(t,y)-a(t,y)*s

c inputs : t time

c y 在時間 t 之 y 值

c s 在時間 t 之 dy/dt 值

c ny y 之維度 (向量大小)

c ires 可忽略

double precision r, s, t, y

dimension y(3), s(3), r(3)

r(1)= -.040d+0*y(1)+1.0d+4*y(2)*y(3)-s(1)

r(2)=.040d+0*y(1)-1.0d+4*y(2)*y(3)

   1 -3.0d7*y(2)*y(2)-s(2)

r(3)= y(1) + y(2) + y(3) - 1.0d+0

return

end

subroutine aplusp(neq, t, y, ml, mu, p, nrowp)

c ----------------------------------------------

c 此函數計算 p=p+a, 其中 a=a(t,y) 為一 ny x ny 矩陣

double precision p, t, y

dimension y(3), p(nrowp,3)

p(1,1) = p(1,1) + 1.0d+0

p(2,2) = p(2,2) + 1.0d+0

return

end

15 JJ ª目 錄 II

Page 18: Scilab 常微分教學

一階常微分方程式組–初值問題

由 Fortran檔案反解,可知微分方程式之 g(t,y),A(t,y)分別為

g(t,y) =

−.04y1 + 104y2y3

0.04y1 − 104y2y3 − 3 × 107y22

y1 + y2 + y3 − 1

A(t,y) =

1 0 00 1 00 0 0

實際上,第三個方程式是代數方程式而非微分方程式。

值得注意的是,函數 g(t,y)的資訊並未出現在指令 impl之參數中,而是透過 res參數間接提供。

16 JJ ª目 錄 II

Page 19: Scilab 常微分教學

一階常微分方程式組–初值問題

2.7 利用 ode指令求解差分方程組

ode指令的第一個參數若為 "discrete"代表求解一差分方程組,

差分方程組

y[k + 1] = f(k,y[k])

初值條件

y[k0] = y0

以 ode求解差分方程組之呼叫格式為:

y=ode("discrete",y0,k0,kvect,f)

其中,y0,k0為初始狀態,而kvect為各元素皆大於 k0的遞增整數向量,代表輸出計算結果的 (離散)時

刻, f則為差分方程式之右邊項。

17 JJ ª目 錄 II

Page 20: Scilab 常微分教學

一階常微分方程式組–初值問題

例如以下遞迴之差分方程式

差分方程組

y[k + 1] = Ay[k] + Bu[k]

A =

0.2 0 00 0.5 00 0 0.9

, B =

111

初值條件

y(1) =

123

當設定初值 y[1]之後,就可以使用如下之指令求得 y(k), k ≥ 1之數值,指令如下:

function yp=a_function(k,y) // 差分方程式

yp=A*y+B*u(k);// u (控制項) 透過外部變數傳入

endfunction

y1= [1;2;3]; // 初值

A=diag([0.2,0.5,0.9]); B= [1;1;1];

u=1:10; // 設定 u (控制項)

n=5;

// 計算出 [y(1),..y(5)]

y=ode("discrete",y1,1,1:n,a_function);

y(:,2)-(A*y1+B*u(1)) // 比較 y(2)

// 計算出 [y3,y5,y7,y9]

y=ode("discrete",y1,1,3:2:9,a_function)

18 JJ ª目 錄 II

Page 21: Scilab 常微分教學

常微分方程式–邊界值問題

3 常微分方程式–邊界值問題

內容

兩點式邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22

特徵值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24

兩個以上解的邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27

多點邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .29

邊界層問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30

微分方程式之邊界條件並不是只限於在一點 (初始時間),也有可能在兩端 (兩點式邊界值問題),甚至多點

(多點式邊界值問題)。 Scilab針對兩點、多點邊界值問題提供 bvode及 bvodeS指令求解。由於bvodeS是

bvode指令的介面重新設計之版本,因此本節將只討論bvodeS之用法。

19 JJ ª目 錄 II

Page 22: Scilab 常微分教學

常微分方程式–邊界值問題

bvodeS指令針對以下之多點邊界值向量 u = (u1, u2, · · · , un)T 之微分方程組

微分方程組

dm1u1

dxm1= f1(x, z)

dm2u2

dxm2= f2(x, z)

...

dmn−1un−1

dxmn−1= fn−1(x, z)

dmnun

dxmn= fn(x, z)

其中z(x) = (u1(x), u11(x), · · · , um1−1

1 (x), · · · , un(x) · · · , umn−1n (x))T 為座標點 x上 u各分量ui 最高階導數 mi

以下的各階導數 (包含 0階)。 z(x)之維度 (向量大小)為m∗ = m1 + m2 + · · · + mn。

這類微分方程組,要能得解還需要 m∗ 個邊界條件。假設這m∗ 個邊界條件在m∗ 個座標 (可重複) x =ζi, i = 1, · · · ,m∗點上滿足以下邊界條件

邊界條件

g1(ζ1, z(ζ1)) = 0

g2(ζ2, z(ζ2)) = 0...

gm∗(ζm∗ , z(ζm∗)) = 0

20 JJ ª目 錄 II

Page 23: Scilab 常微分教學

常微分方程式–邊界值問題

呼叫 bvodeS最簡單的形式為

Z=bvodeS(x,m,n,a,b,fsub,gsub,zeta)

由給定之兩點、多點邊界值微分方程組,可以整理出以下所須的輸出、入參數:

n 微分方程式數目或未知向量 u之階數

a,b 左右邊界

x 實數向量,選定座標 a ≤ xi ≤ b以輸出計算結果

m 整數向量代表微分方程式左邊之微分階數m = [m1,m2, · · · ,mn], m∗ = m1 + m2 + · · · + mn

fsub 向量函數,代表微分方程式之右邊各項 [f1, f2, · · · , fn]T

zeta 滿足邊界條件之點 zeta = [ζ1, ζ2, · · · , ζm∗ ] ,遞增排列,可重複

gsub 邊界條件傳回各邊界點上之邊界條件 gi, i = 1, · · · ,m∗

Z m∗ × k之實數矩陣,Z = [z1, z2, · · · , zk], zi = z(ζi),其中 k為向量 x之大小。而

z(x) = (u1(x), u11(x), · · · , um1−1

1 (x), · · · , un(x) · · · , umn−1n (x))T

代表在任一點 x處之擴增未知向量 (大小為m∗)

21 JJ ª目 錄 II

Page 24: Scilab 常微分教學

常微分方程式–邊界值問題

3.1 兩點式邊界值問題

以下列兩點式邊界值問題為例,

微分方程式

y′′′′1 (x) = (1 − 6x2y′′′1 (x) − 6xy′′1(x))/(y2(x)3)

y′2(x) = 1

邊界條件

y1(1) = 0 y′′1(1) = 0

y2(2) = 1 y′′1(2) = 0 y2(2) = 2

解題步驟如下:

1. 先由微分方程式左邊之階數,訂出階數向量m=[4,1] , m∗ = 4 + 1 = 5

2. 定出擴增未知為 z = [y1; y′1; y′′1 ; y′′′1 ; y2]

3. 用擴增未知向量 z,改寫微分方程式為

y′′′′1 (x) = (1 − 6x2z4(x) − 6xz3(x))/(z5(x)3)

y′2(x) = 1

4. 由邊界條件滿足的位置,確定 zeta=[1 1 2 2 2]

22 JJ ª目 錄 II

Page 25: Scilab 常微分教學

常微分方程式–邊界值問題

5. 用擴增未知向量 z,改寫邊界條件為

z1(1) = 0 z3(1) = 0

y2(2) − 1 = 0 z4(2) = 0 z5(2) − 2 = 0

因此以 bvodeS之解題指令為,

// 微分方程組

function RhS=fsub(x,z)

RhS= [(1-6*x*x*z(4)-6*x*z(3))/(z(5)^3);1]

endfunction

// 邊界條件 (傳回純量而非向量)

function g=gsub(i,z)

g= [z(1) z(3) z(1)-1 z(3) z(5)-2]

g=g(i)

endfunction

// Z 之初始猜值

function [z,lhS]=ystart(x)

z=zeros(5,1);z(5)=1;

lhS= [0;1];

endfunction

n=2; // 方程式數目

m= [4 1];// 微分階數

N=100; //格點

a=1; b=2; // 左右邊界

zeta= [a a b b b]; // 邊界條件之位置

x=linspace(a,b,N); //產生均勻格點

ltol=4; // 改變內定誤差收斂條件.

tol=1e-12;

Z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ltol=ltol,tol=tol,ystart=ystart);

23 JJ ª目 錄 II

Page 26: Scilab 常微分教學

常微分方程式–邊界值問題

3.2 特徵值問題

考慮以下之特徵值問題:

微分方程式

y′′(x) = −λy(x)

邊界條件

y(0) = y′(0)

y(1) = 0

由於任意常數 c乘上 y也是一解,因此可以選 y(0) = 1而不影響特徵值求解。將上式轉寫為:

微分方程式

y′′(x) = −λy(x)

λ′ = 0

微分方程式

y(0) = y′(0) y(0) = 1

y(1) = 0

24 JJ ª目 錄 II

Page 27: Scilab 常微分教學

常微分方程式–邊界值問題

將 x ∈ [0, 1]各點欲解之值整理成向量 z =

y

y′

λ

後,再重寫方程式成為 bovdeS所接受之格式:

微分方程式

y′′(x) = −z3z1

λ′ = 0

邊界條件

z1(0) − z2(0) = 0 z1(0) − 1 = 0

z1(1) = 0

以下即為利用指令 bvodeS求解之程序:

function rhs=fsub(x,z) // 微分方程式右邊項

rhs= [-z(3)*z(1);0]

endfunction

function g=gsub(i,z) // 邊界條件共三項

g= [z(1)-z(2) z(1)-1 z(1)]

g=g(i)

endfunction

// 初始猜值函數

function [z,lhs]=ystart(x,z,la0)

z= [1;0;la0]

lhs= [0;0]

endfunction

a=0;b=1;

m= [2;1];

n=2;

zeta= [a a b]; // 邊界條件的位置

N=101;

x=linspace(a,b,N)';// 輸出結果之位置

25 JJ ª目 錄 II

Page 28: Scilab 常微分教學

常微分方程式–邊界值問題

// 輸入 n (特徵值編號)la0=input('n-th eigenvalue: n= ?');

la0=(%pi/2+la0*%pi)^2; //特徵值之猜值

//

z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ystart=list(ystart,la0));

clf()

// z(1,:)' = y , z(2,:)' = y' , z(3,:) = \lambda

plot2d(x,[z(1,:)' z(2,:)'],style= [5 1],axesflag=5)

xtitle(['Startvalue = '+string(la0);...

'Eigenvalue = '+string(z(3,1))],'x',' ')

legend(['y(x)';'y''(x)'])

注意 bvodeS之輸出結果中,第一行為 y在各點之值,第一行為 y′在各點之值,第三行為 λ在各點之值。

本例之解,yn, n = 0, 1, 2, · · · (與數值有一純量倍數關係)為

yn(x) = sin(s(n)(1 − x))λn = s2(n)

s(n) + tan−1(s(n)) − (n + 1)π = 0, n = 0, 1, 2, · · ·

26 JJ ª目 錄 II

Page 29: Scilab 常微分教學

常微分方程式–邊界值問題

3.3 兩個以上解的邊界值問題

微分方程式

y′′(x) = −ey(x)

邊界條件

y(0) = 0

y(1) = 0

這個邊界值問題多重解,這展示求解其中兩個解,將各點欲解之值整理成向量 z =

[y

y′

]後,再重寫方程式成

微分方程式

y′′(x) = −ez1(x)

27 JJ ª目 錄 II

Page 30: Scilab 常微分教學

常微分方程式–邊界值問題

邊界條件

z1(0) = 0

z1(1) = 0

以下程序,找出為方程式的兩組解

a=0;b=1;m=2;n=1;

zeta= [a b];

N=101;

tol=1e-8*[1 1];

x=linspace(a,b,N);

// 微分方程式右邊項

function rhs=fsub(x,z),rhs=-exp(z(1));endfunction

function g=gsub(i,z) // 邊界條件

g= [z(1) z(1)]

g=g(i)

endfunction

// 初值

function [z,lhs]=ystart(x,z,M)

//z= [4*x*(1-x)*M ; 4*(1-2*x)*M]

z= [M;0]

//lhs= [-exp(4*x*(1-x)*M)]

lhs=0

endfunction

// 使用不同之初值參數 M=1 , 4 會收斂到不同解

z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ystart=list(ystart,1),tol=tol);

z1=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ystart=list(ystart,4),tol=tol);

// 繪出 兩組解

clf();

subplot(2,1,1)

plot2d(x,z(1,:),style= [5])

xtitle('Two different solutions','x',' ')

subplot(2,1,2)

plot2d(x,z1(1,:),style= [5])

xtitle(' ','x',' ')

28 JJ ª目 錄 II

Page 31: Scilab 常微分教學

常微分方程式–邊界值問題

3.4 多點邊界值問題

微分方程式

y′′′(x) = 1, z =

y(x)y′(x)y′′(x)

邊界條件

y(−1) = z1(−1) = 0

y(1) = z1(1) = 2

y(0) = z1(0) = 1

以下即為利用指令 bvodeS求解之程序:

a=-1;b=1;c=0;

// c 點必須在 fixpnt 中 (bvodeS 選擇性參數之ㄧ).

n=1;m= [3]; // 微分方程式之階數

function rhs=fsub(x,z) // 微分方程式右邊項

rhs=1

endfunction

function g=gsub(i,z)

g= [z(1)-2 z(1)-1 z(1)-2]

g=g(i)

endfunction

N=10; zeta= [a c b]; // 必須包含中間點

x=linspace(a,b,N);

// fixpnt 除了兩邊以以外的所有點 (此例為 c)

z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,fixpnt=c);

function y=yex(x) // 正解

y=x.^3/6+x.^2-x./6+1

endfunction

// 計算誤差量

disp(norm(yex(x)-z(1,:)),'norm(yex(x)-z(1,:))= ')

29 JJ ª目 錄 II

Page 32: Scilab 常微分教學

常微分方程式–邊界值問題

3.5 邊界層問題

流體力學層流 (lamilar flow)邊界層問題中,需要求解以下為方程組:

微分方程式

f ′′′(η) = −12ff ′′

邊界條件

η = 0 : f = 0, f ′ = 0

η = ∞ : f ′ = 1

將各點上之未知量表為 z =

f

f ′

f ′′

,可以使用以下之指令求得

function rhs=blas(x,z) // 邊界層方程式右邊項

rhs = -0.5*z(1)*z(3)

endfunction

function g=gsub(i,z) // 邊界條件

g= [z(1) z(2) z(2)-1]

g=g(i)

endfunction

a=0; b=10; // b=10 以代替無限大

n=1; // 一個方程式

m=[3]; // 一個 3 階方程式

N=100;

zeta= [a a b]; // 邊界條件之位置

x=linspa ce(a,b,N);// 計算點

z=bvodeS(x,m,n,a,b,blas,gsub,zeta);

30 JJ ª目 錄 II

Page 33: Scilab 常微分教學

常微分方程式–邊界值問題

注意,η = ∞實際上以 η = 10代替。

同樣的方程式也可以轉成一階微分方程組:

微分方程式

z′1(η) = z2

z′2(η) = z3

z′3(η) = −12z1z3

邊界條件

η = 0 : z1 = 0, z2 = 0

η = ∞ : z2 = 1

利用 bvodeS解以上之一皆微分方程組邊界問題之指令如下:

function rhs=blas2(x,z) // 改用一皆微分方程祖

rhs = [z(2) ; z(3) ; -0.5*z(1)*z(3)]

endfunction

function g=gsub(i,z)

g= [z(1) z(2) z(2)-1]

g=g(i)

endfunction

a=0; b=10;

n=3; // 三個方程式

m=[1 1 1]; // 三個一階微分方程組

N=100;

31 JJ ª目 錄 II

Page 34: Scilab 常微分教學

常微分方程式–邊界值問題

zeta= [a a b]; // 邊界條件之位置x=linspace(a,b,N); // 計算點

z1=bvodeS(x,m,n,a,b,blas2,gsub,zeta);

注意,變數 n,m與前例不同,這裡代表三個一階微分方程式,而前例則代表一個三階微分方程式。

32 JJ ª目 錄 II

Page 35: Scilab 常微分教學

微分–代數方程式

4 微分–代數方程式

內容

微分–代數方程式,使用 dassl指令 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

跨零條件之微分–代數方程式,使用 dasrt指令 . . . . . . . . . . . . . . . . . . . . . . . . . . 36

微分方程組最一般的表示法,是透過非線性代數式表現一階導數量和變量之關係,這類方程式稱為代

數–微分方程組。 Scilab提供 dassl, dasrt兩指令 (請參考 6.4)求解此類方程組。

由於所有高階微分問題,都可以轉為一階微分高維度 (向量)問題,因此 dassl,dasrt指令之應用範圍相

當大。與一般初值問題不同之處在於,代數–微分問題之初始條件還必須包含導數量 y(t0) = y0 這是因為代

數–微分關係在初始時間 t0時,y0, y0之關係並不唯一。但使用者可以選擇輸入一大約之估計值,使求解過程

逐漸收斂到其中一組解。

33 JJ ª目 錄 II

Page 36: Scilab 常微分教學

微分–代數方程式

4.1 微分–代數方程式,使用 dassl指令

dassl說明 dassl (參考 6.4)求解以下問題

微分-代數方程組及初值條件

g(t,y, y) = 0

y(t0) = y0

y(t0) = y0

dassl的呼叫格式如下,

[R]=dassl(x0,t0,t,res ) // 內定簡式

[R [,hd]]=dassl(x0,t0,t [,atol,[rtol]],res [,jac] [,info] [,hd]) // 一般式

其中第一個參數 x0 =

[y0

y0

]為初值 y0, y0 的合成向量。 res代表代數–微分組 g(t,y, y)。而傳回值之矩陣

R的每一列為一依序為 t,y0, y0之向量,也就是

R =

t1 t2 · · · tk

y1 y2 · · · yk

y1 y2 · · · yk

其中 t = [t1t2 · · · tk]為須要輸出計算結果的時刻。例如下頁:

34 JJ ª目 錄 II

Page 37: Scilab 常微分教學

微分–代數方程式

微分–代數方程組 :−0.04y1 + 104y2 ∗ y3 − y1 = 0

0.04y1 − 104y2 ∗ y3 − 3 × 107y22 − y2 = 0

y1 + y2 + y3 − 1 = 0

初值條件

y0 =

100

, y0 =

−0.040.04

0

deff('[r,ires]=chemres(t,y,yd)',[

'r(1)=-0.04*y(1)+1d4*y(2)*y(3)-yd(1);';

'r(2)=0.04*y(1)-1d4*y(2)*y(3)-3d7*y(2)*y(2)-yd(2);'

'r(3)=y(1)+y(2)+y(3)-1;'

'ires=0']);

deff('[pd]=chemjac(x,y,yd,cj)',[ // Jacobian 梯度函數

'pd= [-0.04-cj , 1d4*y(3) , 1d4*y(2);';

'0.04 ,-1d4*y(3)-2*3d7*y(2)-cj ,-1d4*y(2);';

'1 , 1 , 1 ]'])

y0= [1;0;0];

yd0= [-0.04;0.04;0];

t= [1.d-5:0.02:.4,0.41:.1:4,40,400,4000,...

40000,4d5,4d6,4d7,4d8,4d9,4d10];

// 1. 使用內定方法

Y=dassl([y0,yd0],0,t,chemres);

info=list([],0,[],[],[],0,0);

info(2)=1; // 輸出中間計算結果

// 未使用 Jacobian

Y=dassl([y0,yd0],0,4d10,chemres,info);

// 使用 Jacobian 梯度向量函數

Y=dassl([y0,yd0],0,4d10,chemres,chemjac,info);

此例,第一次呼叫 dassl使用內定最簡呼叫方式,第二次設定 info(2)=1選擇輸出計算過程之結果,第三

次呼叫時則提供代數–微分關係之 Jacobian梯度函數以加速收斂。

35 JJ ª目 錄 II

Page 38: Scilab 常微分教學

微分–代數方程式

4.2 跨零條件之微分–代數方程式,使用 dasrt指令

dasrt說明 dasrt (參考 6.4)求解以下問題

微分-代數方程組及初值條件

g(t,y, y) = 0

y(t0) = y0

y(t0) = y0

跨零條件

S(t,y) = 0

dasrt能處理跨零條件;所謂跨零條件,是指動態決定結束計算的條件,只要一個以上的跨零函數為 0時,即

停止計算。程式同時輸出產生跨零條件的時間,及滿足跨零條件的曲面編號。

例如下頁

36 JJ ª目 錄 II

Page 39: Scilab 常微分教學

微分–代數方程式

微分–代數方程組 :

dy

dt= ((2 log(y) + 8)/t − 5)y, 1 ≤ t ≤ 6

跨零條件

S1 = ((2 log(y) + 8)/t − 5)y = 0

S2 = log(y) − 2.2491 = 0

y0=1;t=2:6;t0=1;y0d=3;

atol=1.d-6;rtol=0;ng=2;

// 提供代數--微分關係式

deff('[delta,ires]=res1(t,y,ydot)','ires=0;delta=ydot-((2*log(y)+8)/t-5)*y')

// 提供跨零條件

deff('[rts]=gr1(t,y)','rts= [((2*log(y)+8)/t-5)*y;log(y)-2.2491]')

// 求解

[yy,nn]=dasrt([y0,y0d],t0,t,atol,rtol,res1,ng,gr1);

//(應傳回 nn= [2.4698972 2] = [結束時刻 跨零條件編號])

傳回值 nn= [2.4698972 2] 代表在 t = 2.4698972時,第二個跨零曲面 S2 滿足跨零條件,因此結束計

算。

37 JJ ª目 錄 II

Page 40: Scilab 常微分教學

線性微分及差分方程組模擬簡介

5 線性微分及差分方程組模擬簡介

Scialb以 syslin指令定義線性動態系統,線性動態系統可以使用轉換函數表示法或使用狀態空間表示法。而系

統可以是時間連續或離散兩類。 Scilab針對線性系統提供完整之計算工具環境。因此如果微分或差分方程式

為線性系統時,採用 Scialb線性系統內建之工具,會比使用一般化之常微分,差分方程式計算工具更方便。

本節對 Scialb線性系統和常微分及差分方程式相關之指令只做簡單介紹,有興趣深入了解的讀者,可以由

Scialb所附的線上手冊中查詢 (部分內容已有中文翻譯)。針對 Scialb線性系統較有體系之中文介紹會在後續之

Scilab中文文件工作中陸續進行。

38 JJ ª目 錄 II

Page 41: Scilab 常微分教學

線性微分及差分方程組模擬簡介

5.1 線性微分系統之時間響應

指令 csim針對線性連續系統進行模擬,這個指令能用狀態空間或轉換函數表示離散系統,如

連續系統之狀態空間表示法

x(t) = Ax(t) + Bu(t)

y(t) = Cx(t) + Du(t)

連續系統之轉換函數表示法

y = H(s)u

系統一旦定義 (利用指令 syslin),指令 csim即能選擇不同之輸入 u以進行模擬,如下所示:

// csim 線性微分系統之時間響應範例

//

// 代表多項式 s ()

s=poly(0,'s');

// 隨機產生一個 1 個輸入, 1 個輸出

// 及 3 個內部狀態的動態系統 w

rand('seed',0);w=ssrand(1,1,3);

w('A')=w('A')-2*eye(); // 確保隨機系統為穩定

t=0:0.05:5;

// 繪出以 step 函數輸入 s w 系統之時間響應

xbasc(0);xset("window",0);xselect();

plot2d([t',t'],[(csim('step',t,tf2ss(s)*w))',0*t'])

//繪出以 step 函數輸入 w 系統之時間響應

xbasc(3);xset("window",3);xselect();

plot2d([t',t'],[(csim('step',t,w))',0*t'])

//繪出以 impulse 函數輸入 w/s 系統之時間響應

xbasc(4);xset("window",4);xselect();

plot2d([t',t'],[(csim('impulse',t,tf2ss(1/s)*w))',0*t'])

//輸入改成時間函數 u(t) =|sin(t)|

function u=input(t)

u=abs(sin(t))

endfunction

xbasc();plot2d([t',t'],[(csim(input,t,w))',0*t'])

39 JJ ª目 錄 II

Page 42: Scilab 常微分教學

線性微分及差分方程組模擬簡介

5.2 線性差分系統之時間響應

指令 flts針對線性離散系統進行模擬,這個指令能用狀態空間或轉換函數表示離散系統,如

離散系統之狀態空間表示法

x[k + 1] = Ax[k] + Bu[k]

y[k] = Cx[k] + Du[k]

離散系統之轉換函數表示法

y = H(z)u

系統一旦定義 (利用指令 syslin),指令 flts即能選擇不同之輸入 u以進行模擬,如下所示:

// 給 A,B,C, D 定義系統 (狀態空間法)

A= [1 2 3;0 2 4;0 0 1];B= [1 0;0 0;0 1];C=eye(3,3);

D= [-3 8;4 -0.5;2.2 0.9];

Sys=syslin('d',A,B,C,D);

H=ss2tf(Sys); // H 為轉換函數

u= [1;-1]*(1:10); // u 為控制輸入項

rh=flts(u,H); // 使用轉換函數模擬

rs=flts(u,Sys); // 使用狀態空間模擬

norm(rh-rs,1) // 兩者應一樣

//接力計算, 使用狀態空間

[ys1,x]=flts(u(:,1:4),Sys);ys2=flts(u(:,5:10),Sys,x);

norm([ys1,ys2]-rs,1) // 兩者應一樣

//接力計算, 使用轉換函數

yh1=flts(u(:,1:4),H);yh2=flts(u(:,5:10),H,[u(:,2:4); yh1(:,2:4)]);

norm([yh1,yh2]-rh) // 兩者應一樣

40 JJ ª目 錄 II

Page 43: Scilab 常微分教學

Scialb指令說明

6 Scialb指令說明

內容

ode-常微分方程組求解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42

impl-微分-代數方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .48

bvodeS-bvode的簡化呼叫版 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

dassl,dasrl -微分-代數方程式 (differential algebraic equation) . . . . . . . . . . . . . . . . . 57

external- Scilab物件,外部函數或程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

41 JJ ª目 錄 II

Page 44: Scilab 常微分教學

Scialb指令說明

6.1 ode-常微分方程組求解

常微分方程組求解

呼叫方法

• y=ode(y0,t0,t,f) :最簡呼叫型式

• [y,w,iw]=ode([type],y0,t0,t [,rtol [,atol]],f [,jac] [,w,iw]) :各類數值方法選項

• [y,rd,w,iw]=ode("root",y0,t0,t [,rtol [,atol]],f [,jac],ng,g [,w,iw]) :跨零條件選項

• y=ode("discrete",y0,k0,kvect,f) :離散問題型式

參數

y0 實數向量或矩陣 (初始條件)

t0 實數純量 (初始時間)

t 實數向量 (欲求得解的各個時間點)

f 外部函數 (函數、字串串列 (list))

type 以下字串之一: "adams""stiff""rk""rkf""fix""discrete""roots"rtol,atol 與 y 相同大小的實數或實數向量jac 外部函數 (函數、字串串列 (list))

w,iw 實數向量

k0 整數 (初始時間). kvect :整數向量 (僅用於 type="discrete" 狀況)

42 JJ ª目 錄 II

Page 45: Scilab 常微分教學

Scialb指令說明

參數 (用於 type="roots" 或"root")

ng 整數,函數 g之階數 (僅用於 type="roots" 或"root" 狀況)

g 外部函數 (函數、字串串列 (list)) , 代表跨零函數 (僅用於

type="roots" 或"root" 狀況)

rd 為一 1 x k 向量,第一項代表停止之時間,其餘項代表那幾個 g 向量之分量之正負號產生變化。若 k 大於代表有 1個

以上的曲面 (共 (k-1) )同時被穿越。

參數 (用於 type="discrete")

k0 整數,代表離散初始時間編號

kvect 整數向量,指定離散時間以輸出模擬結果

說明 ode 為下列顯式 (explicit)常微分方程式的標準求解函數:

dydt

= f(t,y)

y(t0) = y0

ode 幾個常微分工具的單一介面,其中 ODEPACK的功能最為完整。求解的型態及方法由第一個參數

type決定,此參數有以下選擇:

43 JJ ª目 錄 II

Page 46: Scilab 常微分教學

Scialb指令說明

內定 (不輸入) ODEPACK程式庫中的 lsoda 求解器 (solver)為內定選擇。它自動由 predictor-corrector

Adams法 (nonstiff)及 BDF (Backward Differentiation Formula,stiff )中挑選適用者。演算法

先假設微分方程式無勁度 (nonstiff)再觀察計算結果動態調整方法。

"adams" 此法適用於無勁度問題 (nonstiff problems)。使用 ODEPACK程式庫中的 lsoda 求解器,並選擇 Adams法。 "stiff": 此法適用於勁度問題 (stiff problems)。使用 ODEPACK程式庫中

"lsoda" 求解器並使用 BDF法。 "rk": 可調式 (Adaptive) 4階 Runge-Kutta法。

"rkf" Fehlberg的 4,5階 Runge-Kutta法 (RKF45),來源為 Shampine及 Watts程式。此法適用無

勁度問題或者計算微分所費代價不大的小幅勁度問題。使用者若需求高精度時,一般不使

用此法。

"fix" 使用與"rkf" 一樣的求解器,但是使用介面簡單的多;只須要傳入rtol 及 atol 兩參數,這是練習時最容易使用的方法。

"root" 具備求根功能,使用 ODEPACK程式庫中的 lsoda 求解器。為 lsoda 的變形能同時求解一非線性向量方程式之根。常微分方程式 dy/dt=f(t,y) 會在解 y通過代數方程式g(t,y)=0之曲面時停止計算。請參考 ??。

"discrete" 離散方程式模擬器。請參考 ??。

ode 最簡單的呼叫方式為:

y=ode(y0,t0,t,f)

其中 y0 為解之初始條件 (向量), t0 為初始時間, t 為求解各時間點所形成之實數向量,矩陣 y 為輸出結果,每一列向量代表一個時間點上之計算值 (向量) y= [y(t(1)),y(t(2)),...] .

輸入參數 f 定義一階常微分方程組的右邊項 (RHS) :

44 JJ ª目 錄 II

Page 47: Scilab 常微分教學

Scialb指令說明

dydt

= f(t,y)

f 為一外部函數,可以利用 Scilab , Fortran或 C語言定義 (請參考 6.5)。

外部函數語法

1. 若 f 為一 Scilab函數它的語法為:

ydot = f(t,y)

其中 t 為一純量 (時間),y 為一實數向量 (狀態, state)而 ydot 為向量 y 之時間導數。

2. 若 f 為字串,代表 Fortran或 C所定義之函式;呼叫 ode 方式為

ode(y0,t0,t,'fex')

代表以 Fortran或 C語言轉寫函數 fex 做為定義微分方程組 (f )之用。

• Fortran函式之語法為:

fex(n,t,y,ydot)

• C函式之語法為:

fex(int *n,double *t,double *y,double *ydot)

其中 n為整數,代表狀態向量 y 之大小, t為精度實數 (時間),y 及 ydot皆為雙精度向量。

3. 如果微分方程組之需要額外之輸入參數,可以利用串列 (list)方式輸入,請參考外部函數說明 (6.5)

45 JJ ª目 錄 II

Page 48: Scilab 常微分教學

Scialb指令說明

選擇性輸入參數 選擇性輸入參數可以用來控制所需之精度, rtol 及 atol 分別作為建立誤差門檻(threshold)所需的絕對及相對誤差之用。y(i) 之估計誤差為 rtol(i)|(y(i)| + atol(i)

如果誤差小於門檻 (threshold)值,積分會繼續進行下一時步 (time step)。若 rtol 及 atol 為常數,rtol(i)及/或 atol(i) 皆設為此常數值。對大部分 ODE求解器, rtol 及 atol 之內定值為 rtol=1.d-3 及 atol=1.d-4 ,而使用 "rfk" 及 "fix" 選項時,rtol=1.d-3 及 atol=1.d-4 。

Jacobian梯度函數 若常微分方程式屬於勁度問題 (stiff problems),最好也提供 f 的 Jacobian梯度函數 jac。 jac 也是一個外部函數

1. Scilab函數原型為

J=jac(t,y)

2. Fortran , C函數原型為:

! Fortran 函數原型

subroutine fex(n,t,y,ml,mu,J,nrpd)

integer n,ml,mu,nrpd

double precision t,y(*),J(*)

// C 函數原型

void fex(int *n,double *t,double *y,int *ml,int *mu,double *J,int *nrpd,)

其中 t 為一實數純量 (時間),y 為實數向量 (state)。輸出矩陣 J 必須計算∇f ,也就是 Jk,i = ∂fk∂xi

46 JJ ª目 錄 II

Page 49: Scilab 常微分教學

Scialb指令說明

選項 type= roots ,設定跨零條件 第一個參數若為 "root" ,則常微分方程式 dy/dt = f(t,y)會在解 y通過代數方程式 g(t,y)=0 之曲面時停止計算。

g 提供曲面之方程式,它是一個外部函數, g 可以用 Scilab , C或 Fortran語言撰寫。

1. Scilab原型

z=g(t,y)

2. C或 Fortran原型

g(n,t,y,ng,gout)

其中 t 為一實數純量 (time), y 為實數向量 (狀態) n 為 y 之大小, gout 為 g 之輸出 (C或 Fortran)。

使用 root 選項時,輸出 rd 為一 1 x k 向量,第一項代表停止之時間,其餘項代表哪幾個 g 向量之分量之正負號產生變化。若 k 大於代表有 1個以上的曲面 (共 (k-1) )同時被穿越。

其他選擇性輸入參數 參數 w 及 iw 式儲存積分資訊之向量。當這些向量參數提供時, ode 就好像是由給定之狀態重新啟動一樣。

47 JJ ª目 錄 II

Page 50: Scilab 常微分教學

Scialb指令說明

6.2 impl-微分-代數方程式

微分-代數方程式

呼叫方法

• y=impl([type],y0,ydot0,t0,t [,atol, [rtol]],res,adda [,jac])

參數

y0,ydot0 實數向量或矩陣 (初始條件). y0 為初始條件。ydot0 為 y 在 t0 的時間導數。t0 實數純量 (初始時間).

t 實數向量 (欲求得解的各個時間點).

res 外部函數 (函數、字串串列 (list)) .輸入參數 res 為一外部函數 (函數、字串串列 (list))• 若 res 為一 Scilab函數時,此函數之原型為:

r = res(t,y,ydot)

其中 t 為一實數純量 (time)而 y 及 ydot 為實數向量 (state and derivative of the state)。

此函數傳回 r=g(t,y)-A(t,y) ydot∗.

• 若 res 為一字串,它代表一 Fortran或 C副程式的名稱,請參考 routines/default/Ex-impl.f 檔案。

• res 也可以為一串列,請參考 odep.ode或外部函數

48 JJ ª目 錄 II

Page 51: Scilab 常微分教學

Scialb指令說明

adda 外部函數 (函數、字串串列 (list)) .輸入參數 adda 也是一外部函數。

• 若 adda 為一 Scilab函數,他的函數原型為:

r = adda(t,y,p)

此函數傳回 r=A(t,y)+p 其中 p 為一加到 A(t,y) 的矩陣。

• 若 adda 為一字串,它代表一 Fortran或 C副程式的名稱,請參考 routines/default/Ex-impl.f 檔案。

• adda 也可以為一串列,請參考 odep.ode或外部函數。

type 字串 ’adams’ 或 ’stiff’atol,rtol 維度和 y 一樣的實數純量或實數向量。

49 JJ ª目 錄 II

Page 52: Scilab 常微分教學

Scialb指令說明

jac 外部函數 (函數、字串串列 (list))輸入參數 jac 也是一外部函數。

• 若 jac 為一 Scilab函數時,此函數之原型為:

j = jac(t,y,ydot)

此函數傳回 r=g(t,y)-A(t,y) ydot∗ 對 y 取微分的梯度函數。 of r=g(t,y)-A(t,y) ydot∗with

• 若 jac 為一字串, 為一字串, 它代表一 Fortran或 C 副程式的名稱,請參考

routines/default/Ex-impl.f 檔案。

• jac 也可以為一串列,請參考 odep.ode或外部函數 .

說明 求解隱式微分方程式

A(t,y)y′ = g(t,y)y(t0) = y0

t0為初始時間, y0為初始條件。 y′0為 y 在 t0的時間導數。

範例

50 JJ ª目 錄 II

Page 53: Scilab 常微分教學

Scialb指令說明

// resid, aplusp 已定義在 routines/default/Ex-impl.f 中

// 為 Fortran 函數

y=impl([1;0;0],[-0.04;0.04;0],0,0.4,'resid','aplusp');

// Using hot restart

//[x1,w,iw]=impl([1;0;0],[-0.04;0.04;0],0,0.2,'resid','aplusp');

// hot start from previous call

//[x1]=impl([1;0;0],[-0.04;0.04;0],0.2,0.4,'resid','aplusp',w,iw);

//maxi(abs(x1-x))

51 JJ ª目 錄 II

Page 54: Scilab 常微分教學

Scialb指令說明

6.3 bvodeS-bvode的簡化呼叫版

bvode的簡化呼叫版

呼叫方法

z=bvodeS(x,m,n,a,b,fsub,gsub,zeta, ...

[ystart,dfsub,dgsub,fixpnt,ndimf,ndimi,ltol,tol,ntol,nonlin, collpnt,subint,iprint,ireg,ifail])

參數

x 希望求得近似解的格點陣列,點 x(i) 必須以遞增方式排列。

m N 階向量,其中mi為向量 u第 i分量的微分方程式 (參數 fsub )之階數 (order),如下所示:

umii =

dmiui

dxmi= fi(x, z(u(x))), i = 1, · · · , N, a < x < b

參數m∗ = m1 + m2 + · · · + mN (mstar)代表此微分方程組的總階數。

n 微分方程式數目 N ≤ 20 ,也是m 之長度。

a 左邊界, a ≤ xi。

b 右邊界 xi ≤ b。

52 JJ ª目 錄 II

Page 55: Scilab 常微分教學

Scialb指令說明

fsub 提供微分方程組的函數名稱,可以使用外部函數 (6.5)。 fsub為以下函數之名稱,

f(x, z(u(x))) =

f1

· · ·· · ·fN

若使用 Scilab函數之原型為 [f]=fsub(x,z) 其中 f 代表上式之計算結果 (向量值),而

z(u(x)) = (u1(x), u11(x), · · · , um1−1

1 (x), · · · , umN−1N (x))T

= (z1, · · · , zm∗)T ,m∗ = m1 + m2 + · · · + mN

代表未知向量 u各分量之各階微分值。gsub 提供計算側邊條件的計算函數名稱,可以使用外部函數 (6.5)。 gsub為以下側邊條件的函

數名稱gj(ζj , z(u(ζj))) = 0, j = 1, · · · ,m∗

m∗ = m1 + m2 + · · · + mN

函數形式為 [g]=gsub (i , z) 其中 1 < i < m∗ , 此函數只傳回第 i 行側邊條件 (純量)

gj(ζj , z(u(ζj)))zeta zeta(j) ( ζj )代表第 j 個側邊條件 (side condition)的座標,必須滿足 ζj ≤ ζj+1 。 zeta各點

必須同時為 fixpnt 向量內一值 (如果使用 fixpnt )。 zeta(j) ( ζj )的長度為m∗ =∑

mi。

53 JJ ª目 錄 II

Page 56: Scilab 常微分教學

Scialb指令說明

z 所有各分量 ui之解以及mi以下之微分量所成的向量 (參考範例)。 z的長度為m∗ =∑

mi

。z(u(x)) = (u1(x), u1

1(x), · · · , um1−11 (x), · · · , umN−1

N (x))T

= (z1, · · · , zm∗)T ,m∗ = m1 + m2 + · · · + mN

選擇性輸入參數

ystart 計算 z(u(x))及 umii 初始近似值的函數名稱,形式為 [z,dmval]= guess (x ) ,其中 z 是維度

為m∗的向量, dmval 是維度為 N 的向量。dfsub f(x, z(u(x)))之 Jacobian梯度函數名稱, Scilab之函數原型為 [df]=dfsub (x, z)

df(i, j) = ∂fi

∂zj, i = 1, · · · , N

j = 1, · · · ,m∗

dgsub 計算側邊條件的 Jacobian梯度函數第 i行,形式為 [dg]=dgsub (i , z )

dg(j) = ∂gi∂zj

, i = 1, · · · ,m∗

j = 1, · · · ,m∗

注意傳回值為一行向量 (row vector)。

fixpnt 包含除了 a (左邊界)及 b(右邊界)以外的所有固定格點之向量。

54 JJ ª目 錄 II

Page 57: Scilab 常微分教學

Scialb指令說明

ndimf 實數工作向量參數的維度, 它的大小會限制次區間的總數。ndimf 參數以下原則設定ndimf ≥ nmax∗nsizef 其中 nsizef = 4+3∗m∗+(5+kd)∗kdm+(2∗m∗−nrec)∗2∗m∗

而 kdm = kd + m∗ ; kd = k ∗ N ; k=ipar(2);nrec為右邊界條件之數目。

ndimi 整數向量參數它的大小會限制次區間的總數。 ndimi 參數以下原則設定 ndimi ≥ nmax ∗nsizei其中 nsizei = 3 + kdm而 kdm = kd + m∗ ; kd = k ∗N ; k=ipar(2);nrec為右邊界條

件之數目。

ltol 維度為 ntol 的陣列。 ltol(j) = l 告知 z(u) 的第 j-th分量用於容忍精度 tol中以控制誤差。

1 ≤ ltol1 ≤ ltol2 ≤ ... ≤ ltolntol ≤ m∗

tol 維度為 ntol的陣列。 tolj 為 z的第 ltolj 個分量的誤差容忍精度。因此,程式企圖在每一次

區間內滿足

|z(v)ltol(j) − z(u)ltol(j)| ≤ tol(j)|z(u)ltol(j)| + tol(j), j = 1, · · · , ntol

其中 v(x)為近似解。ntol 計算容忍精度所參考的分量解及其微分值數目,其中 0 ≤ ntot ≤ m∗,請參考 ltol , tol 兩

參數之設定。

nonlin 0 :線性問題, 1 :非線性問題

collpnt 每一次區間 (subinterval)內所使用的計算點 ( collocation points)數其中 max mi ≤ k ≤ 7 (內

部計算時在輸入的格點間先分割出 subint個次區間,每一次區間內,分佈計算點以提高計算精度)。如果collpnt=0 則設定 collpnt = maxi(maxmi + 1, 5 − max mi)

subint 網格間之次區間數目。如果 subint = 0 則代表內定值 subint = 5。

55 JJ ª目 錄 II

Page 58: Scilab 常微分教學

Scialb指令說明

iprint 輸出控制 ( = iprint )

• = -1完全診斷列印

• = 0部分列印

• = 1不列印

ireg

• = 0正規 (regular)問題

• = 1如果第一個鬆弛因數 (relax factor RELAX )為 rstart (譯註: RSTART為 colnew.f內

之固定參數, RESTART=1.D-2而 RELAX為控制分線性迭代的內部變數),且非線迭代

不依靠過去之受斂紀錄。 (只用於極度敏感之非線性問題).

• = 2在以下兩種狀況下馬上停止計算 (a)連續兩次不收斂,或 (b)第一次得到誤差估

計。

ifail 若 ifail=1,所有呼叫 bvode所需的參數會顯示列印。

56 JJ ª目 錄 II

Page 59: Scilab 常微分教學

Scialb指令說明

6.4 dassl,dasrl -微分-代數方程式 (differential algebraic equation)

微分-代數方程式 (differential algebraic equation)

呼叫方法

[r [,hd]]=dassl(x0,t0,t [,atol,[rtol]],res [,jac] [,info] [,hd]) // 一般式

[r,nn,[,hd]]=dasrt(x0,t0,t [,atol,[rtol]],res [,jac],ng, surf [,info] [,hd])//加上跨零條件

參數

x0 代表初值,為 y0 (ydot0 暫時估計為 0 ) 或 [y0 ydot0] 。若為後者, 代數方程式

g(t,y0,ydot0)=0 必須滿足。如果 ydot0 只是一個估計值時 (不滿足代數方程式) 可設

info(7)=1。• y0 :實數向量,初始條件之。

• ydot0 :實數向量, y在 t0 的時間微分, (可以為一估計值)。

t0 實數,初始時間。

t 實數純量或行向量,為希望計算出解的時間。如果希望在 dassl的每一計算過程皆輸出果

時,可以設定輸入參數 info(2)=1。atol,rtol 實數純量或和 y大小一樣的列向量。. atol,rtol 分別提供的絕對及相對誤差容忍精度。若

為向量,代表 y各分量的容忍精度。

57 JJ ª目 錄 II

Page 60: Scilab 常微分教學

Scialb指令說明

res 外部函數 (函數、字串串列 (list)) 。計算 g(t,y,ydot) .

• Scilab函數:若輸入函數名稱,則函數原型為 [r,ires]=res(t,y,ydot) 而 res 傳回r=g(t,y,ydot) 的殘數 r (residue)及一錯誤旗標 ires 。 ires = 0 如果 res 計算成功,否則 ires=-1 代表殘數無法計算, ires=-2 如果輸入的參數超出允許的範圍。

• 串列 (list) :若輸入串列時,格式為:

list(res,x1,x2,...)

其中 res 的函數原型變為

r=res(t,y,ydot,x1,x2,...)

而 res 雖然是 (t,y,ydot,x1,x2,...) 的函數,一樣必須傳回 r=g(t,y,ydot) 之數值。

• 字串:如果輸入為字串時,它代表一 fortran副程式 (請參考 routines/defaut/目錄中之範

例檔 Ex-dassl.f )。

58 JJ ª目 錄 II

Page 61: Scilab 常微分教學

Scialb指令說明

jac 外部函數 (函數、字串串列 (list)) 。給一實數 c ,計算 dgdy + cdg

dy 數值之函數。

• Scilab函數:若為 Scilab函數,則函數原型為 r=jac(t,y,ydot,c) ,函數 jac 傳回dgdy (t, y, y) + cdg

dy (t, y, y)其中|∗c∗為一實數純量

• 串列 (list) :若為串列,格式為

list(jac,x1,x2,...)

jac 的函數原型成為

r=jac(t,y,ydot,x1,x2,...)

而 jac 雖然是 (t,y,ydot,cj,x1,x2,...) 的函數,一樣必須傳回 dg/dy+cj dg/dydot∗之數值。

• 字串:如果輸入為字串時,它代表一 fortran副程式 (請參考 routines/defaut/目錄中之範

例檔 Ex-dassl.f )。

59 JJ ª目 錄 II

Page 62: Scilab 常微分教學

Scialb指令說明

info 內含 7個元素的串列,內定值為 ([],0,[],[],[],0,0);

• info(1) :實數純量,設定計算 g 的最大時間,若輸入一空矩陣 [] 代表無限制。

• info(2) :用以設定 dassl 是否傳回計算過程間的結果, (flag=1 )代表輸出所有中間計

算結果, or (flag=0 )代表只輸出指定時間 (參數 t )的結果。

• info(3) : 2 元素之向量 [ml,mu] 用以代表函數 jac 所計算出的帶狀 (band)矩陣;

r(i − j + ml + mu + 1, j) = dgdy (t, y, y) + cdg

dy (t, y, y)若 jac 傳回滿 (full) 矩陣時,設

info(3)= [] 。 (譯註: ml , mu 代表帶狀矩陣不為零之水平元素,離對角線之左邊指標距離,及右邊指標距離)

• info(4) :實數純量,設定最大時間進階距離 (time step size)。 info(4)= [] 代表無限制。

• info(5) :實數純量,代表初始時間進階距離 (initial step size)。 info(4)= [] 代表無設定。.

• info(6) : info(6)=1 代表已知解必然為非負 (non negative),否則設 info(6)=0。

• info(7) : info(7)=1 代表參數 x0 中所提供的 ydot0 只是一估計值,但若 info(7)=0 代表滿足 g(t0,y0,ydot0)=0。

hd 實數向量,用來儲存 dassl計算內容以便重新計算。r 實數矩陣,每一列為向量 [t;y(t); y(t)]其中 t代表所計算的時間, y(t), y(t)為解及其其微

分值 (列向量)。

60 JJ ª目 錄 II

Page 63: Scilab 常微分教學

Scialb指令說明

參數 (僅用於指令 dasrt)

nn 傳回值,兩元素之向量 [times num] times 為跨零面的產生時間, num 為跨零面 (crossed

surface)之編號數。

ng 跨零曲面數目

surf 外部函數 (函數、字串串列 (list))。計算 ng個元素的列向量函數 surf(t,y) ,每一分量代表一區面,

• Scilab函數:若為 Scilab時,函數原型須為 surf(t,y)

• 串列 (list) :若為串列時,格式為

list(surf,x1,x2,...)

此時 surf 之函數原型為

r=surf(t,y,x1,x2,...)

• 字串:若為字串時代表一 fortran副程式 (請參考 routines/defaut/目錄中之範例檔

fsurfd.f )

dassl說明

61 JJ ª目 錄 II

Page 64: Scilab 常微分教學

Scialb指令說明

微分-代數方程式

g(t,y, y) = 0

初值條件

y(t0) = y0

y(t0) = y0

dasrl說明

微分-代數方程式

g(t,y, y) = 0

初值條件

y(t0) = y0

y(t0) = y0

跨零條件

S(t,y) = 0

62 JJ ª目 錄 II

Page 65: Scilab 常微分教學

Scialb指令說明

只要一個以上的跨零函數為 0時,即停止計算。程式同時輸出產生跨零條件的時間,及滿足跨零條件的區面

編號。

詳細的範例可參考 SCIDIR/tests/dassldasrt.tst

63 JJ ª目 錄 II

Page 66: Scilab 常微分教學

Scialb指令說明

6.5 external- Scilab物件,外部函數或程序

Scilab物件,外部函數或程序

說明 外部函數透過 Scilab函數之參數傳遞至 Scilab函數內部使用,常用於 Scilab特定指令中 (例如 ode ,

optim, schur等 Scilab指令)。

外部函數必須具備特定之參數協定 (或稱函數原型),使 Scilab函數可以用公開之軟體協定先行設計,如此

可以增加軟體開發之彈性。

Scilab函數原型 例如外部函數 costfunc 可作為 optim 的參數。他的 Scilab函數原型為:

[f,g,ind]=costfunc(x,ind)

而 optim 使用 costfunc 的方式為:

optim(costfunc,...)

在這裡, costfunc ( optim所需要的代價函數)計算函數 f(x)及函數梯度 g = ∇f(x)在 x上之值。 (ind 為一整數,在 optim 內有其定義)

如果外部函數內需要額外變動之參數以執行時,這些參數可以透過全域變數的方式影響外部函數。

使用串列傳遞額外參數 另外,也可以利用 list將所需的參數傳給外部函數。例如:外部函數

[f,g,ind]=costfunc(x,ind,a,b,c)

64 JJ ª目 錄 II

Page 67: Scilab 常微分教學

Scialb指令說明

所需要的額外參數 a,b,c並未規範在 optim之內,這種狀況可以在呼叫 optim時,以串列 list(costfunc,a,b,c)形式輸入函數參數:

optim(list(costfunc,a1,b1,c1),....

使用 Fortran 或 C函式 外部函數也可以是 Fortran或 C函式:這項功能能提高系統之計算效率。以 Fortran或

C函式作為外部函數時,直接將 Fortran或 C函式的名稱當作外部函數參數即可。

Fortran或 C 函式與 Scilab函數之介面規範有時並未在 Scilab文件中詳細說明,此時可參考次目錄

routines/default內許多用 Fortran或 C函式設計的外部函數 (請參考 README 檔)。

Fortran或 C函式所設計之外部函數也可以用動態方式連結到系統。

65 JJ ª目 錄 II

Page 68: Scilab 常微分教學

後記

7 後記

本文設計之目標是希望能讓大學生讀者能自修而學習到 Scilab用法。讀者若下載範例後依進度演練後,應該

就會有所得。最常見到學習無效的狀況是,只讀文章但不實際演練。如果讀者是這種狀況,可能不是學習能

力不足,而是方法不對;下載範例,依序演練才是最佳方法。

作者希望能藉著推廣 Scilab而達成計算程序標準化及普及化之目標,這對讀者之學習上之投資也算是一保

障。因此讀者若與網路連線時,請將本文電子檔介紹其他朋友、同學以擴大日後能交換學習資訊的族群。

有關本文內容之錯、別、漏字及其他內容相關之指正、建議或學習問題請於

中文Scilab論壇中提出。 歡迎加入我們的行列。

66 JJ ª目 錄 II