Estimating Forcing Functions for the FitzHugh-Nagumo Equations

This page provides a demonstration of the use of forcing functiona perturbed set of FitzHugh-Nagumo Equations:

Here we will assume knowledge of $a$, $b$ and $c$, and estimate $g(t)$ from data.

The format of this demonstration follows that detailed in FhNEx.html and commentary will therefore be restricted to terms unique to forcing function estimation.

Contents

RHS Functions

Since we are using a linear function to begin with, we make use of the forcing set of functions (although fhnfunodep will be used to produce data).

addpath('../FhN')

odefn       = @fhnfunodep;        % Function for ODE solver (exact)

fn.fn       = @forcingfun;        % RHS function

fn.dfdx     = @forcingdfdx;       % Derivative wrt inputs (Jacobian)
fn.dfdp     = @forcingdfdp;       % Derviative wrt parameters

fn.d2fdx2   = @forcingd2fdx2;     % Hessian wrt inputs
fn.d2fdxdp  = @forcingd2fdxdp;    % Cross derivatives wrt inputs and parameters
fn.d2fdp2   = @forcingd2fdp2;     % Hessian wrt parameters

fn.d3fdx2dp = @forcingd3fdx2dp;   % Third derivative wrt inputs, inputs, pars
fn.d3fdx3   = @forcingd3fdx3;     % Third derivative wrt inputs
fn.d3fdxdp2 = @forcingd3fdxdp2;   % Third derivative wrt inputs, pars and pars
Warning: Name is nonexistent or not a directory: ..\FhN.

Observation times

tspan = 0:0.05:20;    % Observation times

obs_pts{1} = 1:length(tspan);      % Which components are observed at
obs_pts{2} = 1:length(tspan);      % which observation times.

tfine = 0:0.05:20;    % Times to plot solutions

Various Parameters

y0 = [-1,1];               % Initial conditions
pars0 = [0.2; 0.2; 3];     % Parameters for the FitzHugh-Nagumo equations

% Set up a perturbation functional data object

basis_obj = create_bspline_basis([0 20],42,3,0:0.5:20);
quadvals = MakeQuadPoints(0:0.5:20,21);      % We will need to use
basis_obj = putquadvals(basis_obj,quadvals); % quadrature points later

%pcoef = zeros(42,1);
pcoef(floor(42/3):(ceil(42/3)+5)) = 10;
fd_obj = fd(pcoef,basis_obj);

% Finally decide on a noise level:

sigma = 0.25;              % Noise Level

Extra Information for the System:

In particular, we need to specify the original ODEs and their derifatives with respect to components (in this case the FitzHugh-Nagumo Equations) and also the option of adding further information for the original system.

fn_extras.fn      = @fhnfun;    % Original function
fn_extras.dfdx    = @fhndfdx;   % First derivative
fn_extras.d2fdx2  = @fhnd2fdx2; % Second derivative
fn_extras.d3fdx3  = @fhnd3fdx3; % Third derivative

fn_extras.extras  = [];        % Original information to fn_extras.fn.

% We also need to add parameters:

fn_extras.pars = pars0;

% We also need to specify a basis for the forcing components and a vector
% indicating which components are to be forced.

fn_extras.basisp = {basis_obj};   % Cell array of basis functions.
fn_extras.which  = 1;             % Force the first component of the
                                  % system only.

% Note that although we are only forcing one component here, the forcing
% basis is still represented as a cell array and we could equally have
% estimated a number of forcing functions.

Penalties on Forcing Functions

We can also place roughness penalties on forcing functions, these will then occur as inputs into Profile_GausNewt.

pen   = @forcingpen;   % Penalty
dpen  = @forcingdpen;  % Derivative with respect to forcing co-efficients
d2pen = @forcingd2pen; % Second derivative

% These penalty functions also require extra arguments in the form of a
% struct to specify the basis, the degree of smoothing and the smoothing
% penalty:

