Sie sind auf Seite 1von 6

Runge-Kutta method in MATLAB

Jakob Kibsgaard

Many physical problems can be thought of as a system of ordinary differential


equations y(x)=f(x,y) with an initial condition y(0)=y0 , where y and f(x,y) are
generally understood as column vectors. It is therefor of great importance to be
able to solve such a system of equations.

Runge-Kutta method

The simplest method (and least accurate) for integrating such a problem is the
Euler method. The derivative at the starting point of each interval is extrapolated
to find the next function value. The method only has first-order accuracy.
yn+1 = yn + hf (xn , yn )

(1)

y(x)
2

x1

x3

x2

Figure 1: The Euler method which advances a solution from xn to xn+1 xn + h.


A better way of solving this kind of problem was devised by Runge and Kutta.
The methods are one-step methods where the solution y is advanced by one step h
as y1 = y0 + hk, where k is a cleverly chosen constant. The first order Runge-Kutta
method is simply the Euler method i.e. k = f (x0 , y0 ).
The second order Runge-Kutta method advances the solution by the use of an
auxiliary evaluation of the derivative (see figure 2).

y(x)
Auxiliary point
2
1

x1

x3

x2

Figure 2: The second order Runge-Kutta method. Second-order accuracy is obtained by


using the initial derivative at each step to find a point halfway across the interval, then
using the midpoint derivative across the full width h of the interval.

This gives the following set of equations:


k0 = f (x0 , y0 )
h
y1/2 = y0 + k0
2
k1/2 = f (x1/2 , y1/2 )
y1 = y0 + h k1/2

(2)

Another approach (also of second order) is first to take the full step with the
Euler method then calculate the derivative of this point k1 = f (x1 , y0 + hk0 ). The
average between k0 and k1 can now be chosen as the final k = 12 (k0 + k1 ), which
then can be used to take the step y1 = y0 + h k. The following set of equations is
therefor obtained:
k0 = f (x0 , y0 )
k1 = f (x1 , y0 + hk0 )
1
k =
(k0 + k1 )
2
y1 = y0 + h k

(3)

The two second order methods can be combined to yield a third order method,
where the k constant is given as:
4
1
1
k = k0 + k1/2 + k1
6
6
6
where k0 , k1/2 and k1 can be found in equation 2 and 3.

(4)

Adaptive Stepsize Control

In principle one could now use the above equations with the same stepsize h until
the end point of the given interval is reached. A better approach when computing
time is taken into consideration is to use adaptive stepsize control. By implementing
this uninteresting parts of the function can be crossed in a few big steps, while the
interesting parts are crossed with small stepsizes. The program therefor tries to
the biggest step without exceeding a certain tolerance specified by the user. The
tolerance is given as:
s
h
tol = (eps | y | +acc)
(5)
ba
where eps is relative accuracy and acc is the absolute accuracy specified by the user.
The error of a step can be estimated by comparing the solution for a full-step and
that of two half-steps:
| y(h) y(2 h2 ) |
(6)
err =
2k 1
If the err > 2 tol the step should be rejected and a new stepsize with h = h2
should be used. If err < 2 tol the step is accepted and a new stepsize is found by:
hN ext = hCurrent (

tol P ower
)
Saf ety
err

(7)

where P ower 0.25 and Saf ety 0.95. As a further safety one could implement
the condition that if hN ext > 2 hCurrent then new stepsize should only be hN ext =
2 hCurrent .

Generalization

A higher order ordinary differential equation can be replaced by at set of coupled


first order differential equations e.g.:

z = z ;

y1 = y2
y1 = z

y2 = z
y2 = y1

It is very easy to generalize the source code in MATLAB. All there needs to be
done is to replace the ys (numbers) with Y s (vectors) where:

Y =

y1
y2
..
.
yn

and

Y = F (x, Y ) =

f1 (x, Y )
f2 (x, Y )
..
.
fn (x, Y )

The initial condition is now also a column vector Y (x0 ) = Y0 . Notice that the
ks also becomes vectors. The only real (though small) adjustment in the source
code apart from changing to vectors is the estimate of the error. The error of a step
is simply the maximum value of the errors for the individual differential equations:
| Y (h) Y (2 h2 ) |
err = max
2k 1

