You are on page 1of 68

常微分及差分方程組

Scilab 教學系列 ∗
中文 Scilab
李運璋 (Scilab 中文開發群)


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

i JJ ª 目 錄 II
目 錄

目 錄 邊界層問題 . . . . . . . . . . . . . . . . . . . . 30

微分–代數方程式 33
序 1 微分–代數方程式, 使用 dassl 指令 . . . . . . . 34
跨零條件之微分–代數方程式, 使用 dasrt 指令 . 36
一階常微分方程式組–初值問題 2
一階純量微方方程式 . . . . . . . . . . . . . . 5 線性微分及差分方程組模擬簡介 38
一階純量微方方程式, 使用 C 語言 . . . . . . . 6 線性微分系統之時間響應 . . . . . . . . . . . . 39
向量微分程式 . . . . . . . . . . . . . . . . . . 7 線性差分系統之時間響應 . . . . . . . . . . . . 40
矩陣微分方程式 . . . . . . . . . . . . . . . . . 8
跨零條件 . . . . . . . . . . . . . . . . . . . . . 11 Scialb 指令說明 41
隱式微分方程式 . . . . . . . . . . . . . . . . . 14 ode-常微分方程組求解 . . . . . . . . . . . . . 42
利用 ode 指令求解差分方程組 . . . . . . . . . 17 impl-微分-代數方程式 . . . . . . . . . . . . . . 48
bvodeS-bvode 的簡化呼叫版 . . . . . . . . . . . 52
常微分方程式–邊界值問題 19 dassl,dasrl -微分-代數方程式 (differential alge-
兩點式邊界值問題 . . . . . . . . . . . . . . . . 22 braic equation) . . . . . . . . . . . . . . . 57
特徵值問題 . . . . . . . . . . . . . . . . . . . 24 external- Scilab 物件, 外部函數或程序 . . . . . 64
兩個以上解的邊界值問題 . . . . . . . . . . . . 27
多點邊界值問題 . . . . . . . . . . . . . . . . . 29 後記 66

ii JJ ª 目 錄 II

1 序

計算工具對科學教育之重要性,就如同紙筆對文化傳承一樣;欠缺這類輔助工具,就無法面對環境所提出之
挑戰。工程師、研究人員因此而失去成長的機會,久而久之也就以為我們的文化並不擅長處理科學事項,只
能接受現況。
計算工具沒有了自主性,科技也就失去了根本,外來科技文化很容易的將我們的環境變成一個殖民地。但
要改變現況並不容易;因為現況既已行之久遠,那麼環境早已具備反撲任何改變它的企圖心。所以我們認為
引入 Scilab 到國內高等教育體系是否能成功,關鍵不僅僅在於理念是否服人,也必須具有持續降低 Scilab 學
習成本之實際行動。這樣才能讓新加入的成員很快就具備對抗環境挑戰的實力而能擺脫工具技術上之箝制。
目前針對碩、博士研究生推廣 Scilab 會比向大學生介紹它容易許多。學生程度上差異只是一個原因,計算
工具能夠減輕研究生之研究課題壓力才是主因。因此要將 Scilab 向下推廣到大學生之間,應讓 Scilab 轉成理
工大學生課堂上的輔助學習工具才易成功,而這須要課堂上授課教師願意配合。
所以我們有一系列針對大學理工課堂上所需的 Scilab 引介文章,希望填補課堂之學理和計算工具之間的空
白處,讓教師和學生都願意推介 Scilab。計畫中的主題如下:
『常微分及差分方程組』、『非線性聯立方程式、最佳化及最小二乘法』、『線性代數』、『機率、統
計』、『控制』、『訊號處理』、
這一系列文章應能彌補 Scilab 線上手冊之不足,使大學生易於接受。也希望能做為下一個階段撰寫高中生
教學文件的參考文章。

1 JJ ª 目 錄 II
一階常微分方程式組--初值問題

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