pen_extras. basis = {basis_obj}; % Same basis as fn_extras.
pen_extras.deg    = 2;           % Penalize the second derivative
pen_extras.lambda = 0.0001;      % Smoothing parameter.

Initial Forcing Estimates

We start off assuming the forcing function is zero. Since the coefficients of a basis expansion for it occur as parameters in the profiled estimation scheme we set them as:

startpars = zeros(getnbasis(basis_obj),1);

Create trajectories

odeopts = odeset('RelTol',1e-13);
[full_time,full_path] = ode45(odefn,tspan,y0,odeopts,pars0,fd_obj);
[plot_time,plot_path] = ode45(odefn,tfine,y0,odeopts,pars0,fd_obj);

Set up observations

Tcell = cell(1,size(full_path,2));
path = Tcell;

for i = 1:length(obs_pts)
    Tcell{i} = full_time(obs_pts{i});
    path{i} = full_path(obs_pts{i},i);
end

% add noise

Ycell = path;
for i = 1:length(path)
    Ycell{i} = path{i} + sigma*randn(size(path{i}));
end

% and set wts

wts = [];

if isempty(wts)                             % estimate wts if not given
    for i = 1:length(Ycell)
        wts(i) = 1./sqrt(var(Ycell{i}));
    end
end

Fitting parameters

lambda = 1000;          % Smoothing for model-based penalty
lambda = lambda*wts;

lambda0 = 1;   % Smoothing for 1st-derivative penalty

nknots = 401;    % Number of knots to use.
nquad = 5;       % No. between-knots quadrature points.
norder = 6;      % Order of B-spline approximation

Optimisation control

lsopts_out = optimset('DerivativeCheck','off','Jacobian','on',...
    'Display','iter','MaxIter',1000,'TolFun',1e-8,'TolX',1e-10);

% Other observed optimiation control
lsopts_other = optimset('DerivativeCheck','off','Jacobian','on',...
    'Display','on','MaxIter',1000,'TolFun',1e-14,'TolX',1e-14,...
    'JacobMult',@SparseJMfun);

% Optimiation control within profiling
lsopts_in = optimset('DerivativeCheck','off','Jacobian','on',...
    'Display','off','MaxIter',1000,'TolFun',1e-14,'TolX',1e-14,...
    'JacobMult',@SparseJMfun);

Setting up functional data objects

% set up knots

range = [min(full_time),max(full_time)];  % range of observations

knots_cell = cell(size(path));            % knots for each basis
knots_cell(:) = {linspace(range(1),range(2),nknots)};

% set up bases

basis_cell = cell(1,length(path));   % Create cell arrays.
Lfd_cell = cell(1,length(path));

nbasis = zeros(length(path),1);

bigknots = knots_cell{1};            % bigknots used for quadrature points
nbasis(1) = length(knots_cell{1}) + norder - 2;
for i = 2:length(path)
    bigknots = [bigknots knots_cell{i}];
    nbasis(i) = length(knots_cell{i}) + norder -2;
end

quadvals = MakeQuadPoints(bigknots,nquad);   % Create simpson's rule
                                             % quadrature points and values
for i = 1:length(path)
    basis_cell{i} = MakeBasis(range,nbasis(i),norder,...  % create bases
        knots_cell{i},quadvals,4);                        % with quadrature
    Lfd_cell{i} = fdPar(basis_cell{i},1,lambda0);         % pts  attatched
end

Smooth the data

DEfd = smoothfd_cell(Ycell,Tcell,Lfd_cell);
coefs = getcellcoefs(DEfd);

devals = eval_fdcell(tfine,DEfd,0);
for i = 1:length(path)
    subplot(length(path),1,i);
    plot(plot_time,plot_path(:,i),'b','LineWidth',2);
    hold on;
    plot(tfine,devals{i},'r','LineWidth',2);
    plot(Tcell{i},Ycell{i},'b.');
    hold off;
end

Re-Smooth with a Model-Based Penalty

