跳轉到內容

MATLAB 程式設計/高階主題/工具箱和擴充套件/符號工具箱

來自華夏公益教科書,開放的世界中的開放書籍




符號數學工具箱簡介

[編輯 | 編輯原始碼]

符號工具箱使用起來有點困難,但在需要符號表達式的應用程式中,由於計算精度的原因,它非常有用。工具箱只需呼叫 MAPLE 核心,並使用您宣告的所有符號表達式,然後將(通常是符號)表示式返回給 MATLAB。重要的是要記住,MAPLE 不是一個數值引擎,這意味著它不允許您做 MATLAB 可以做的事情。相反,它作為一個補充提供 MATLAB 作為數值引擎難以處理的函式。

符號數學工具箱需要一些時間來初始化,因此如果您在宣告會話中的第一個符號變數後幾秒鐘沒有發生任何事情,並不意味著您做錯了什麼。

MATLAB 學生版附帶符號數學工具箱的副本。

符號變數

[編輯 | 編輯原始碼]

您可以使用 'sym' 函式宣告單個符號變數,如下所示。

>> a = sym('a1')
a = a1

您可以像其他所有操作一樣建立符號表達式的陣列


>> a1 = sym('a1');
>> a2 = sym('a2');
>> a  = [a1, a2]
a = [ a1,  a2]


符號變數也可以使用 'syms' 函式一次宣告多個。預設情況下,建立的符號變數與 'syms' 函式的引數具有相同的名稱。以下建立了三個符號變數 a、b 和 c。

>> syms a b c
>> a
a = a

符號數

[編輯 | 編輯原始碼]

符號數允許分數的精確表示,旨在幫助避免舍入誤差和表示誤差。本節幫助解釋如何宣告它們。

如果您嘗試將數字新增到符號陣列中,它會自動將其轉換為符號數字。

>> syms a1, a2;
>> a = [a1, a2];
>> a(3) = 1; %would normally be class 'double'
>> class(a(3))
ans = sym

符號數也可以使用語法 a(3) = sym('number') 宣告。符號數和普通 MATLAB 數字之間的區別在於,如果可能,MAPLE 會將符號數保留為分數,這是答案的精確表示。例如,要將數字 0.5 表示為分數,您可以使用

>> sym(0.5)
ans = 1/2

當然,MATLAB 通常會返回 0.5。要讓 MATLAB 將其更改回 'double',請鍵入

>> double(ans)
ans = 0.5000

其他類轉換也是可能的;例如,要將其更改為字串,請使用 'char' 函式。不幸的是,沒有函式可以將符號變數直接更改為函式控制代碼。

注意事項:如果您不使用正確的語法,建立負指數的符號變數可能會出現問題。您不能這樣做

>>  sym('2^-5')
??? Error using ==> sym.sym>char2sym
Not a valid symbolic expression.

相反,您必須這樣做

>>  sym('2^(-5)')
ans = 2^(-5)

因此,MAPLE 對您可使用的運算子比 MATLAB 更挑剔。

符號函式

[編輯 | 編輯原始碼]

您可以建立符號變數的函式,而不僅僅是變數本身。這可能是最直觀的方法

>> syms a b c %declare variables
>> f = a + b + c
ans = a + b + c

如果您以這種方式執行此操作,那麼您隨後可以相對於這些變數中的任何一個執行替換、微分等等。

如果您想建立實際函式,它不會太難

>> syms a b c
>> f(a,b,c) = a + b + c % or f = symfun(a + b + c, [a b c]) if you want to be more explicit
f(a, b, c) = a + b + c
>> f(1,2,3)
ans = 6

將值代入符號變數

[編輯 | 編輯原始碼]

可以將替換代入符號變數的函式。假設您定義了函式 f = a + b + c,並且希望將 a = 3 代入 f。您可以使用以下語法執行此操作

>> syms a b c  %declare variables
>> f = a + b + c;
>> subs(f, a, 3)
ans = 3+b+c

請注意此函式呼叫的形式。第一個引數是您要代入的函式的名稱。第二個可以是您要代入的符號變數的名稱其當前值,但如果您想避免混淆,它們應該始終相同。第三個引數是您要代入該變數的值。

您代入的值不必是數字。您還可以透過使用字串代入其他變數(包括函式中已經存在的變數)。使用相同的 f

>> subs(f, a, 'x')
ans = x+b+c
>> subs(f, a, 'b')
ans = 2*b + c