內容
一階純量微方方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
一階純量微方方程式, 使用 C 語言 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
向量微分程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
矩陣微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
跨零條件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
隱式微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
利用 ode 指令求解差分方程組 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

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

微分方程組
dy
= f (t, y)
dt

初值條件

y(t0 ) = y0

2 JJ ª 目 錄 II
一階常微分方程式組–初值問題

其中 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 維向量微分關係,例如下
列:

三階常微分方程式
1
f 000 (η) + f (η)f 00 (η) = 0
2
等價於

3 JJ ª 目 錄 II
一階常微分方程式組–初值問題

一階三維常微分方程組

y10 (η) = y2 (η)


y20 (η) = y3 (η)
1
y30 (η) = − y1 (η)y3 (η)
2

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

4 JJ ª 目 錄 II
一階常微分方程式組–初值問題

2.1 一階純量微方方程式

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

微分方程組

ẏ = y 2 − y sin(t) + cos(t)

初值條件

y(0) = 0

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

y0=0;t0=0; // 2. 初始時間及初值
function ydot=f(t,y) // 1. 提供非線性方程式 f t=0:0.1:%pi; // 3. 設定輸出結果之時間
ydot=y^2-y*sin(t)+cos(t) Y=ode(y0,t0,t,f) // 4. 呼叫 ode 指令
endfunction 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
一階常微分方程式組–初值問題

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

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


數:

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


#include <math.h> // 在 TMPDIR 內編譯出動態連結檔,
void myode(int *n,double *t,double *y,double *ydot) // 以及一自動載入程序檔 loader.sce
{ ilib_for_link('myode','myode.o',[],'c','Makefile','loader.sce');
ydot[0]=y[0]*y[0]-y[0]*sin(*t)+cos(*t); 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
一階常微分方程式組–初值問題

2.3 向量微分程式

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

微分方程組

ẋ = Ax(t) + Bu(t)
[ ] [ ]
1 1 1
A= ,B =
0 2 1

初值條件
[ ]
1
x(0) =
0

ut=sin(omega*t)
// A 及 u 必須利用串列告知函數原型 endfunction
function xdot=linear(t,x,A,u) A= [1 1;0 2];B= [1;1];omega=5;// 線性系統資訊
xdot=A*x+B*u(t) // B 透過全域變數傳遞 // 在 t=0.1, 0.2, 0.5 ,1. 提供 x(t) 的時刻
endfunction // x0= [1;0] ; 初始值
// omega 透過全域變數傳遞 //最後一參數為串列,提供額外參數 A 及 u 資訊
function ut=u(t) // 輸入函數 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
一階常微分方程式組–初值問題

2.4 矩陣微分方程式

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

微分方程組

Ẏ = 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
一階常微分方程式組–初值問題

Riccati 矩陣微分方程式

Ẋ = AT X + 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
一階常微分方程式組–初值問題

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

矩陣微分方程式

Ẋ = AX
[ ]
1 1
A=
0 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
一階常微分方程式組–初值問題

2.5 跨零條件

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

微分方程組
dy
= f (t, y)
dt

初值條件

y(t0 ) = y0

跨零條件

g(t, y) = 0

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

11 JJ ª 目 錄 II
一階常微分方程式組–初值問題

例如以下問題:

微分方程式及初值條件

ẏ = 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 改為
 
2
 
g(t, y) = y −  2 
33

則 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
一階常微分方程式組–初值問題

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

13 JJ ª 目 錄 II
一階常微分方程式組–初值問題

2.6 隱式微分方程式

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


集結在等號左邊,

隱式微分方程組

A(t, y)y0 = 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)y0 之結果,也就是

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
一階常微分方程式組–初值問題

例如以下指令呼叫impl,

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

由指令反解,可知輸出結果時刻是在 t = 0.4,而初值 y0 , y0 0 為
   
1 −0.04
   
