问题 在Matlab中构造分段符号函数


我试图在Matlab中生成一个分段符号函数。它必须是符号的原因是我希望能够在之后集成/区分函数和/或插入实际值。我有以下功能:

x^3/6   ->   0 < x <= 1
(1/6)*(-3*x^3+12*x^2-12x+4)   ->   1 < x <= 2
(1/6)*(3*x^3-24*x^2+60x-44)   ->   2 < x <= 3
(1/6)*(4-x)^3   ->   3 < x <= 4
0   ->   otherwise

例如,我想把这个函数放在一个变量中(比如说f),然后调用

int(diff(f, 1)^2, x, 0, 4) % numbers could be different

得到(标量)结果2/3。

我尝试了各种各样的事情,涉及分段()函数和符号比较,但没有任何效果......你能帮忙吗? :-)


6082
2017-09-10 18:02


起源



答案:


一种选择是使用 heaviside 函数使每个等式在其给定范围之外等于零,然后将它们全部加在一起形成一个等式:

syms x;
f = (heaviside(x)-heaviside(x-1))*x^3/6 + ...
    (heaviside(x-1)-heaviside(x-2))*(1/6)*(-3*x^3+12*x^2-12*x+4) + ...
    (heaviside(x-2)-heaviside(x-3))*(1/6)*(3*x^3-24*x^2+60*x-44) + ...
    (heaviside(x-3)-heaviside(x-4))*(1/6)*(4-x)^3;
double(int(diff(f, 1)^2, x, 0, 4))

ans =

    0.6667

另一种方法是在每个子范围内为每个函数执行集成,然后添加结果:

syms x;
eq1 = x^3/6;
eq2 = (1/6)*(-3*x^3+12*x^2-12*x+4);
eq3 = (1/6)*(3*x^3-24*x^2+60*x-44);
eq4 = (1/6)*(4-x)^3;
total = int(diff(eq1, 1)^2, x, 0, 1) + ...
        int(diff(eq2, 1)^2, x, 1, 2) + ...
        int(diff(eq3, 1)^2, x, 2, 3) + ...
        int(diff(eq4, 1)^2, x, 3, 4)

total =

2/3

更新:

虽然它在问题中提到了 piecewise 功能不起作用, 卡兰的回答 建议它,至少在较新版本中。的文档 piecewise 目前说它是在R2016b中引入的,但它显然早得多。我在文档中找到了它 符号数学工具箱 早在R2012b,但调用语法与现在不同。我在早期的Symbolic Math Toolbox文档中找不到它,但它确实在其他工具箱(例如Statistics和Spline Toolboxes)中显示为一个函数,这解释了它在问题中的提及(以及为什么它没有为当时的符号方程工作)。


9
2017-09-10 18:13



它应该是60 * x。 - Jonas
@Jonas:谢谢。该 12x 也需要修复。 - gnovice
关于 早在R2012b,您可能指的是MuPAD分段函数,它是与符号数学工具箱不同的接口。对于SMT,它是在R2016b中引入的。很抱歉与工具箱混淆。如果我能回答任何其他问题,请告诉我。 - Karan Gill
@Karan:我现在看到了。它首先出现在R2012b的文档中(需要MathWorks登录),但仅作为可通过MuPAD接口访问的函数,而不是MATLAB本身。 R2016b的最新版本可以直接从MATLAB调用。 - gnovice


答案:


一种选择是使用 heaviside 函数使每个等式在其给定范围之外等于零,然后将它们全部加在一起形成一个等式:

syms x;
f = (heaviside(x)-heaviside(x-1))*x^3/6 + ...
    (heaviside(x-1)-heaviside(x-2))*(1/6)*(-3*x^3+12*x^2-12*x+4) + ...
    (heaviside(x-2)-heaviside(x-3))*(1/6)*(3*x^3-24*x^2+60*x-44) + ...
    (heaviside(x-3)-heaviside(x-4))*(1/6)*(4-x)^3;
double(int(diff(f, 1)^2, x, 0, 4))

ans =

    0.6667

另一种方法是在每个子范围内为每个函数执行集成,然后添加结果:

syms x;
eq1 = x^3/6;
eq2 = (1/6)*(-3*x^3+12*x^2-12*x+4);
eq3 = (1/6)*(3*x^3-24*x^2+60*x-44);
eq4 = (1/6)*(4-x)^3;
total = int(diff(eq1, 1)^2, x, 0, 1) + ...
        int(diff(eq2, 1)^2, x, 1, 2) + ...
        int(diff(eq3, 1)^2, x, 2, 3) + ...
        int(diff(eq4, 1)^2, x, 3, 4)

total =

2/3

更新:

虽然它在问题中提到了 piecewise 功能不起作用, 卡兰的回答 建议它,至少在较新版本中。的文档 piecewise 目前说它是在R2016b中引入的,但它显然早得多。我在文档中找到了它 符号数学工具箱 早在R2012b,但调用语法与现在不同。我在早期的Symbolic Math Toolbox文档中找不到它,但它确实在其他工具箱(例如Statistics和Spline Toolboxes)中显示为一个函数,这解释了它在问题中的提及(以及为什么它没有为当时的符号方程工作)。


9
2017-09-10 18:13



它应该是60 * x。 - Jonas
@Jonas:谢谢。该 12x 也需要修复。 - gnovice
关于 早在R2012b,您可能指的是MuPAD分段函数,它是与符号数学工具箱不同的接口。对于SMT,它是在R2016b中引入的。很抱歉与工具箱混淆。如果我能回答任何其他问题,请告诉我。 - Karan Gill
@Karan:我现在看到了。它首先出现在R2012b的文档中(需要MathWorks登录),但仅作为可通过MuPAD接口访问的函数,而不是MATLAB本身。 R2016b的最新版本可以直接从MATLAB调用。 - gnovice


从R2016b开始,使用 分段 功能

syms x
y = piecewise(x<0, -1, x>0, 1)

y =
piecewise(x < 0, -1, 0 < x, 1)

对于这种情况:

syms x
f = piecewise( ...
0< x <=1, x^3/6, ...
1 < x <= 2, (1/6)*(-3*x^3+12*x^2-12*x+4), ...
2 < x <= 3, (1/6)*(3*x^3-24*x^2+60*x-44), ...
3 < x <= 4, (1/6)*(4-x)^3, ...
0)

f =
piecewise(x in Dom::Interval(0, [1]), x^3/6, x in Dom::Interval(1, [2]), - x^3/2 + 2*x^2 - 2*x + 2/3, x in Dom::Interval(2, [3]), x^3/2 - 4*x^2 + 10*x - 22/3, x in Dom::Interval(3, [4]), -(x - 4)^3/6, 0)

int(diff(f, 1)^2, x, 0, 4)
ans =
2/3

3
2018-02-01 22:36



对于downvotes的解释会有所帮助,因为这是在Symbolic Math Toolbox中创建分段函数的推荐方法。 - Karan Gill
我猜是因为你的旧例子根本不符合这个问题;你的新例子应该补救那个。此外,我的答案中的更新可能是有意义的。人们可能已经投票,因为这个问题具体提到了 piecewise 没有工作,它实际上没有被问及,但现在你正在显示。 - gnovice
很公平。我希望我编辑的答案很有用。很高兴回答任何其他问题。 - Karan Gill