我有以下简单的ODE:
dx/dt=-1
在初始条件x(0)= 5的情况下,我对x(t)== 1的情况感兴趣。因此,我具有以下事件功能:
function [value,isterminal,direction] = test_events(t,x)
value = x-1;
isterminal = 0;
direction = 0;
end
这应该在t = 4产生一个事件。但是,如果我运行以下代码,则会得到两个事件,一个事件在t = 4,另一个事件在附近的位置t = 4 + 5.7e-14:
options = odeset('Events',@test_events);
sol = ode45(@(t,x)-1,[0 10],5,options);
fprintf('%.16f\n',sol.xe)
% 4.0000000000000000
% 4.0000000000000568
如果我运行类似的代码来查找x(t)== 0或x(t)==-1(分别为value = x;或value = x + 1;),则我只有一个事件。为什么会产生两个事件?
更新:如果选项结构更改为以下内容:
options = odeset('Events',@test_events,'RelTol',1e-4);
...然后ODE仅在t = 4 + 5.7e-14时返回一个事件。如果“ RelTol”设置为1e-5,则它将在t = 4返回一个事件。如果“ RelTol”设置为1e-8,它将返回与默认事件相同的两个事件(“ RelTol” = 1e-3)。此外,将初始条件从x(0)= 5更改为x(0)= 4会生成一个事件,但是将x(0)= 4和'RelTol'= 1e-8设置为会生成两个事件。
更新2:观察sol.x和sol.y输出(分别为t和x),时间以整数[0 1 2 3 4 5 6 7 ...]进行,直到x以整数进行直到x(t = 5)像这样:[5 4 3 2 1 1.11e-16 -1.000 -2.000 ...]。这表明在t = 4和t = 5之间发生某种事情,在ODE解决方案中产生了“碰撞”。为什么?
答案 0 :(得分:0)
一个推测可能解释在此简单问题中如何发生舍入误差:使用ODE导数函数的评估k_n
(也称为“密集输出”)在内部步骤之间插值解决方案。理论形式是
b_1(u)k_1 + b_2(u)k_2 + ...b_s(u)k_s
其中0 <= u<= 1
是内部点之间的时间间隔内的参数,即t = (1-u)*t_k+u*t_{k+1}
。
系数多项式不是平凡的。尽管在示例中,所有k_i=1
都是常数,但求和b_1(u)+...+b_s(u)
会累积舍入误差,即使在y_k
和{{ 1}}是正确的。在该累积浮点噪声范围内,该值可能会在根附近振荡,从而导致检测到多个零交叉。