y0 = 0 , y0 0 =  0.04 
0 0

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

   1 -3.0d7*y(2)*y(2)-s(2)
c r(3)= y(1) + y(2) + y(3) - 1.0d+0
c routines/default/Ex-impl.f 檔 return
c end
subroutine resid(neq, t, y, s, r, ires)
c ---------------------------------------- subroutine aplusp(neq, t, y, ml, mu, p, nrowp)
c 此函數計算 r=g(t,y)-a(t,y)*s c ----------------------------------------------
c inputs : t time c 此函數計算 p=p+a, 其中 a=a(t,y) 為一 ny x ny 矩陣
c y 在時間 t 之 y 值 double precision p, t, y
c s 在時間 t 之 dy/dt 值 dimension y(3), p(nrowp,3)
c ny y 之維度 (向量大小) p(1,1) = p(1,1) + 1.0d+0
c ires 可忽略 p(2,2) = p(2,2) + 1.0d+0
double precision r, s, t, y return
dimension y(3), s(3), r(3) end
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)

15 JJ ª 目 錄 II
一階常微分方程式組–初值問題

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

 
−.04y1 + 104 y2 y3
 
g(t, y) = 0.04y1 − 104 y2 y3 − 3 × 107 y22 
y1 + y2 + y3 − 1
 
1 0 0
 
A(t, y) = 0 1 0
0 0 0

實際上,第三個方程式是代數方程式而非微分方程式。
值得注意的是,函數 g(t, y) 的資訊並未出現在指令 impl 之參數中,而是透過 res 參數間接提供。

16 JJ ª 目 錄 II
一階常微分方程式組–初值問題

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
一階常微分方程式組–初值問題

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

差分方程組

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


   
0.2 0 0 1
   
A =  0 0.5 0  , B = 1
0 0 0.9 1

初值條件
 
1
 
y(1) = 2
3

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

n=5;
function yp=a_function(k,y) // 差分方程式 // 計算出 [y(1),..y(5)]
yp=A*y+B*u(k);// u (控制項) 透過外部變數傳入 y=ode("discrete",y1,1,1:n,a_function);
endfunction y(:,2)-(A*y1+B*u(1)) // 比較 y(2)
y1= [1;2;3]; // 初值 // 計算出 [y3,y5,y7,y9]
A=diag([0.2,0.5,0.9]); B= [1;1;1]; y=ode("discrete",y1,1,3:2:9,a_function)
u=1:10; // 設定 u (控制項)

18 JJ ª 目 錄 II
常微分方程式–邊界值問題

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

內容
兩點式邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
特徵值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
兩個以上解的邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
多點邊界值問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
邊界層問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

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


(多點式邊界值問題)。 Scilab 針對兩點、多點邊界值問題提供 bvode 及 bvodeS指令求解。由於bvodeS 是
bvode 指令的介面重新設計之版本,因此本節將只討論bvodeS 之用法。

19 JJ ª 目 錄 II
常微分方程式–邊界值問題

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

