使用 Matlab 或 Scilab 查找两个函数之间的交集
Finding intersection between two functions using Matlab or Scilab
我正在这样做:
>> plot(x,y1,x,y2);
>> x=0:0.001:5;
>> y1=sin(x)+cos(1+x.^2)-1;
>> y2 = ((1/2).*x)-1;
>> find (y1==y2)
得到这个:
ans =
Empty matrix: 1-by-0
作为答案,简直让我发疯!我不知道为什么 Matlab 和 Scilab 不给我相交的答案。我一直在尝试使间隔更小,例如 x = 0:0.0001:5
;但它没有改变任何东西。我怎样才能使它 return 对我来说是交集值?
谢谢。
也许这两个向量在任何地方都没有完全相等的值。您可以尝试搜索最小的差异:
abs(y1-y2)<tolerance
其中 tolerance=0.001 是一个小数字
你要记住,Matlab 是用来寻找问题的数值解的。您正在提供一组离散输入点 x=0:0.001:5;
并要求它计算离散输出点 y1[x]
和 y2[x]
。这意味着 y1
和 y2
不是连续的,也不一定像它们的连续对应物那样相交。我没有 Matlab,所以我没有 运行 你的代码,但你的离散函数很可能不会相互交错。也就是说,在a = b
处不存在点对a = y1[x_i]
和b = y2[x_i]
。相反,您最有可能想要做的是寻找点,其中 y2-y1
在特定输入处位于零的一侧,而在下一个输入处位于零的另一侧。这意味着函数的连续对应部分会在两者之间的某个地方交叉。
函数相交但不交叉的情况有点棘手,但思路是一样的。
编辑:
这种事情最容易让你的头脑陷入困境,所以我创建了一个来说明我的意思。
这里我使用的点数比你尝试使用的要少很多,但思路是一样的。您可以看到 y1 和 y2 的连续版本在几个地方交叉,但是您要求 matlab 做的是在 y1 中找到一个点,该点等于 y2 中的一个点,对于相同的 x 值。在此图像中,您可以看到许多接近,但是您的计算机以非常高的精度存储浮点数,因此它们实际上相等的可能性非常小。
当您增加采样点的数量时,图像开始看起来更像它的连续对应物。
现有的两个答案解释了为什么您不能如此轻松地找到准确的交叉点。但您真正需要的是 如何做 以获得精确的交点?
在您的特定情况下,您知道要计算其交集的分析函数。您可以将 fzero
与(可选匿名)函数一起使用,以查找由两个原始函数的差异定义的函数的零:
y1fun = @(x) sin(x)+cos(1+x.^2)-1;
y2fun = @(x) ((1/2).*x)-1;
diff_fun = @(x) y1fun(x)-y2fun(x);
x0 = 1; % starting point for fzero's zero search
x_cross = fzero(diff_fun,x0);
现在,这将为您提供 one 差函数的零,即 one 函数的交集。事实证明,找到函数的 每个 零是一项具有挑战性的任务。通常,您必须使用不同的起始点 x0
多次调用 fzero
。如果你怀疑你的函数是什么样子,这根本不是无望的。
那么如果你的函数比较乱怎么办?在一般情况下,您可以使用插值函数来扮演上面示例中的 y1fun
和 y2fun
的部分,例如使用 interp1
:
% generate data
xdata = 0:0.001:5;
y1data = sin(xdata)+cos(1+xdata.^2)-1;
y2data = ((1/2).*xdata)-1;
y1fun = @(x) interp1(xdata,y1data,x);
y2fun = @(x) interp1(xdata,y2data,x);
x0 = 1; % starting point for fzero's zero search
x_cross = fzero(@(x)y1fun(x)-y2fun(x),x0);
这又回到了最初的问题。请注意,interp1
默认情况下使用线性插值,具体取决于您的函数的外观和数据的散布方式,您可以选择其他选项。还要注意外推选项(要避免)。
所以在这两种情况下,每次调用 fzero
都会得到一个交叉点。通过仔细选择起点,您应该能够尽可能准确地找到所有零点。
我正在这样做:
>> plot(x,y1,x,y2);
>> x=0:0.001:5;
>> y1=sin(x)+cos(1+x.^2)-1;
>> y2 = ((1/2).*x)-1;
>> find (y1==y2)
得到这个:
ans =
Empty matrix: 1-by-0
作为答案,简直让我发疯!我不知道为什么 Matlab 和 Scilab 不给我相交的答案。我一直在尝试使间隔更小,例如 x = 0:0.0001:5
;但它没有改变任何东西。我怎样才能使它 return 对我来说是交集值?
谢谢。
也许这两个向量在任何地方都没有完全相等的值。您可以尝试搜索最小的差异:
abs(y1-y2)<tolerance
其中 tolerance=0.001 是一个小数字
你要记住,Matlab 是用来寻找问题的数值解的。您正在提供一组离散输入点 x=0:0.001:5;
并要求它计算离散输出点 y1[x]
和 y2[x]
。这意味着 y1
和 y2
不是连续的,也不一定像它们的连续对应物那样相交。我没有 Matlab,所以我没有 运行 你的代码,但你的离散函数很可能不会相互交错。也就是说,在a = b
处不存在点对a = y1[x_i]
和b = y2[x_i]
。相反,您最有可能想要做的是寻找点,其中 y2-y1
在特定输入处位于零的一侧,而在下一个输入处位于零的另一侧。这意味着函数的连续对应部分会在两者之间的某个地方交叉。
函数相交但不交叉的情况有点棘手,但思路是一样的。
编辑:
这种事情最容易让你的头脑陷入困境,所以我创建了一个来说明我的意思。
这里我使用的点数比你尝试使用的要少很多,但思路是一样的。您可以看到 y1 和 y2 的连续版本在几个地方交叉,但是您要求 matlab 做的是在 y1 中找到一个点,该点等于 y2 中的一个点,对于相同的 x 值。在此图像中,您可以看到许多接近,但是您的计算机以非常高的精度存储浮点数,因此它们实际上相等的可能性非常小。
当您增加采样点的数量时,图像开始看起来更像它的连续对应物。
现有的两个答案解释了为什么您不能如此轻松地找到准确的交叉点。但您真正需要的是 如何做 以获得精确的交点?
在您的特定情况下,您知道要计算其交集的分析函数。您可以将 fzero
与(可选匿名)函数一起使用,以查找由两个原始函数的差异定义的函数的零:
y1fun = @(x) sin(x)+cos(1+x.^2)-1;
y2fun = @(x) ((1/2).*x)-1;
diff_fun = @(x) y1fun(x)-y2fun(x);
x0 = 1; % starting point for fzero's zero search
x_cross = fzero(diff_fun,x0);
现在,这将为您提供 one 差函数的零,即 one 函数的交集。事实证明,找到函数的 每个 零是一项具有挑战性的任务。通常,您必须使用不同的起始点 x0
多次调用 fzero
。如果你怀疑你的函数是什么样子,这根本不是无望的。
那么如果你的函数比较乱怎么办?在一般情况下,您可以使用插值函数来扮演上面示例中的 y1fun
和 y2fun
的部分,例如使用 interp1
:
% generate data
xdata = 0:0.001:5;
y1data = sin(xdata)+cos(1+xdata.^2)-1;
y2data = ((1/2).*xdata)-1;
y1fun = @(x) interp1(xdata,y1data,x);
y2fun = @(x) interp1(xdata,y2data,x);
x0 = 1; % starting point for fzero's zero search
x_cross = fzero(@(x)y1fun(x)-y2fun(x),x0);
这又回到了最初的问题。请注意,interp1
默认情况下使用线性插值,具体取决于您的函数的外观和数据的散布方式,您可以选择其他选项。还要注意外推选项(要避免)。
所以在这两种情况下,每次调用 fzero
都会得到一个交叉点。通过仔细选择起点,您应该能够尽可能准确地找到所有零点。