我在MATLAB中有一个函数,它将另一个函数作为参数。我想以某种方式定义一个可以传入的分段内联函数。这在MATLAB中是否可行?
编辑:我想表达的功能是:
f(x) = { 1.0, 0.0 <= x <= 0.5,
-1.0, 0.5 < x <= 1.0
where 0.0 <= x <= 1.0
答案 0 :(得分:12)
你确实定义了一个带有三个断点的分段函数,即[0,0.5,1]。但是,您尚未在中断之外定义函数的值。 (顺便说一下,我在这里使用了“break”这个术语,因为我们确实定义了一个简单形式的样条,一个分段常数样条。我也可能使用了术语knot,这是样条世界中的另一个常用词。 )
如果您完全知道永远不会评估[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])
从一开始就很容易生成更复杂的样条线。我称之为construct再次构造一个样条曲线。真的,这是我们可能领导的地方。事实上,这是领先的地方。样条函数是一个分段函数,在结点或断点列表中小心地绑在一起。特别是样条曲线通常具有指定的连续性顺序,因此,例如,三次样条曲线在断点处将是两次可微分(C2)。还有分段三次函数,它们只是C1函数。我在所有这一点上的观点是我已经描述了一个简单的起点来形成任何分段函数。它对多项式样条很有效,尽管选择这些函数的系数可能需要一点点数学。
创建此函数的另一种方法是显式分段多项式。在MATLAB中,我们有一个鲜为人知的函数mkpp。试试这个......
pp = mkpp([0 .5 1],[1;-1]);
如果你是splines工具箱,那么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中构建一个函数的几种方法。
答案 1 :(得分:5)
不幸的是,MATLAB没有一个三元运算符可以使这种事情变得更容易,但是为了稍微扩展gnovice的方法,你可以创建一个像这样的匿名函数:
fh = @(x) ( 2 .* ( x <= 0.5 ) - 1 )
通常,匿名函数比内联函数对象更强大,并允许您创建闭包等。
答案 2 :(得分:4)
如果你真的想要创建内联函数(而不是anonymous function),那么以下可能是最简单的方法:
f = inline('2.*(x <= 0.5)-1');
然而,正如其他答案中所指出的,匿名函数更常用,效率更高:
f = @(x) (2.*(x <= 0.5)-1);
答案 3 :(得分: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))