微分方程組
dm1 u1
= f1 (x, z)
dxm1
m
d 2 u2
= f2 (x, z)
dxm2
..
.
dmn−1 un−1
= fn−1 (x, z)
dxmn−1
dmn un
= fn (x, z)
dxmn
1 −1 n −1 (x))T 為座標點 x 上 u 各分量u 最高階導數 m
其中z(x) = (u1 (x), u11 (x), · · · , um
1 (x), · · · , un (x) · · · , um
n i i
以下的各階導數 (包含 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
常微分方程式–邊界值問題

呼叫 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 之大小。而


1 −1 n −1
z(x) = (u1 (x), u11 (x), · · · , um
1 (x), · · · , un (x) · · · , um
n (x))T

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

21 JJ ª 目 錄 II
常微分方程式–邊界值問題

3.1 兩點式邊界值問題

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

微分方程式

y10000 (x) = (1 − 6x2 y1000 (x) − 6xy100 (x))/(y2 (x)3 )


y20 (x) = 1

邊界條件

y1 (1) = 0 y100 (1) = 0


y2 (2) = 1 y100 (2) = 0 y2 (2) = 2

解題步驟如下:

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

2. 定出擴增未知為 z = [y1 ; y10 ; y100 ; y1000 ; y2 ]

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

y10000 (x) = (1 − 6x2 z4 (x) − 6xz3 (x))/(z5 (x)3 )


y20 (x) = 1

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

22 JJ ª 目 錄 II
常微分方程式–邊界值問題

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

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

因此以 bvodeS 之解題指令為,

z=zeros(5,1);z(5)=1;
// 微分方程組 lhS= [0;1];
function RhS=fsub(x,z) endfunction
RhS= [(1-6*x*x*z(4)-6*x*z(3))/(z(5)^3);1] n=2; // 方程式數目
endfunction m= [4 1];// 微分階數
// 邊界條件 (傳回純量而非向量) N=100; //格點
function g=gsub(i,z) a=1; b=2; // 左右邊界
g= [z(1) z(3) z(1)-1 z(3) z(5)-2] zeta= [a a b b b]; // 邊界條件之位置
g=g(i) x=linspace(a,b,N); //產生均勻格點
endfunction ltol=4; // 改變內定誤差收斂條件.
// Z 之初始猜值 tol=1e-12;
function [z,lhS]=ystart(x) Z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ltol=ltol,tol=tol,ystart=ystart);

23 JJ ª 目 錄 II
常微分方程式–邊界值問題

3.2 特徵值問題

考慮以下之特徵值問題:

微分方程式

y 00 (x) = −λy(x)

邊界條件

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

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

微分方程式

y 00 (x) = −λy(x)
λ0 = 0

微分方程式

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


y(1) = 0

24 JJ ª 目 錄 II
常微分方程式–邊界值問題

 
y
 0
將 x ∈ [0, 1] 各點欲解之值整理成向量 z = y  後,再重寫方程式成為 bovdeS 所接受之格式:
λ

微分方程式

y 00 (x) = −z3 z1
λ0 = 0

邊界條件

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


z1 (1) = 0

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

z= [1;0;la0]
function rhs=fsub(x,z) // 微分方程式右邊項 lhs= [0;0]
rhs= [-z(3)*z(1);0] endfunction
endfunction a=0;b=1;
function g=gsub(i,z) // 邊界條件共三項 m= [2;1];
g= [z(1)-z(2) z(1)-1 z(1)] n=2;
g=g(i) zeta= [a a b]; // 邊界條件的位置
endfunction N=101;
// 初始猜值函數 x=linspace(a,b,N)';// 輸出結果之位置
function [z,lhs]=ystart(x,z,la0)

25 JJ ª 目 錄 II
常微分方程式–邊界值問題

// 輸入 n (特徵值編號) // z(1,:)' = y , z(2,:)' = y' , z(3,:) = \lambda


la0=input('n-th eigenvalue: n= ?'); plot2d(x,[z(1,:)' z(2,:)'],style= [5 1],axesflag=5)
la0=(%pi/2+la0*%pi)^2; //特徵值之猜值 xtitle(['Startvalue = '+string(la0);...
// 'Eigenvalue = '+string(z(3,1))],'x',' ')
z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,ystart=list(ystart,la0)); legend(['y(x)';'y''(x)'])
clf()

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


本例之解,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
常微分方程式–邊界值問題

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

微分方程式

y 00 (x) = −ey(x)

邊界條件

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

[ ]
y
這個邊界值問題多重解,這展示求解其中兩個解,將各點欲解之值整理成向量 z = 0 後,再重寫方程式成
y

微分方程式

y 00 (x) = −ez1 (x)

27 JJ ª 目 錄 II
常微分方程式–邊界值問題

