Matlab Demo
More on Inline FunctionsAs I was preparing these notes, I learned something new about inline functions. A standard inline function stores away the definition (as a string), and does not evaluate it until the function is called. At that point, any variable names other than the arguments are undefined: >> a = 2
a =
2
>> f = inline('a*x','x')
f =
Inline function:
f(x) = a*x
>> f(5)
??? Error using ==> inlineeval
Undefined function or variable 'a'.
An inline function defined with the other notation evaluates variables that are not arguments. I did not see that mentioned in the manual: >> a = 2
a =
2
>> f = @(x) a*x
Numerical DifferentiationFirst DerivativeThe only differentiation routines built into Matlab are ppder (for polynomials), fnder (for splines), and diff (symbolic differentiation). For general functions you need to program your own formulas. Example: Estimate the derivative of ex at x=1. The standard forward / backward / centered difference formulas produce >> h = 0.1; x = 1; If you have irregular given data points, you can interpolate and differentiate the interpolant, using either polynomials or splines. >> xx = [0.5,1.2,2,3]; yy = exp(xx); Second Derivative>> centered = (exp(x+h) - 2*exp(x) + exp(x-h))/h^2 Numerical IntegrationOne-Dimensional IntegralThe standard integration routines in Matlab are quad and quadl. Example: Integrate ex from 0 to 1. >> [I,neval] = quad('exp',0,1), error = I - (exp(1)-1)
In my opinion, numerical integration is a weak spot in Matlab. There ought to be some routines for doing mildly singular integrals, such as sqrt(x), or more seriously singular integrals, such as 1/sqrt(x). Notice that integrating sqrt(x) takes a lot more evaluations than the exponential function. Most of them are near 0, where the singularity is. >> [I,neval] = quadl('sqrt',0,1), error = I - 2/3
Multidimensional IntegralsExample: Integrate ex+y sin x over the square [0,1] x [1,2]. Let's do the exact integral first: >> true = int(int(sym('exp(x+y)*sin(x)'),'x',0,1),'y',1,2)
Method 1: Do an interated integral. This is considerably more tricky than it seems. I tried to do it with inline functions and failed. You have to use functions stored in files. Defining the integrand is easy: function z = f(x,y) The inner integral is function z = inner(y) Notice some things here:
After the setup it works quite well: >> I = quad('inner',1,2), error = I - true
Method 2: Use dblquad: >> I = dblquad('f',0,1,1,2), error = I - true
The fact that you get exactly the same number is no coincidence: behind the scenes, dblquad does precisely what we did in Method 1. The only problem with dblquad is that it requires a rectangular area. If you want to integrate over a different area, you need to write your function so that it has value 0 outside the area, and the resulting discontinuity will slow it down a bit. Do-It-Yourself ODE SolversExample: y'(t) = -2 t y2(t), y(0) = 1, true solution y(t) = 1/(1 + t2). Use step size 0.1 from 0 to 2. Euler's Method:>> f = inline('-2*t.*y.^2','t','y'); y0 = 1;
Runge-Kutta:>> y_rk = zeros(size(t)); y_rk(1) = y0;
Multistep:Notice that we need Runge-Kutta to provide start-up values. We also need a separate vector for the f values. >> y_abm = zeros(size(t)); y_abm(1:4) = y_rk(1:4);
Matlab ODE SolversODE45We do the same example as before: >> [tt,y_ode45] = ode45(f,[0,2],y0);
Comments:
You can set various options with the odeset command. For example, let's do the same calculation with reduced accuracy: >> odeset
AbsTol: [ positive scalar or vector {1e-6} ]
RelTol: [ positive scalar {1e-3} ]
NormControl: [ on | {off} ]
NonNegative: [ vector of integers ]
OutputFcn: [ function_handle ]
OutputSel: [ vector of integers ]
Refine: [ positive integer ]
Stats: [ on | {off} ]
InitialStep: [ positive scalar ]
MaxStep: [ positive scalar ]
BDF: [ on | {off} ]
MaxOrder: [ 1 | 2 | 3 | 4 | {5} ]
Jacobian: [ matrix | function_handle ]
JPattern: [ sparse matrix ]
Vectorized: [ on | {off} ]
Mass: [ matrix | function_handle ]
MStateDependence: [ none | {weak} | strong ]
MvPattern: [ sparse matrix ]
MassSingular: [ yes | no | {maybe} ]
InitialSlope: [ vector ]
Events: [ function_handle ]
>> options = odeset('AbsTol',1.e-3);
>> [tt,y_ode45] = ode45(f,[0,2],y0,options);
In this particular example, that has no effect. You still get the same values for tt. Higher Order ODEsAs an example of a higher order ODE, or equivalently a system of ODEs, consider the van der Pol equation y ''(t) - μ [1 - y2(t)] y '(t) + y(t) = 0 Solutions of this equation become approximately periodic with a period of order μ. The time scales involved are of order μ and 1/μ, so for large values of μ this equation becomes stiff. Runge-Kutta:All the standard methods are unchanged when you go from scalar equations to vector equations. I will just illustrate that with the Runge-Kutta method here. We use the van der Pol equation with μ=2 (non-stiff). >> mu = 2; z0 = [1;0]; h = 0.1; >> f = @(t,z) [z(2);mu*(1-z(1)^2)*z(2)-z(1)]; >> t_rk = 0:h:20; z_rk = zeros(2,length(t_rk)); z_rk(:,1) = z0;
Notice two things here:
ODE45Passing the value of μ is a bit tricky. We have two choices:
We use the second method. >> f = @(t,z,mu) [z(2);mu*(1-z(1)^2)*z(2)-z(1)];
I ran into one problem here: notice that it says z_rk(1,:), but z_ode45(:,1). Even though z0 is a column vector, and f is written to produce column vectors, ODE45 outputs row vectors. Live with it. Stiff ODEsThis time we use μ=100, which makes the problem quite stiff. You can still solve it with ODE45, but it is much faster to use ODE23s: >> mu = 100; z0 = [1;0];
For comparison, I tried to run standard Runge-Kutta with step size h=0.01 on this problem. It did OK for a little bit, then this happened: >> z_rk(1,50)
Last Updated: March 12, 2009 |