7

我在 MATLAB 中有一个函数,它以另一个函数作为参数。我想以某种方式定义一个可以传入的分段内联函数。这在 MATLAB 中是否可能?

编辑:我想代表的功能是:

f(x) = { 1.0,  0.0 <= x <= 0.5,
         -1.0, 0.5 < x <= 1.0

where 0.0 <= x <= 1.0
4

4 回答 4

12

您确实已经定义了一个具有三个断点的分段函数,即在 [0, 0.5, 1] 处。但是,您还没有在中断之外定义函数的值。(顺便说一句,我在这里使用了术语“中断”,因为我们实际上是在定义一种简单形式的样条曲线,一个分段常数样条曲线。我可能还使用了术语“结”,这是样条曲线世界中的另一个常用词。 )

如果您绝对知道您永远不会评估 [0,1] 之外的函数,那么就没有问题。因此,只需在 x = 0.5 处定义一个带有 ONE 断点的分段函数。定义像您这样的分段常量函数的简单方法是使用逻辑运算符。因此,测试 (x > 0.5) 返回一个常数,即 0 或 1。通过缩放和转换该结果,很容易生成一个满足您要求的函数。

constfun = @(x) (x > 0.5)*2 - 1;

内联函数做类似的事情,但与匿名函数相比,内联函数非常慢。我强烈建议使用匿名表格。作为测试,试试这个:

infun = inline('(x > 0.5)*2 - 1','x');
x = 0:.001:1;

tic,y = constfun(x);toc
Elapsed time is 0.002192 seconds.

tic,y = infun(x);toc
Elapsed time is 0.136311 seconds.

是的,内联函数的执行时间比匿名表单要多得多。

我在这里使用的简单分段常数形式的一个问题是,当您有更多断点时,它很难扩展。例如,假设您希望定义一个函数,该函数根据点所在的间隔采用三个不同的值?虽然这也可以通过创造性地使用测试来完成,小心地移动和缩放它们,但它可能会变得令人讨厌。例如,如何定义返回的分段函数

-1 when x < 0,
2 when 0 <= x < 1,
1 when 1 <= x

一种解决方案是使用单位Heaviside函数。所以首先,定义一个基本单元 Heaviside 函数。

H = @(x) (x >= 0);

我们的分段函数现在是从 H(x) 导出的。

P = @(x) -1 + H(x)*3 + H(x-1)*(-1);

看到 P(x) 有三个部分。第一项是 x 在第一个断点以下发生的情况。然后我们添加一个在零以上生效的部分。最后,第三部分在上面 x == 1 中添加了另一个偏移量。它很容易绘制。

ezplot(P,[-3,3])

从这个开始很容易生成更复杂的样条。我再次将此构造称为样条曲线。真的,这就是我们可能领先的地方。事实上,这就是导致的地方。样条曲线是一个分段函数,在一系列节点或断点处小心地捆绑在一起。特别是样条曲线通常具有指定的连续性顺序,例如,三次样条曲线将在断点处两次可微 (C2)。还有只有 C1 函数的分段三次函数。我的观点是,我已经描述了一个简单的起点来形成任何分段函数。它对多项式样条曲线非常有效,尽管选择这些函数的系数可能需要一些数学知识。

创建此函数的另一种方法是显式分段多项式。在 MATLAB 中,我们有一个鲜为人知的函数 mkpp。试试这个...

pp = mkpp([0 .5 1],[1;-1]);

如果你有样条工具箱,那么 fnplt 会直接为你绘制。假设您没有那个 TB,请执行以下操作:

ppfun = @(x) ppval(pp,x);
ezplot(ppfun,[0 1])

回顾一下 mkpp 调用,毕竟还是比较简单的。第一个参数是曲线中的断点列表(作为 ROW 向量)。第二个参数是一个 COLUMN 向量,具有分段常数值,曲线将在这两个定义的中断间隔内呈现。

几年前,我发布了另一个选项,piecewise_eval。它可以从 MATLAB Central 文件交换中下载。这是一个允许用户将分段函数纯粹指定为断点列表的函数,以及这些断点之间的功能块。因此,对于在 x = 0.5 处具有单个中断的函数,我们将这样做:

fun = @(x) piecewise_eval(x,0.5,{1,-1});

请注意,第三个参数提供了每个段中使用的值,尽管这些部分不必是纯粹的常量函数。如果您希望函数返回感兴趣的区间之外的 NaN,这也很容易实现。

fun = @(x) piecewise_eval(x,[0 0.5 1],{NaN,1,-1,NaN});

在所有这些相当长的游览中,我的观点是了解分段函数是什么,以及在 MATLAB 中构建分段函数的几种方法。

于 2009-04-28T11:13:03.827 回答
5

不幸的是,MATLAB 没有三元运算符可以使这种事情变得更容易,但是为了稍微扩展 gnovice 的方法,您可以创建一个匿名函数,如下所示:

fh = @(x) ( 2 .* ( x <= 0.5 ) - 1 )

一般来说,匿名函数比内联函数对象更强大,并且允许你创建闭包等。

于 2009-04-28T06:43:21.353 回答
4

如果您真的想创建一个内联函数(而不是匿名函数),那么以下可能是最简单的方法:

f = inline('2.*(x <= 0.5)-1');

但是,正如其他答案中所指出的,匿名函数更常用且效率更高:

f = @(x) (2.*(x <= 0.5)-1);
于 2009-04-28T03:59:33.370 回答
2

我只需要解决这个问题,我认为最简单的方法是使用匿名函数。假设你有一个分段函数:

when x<0    : x^2 + 3x
when 0<=x<=4: e^x
when x>4    : log(x)

我首先为每个分段区域定义逻辑掩码:

PIECE1 = @(x) x<0
PIECE2 = @(x) x>=0 & x<=4
PIECE3 = @(x) x>4

然后我把它们放在一起:

f = @(x) PIECE1(x).*(x.^2+3*x) + PIECE2(x).*exp(x) + PIECE3(x).*log(x)

x = -10:.1:10
figure;
plot(x,f(x))
于 2013-11-06T15:11:34.267 回答