function [DCM] = spm_dcm_fmri_nmm(P) % Estimates parameters of a DCM (neural mass model) for fMRI data % FORMAT [DCM] = spm_dcm_estimate(DCM) % DCM - DCM structure or its filename % % Expects %-------------------------------------------------------------------------- % DCM.a % switch on endogenous connections % DCM.b % switch on bilinear modulations % DCM.c % switch on exogenous connections % DCM.U % exogenous inputs % DCM.Y.y % responses % DCM.Y.X0 % confounds % DCM.Y.Q % array of precision components % DCM.n % number of regions % DCM.v % number of scans % % Options %-------------------------------------------------------------------------- % DCM.options.nmm % neural mass model % DCM.options.centre % mean-centre inputs % DCM.options.nograph % graphical display % DCM.options.P % starting estimates for parameters % DCM.options.hidden % indices of hidden regions % DCM.options.maxnodes % maximum number of (effective) nodes % DCM.options.maxit % maximum number of iterations % DCM.options.hE % expected precision of the noise % DCM.options.hC % variance of noise expectation % % Evaluates: %-------------------------------------------------------------------------- % DCM.M % Model structure % DCM.Ep % Condition means (parameter structure) % DCM.Cp % Conditional covariances % DCM.Vp % Conditional variances % DCM.Pp % Conditional probabilities % DCM.H1 % 1st order hemodynamic kernels % DCM.H2 % 2nd order hemodynamic kernels % DCM.K1 % 1st order neuronal kernels % DCM.K2 % 2nd order neuronal kernels % DCM.R % residuals % DCM.y % predicted data % DCM.T % Threshold for Posterior inference % DCM.Ce % Error variance for each region % DCM.F % Free-energy bound on log evidence % DCM.ID % Data ID % DCM.AIC % Akaike Information criterion % DCM.BIC % Bayesian Information criterion % %__________________________________________________________________________ % Copyright (C) 2002-2012 Wellcome Trust Centre for Neuroimaging % Karl Friston % $Id: spm_dcm_fmri_nmm.m 6922 2016-11-02 17:28:23Z karl $ SVNid = '$Rev: 6922 $'; %-Load DCM structure %-------------------------------------------------------------------------- if ~nargin %-Display model details %---------------------------------------------------------------------- Finter = spm_figure('GetWin','Interactive'); set(Finter,'name','Dynamic Causal Modelling') %-Get DCM %---------------------------------------------------------------------- [P, sts] = spm_select(1,'^DCM.*\.mat$','select DCM_???.mat'); if ~sts, DCM = []; return; end spm('Pointer','Watch') spm('FigName','Estimation in progress'); end if isstruct(P) DCM = P; P = ['DCM-' date '.mat']; else load(P) end % check options %========================================================================== try, DCM.options.nmm; catch, DCM.options.nmm = 'TFM'; end try, DCM.options.two_state; catch, DCM.options.two_state = 0; end try, DCM.options.stochastic; catch, DCM.options.stochastic = 0; end try, DCM.options.nonlinear; catch, DCM.options.nonlinear = 0; end try, DCM.options.centre; catch, DCM.options.centre = 0; end try, DCM.options.hidden; catch, DCM.options.hidden = []; end try, DCM.options.hE; catch, DCM.options.hE = 6; end try, DCM.options.hC; catch, DCM.options.hC = 1/128; end try, DCM.options.maxit; catch, DCM.options.maxit = 32; end try, DCM.options.maxnodes; catch, DCM.options.maxnodes = 16; end try, DCM.n; catch, DCM.n = size(DCM.c,1); end try, DCM.v; catch, DCM.v = size(DCM.Y.y,1); end try, M.nograph = DCM.options.nograph; catch, M.nograph = spm('CmdLine'); end try, M.Nmax = DCM.M.Nmax; catch, M.Nmax = DCM.options.maxit; end % unpack %-------------------------------------------------------------------------- U = DCM.U; % exogenous inputs Y = DCM.Y; % responses n = DCM.n; % number of regions v = DCM.v; % number of scans % detrend outputs (and inputs) %-------------------------------------------------------------------------- Y.y = spm_detrend(Y.y); if DCM.options.centre U.u = spm_detrend(U.u); end % check scaling of Y (enforcing a maximum change of 4%) %-------------------------------------------------------------------------- scale = max(max((Y.y))) - min(min((Y.y))); scale = 4/max(scale,4); Y.y = Y.y*scale; Y.scale = scale; % check confounds (add constant if necessary) %-------------------------------------------------------------------------- if ~isfield(Y,'X0'),Y.X0 = ones(v,1); end if ~size(Y.X0,2), Y.X0 = ones(v,1); end % fMRI slice time sampling %-------------------------------------------------------------------------- try, M.delays = DCM.delays; catch, M.delays = ones(n,1); end try, M.TE = DCM.TE; end % create priors %========================================================================== % priors (and initial states) - neuronal %-------------------------------------------------------------------------- [nE,nC] = spm_dcm_neural_priors(DCM.a,DCM.b,DCM.c,DCM.options.nmm); [xn,fn] = spm_dcm_x_neural(nE,DCM.options.nmm); % fix some neuronal (neural mass) parameters %-------------------------------------------------------------------------- p = {'T','D','R','G'}; for i = 1:numel(p) try nC.(p{i}) = spm_zeros(nC.(p{i})); end end pE.N = rmfield(nE,{'M','N','E','F'}); pC.N = rmfield(nC,{'M','N','E','F'}); % add neurovascular parameters %-------------------------------------------------------------------------- pE.J = sparse(4,3); pC.J = sparse(4,3) + 1/16; % and hemodynamic priors %-------------------------------------------------------------------------- bE.transit = sparse(n,1); bC.transit = sparse(n,1) + 1/256; bE.decay = sparse(n,1); bC.decay = sparse(n,1) + 1/256; bE.epsilon = sparse(1,1); bC.epsilon = sparse(1,1) + 1/256; x.x = xn; x.h = sparse(n,4); pE.H = bE; pC.H = bC; % Using specified priors %-------------------------------------------------------------------------- str = 'Using specified priors'; try, M.P = DCM.options.P; end % initial parameters try, pE = DCM.options.pE; fprintf(str); end % prior expectation try, pC = DCM.options.pC; fprintf(str); end % prior covariance % hyperpriors over precision - expectation and covariance %-------------------------------------------------------------------------- hE = sparse(n,1) + DCM.options.hE; hC = speye(n,n) * DCM.options.hC; i = DCM.options.hidden; hE(i) = -4; hC(i,i) = exp(-16); % complete model specification %-------------------------------------------------------------------------- M.IS = @spm_gen_fmri; % integration scheme M.fn = fn; % neuronal equations of motion M.x = x; % initial condition (states) M.pE = pE; % prior expectation (parameters) M.pC = pC; % prior covariance (parameters) M.hE = hE; % prior expectation (precisions) M.hC = hC; % prior covariance (precisions) M.m = size(U.u,2); M.n = size(spm_vec(x),1); M.l = n; M.ns = v; % nonlinear system identification (Variational Laplace) %========================================================================== [Ep,Cp,Eh,F] = spm_nlsi_GN(M,U,Y); % predicted responses (y) and residuals (R) %-------------------------------------------------------------------------- y = feval(M.IS,Ep,M,U); R = Y.y - y; R = R - Y.X0*spm_inv(Y.X0'*Y.X0)*(Y.X0'*R); Ce = exp(-Eh); % Bilinear representation and first-order hemodynamic kernel %-------------------------------------------------------------------------- H.f = @spm_fx_hdm; H.g = @spm_gx_hdm; H.x = M.x.h; H.m = M.m; [H0,H1] = spm_kernels(H,Ep.H,64,1/2); % and neuronal kernels %-------------------------------------------------------------------------- N.f = M.fn; N.x = M.x.x; N.m = M.m; [K0,K1] = spm_kernels(N,Ep.N,64,8/1000); % Bayesian inference and variance %-------------------------------------------------------------------------- T = full(spm_vec(pE)); sw = warning('off','SPM:negativeVariance'); Pp = spm_unvec(1 - spm_Ncdf(T,abs(spm_vec(Ep)),diag(Cp)),Ep); Vp = spm_unvec(full(diag(Cp)),Ep); warning(sw); try, M = rmfield(M,'nograph'); end % Store parameter estimates %-------------------------------------------------------------------------- DCM.M = M; DCM.Y = Y; DCM.U = U; DCM.Ce = Ce; DCM.Ep = Ep; DCM.Cp = Cp; DCM.Pp = Pp; DCM.Vp = Vp; DCM.H1 = H1; DCM.K1 = K1; DCM.R = R; DCM.y = y; DCM.T = 0; % Data ID and log-evidence %========================================================================== if isfield(M,'FS') try ID = spm_data_id(feval(M.FS,Y.y,M)); catch ID = spm_data_id(feval(M.FS,Y.y)); end else ID = spm_data_id(Y.y); end % Save approximations to model evidence: negative free energy, AIC, BIC %-------------------------------------------------------------------------- evidence = spm_dcm_evidence(DCM); DCM.F = F; DCM.ID = ID; DCM.AIC = evidence.aic_overall; DCM.BIC = evidence.bic_overall; % Save SPM version and revision number of code used %-------------------------------------------------------------------------- [DCM.version.SPM.version, DCM.version.SPM.revision] = spm('Ver'); DCM.version.DCM.version = spm_dcm_ui('Version'); DCM.version.DCM.revision = SVNid; %-Save DCM %-------------------------------------------------------------------------- if ~isstruct(P) save(P,'DCM','F','Ep','Cp', spm_get_defaults('mat.format')); end