123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- function [x,P] = spm_ekf(M,y)
- % Extended Kalman Filtering for dynamic models
- % FORMAT [x,P] = spm_ekf(M,y)
- % M - model specification structure
- % y - output or data (N x T)
- %
- % M(1).x % initial states
- % M(1).f = inline(f,'x','v','P') % state equation
- % M(1).g = inline(g,'x','v','P') % observer equation
- % M(1).pE % parameters
- % M(1).V % observation noise precision
- %
- % M(2).v % initial process f(noise)
- % M(2).V % process f(noise) precision
- %
- % x - conditional expectation of states
- % P - {1 x T} conditional covariance of states
- %__________________________________________________________________________
- % See notes at the end of this script for details and a demo. This routine
- % is based on:
- %
- % var der Merwe R, Doucet A, de Freitas N and Wan E (2000). The
- % unscented particle filter. Technical Report CUED/F-INFENG/TR 380
- %__________________________________________________________________________
- % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
- % Karl Friston
- % $Id: spm_ekf.m 1143 2008-02-07 19:33:33Z spm $
- % check model specification
- %--------------------------------------------------------------------------
- M = spm_DEM_M_set(M);
- dt = M(1).E.dt;
- if length(M) ~=2
- errordlg('spm_ekf requires a two-level model')
- return
- end
- % INITIALISATION:
- % =========================================================================
- dfdx = spm_diff(M(1).f,M(1).x,M(2).v,M(1).pE,1);
- dfdv = spm_diff(M(1).f,M(1).x,M(2).v,M(1).pE,2);
- dgdx = spm_diff(M(1).g,M(1).x,M(2).v,M(1).pE,1);
- Jx = spm_expm(dfdx);
- T = length(y); % number of time points
- % covariances
- %--------------------------------------------------------------------------
- iR = M(1).V;
- for i = 1:length(M(1).Q)
- iR = iR + M(1).Q{i}*exp(M(1).hE(i));
- end
- iQ = M(1).W;
- for i = 1:length(M(1).R)
- iQ = iQ + M(1).R{i}*exp(M(1).gE(i));
- end
- R = inv(iR); % EKF measurement noise variance.
- Q = inv(iQ); % EKF process noise variance.
- x = M(1).x; % EKF estimate of the mean of states
- Q = Q + Jx*dfdv*inv(M(2).V)*dfdv'*Jx'; % EKF process noise variance.
- P = {pinv(full(dgdx'*R*dgdx))}; % EKF conditional covariance of states
- for t = 2:T
- % PREDICTION STEP:
- %----------------------------------------------------------------------
- f = M(1).f(M(1).x,M(2).v,M(1).pE);
- dfdx = spm_diff(M(1).f,M(1).x,M(2).v,M(1).pE,1);
- xPred = M(1).x + spm_dx(dfdx,f,dt);
- Jx = spm_expm(dfdx);
- PPred = Q + Jx*P{t-1}*Jx';
- % CORRECTION STEP:
- %----------------------------------------------------------------------
- yPred = M(1).g(xPred,M(2).v,M(1).pE);
- Jy = spm_diff(M(1).g,xPred,M(2).v,M(1).pE,1);
- K = PPred*Jy'*inv(R + Jy*PPred*Jy');
- M(1).x = xPred + K*(y(:,t) - yPred);
- x(:,t) = M(1).x;
- P{t} = PPred - K*Jy*PPred;
- % report
- %----------------------------------------------------------------------
- fprintf('EKF: time-step = %i : %i\n',t,T);
- end
- return
- % notes and demo:
- %==========================================================================
- % The code below generates a nonlinear, non-Gaussian problem (S) comprising
- % a model S.M and data S.Y (c.f. van der Merwe et al 2000))
- %
- % The model is f(x) = dxdt
- % = 1 + sin(o.o4*pi*t) - log(2)*x + n
- % y = g(x)
- % = (x.^2)/5 : if t < 30
- % -2 + x/2 : otherwise
- % i.e. the output nonlinearity becomes linear after 30 time steps. In this
- % implementation time is modelled as an auxiliary state variable. n is
- % the process noise, which is modelled as a log-normal variate. e is
- % Gaussian observation noise.
- % model specification
- %--------------------------------------------------------------------------
- f = '[1; (1 + sin(P(2)*pi*x(1)) - P(1)*x(2) + exp(v))]';
- g = '(x(1) > 30)*(-2 + x(2)/2) + ~(x(1) > 30)*(x(2).^2)/5';
- M(1).x = [1; 1]; % initial states
- M(1).f = inline(f,'x','v','P'); % state equation
- M(1).g = inline(g,'x','v','P'); % observer equation
- M(1).pE = [log(2) 0.04]; % parameters
- M(1).V = 1e5; % observation noise precision
- M(2).v = 0; % initial process log(noise)
- M(2).V = 2.4; % process log(noise) precision
- % generate data (output)
- %--------------------------------------------------------------------------
- T = 60; % number of time points
- S = spm_DEM_generate(M,T);
- % EKF
- %--------------------------------------------------------------------------
- ekf_x = spm_ekf(M,S.Y);
- % plot results
- %--------------------------------------------------------------------------
- x = S.pU.x{1};
- plot([1:T],x(2,:),[1:T],ekf_x(2,:))
- legend({'true','EKF'})
|