如果 x 已經是符號變數,則可以省略引號(但如果它不是,您將收到未定義變數錯誤)

>> syms x
>> subs(f,a,x)
ans = x+b+c

允許多次替換;要執行此操作,只需將它們中的每一個都宣告為陣列。例如,要將 1 代入 a,將 2 代入 b,請使用

>> subs(f, [a,b], [1,2])
ans = 3+c

最後,如果您為函式中的所有符號值代入,MATLAB 會自動將值更改回 double,以便您可以在 MATLAB 工作區中操作它。

>> subs(f, [a,b,c], [1,2,3])
ans = 6
>> class(ans)
ans = double

使用符號矩陣作為輸入的函式

[編輯 | 編輯原始碼]

不幸的是,symfun 似乎不允許使用符號矩陣作為函式輸入。您可以手動將矩陣的每個元素新增到輸入變數列表中,或者甚至使用 subs 以迭代方式替換輸入值(如果您只是使用符號表達式),但這兩種解決方案都需要鍵入所有索引。相反,最簡單的路徑是宣告一個匿名函式

>> A = sym('A',2) % declare a 2x2 symbolic matrix
>> sum_elements = @(myMat) myMat(1,1) + myMat(1,2) + myMat(2,1) + myMat(2,2);
sum_elements = @(myMat)myMat(1,1)+myMat(1,2)+myMat(2,1)+myMat(2,2)
>> sum_elements(A)
ans = A1_1 + A1_2 + A2_1 + A2_2

代數函式操作

[編輯 | 編輯原始碼]

符號數學工具箱允許您使用多種不同的方法來操作函式。首先,您可以使用 'factor' 對函式進行因式分解,並使用 'expand' 將其展開

>> syms a b
>> f = a^2 - 2*a*b + b^2;
>> factor(f);
ans =  (a - b)^2
>> expand(ans)
ans =  a^2 - 2*a*b + b^2

'collect' 函式與 'expand' 函式的作用相同,但隻影響多項式項。'Expand' 也可以用於擴充套件三角函式和對數/指數函式,使用相應的恆等式。

函式的 Horner(巢狀)表示由 'horner' 給出

>> horner(f)
ans = b^2+(-2*b+a)*a

與展開版本相比,這種表示在計算時所需的運算次數相對較少,因此有助於提高計算效率。

符號計算中常見的一個問題是,返回的答案往往不是最簡形式。MATLAB 的函式 'simple' 將執行所有可能的函式操作,然後返回最的函式。為此,請執行以下操作

>> Y = simple(f)
Y =  (a - b)^2

代數方程

[編輯 | 編輯原始碼]

符號數學工具箱能夠解決任何變數的代數表示式,前提是數學上可以做到這一點。它還可以解決單個方程和代數系統。

使用單個變數解決代數方程

[編輯 | 編輯原始碼]

MATLAB 使用 'solve' 函式來解決代數方程。語法是 solve(f, var),其中 f 是您要解決的函式,var 是要解決的變數。如果 f 是單個變數的函式,您將得到一個數字,而如果它是多個變數,您將得到一個符號表達式。

首先,假設我們要解決關於 x 的二次方程 x^2 = 16。解是 x = -4 和 x = 4。為此,您可以將函式直接放入 'solve' 中,或者可以根據 x 定義一個函式並將其傳遞到 'solve' 函式中。第一種方法比較直觀

>> solve('x^2 = 16', x)
ans = -4
       4
>> solve(x^2 - 16, x)
ans = -4
       4

這兩種語法都適用。第一個必須用引號括起來,否則會收到 '無效賦值' 錯誤。在第二個中,x 必須事先定義為符號變數,否則會收到 '未定義變數' 錯誤。

對於第二種方法,您將要解決的方程分配給一個虛擬變數,如下所示

>> syms x
>> y = x^2 - 16;
>> solve(y, x);

請注意,由於 MATLAB 假設在解決方程時 y = 0,因此您必須從兩邊減去 16,以將方程轉換為標準形式。

為特定變數解決符號函式

[編輯 | 編輯原始碼]

執行此操作的格式類似於為單個變數解決的格式,但您將獲得一個符號函式而不是數字作為輸出。但需要注意一些事項。

例如,假設您要解決關於 x 的方程 y = 2x + 4。預期解是 x = (y-4)/2。讓我們看看如何讓 MATLAB 完成此操作。首先,讓我們看看如何

