spm_dcm_mtf.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. function [S,K,s,w,t,dfdx] = spm_dcm_mtf(P,M,U)
  2. % computes transfer functions using the system's eigenspectrum
  3. % FORMAT [S,K,s,w,t,dfdx] = spm_dcm_mtf(P,M,[U])
  4. %
  5. % P - model parameters
  6. % M - model (with flow M.f and expansion point M.x and M.u)
  7. % U - induces expansion around steady state (from spm_dcm_neural_x(P,M))
  8. %
  9. % S - modulation transfer functions (complex)
  10. % K - Volterra kernels (real)
  11. % s - eigenspectrum (complex)
  12. % w - frequencies (Hz) = M.Hz
  13. % t - time (seconds) = M.pst
  14. % dfdx - Jacobian
  15. %
  16. % This routine uses the eigensolution of a dynamical systems Jacobian to
  17. % complete the first-order Volterra terminals and transfer functions in
  18. % peristimulus and frequency space respectively. The advantage of using
  19. % the-solution is that unstable modes (eigenvectors of the Jacobian) can be
  20. % conditioned (suppressed). Furthermore, this provides for a
  21. % computationally efficient and transparent evaluation of the transfer
  22. % functions that draws on linear signal processing theory in frequency
  23. % space.
  24. %__________________________________________________________________________
  25. % Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging
  26. % Karl Friston
  27. % $Id: spm_dcm_mtf.m 6856 2016-08-10 17:55:05Z karl $
  28. % get local linear approximation
  29. %==========================================================================
  30. % solve for steady-state - if required
  31. %--------------------------------------------------------------------------
  32. if nargin > 2
  33. M.x = spm_dcm_neural_x(P,M);
  34. end
  35. % check expansion points
  36. %--------------------------------------------------------------------------
  37. try, M.x; catch, M.x = spm_dcm_x_neural(P,M.dipfit.model); end
  38. try, M.u; catch, M.u = sparse(M.m,1); end
  39. % frequencies and peristimulus time of interest
  40. %--------------------------------------------------------------------------
  41. w = (1:64)';
  42. t = (0:64 - 1)'/64;
  43. try, w = M.Hz(:); end
  44. try, t = M.pst(:); end
  45. try, t = M.dt*(1:M.N)'; end
  46. % delay operator - if not specified already
  47. %--------------------------------------------------------------------------
  48. if isfield(M,'D')
  49. dfdx = spm_diff(M.f,M.x,M.u,P,M,1);
  50. dfdu = spm_diff(M.f,M.x,M.u,P,M,2);
  51. D = M.D;
  52. else
  53. if nargout(M.f) == 4
  54. [f,dfdx,D,dfdu] = feval(M.f,M.x,M.u,P,M);
  55. elseif nargout(M.f) == 3
  56. [f,dfdx,D] = feval(M.f,M.x,M.u,P,M);
  57. dfdu = spm_diff(M.f,M.x,M.u,P,M,2);
  58. elseif nargout(M.f) == 2
  59. [f,dfdx] = feval(M.f,M.x,M.u,P,M);
  60. dfdu = spm_diff(M.f,M.x,M.u,P,M,2);
  61. D = 1;
  62. else
  63. dfdx = spm_diff(M.f,M.x,M.u,P,M,1);
  64. dfdu = spm_diff(M.f,M.x,M.u,P,M,2);
  65. D = 1;
  66. end
  67. end
  68. % Jacobian and eigenspectrum
  69. %==========================================================================
  70. if nargout(M.g) == 2
  71. [g,dgdx] = feval(M.g,M.x,M.u,P,M);
  72. else
  73. dgdx = spm_diff(M.g,M.x,M.u,P,M,1);
  74. end
  75. dfdx = D*dfdx;
  76. dfdu = D*dfdu;
  77. try
  78. [v,s] = eig(full(dfdx),'nobalance');
  79. catch
  80. v = eye(size(dfdx));
  81. s = NaN(size(dfdx));
  82. end
  83. s = diag(s);
  84. % condition unstable eigenmodes
  85. %--------------------------------------------------------------------------
  86. if max(w) > 1
  87. s = 1j*imag(s) + real(s) - exp(real(s));
  88. else
  89. s = 1j*imag(s) + min(real(s),-1/32);
  90. end
  91. % Transfer functions
  92. %==========================================================================
  93. % transfer functions (FFT of kernel)
  94. %--------------------------------------------------------------------------
  95. nw = size(w,1); % number of frequencies
  96. nt = size(t,1); % number of time bins
  97. ng = size(dgdx,1); % number of outputs
  98. nu = size(dfdu,2); % number of inputs
  99. nk = size(v,2); % number of modes
  100. S = zeros(nw,ng,nu);
  101. K = zeros(nt,ng,nu);
  102. % derivatives over modes
  103. %--------------------------------------------------------------------------
  104. dgdv = dgdx*v;
  105. dvdu = pinv(v)*dfdu;
  106. for j = 1:nu
  107. for i = 1:ng
  108. for k = 1:nk
  109. % transfer functions (FFT of kernel)
  110. %--------------------------------------------------------------
  111. Sk = 1./(1j*2*pi*w - s(k));
  112. S(:,i,j) = S(:,i,j) + dgdv(i,k)*dvdu(k,j)*Sk;
  113. % kernels
  114. %--------------------------------------------------------------
  115. if nargout > 1
  116. Kk = exp(s(k)*t);
  117. K(:,i,j) = K(:,i,j) + real(dgdv(i,k)*dvdu(k,j)*Kk);
  118. end
  119. end
  120. end
  121. end
  122. return
  123. % NOTES: internal consistency with explicit Fourier transform of kernels
  124. %==========================================================================
  125. % augment and bi-linearise (with intrinsic delays)
  126. %--------------------------------------------------------------------------
  127. M.D = D;
  128. [M0,M1,L] = spm_bireduce(M,P);
  129. % project onto spatial modes
  130. %--------------------------------------------------------------------------
  131. try, L = M.U'*L; end
  132. % kernels
  133. %--------------------------------------------------------------------------
  134. N = length(t);
  135. dt = (t(2) - t(1));
  136. [K0,K1] = spm_kernels(M0,M1,L,N,dt);
  137. % Transfer functions (FFT of kernel)
  138. %--------------------------------------------------------------------------
  139. S1 = fft(K1)*dt;
  140. w1 = ((1:N) - 1)/(N*dt);
  141. j = w1 < max(w);
  142. S1 = S1(j,1,1);
  143. w1 = w1(j);
  144. subplot(2,2,1), plot(t,K(:,1,1),t,K1(:,1,1));
  145. title('kernels','fontsize',16)
  146. xlabel('peristimulus time')
  147. subplot(2,2,2), plot(w,real(S(:,1,1)), w1,real(S1(:,1,1))); hold on
  148. subplot(2,2,2), plot(w,imag(S(:,1,1)),':',w1,imag(S1(:,1,1)),':'); hold off
  149. title('transfer functions','fontsize',16)
  150. xlabel('frequency');