(8)

Source Code

4.1
4.1.1

Solving one first order differential equation


RK.m

function [res,err] = RK(a,ya,b,h_0,acc,eps);


% The function RK.m solves a differential equation. This is done by the
% Runge-Kutta method, which finds the value y(b) of a function there fulfils dy/dx=f(x,y)
% and the initial condition y(a)=ya. All (x,y)-pairs are saved and used in a plot finally.
%
%
%
%
%
%
%

INPUT
a:
ya:
b:
h_0:
acc:
eps:

The start-point for the interval we are considering.


The y-value in x=a.
The end-point of the interval we are considering.
Initial step value.
The demanded absolute accuracy.
The demanded relative accuracy.

% OUTPUT:
% Res: The y-value of x=b.
% err: The calculated (over all steps) total error.
% Initialize variables
inc=1;
err=0;
x(inc)=a;
y(inc)=ya;
h=h_0;
inc=2;
% The first run of the function RKstep.m, which finds the next
% (x,y)-pairs and the error for the step by the Runge-Kutta method.
[x(inc),y(inc),y_old,err_step] = RKStep(x,y,h);
% Loop to find the following points.
while x(inc)<b
% Makes sure that the interval is not exceeded
tol=acc*sqrt(h/(b-a))+eps*y(inc)*sqrt(h/(b-a));
% The tolerance is calculated
inc=inc+1;
if err_step>2*tol
% If the error for the step is too large -> The point (x(inc),Y(inc)) is
% calculated again with h=h/2.
h=h/2;
if h > (b-x(inc-1));
% Makes sure that the interval end point is not exceeded
h = b-x(inc-1);
end
inc=inc-1;
[x(inc),y(inc),y_old,err_step] = RKStep(x(inc-1),y_old,h);
else
% The previous point is accepted and a new step is found.
err=sqrt(err^2+err_step^2);
% The total error for the entire interval is added up.
h_old=h;
h=0.95*(tol/err_step)^0.25*h; % A new step size is found.
if h>2*h_old
% If the increase in h is too large -> h=2*h.
h=2*h_old;
if h > (b-x(inc-1));
% Makes sure that the interval end-point is not exceeded.
h = b-x(inc-1);
end
[x(inc),y(inc),y_old,err_step] = RKStep(x(inc-1),y(inc-1),h); % The new (x,y) point
% and the error are found
% with RKStep.m
else
if h > (b-x(inc-1));
% Makes sure that the interval end-point is not exceeded.
h = b-x(inc-1);
end
[x(inc),y(inc),y_old,err_step] = RKStep(x(inc-1),y(inc-1),h); % The new (x,y) point
% and the error are found
% with RKStep.m
end
end
end
err=sqrt(err^2+err_step^2);
% The error for the last step is included in the total error.
plot(x,y)
% The function y(x) is plotted.
res=y(inc);
% The value of y in x=b is written out.

4.1.2

RKStep.m

function [x,y,y_old,err_step] = RKStep(x,y,h);