>> syms x
>> y = 2*x + 4;
>> solve(y, x)
ans = -2

這裡發生了什麼?MATLAB 工具箱假設您宣告的 'y' 為解決方程的目的為 0!因此它解決了關於 x 的方程 2x + 4 = 0。為了做到您想要做的事情,您必須將原始方程 y = 2x + 4 轉換為標準形式,即 2x + 4 - y = 0。完成此操作後,您需要分配一個 '虛擬' 變數,如下所示

>> syms x y
>> S = 2*x + 4 - y; %S is the 'dummy'
>> solve(S, x)
ans = -2 + 1/2*y

當然,這與我們預期的一樣。您也可以像對單個變數的函式那樣,將函式直接傳遞到 'solve' 函式中,如下所示

>> solve('y = 2*x + 4', x);

第一種方法更可取,因為一旦設定好,它對函式的更改就更加靈活。在第二種方法中,如果您對函式進行任何更改,您將必須更改對 'solve' 的每次呼叫,而在第一種方法中,您只需要更改 S 的原始定義。

解決代數系統

[編輯 | 編輯原始碼]

'solve' 命令還允許您解決代數方程組,並嘗試返回這些方程組的所有解。作為第一個示例,讓我們考慮線性系統

a + b = 3
a + 2*b = 6,

它的解為 (a,b) = (0,3)。您可以告訴 MATLAB 如下解決它

>> syms a b
>> f(1) = a + b - 3;
>> f(2) = a + 2*b - 6;
>> [A,B] = solve(f(1), f(2))
A = 0
B = 3

如果只指定了一個輸出變數,但有多個方程,MATLAB 將在結構陣列中返回解

>> SOLUTION = solve(f(1), f(2))
SOLUTION =
a: [1x1 sym]
b: [1x1 sym]
>> SOLUTION.a
a = 0
>> SOLUTION.b
b = 3

這樣做的優點是,欄位具有與原始變數相同的名稱,而在另一種形式中,很容易混淆哪個變數進入陣列的哪個位置。此外,結構陣列對於大型系統來說更方便。

現在讓我們看一個稍微複雜的示例

a^2 + b^2 = 1
a + b = 1

它的解為 (a,b) = (0,1) 和 (a,b) = (1,0)。現在將它放入 MATLAB 中,得到

>> f = [a^2 + b^2 - 1, a + b - 1]; SOLUTION = solve(f(1), f(2));
>> SOLUTION.a
ans = 1
      0
>> SOLUTION.b
ans = 0
      1

這裡給出了兩種解,a(1) 對應於 b(1),a(2) 對應於 b(2)。要將一個解一起放入單個數組中,您可以使用普通的陣列索引,例如

>> Solution1 = [SOLUTION.a(1), SOLUTION.b(1)]
Solution1 = [1, 0]

解析微積分

[編輯 | 編輯原始碼]

除了代數功能外,MATLAB 的符號工具箱還可以執行許多常見的微積分任務,包括解析積分、微分、偏微分、積分變換和解決常微分方程,前提是給定任務在數學上是可能的。

使用一個變數進行微分和積分

[編輯 | 編輯原始碼]

使用 'diff' 函式對包含一個或多個變數的函式進行微分。像往常一樣,您可以在微分之前定義函式(建議用於 M 檔案),或者您可以手動將其作為引數寫入(建議用於命令列工作)。如果表示式中只有一個符號變數,MATLAB 會假設它是您要微分的變數。語法很簡單

>> syms x
>> f = x^2 - 3*x + 4;
>> diff(f) % or diff('x^2 - 3*x + 4')
ans =  2*x - 3

類似地,積分是使用 'int' 函式完成的。只指定函式會導致進行不定積分或函式的反導數。

>> int(f)
ans =  x^3/3 - (3*x^2)/2 + 4*x

請注意,如果您只指定一個輸出引數(或不指定任何引數),'int' 函式會省略積分常數。您只需要知道它在那裡。

要在單變數函式上進行定積分,只需指定起點和終點。

>> int(f, 0,1)
ans = 17/6

多變數函式的微分和積分

[編輯 | 編輯原始碼]

表示多元函式(偏導數)導數的一種方便方法是雅可比矩陣,由 'jacobian' 函式執行。要使用它,您應該定義一個符號函式陣列,然後將其傳遞給函式(注意此函式的使用與 'solve' 的使用之間的區別,'solve' 需要您分別傳遞每個方程,而此函式要求您將所有方程都放在同一個陣列中)

