我已经解决了初始值微分方程并绘制了ODE45给出的Y值。从图中我可以模糊地告诉根应该在哪里,但在给定的任务中我需要非常准确地找到它。
我的第一个猜测是将多项式调整为我的X和Y值,然后求解多项式方程。但是我使用了polyfit并且有69个知道值,这给了我68级的多项式,这是我无法解决的。那么,有没有人知道如何在不知道实际方程的情况下找到一组给定Y值的“根”?它写在任务中应该使用插值!
提前致谢!
答案 0 :(得分:2)
给定Y值的向量(在相应的X值稳定增加的意义上排序),您可以很容易地发现根位于哪个X值附近。根是Y值为零的位置或两个改变符号的连续Y值之间。这个想法在这段代码中说明了:
X = -1:0.1:1;
Y = X.*X - 0.4;
root_exact_pos = find(Y==0);
root_approx_pos = find(diff(sign(Y))~=0);
根位于X
值,X(root_exact_pos(k))
或X(root_approx_pos(k))
和X(root_approx_pos(k)+1)
之间,k
从1到元素数量相应的根位置数组。
从这里你可以应用你想要的任何插值来找到更好的近似根(我会在2点之间使用线性)。
答案 1 :(得分:1)
你说你需要“非常准确地找到根”。如果您使用ODE45
以数字方式求解微分方程,那么@ CST-Link的答案不是如何做到的。事实上,这是一个坏主意。它需要以高分辨率输出您的解决方案点并引入误差,如果您正在积分的方程是保守的(即,您将有效地从总能量应始终保持不变的解决方案中添加或减去能量),这可能会特别糟糕。您需要使用Matlab的ODE求解器的事件检测(过零)功能。这通常能够以接近机器epsilon eps
的精度找到您的根。虽然@ CST-Link给出的技术只能给出ODE45步长的精确度,这可能非常大(插值可用于帮助改善这一点,但你不会接近{{ 1}}除非你使用小步长。)
查看Matlab对eps
的帮助,事件功能似乎令人困惑,因此我将尝试使用基于ODE45
(ballode
和{{1}的代码提供更简单的示例更多信息),Matlab包含的示例,用于演示事件。
help ballode
这个例子就是球在垂直方向上的简单弹道运动:函数edit ballode
。目标是准确地检测球在穿过地平面时的速度,function eventsdemo
options = odeset('Events',@efun); % specify name of events function
[t,y,te,ye,ie] = ode45(@f,[0 10],[0;20],options); % integrate
figure
plot(t,y(:,1),'b',te,ye(:,1),'r.')
function dydt = f(t,y)
dydt = [y(2);-9.8]; % differential equation for ballistic motion
function [value,isterminal,direction] = efun(t,y)
value = y(1);
isterminal = 1;
direction = -1;
线在负方向。如果过早发现接触,球的速度将低于现实,能量将会丢失;太晚了,注入了能量。 f
的{{1}}输出定义了交叉点必须等于零的等式。这可以根据需要简单或复杂,可以取决于所有状态变量和时间,并且您可以通过指定向量来检测多个交叉。在你的情况下,听起来你对x轴的根感兴趣,所以我想你可能有一个相同的y(1) == 0
定义。如果您只想要第一个根或者只有一个根,那么value
将在找到时停止集成。最后,如果您不知道函数在根处的斜率/梯度,可以将efun
设置为零。使用上面的代码尝试此事件函数(value
可用于指出在isterminal
和direction
输出中触发了三个事件中的哪一个:
ie
一些小问题。您需要将最终积分时间设置为足够长。换句话说,该事件必须在te
和ye
之间发生(如果您不知道您的活动在哪个时间点,请参阅function [value,isterminal,direction] = efun(t,y)
value = [y(2) y(1)-10 y(1)];
isterminal = [0 0 1];
direction = [-1 0 -1];
以便迭代调用t0
的方案会发生)。如果将tf
设置为零,则输出ballode
向量和ODE45
矩阵将被裁剪为在终端事件发生时结束。最后,如果您指定固定的步长输出,例如isterminal
,则最后一个输出点的步长可能会更小。