Suppose we wish to solve the system of equations $\frac{d\mathbf{y}}{dx}=\mathbf{f}(x,\mathbf{y})$
, with conditions applied at two different points $x=a$
and $x=b$
.
More commonly, problems of this sort will be written as a higher-order (that is, a second-order) ODE with derivative boundary conditions We can reduce any such equation to a system of first-order equations, however, so we only need to consider how to solve systems of first-order equations.
Such problems are known as ‘Boundary Value Problems’ (BVPs).
For a system to be well defined, there should be as many conditions as there are first-order equations. For example, to solve two second-order ODEs you would need four conditions, as this system would equate to one with four first-order ODEs.
Suppose we wish to solve the system of $n$
equations, $\frac{d\mathbf{y}}{dx}=\mathbf{f}(x,\mathbf{y})$
, with conditions applied at two different points $x=a$
and $x=b$
.
In order to use the inbuilt MATLAB ODE solvers, you need to follow the steps below:
Construct a function (here called deriv
) which has input arguments $x$
and $\mathbf{y}=(y_1,\ldots,y_n)$
and returns the value of the derivative $\frac{d\mathbf{y}}{dx}$
, that is $\mathbf{f}(x,\mathbf{y})$
.
Construct a function (here called bcs
) which has input arguments $\mathbf{y}(a)$
and $\mathbf{y}(b)$
and returns the value of the residual for each specified boundary condition. For example to apply $y_1(a)=1$
and $y_1(b)=0$
use
function res = bcs(ya,yb)
res = [ ya(1) - 1
yb(1)];
To apply conditions to the other variables, $y_2$
, etc. change the index to ya(2)
or yb(2)
, for example.
Define the solution domain and provide an initial guess for the solution on the solution domain. Use the command
solinit = bvpinit([a,b],[0,0]);
This defines the domain for solution as $[a,b]$
, and the initial guess for the solution at the points specified in the domain as $[0,0]$
.
(Note that we could use a more accurate initial guess, that is define the domain using linspace(a,b,100)
and then define the solution on these points.)
Call the ODE solver bvp4c
, using the following command
sol = bvp4c(@deriv,@bcs,solinit);
The various parameters are:
@deriv
, a handle to a function that given $x$
and $\mathbf{y}$
returns the value of the derivative $\frac{d\mathbf{y}}{dx}$
;
@bcs
, a handle to a function that defines the boundary conditions;
solinit
, the structure defining the solution’s domain and that initial guess at the solution; and
sol
, a structure that contains the solution.
Plot the results, which are now stored as sol.x
and sol.y
.
plot(sol.x,sol.y(1,:),'b-x');
Suppose we wish to solve the following boundary value problem.
Consider the equation
$$ \frac{d^2y}{dx^2} + y = 0 \,. $$
subject to $y'(0) = 1$
and $y(\pi) = 0$
.
The exact solution is $y = \sin(x)$
.
To solve this numerically, we first need to reduce the second-order equation to a system of first-order equations,
$$ \frac{dy}{dx} = z \,, $$
$$ \frac{dz}{dx} = -y \,. $$
with $z(0) = 1$
and $y(\pi) = 0$
.
Example code to solve this is given by:
% Function to solve d^2ydx^2+y = 0.
function SimpleBVP()
%% Set up, solve, & plot the BVP
% Initial guess for solution on solution domain
solinit = bvpinit([0,pi],[0,0]);
% Solve the BVP
sol = bvp4c(@deriv,@bcs,solinit);
% Plot the solution
plot(sol.x,sol.y(1,:),'b-x');
%% Function to evaluate the right hand side of the system
function dYdx = deriv(x,Y)
dYdx(1) = Y(2);
dYdx(2) = -Y(1);
end
%% Function to evaluate the boundary values, y'(a)=1, y(b)=0
function res = bcs(ya,yb)
res = [ ya(2) - 1
yb(1)];
end
end
You can run the code by saving in a file named SimpleBVP.m
and executing it with SimpleBVP()
.
The main elements of this code are:
solinit = bvpinit([0,pi],[0,0]);
which defines the domain for solution through $[0,\pi]$
and the initial guess for the solution at the points specified in the domain, $[0,0]$
.
sol = bvp4c(@deriv,@bcs,solinit);
which is the call to the bvp4c
solver, the various parameters are:
@deriv
, a handle to a function that returns the value of the derivative $\frac{dy}{dx}$
for a given $x$
and $y$
;
@bcs
is a handle to a function that defines the boundary conditions; and
solinit is the structure defining the solution domain and initial guess.
plot(sol.x,sol.y(1,:),'b-x');
which plots the solution.
function dydx = deriv(x,y)
which is a function that returns the value of $\frac{d\mathbf{y}}{dx}$
for a given $x$
and $\mathbf{y}$
at that point (which here is the vector $[−z,y]$
).
function res = bcs(ya,yb)
which is a function which defines the boundary conditions applied at $a=0$
and $b=1$
.
Running the code (using SimpleBVP()
) yields the following plot:
This is plotted against the exact solution, $y=\sin(x)$
, in the next figure: