MATLAB 编程/高级主题/工具箱和扩展/符号工具箱
此页面可能需要更新以反映当前知识。 Maple 不再用于符号工具箱。2008 年,Mathworks 收购了 MuPAD,现在它被用于 Matlab 符号工具箱中。 [1] 语法应该相同,但有人需要检查每个示例。 您可以 帮助更新它、讨论进度或 请求协助。 |
符号工具箱使用起来有点困难,但在需要符号表达式的应用程序中,由于计算精度的原因,它非常有用。工具箱只需调用 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个变量。
多元函数的不定积分与单变量函数相同;传递函数,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 变换)及其反变换(如果存在)。语法类似于其他符号数学函数:声明一个函数并将其传递给相应的函数以获得变换(或反变换)。