邊界條件

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

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

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


z= [M;0]
a=0;b=1;m=2;n=1; //lhs= [-exp(4*x*(1-x)*M)]
zeta= [a b]; lhs=0
N=101; endfunction
tol=1e-8*[1 1];
x=linspace(a,b,N); // 使用不同之初值參數 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);
function rhs=fsub(x,z),rhs=-exp(z(1));endfunction
// 繪出 兩組解
function g=gsub(i,z) // 邊界條件 clf();
g= [z(1) z(1)] subplot(2,1,1)
g=g(i) plot2d(x,z(1,:),style= [5])
endfunction xtitle('Two different solutions','x',' ')
subplot(2,1,2)
// 初值 plot2d(x,z1(1,:),style= [5])
function [z,lhs]=ystart(x,z,M) xtitle(' ','x',' ')

28 JJ ª 目 錄 II
常微分方程式–邊界值問題

3.4 多點邊界值問題

微分方程式
 
y(x)
 
y 000 (x) = 1, z =  y 0 (x) 
y 00 (x)

邊界條件

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

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

endfunction
a=-1;b=1;c=0; N=10; zeta= [a c b]; // 必須包含中間點
// c 點必須在 fixpnt 中 (bvodeS 選擇性參數之ㄧ). x=linspace(a,b,N);
n=1;m= [3]; // 微分方程式之階數 // fixpnt 除了兩邊以以外的所有點 (此例為 c)
function rhs=fsub(x,z) // 微分方程式右邊項 z=bvodeS(x,m,n,a,b,fsub,gsub,zeta,fixpnt=c);
rhs=1 function y=yex(x) // 正解
endfunction y=x.^3/6+x.^2-x./6+1
function g=gsub(i,z) endfunction
g= [z(1)-2 z(1)-1 z(1)-2] // 計算誤差量
g=g(i) disp(norm(yex(x)-z(1,:)),'norm(yex(x)-z(1,:))= ')

29 JJ ª 目 錄 II
常微分方程式–邊界值問題

3.5 邊界層問題

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

微分方程式
1
f 000 (η) = − f f 00
2

邊界條件

η=0: f = 0, f 0 = 0
η=∞: f0 = 1
 
f
 
將各點上之未知量表為 z =  f 0  ,可以使用以下之指令求得
f 00

function rhs=blas(x,z) // 邊界層方程式右邊項 a=0; b=10; // b=10 以代替無限大


rhs = -0.5*z(1)*z(3) n=1; // 一個方程式
endfunction m=[3]; // 一個 3 階方程式
N=100;
function g=gsub(i,z) // 邊界條件 zeta= [a a b]; // 邊界條件之位置
g= [z(1) z(2) z(2)-1] x=linspa ce(a,b,N);// 計算點
g=g(i) z=bvodeS(x,m,n,a,b,blas,gsub,zeta);
endfunction

30 JJ ª 目 錄 II
常微分方程式–邊界值問題

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


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

微分方程式

z10 (η) = z2
z20 (η) = z3
1
z30 (η) = − z1 z3
2

邊界條件

η=0: z1 = 0, z2 = 0
η=∞: z2 = 1

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

g=g(i)
function rhs=blas2(x,z) // 改用一皆微分方程祖 endfunction
rhs = [z(2) ; z(3) ; -0.5*z(1)*z(3)]
endfunction a=0; b=10;
n=3; // 三個方程式
function g=gsub(i,z) m=[1 1 1]; // 三個一階微分方程組
g= [z(1) z(2) z(2)-1] N=100;

31 JJ ª 目 錄 II
常微分方程式–邊界值問題

zeta= [a a b]; // 邊界條件之位置 z1=bvodeS(x,m,n,a,b,blas2,gsub,zeta);


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

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

32 JJ ª 目 錄 II
微分–代數方程式

4 微分–代數方程式

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