>> syms a b
>> f = [a^2 + b^2 - 1, a + b - 1];
>> Jac = jacobian(f)
Jac = [ 2*a, 2*b]
      [   1,   1]

請注意,第一行是 f(1) 的梯度,第二行是 f(2) 的梯度。

如果您只想獲得特定偏導數,而不是整個雅可比矩陣,您可以使用要微分的函式和要微分的變數呼叫 'diff' 函式。如果沒有指定,則相對於字母表中離 'x' 最近的變數進行微分。

>> diff(f(1), a)
ans = 2*a

值得注意的是,為了完成**隱式**微分,可以透過乘以 來明確地說明隱式假設,其中 是多變數方程中的第i個變數。


Clipboard

要做到
舉一個簡單隱函式的例子(比如 或類似的)


多元函式的不定積分與單變數函式相同;傳遞函式,MATLAB 將返回關於最靠近 x 的變數的不定積分

>> int(f(1))
ans = a^2*b+1/3*b^3-b

這是關於 b 的積分。為了避免混淆,您可以使用第二個引數指定積分變數,就像微分一樣。

>> int(f(1), a)
ans = 1/3*a^3+b^2*a-a

定積分(據我所知)只能針對一個變數一次進行,這是透過指定變數,然後指定邊界來完成的

>> int(f(1), a, 1, 2) %integrate a from 1 to 2, holding b constant
ans = 4/3 + b^2

微分方程的解析解

[edit | edit source]

MATLAB 可以解決一些簡單的微分方程形式。與積分和代數求解技術不同,微分方程求解器語法要求您以特定方式手動輸入函式。導數可以使用符號'DNV'來指定,其中 N 是導數的階數,V 是正在變化的變數。但是,更新版本的 MATLAB 支援以符號等式形式輸入微分方程。例如,假設您要尋找方程 的解,其解的形式為 x(t) = A*cos(t) + B*sin(t)。您可以將此方程輸入到'dsolve'函式中,如下所示

>> syms x
>> dsolve('D2x = -x')
ans = C1*sin(t)+C2*cos(t)
>> % or
>> syms x(t)
>> dsolve(diff(x, t, 2) == -x)
ans = C1*sin(t)+C2*cos(t)

與'int'函式不同,dsolve 包含積分常數。要指定初始條件,只需將額外的引數作為字串傳遞給'dsolve'函式即可。如果 x'(0) = 2 且 x(0) = 4,則它們將以以下方式插入

>> dsolve('D2x = -x', 'Dx(0) = 2', 'x(0) = 4')
ans = 2*sin(t)+4*cos(t)
>> % or
>> Dx = diff(x, t);
>> dsolve(diff(x, t, 2) == -x, Dx(0) == 2, x(0) == 4)
ans = 2*sin(t)+4*cos(t)

請注意,初始條件也可以作為字串傳遞。

MATLAB 還可以解決微分方程組。一個可接受的語法是將每個方程作為單獨的字串傳遞,然後將每個初始條件作為單獨的字串傳遞

>> % in older versions you were required to use strings
>> % SOLUTION = dsolve('Df=3*f+4*g', 'Dg =-4*f+3*g', 'f(0) = 0', 'g(0) = 1')
>> syms f(t) g(t)
>> SOLUTION = dsolve(diff(f) == 3*f + 4*g, diff(g) == -4*f + 3*g, f(0) == 0, g(0) == 1)
SOLUTION  = f: [1x1 sym]
            g: [1x1 sym]
>> SOLUTION.f
SOLUTION.f = exp(3*t)*sin(4*t)
>> SOLUTION.g
SOLUTION.g = exp(3*t)*cos(4*t)

'dsolve'函式與'solve'函式類似,因此它將解作為結構陣列返回,其欄位名與您使用的變數相同。與'solve'函式類似,您也可以透過指定多個輸出變數將變數放在單獨的陣列中。

積分變換

[edit | edit source]

MATLAB 的符號數學工具箱允許您找到積分變換(特別是拉普拉斯變換、傅立葉變換和 Z 變換)及其反變換(如果存在)。語法類似於其他符號數學函式:宣告一個函式並將其傳遞給相應的函式以獲得變換(或反變換)。

  1. http://en.wikipedia.org/wiki/MuPAD
華夏公益教科書