Здравствуйте, все!
Тестируя собственноручно написанный явный метод Адамса для ОДУ первого порядка, встретился с весьма неприяной ситуацией (и для всех стандартных основных методов, кстати тоже) зависимости точности решения от (наверное, погрешности определения) величины шага. Код метода в scilab вот:
Код:
function [tr, xr] = Adams4 (t0,x0,h,te)
tr = [t0: h: te]; n = length(tr);xr =zeros (n);
[t1, x1] = RK4 (t0, x0, h); [t2, x2] = RK4 (t1, x1, h);
[t3, x3] = RK4 (t2, x2, h);
xr(1) = x0; xr(2) = x1;xr(3) = x2; xr(4) = x3;
f0 = func(tr(1), xr(1)); f1 = func(tr(2), xr(2));
f2 = func(tr(3), xr(3)); f3 = func(tr(4), xr(4));
for k = 5:1:length(tr)
dx=55.0.*f3-59.0.*f2+37.0.*f1-9.0.*f0;
xr(k) = xr(k-1)+ h.*dx./24.0;
f0 = f1; f1 = f2; f2 = f3; f3 = func(tr(k), xr(k));
end
endfunction
function [t,x] = RK4 (t,x,h, t0,te)
g1 = h.*func(t,x);
t2 = t + 0.5.*h; x2 = x + 0.5.*g1;
g2 = h.*func(t2, x2);
t3 = t + 0.5.*h; x3 = x + 0.5*g2;
g3 = h.*func(t3, x3);
t4 = t + h; x4 = x + g3;
g4 = h.*func(t4, x4);
dx=(g1+2.0.*g2+2.0.*g3+ g4)./6.0;
x = x + dx; t = t+h;
endfunction
function res = func(t,x)
res = -x.*tan(t) + 1.0./cos(t);
endfunction
Так вот, делая два следующих вызова этой функции:
Код:
[te, xe2] = Adams4 (%pi, 1.0, 3.0.*%pi./99.0, 4.0.*%pi);
и
Код:
[te, xe2] = Adams4 (%pi, 1.0, 3.0.*%pi./100.0, 4.0.*%pi);
, получаем в первом случае правильный ответ, а во втором неправильный совершенно.
Любопытно, что встроенный в scilab решатель в обоих случаях решает правильно.
И вот по по этому поводу вопрос: можно ли с этой сильной неустойчивостью чего-нибудь сделать, как-нибудь её победить?
Как гипотеза: использовать переменный шаг при этом подбирать его так, чтобы он согласовался с основным шагом.