微分方程組最一般的表示法,是透過非線性代數式表現一階導數量和變量之關係,這類方程式稱為代
數–微分方程組。 Scilab 提供 dassl, dasrt 兩指令 (請參考 6.4 ) 求解此類方程組。
由於所有高階微分問題,都可以轉為一階微分高維度 (向量) 問題,因此 dassl,dasrt 指令之應用範圍相
當大。與一般初值問題不同之處在於,代數–微分問題之初始條件還必須包含導數量 ẏ(t0 ) = ẏ0 這是因為代
數–微分關係在初始時間 t0 時,y0 , ẏ0 之關係並不唯一。但使用者可以選擇輸入一大約之估計值,使求解過程
逐漸收斂到其中一組解。

33 JJ ª 目 錄 II
微分–代數方程式

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

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

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

g(t, y, ẏ) = 0
y(t0 ) = y0
ẏ(t0 ) = ẏ0

dassl 的呼叫格式如下,

[R]=dassl(x0,t0,t,res ) // 內定簡式
[R [,hd]]=dassl(x0,t0,t [,atol,[rtol]],res [,jac] [,info] [,hd]) // 一般式
[ ]
y0
其中第一個參數 x0 = 為初值 y0 , ẏ0 的合成向量。 res 代表代數–微分組 g(t, y, ẏ)。而傳回值之矩陣
ẏ0
R 的每一列為一依序為 t, y0 , ẏ0 之向量,也就是
 
t1 t2 · · · tk
 
R = y1 y2 · · · yk 
ẏ1 ẏ2 · · · ẏk
其中 t = [t1 t2 · · · tk ] 為須要輸出計算結果的時刻。
例如下頁:

34 JJ ª 目 錄 II
微分–代數方程式

微分–代數方程組 :
−0.04y1 + 104 y2 ∗ y3 − ẏ1 = 0
0.04y1 − 104 y2 ∗ y3 − 3 × 107 y22 − ẏ2 = 0
y1 + y2 + y3 − 1 = 0

初值條件    
1 −0.04
   
y0 =  0  , ẏ0 =  0.04 
0 0

y0= [1;0;0];
yd0= [-0.04;0.04;0];
deff('[r,ires]=chemres(t,y,yd)',[ t= [1.d-5:0.02:.4,0.41:.1:4,40,400,4000,...
'r(1)=-0.04*y(1)+1d4*y(2)*y(3)-yd(1);'; 40000,4d5,4d6,4d7,4d8,4d9,4d10];
'r(2)=0.04*y(1)-1d4*y(2)*y(3)-3d7*y(2)*y(2)-yd(2);' // 1. 使用內定方法
'r(3)=y(1)+y(2)+y(3)-1;' Y=dassl([y0,yd0],0,t,chemres);
'ires=0']); info=list([],0,[],[],[],0,0);
deff('[pd]=chemjac(x,y,yd,cj)',[ // Jacobian 梯度函數 info(2)=1; // 輸出中間計算結果
'pd= [-0.04-cj , 1d4*y(3) , 1d4*y(2);'; // 未使用 Jacobian
'0.04 ,-1d4*y(3)-2*3d7*y(2)-cj ,-1d4*y(2);'; Y=dassl([y0,yd0],0,4d10,chemres,info);
'1 , 1 , 1 ]']) // 使用 Jacobian 梯度向量函數
Y=dassl([y0,yd0],0,4d10,chemres,chemjac,info);

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


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

35 JJ ª 目 錄 II
微分–代數方程式

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

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

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

g(t, y, ẏ) = 0
y(t0 ) = y0
ẏ(t0 ) = ẏ0

跨零條件

S(t, y) = 0

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


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

36 JJ ª 目 錄 II
微分–代數方程式

微分–代數方程組 :
dy
= ((2 log(y) + 8)/t − 5)y, 1 ≤ t ≤ 6
dt

跨零條件

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