[newcoefs,resnorm2] = lsqnonlin(@SplineCoefErr,coefs,[],[],...
    lsopts_other,basis_cell,Ycell,Tcell,wts,lambda,fn,[],startpars,...
    fn_extras);

tDEfd = Make_fdcell(newcoefs,basis_cell);

% plot results along with exact solution, there is a noticeable lack of
% fit.

devals = eval_fdcell(tfine,tDEfd,0);
for i = 1:length(Ycell)
    subplot(length(Ycell),1,i);
    plot(tfine,devals{i},'r','LineWidth',2);
    hold on;
    plot(Tcell{i},Ycell{i},'b.');
    plot(plot_time,plot_path(:,i),'c');
    hold off
end
Optimization terminated: relative function value
 changing by less than OPTIONS.TolFun.

Now do the profiled estimation

Recall that at this point we are estimating the coefficients of the forcing functions.

[fcoefs,DEfd] = Profile_GausNewt(startpars,lsopts_out,tDEfd,fn,lambda,...
    Ycell,Tcell,wts,[],lsopts_in,fn_extras,pen,dpen,pen_extras);

% DEfd now takes the form of a smooth to the data and we can see that it
% fits better:

devals = eval_fdcell(tfine,DEfd,0);
for i = 1:length(path)
    subplot(length(path),1,i);
    plot(tfine,devals{i},'r','LineWidth',2);
    hold on;
    plot(Tcell{i},Ycell{i},'b.');
    plot(plot_time,plot_path(:,i),'c');
    hold off