% The current y-values are saved in y_old.
y_old=y;
% The y-value in x=x+h is found with a stepsize h:
k_0=f(x,y);
k_1=f(x+h,y+h*k_0);
k_half=f(x+h/2,y+h/2*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
y_h=y+k*h;
% The y-value in x=x+h is found in two turns, each with a stepsize h/2:
% First call:
k_0=f(x,y);
k_1=f(x+h/2,y+h/2*k_0);
k_half=f(x+h/4,y+h/4*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
y=y+k*h/2;
x=x+h/2;
% Second call:
k_0=f(x,y);
k_1=f(x+h/2,y+h/2*k_0);
k_half=f(x+h/4,y+h/4*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
y=y+k*h/2;
x=x+h/2;
% The error estimate:
err_step=abs(y_h-y)/7;

4.2
4.2.1

Solving a set of first order differential equations


RK2.m

function [res,err] = RK2(a,ya,ya_diff,b,h_0,acc,eps);


%
%
%
%

The function RK2.m solves


Runge-Kutta method, which
and the initial condition
All (x,y)-pairs are saved

%
%
%
%
%
%
%
%

INPUT
a:
ya:
ya_diff:
b:
h_0:
acc:
eps:

a system of differential equations. This is done by the


finds the value y(b) of a function there fulfils dy/dx=f(x,y)
y(a)=ya. The program saves y-values in the vector Y, Y=[y,y]
and used in a plot finally.

The start-point for the interval we are considering.


The y-value in x=a.
The y-value in x=a.
The end-point of the interval we are considering.
Initial step value.
The demanded absolute accuracy.
The demanded relative accuracy.

%OUTPUT:
%Res: The y-value of x=b.
%err: The calculated (over all steps) total error.
% Initialize variables
inc=1;
err=0;
x(inc)=a;
Y(:,inc)=[ya ; ya_diff];
h=h_0;
inc=2;
% The first run of the function RK2step.m, which finds the next
% (x,Y)-pairs and the error for the step by the Runge-Kutta method.
[x(inc),Y(:,inc),Y_old,err_step] = RK2Step(x,Y,h);

% Loop to find the following points.


while x(inc)<b
% Makes sure that the interval is not exceeded
tol=acc*sqrt(h/(b-a))+eps*max(Y(:,inc))*sqrt(h/(b-a));
% The tolerance is calculated
inc=inc+1;
if err_step>2*tol
% If the error for the step is too large -> The point (x(inc),Y(inc)) is
% calculated again with h=h/2.
h=h/2;
if h > (b-x(inc-1));
% Makes sure that the interval end point is not exceeded
h = b-x(inc-1);
end
inc=inc-1;
[x(inc),Y(:,inc),Y_old,err_step] = RK2Step(x(inc-1),Y_old,h);
else
% The previous point is accepted and a new step is found.
err=sqrt(err^2+err_step^2);
% The total error for the entire interval is added up.
h_old=h;
h=0.95*(tol/err_step)^0.25*h; % A new step size is found.
if h>2*h_old
% If the increase in h is too large -> h=2*h.
h=2*h_old;
if h > (b-x(inc-1));
% Makes sure that the interval end-point is not exceeded.
h = b-x(inc-1);
end
[x(inc),Y(:,inc),Y_old,err_step] = RK2Step(x(inc-1),Y(:,inc-1),h); % The new (x,Y) points and the error
% are found with RK2Step.m
else
if h > (b-x(inc-1));
% Makes sure that the interval end-point is not exceeded.
h = b-x(inc-1);
end
[x(inc),Y(:,inc),Y_old,err_step] = RK2Step(x(inc-1),Y(:,inc-1),h);
% The new (x,Y) points and the error
% are found with RK2Step.m
end
end
end
err=sqrt(err^2+err_step^2);
% The error for the last step is included in the total error.
plot(x,Y(1,:))
% The function y(x) is plotted.
res=Y(1,inc);
% The value of y in x=b is written out.

4.2.2

RK2Step.m

function [x,Y,Y_old,err_step] = RK2Step(x,Y,h);


% The current Y-values are saved in Y_old.
Y_old=Y;
% The y-value in x=x+h is found with a stepsize h:
k_0=f(x,Y);
k_1=f(x+h,Y+h*k_0);
k_half=f(x+h/2,Y+h/2*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
Y_h=Y+k*h;
% The y-value in x=x+h is found in two turns, each with a stepsize h/2:
% First call:
k_0=f(x,Y);
k_1=f(x+h/2,Y+h/2*k_0);
k_half=f(x+h/4,Y+h/4*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
Y=Y+k*h/2;
x=x+h/2;
% Second call:
k_0=f(x,Y);
k_1=f(x+h/2,Y+h/2*k_0);
k_half=f(x+h/4,Y+h/4*k_0);
k=1/6*k_0+4/6*k_half+1/6*k_1;
Y=Y+k*h/2;
x=x+h/2;
% The error estimate:
err_step=max(abs(Y_h-Y)/7);

Das könnte Ihnen auch gefallen