S2 = log(y) − 2.2491 = 0

// 提供跨零條件
y0=1;t=2:6;t0=1;y0d=3; deff('[rts]=gr1(t,y)','rts= [((2*log(y)+8)/t-5)*y;log(y)-2.2491]')
atol=1.d-6;rtol=0;ng=2; // 求解
[yy,nn]=dasrt([y0,y0d],t0,t,atol,rtol,res1,ng,gr1);
// 提供代數--微分關係式 //(應傳回 nn= [2.4698972 2] = [結束時刻 跨零條件編號])
deff('[delta,ires]=res1(t,y,ydot)','ires=0;delta=ydot-((2*log(y)+8)/t-5)*y')

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


算。

37 JJ ª 目 錄 II
線性微分及差分方程組模擬簡介

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

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


統可以是時間連續或離散兩類。 Scilab 針對線性系統提供完整之計算工具環境。因此如果微分或差分方程式
為線性系統時,採用 Scialb 線性系統內建之工具,會比使用一般化之常微分,差分方程式計算工具更方便。
本節對 Scialb 線性系統和常微分及差分方程式相關之指令只做簡單介紹,有興趣深入了解的讀者,可以由
Scialb 所附的線上手冊中查詢 (部分內容已有中文翻譯)。針對 Scialb 線性系統較有體系之中文介紹會在後續之
Scilab 中文文件工作中陸續進行。

38 JJ ª 目 錄 II
線性微分及差分方程組模擬簡介

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

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

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

ẋ(t) = Ax(t) + Bu(t)


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

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

y = H(s)u

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

plot2d([t',t'],[(csim('step',t,tf2ss(s)*w))',0*t'])
// csim 線性微分系統之時間響應範例 //繪出以 step 函數輸入 w 系統之時間響應
// xbasc(3);xset("window",3);xselect();
// 代表多項式 s () plot2d([t',t'],[(csim('step',t,w))',0*t'])
s=poly(0,'s'); //繪出以 impulse 函數輸入 w/s 系統之時間響應
// 隨機產生一個 1 個輸入, 1 個輸出 xbasc(4);xset("window",4);xselect();
// 及 3 個內部狀態的動態系統 w plot2d([t',t'],[(csim('impulse',t,tf2ss(1/s)*w))',0*t'])
rand('seed',0);w=ssrand(1,1,3); //輸入改成時間函數 u(t) =|sin(t)|
w('A')=w('A')-2*eye(); // 確保隨機系統為穩定 function u=input(t)
t=0:0.05:5; u=abs(sin(t))
// 繪出以 step 函數輸入 s w 系統之時間響應 endfunction
xbasc(0);xset("window",0);xselect(); xbasc();plot2d([t',t'],[(csim(input,t,w))',0*t'])

39 JJ ª 目 錄 II
線性微分及差分方程組模擬簡介

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

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

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

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


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

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

y = H(z)u

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

rs=flts(u,Sys); // 使用狀態空間模擬
// 給 A,B,C, D 定義系統 (狀態空間法) norm(rh-rs,1) // 兩者應一樣
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]; [ys1,x]=flts(u(:,1:4),Sys);ys2=flts(u(:,5:10),Sys,x);
Sys=syslin('d',A,B,C,D); norm([ys1,ys2]-rs,1) // 兩者應一樣
H=ss2tf(Sys); // H 為轉換函數 //接力計算, 使用轉換函數
u= [1;-1]*(1:10); // u 為控制輸入項 yh1=flts(u(:,1:4),H);yh2=flts(u(:,5:10),H,[u(:,2:4); yh1(:,2:4)]);
rh=flts(u,H); // 使用轉換函數模擬 norm([yh1,yh2]-rh) // 兩者應一樣

40 JJ ª 目 錄 II
Scialb 指令說明

6 Scialb 指令說明