end
 Iteration       steps    Residual   Improvement   Grad-norm     parameters
     1           1         126.093      0.592753        0.298     -0.74061   -0.066343     0.51962     -1.4236    -0.72229     0.45195    0.056012     -1.0448     0.36335     -0.3683     -1.0082   -0.005413    -0.95034      8.7874     -2.6424      1.3379      3.5346       4.958      7.9916       -1.69      8.9789      7.6286     -1.8416     0.67843    -0.45554      2.3315   -0.092889     0.31005     -1.0432      2.4937     -2.8465     -3.2763     0.12289    -0.53359     0.72481    -0.97313     0.92401     -1.2589     0.73558    -0.62486     0.36293      1.9134
     2           1         72.7815      0.422797       0.0348     -0.543809    0.0390957     0.516403       -1.356    -0.665423     0.432098    0.0144772    -0.977691     0.377309     0.243895    -0.780672      1.15339     -1.13211      16.0818      3.05923    -0.152166      7.74569      12.3853      8.40364      -1.6618      6.87211      8.87325     0.309595    -0.575085    -0.684515      2.02412    0.0723844     0.403837     0.293083    0.0533429    -0.438236    -0.782215     -1.51268    0.0342214     0.695885    -0.924587     0.921273     -1.23676     0.664204    -0.593956     0.414861      1.71205
     3           1         47.4938      0.347447       0.0049     -0.715957   -0.0300497     0.561359      -1.2115    -0.506859     0.649419     0.283191    -0.797805     0.712243      0.44896    -0.389681     0.148751      0.38651      7.89654      11.4206      1.92934      8.62524      13.0305      8.78573   -0.0574364      2.13521      7.14525     0.191142      -1.6327     -1.39984      1.74743    -0.185594     0.348316    -0.217555     0.515205    -0.157832     0.173842     -1.05544    -0.221741     0.693638     -0.91932     0.913194     -1.20305     0.713828    -0.588338     0.367317      1.68152
     4           1         42.5592        0.1039     0.000321     -0.715045    -0.041507     0.563264     -1.19524    -0.484007     0.671902     0.311927    -0.689212     0.751827     0.615595    -0.473893     0.459882   -0.0831338      9.12517      12.3077      6.32168      9.84922      12.3152      8.96157     0.683865    -0.820837      2.59282   -0.0508123     -1.09665      -1.1372      1.88296   -0.0315437     0.394611    -0.220598     0.354213    -0.259916     0.379593    -0.841356    -0.237914     0.757766    -0.922057     0.938468      -1.2212     0.690566       -0.606     0.374637      1.69128
     5           1         42.3398    0.00515544    3.84e-005     -0.720761   -0.0416537     0.563535     -1.19708    -0.486534     0.669067     0.306695    -0.693857     0.746413     0.610066    -0.469159     0.440291   -0.0508425      9.05762      12.2901      7.48831      10.2603      12.2103      8.90905     0.826736     -1.32213      0.85847    -0.422614    -0.928106     -1.19913      1.90477   -0.0708986     0.407958    -0.241958     0.357149    -0.256231     0.369341    -0.817005    -0.241774     0.753444    -0.916983      0.93269     -1.21777     0.690004    -0.604909     0.372529      1.69073
     6           1          42.339  1.89533e-005    5.64e-006     -0.720825    -0.041736     0.563424     -1.19735    -0.486874     0.668637     0.306201    -0.694535     0.746017     0.609175    -0.469827     0.440023   -0.0504314      9.05743       12.303      7.56272      10.2486      12.2188      8.90285     0.834049     -1.33174     0.732646    -0.458082     -0.90851     -1.20296      1.90775   -0.0738449     0.408676    -0.240962     0.357092     -0.25465       0.3566    -0.814203    -0.242588     0.754458     -0.91737     0.933962     -1.21846     0.689439    -0.604891     0.373614      1.69102
     7           1          42.339  1.45619e-008    1.38e-007     -0.720822   -0.0417374     0.563415     -1.19735    -0.486883     0.668626     0.306195    -0.694572     0.746036     0.609076    -0.469778     0.439908   -0.0502118       9.0568      12.3036      7.56565      10.2476      12.2187      8.90246     0.834309     -1.33185     0.729867    -0.458573    -0.907431      -1.2033      1.90798   -0.0741554     0.408809    -0.241104     0.357339    -0.254891     0.356914    -0.814291    -0.242613     0.754476    -0.917333      0.93397     -1.21846     0.689354    -0.604886     0.373709      1.69101
     8           1          42.339  1.26056e-010    5.35e-009     -0.720822   -0.0417377     0.563414     -1.19735    -0.486883     0.668625     0.306194    -0.694573     0.746036     0.609071    -0.469779     0.439909   -0.0502163      9.05682      12.3036      7.56575      10.2475      12.2187      8.90245     0.834316     -1.33185     0.729817    -0.458599    -0.907401     -1.20329      1.90798   -0.0741527     0.408801    -0.241093     0.357339    -0.254889     0.356877    -0.814287    -0.242609     0.754477    -0.917329     0.933971     -1.21846     0.689348    -0.604886     0.373714      1.69101

Examine Forcing Functions

First we constitute the approximated forcing function:

fd_approx = fd(fcoefs,basis_obj);

% Now plot the results along with the original forcing function:

force_devals = eval_fd(tfine,fd_obj);
approx_devals = eval_fd(tfine,fd_approx);

subplot(1,1,1)
plot(tfine,force_devals,'r','LineWidth',2);
hold on
plot(tfine,approx_devals,'b','LineWidth',2);
hold off

Calculate a Sample Information Matrix

d2Jdp2 = make_d2jdp2(DEfd,fn,Ycell,Tcell,lambda,fcoefs,[],wts,...
    fn_extras,d2pen,pen_extras);

d2JdpdY = make_d2jdpdy(DEfd,fn,Ycell,Tcell,lambda,fcoefs,[],wts,fn_extras);

dpdY = -d2Jdp2\d2JdpdY;

S = make_sigma(DEfd,Tcell,Ycell,0);

Cov = dpdY*S*dpdY';

Calculate Hotelling Distance from Zero

Look at the distance of fcoefd from 0 with respect to the metric defined by Cov. This is a heuristic Wald test for the goodness of fit of the original equations.

disp(['Goodness of fit = ',num2str(fcoefs'*inv(Cov)*fcoefs)])
Goodness of fit = 1800.802