內容
ode-常微分方程組求解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
impl-微分-代數方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
bvodeS-bvode 的簡化呼叫版 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
dassl,dasrl -微分-代數方程式 (differential algebraic equation) . . . . . . . . . . . . . . . . . 57
external- Scilab 物件, 外部函數或程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

41 JJ ª 目 錄 II
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
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) 常微分方程式的標準求解函數:

dy
= f (t, y)
dt
y(t0 ) = y0

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


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

43 JJ ª 目 錄 II
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
Scialb 指令說明

dy
= f (t, y)
dt
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
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
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
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
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
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)y0 = g(t, y)


y(t0 ) = y0

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

範例

50 JJ ª 目 錄 II
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
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), 如下所示:
dmi ui
umi
i = = fi (x, z(u(x))), i = 1, · · · , N, a < x < b
dxmi
參數 m∗ = m1 + m2 + · · · + mN (mstar) 代表此微分方程組的總階數。
n 微分方程式數目 N ≤ 20 , 也是 m 之長度。
a 左邊界, a ≤ xi 。
b 右邊界 xi ≤ b 。

52 JJ ª 目 錄 II
Scialb 指令說明

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


 
f1
 ··· 
 
f (x, z(u(x))) =  
 ··· 
fN

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


1 −1 mN −1
z(u(x)) = (u1 (x), u11 (x), · · · , um
1 (x), · · · , uN (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
Scialb 指令說明


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

1 −1 mN −1
z(u(x)) = (u1 (x), u11 (x), · · · , um
1 (x), · · · , uN (x))T
= (z1 , · · · , zm∗ )T , m∗ = m1 + m2 + · · · + mN

選擇性輸入參數

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


i


為 m 的向量, dmval 是維度為 N 的向量。
dfsub f (x, z(u(x))) 之 Jacobian 梯度函數名稱, Scilab 之函數原型為 [df]=dfsub (x, z)
∂fi
df (i, j) = ∂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
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 (max mi + 1, 5 − max mi )
subint 網格間之次區間數目。如果 subint = 0 則代表內定值 subint = 5 。

55 JJ ª 目 錄 II
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
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
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
Scialb 指令說明

dg
jac 外部函數 (函數、字串串列 (list)) 。給一實數 c , 計算 dy + c ddgẏ 數值之函數。

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


dg dg
dy (t, y, ẏ) + c dẏ (t, 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
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) 矩陣;


dg
r(i − j + ml + mu + 1, j) = dy (t, y, ẏ) + c ddgẏ (t, 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); ẏ(t)] 其中 t 代表所計算的時間, y(t), ẏ(t) 為解及其其微
分值 (列向量)。

60 JJ ª 目 錄 II
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
Scialb 指令說明

微分-代數方程式

g(t, y, ẏ) = 0

初值條件

y(t0 ) = y0
ẏ(t0 ) = ẏ0

dasrl 說明

微分-代數方程式

g(t, y, ẏ) = 0

初值條件

y(t0 ) = y0
ẏ(t0 ) = ẏ0

跨零條件

S(t, y) = 0

62 JJ ª 目 錄 II
Scialb 指令說明

只要一個以上的跨零函數為 0 時,即停止計算。程式同時輸出產生跨零條件的時間,及滿足跨零條件的區面
編號。
詳細的範例可參考 SCIDIR/tests/dassldasrt.tst

63 JJ ª 目 錄 II
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
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
後記

7 後記

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


就會有所得。最常見到學習無效的狀況是,只讀文章但不實際演練。如果讀者是這種狀況,可能不是學習能
力不足,而是方法不對;下載範例,依序演練才是最佳方法。
作者希望能藉著推廣 Scilab 而達成計算程序標準化及普及化之目標,這對讀者之學習上之投資也算是一保
障。因此讀者若與網路連線時,請將本文電子檔介紹其他朋友、同學以擴大日後能交換學習資訊的族群。

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

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

66 JJ ª 目 錄 II

You might also like