latencyfit4AM.m 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. function [lat,coeff,rs,converge,yf] = latencyfit4AM(y,t,peak,fig)
  2. %Fits a double Gaussian + cumulative Gaussian to neural data. latency is
  3. %taken as the point at which the fit reaches 33% of its maximum.
  4. %Input args:
  5. %y = row vector of neural data, can be raw MUA or difference
  6. %t = row vector of time in ms (same length as y)
  7. %peak: 1 = chooses starting guesses appropriate for raw MUA (default), 2 (or any other value) = starting values for modulation curves
  8. %fig = 1 (open a figure and show the fit), 0 = no figure (default)
  9. %Output args
  10. %lat = latency at 33% of the peak
  11. %coeff = fit coefficients
  12. %rs = adjusted r-squared value of fit
  13. %converge - did fit converge?
  14. %M.W.Self 2014
  15. %Checks
  16. if nargin < 3
  17. peak = 1;
  18. end
  19. if nargin < 4
  20. fig = 0;
  21. end
  22. if size(y,1)>size(y,2)
  23. y = y';
  24. end
  25. if size(t,1)>size(t,2)
  26. t = t';
  27. end
  28. if peak == 1
  29. %These are the limits and initial guesses of the fit.
  30. %These can be used to restrain the fit to exclude unlikely values and
  31. %prevent fitting of noise.
  32. %Note also that the initial guesses for the gains will depend on your
  33. %units. This was designed to fit normalised MUA data, i.e. the data
  34. %falls mostly between 0 and 1.
  35. %The second Gaussian will sometimes fit noise components, but this
  36. %generally has little impact on the overall goodness of fit or the
  37. %measured latency.
  38. %PEAK FITTING LIMITS
  39. %1t Gaussian, mean = 20-100ms [50ms]
  40. %2nd Gaussian, mean = 40-200ms [100ms]
  41. %CumGauss, mean = 50-200ms [100ms]
  42. %first Gaussian
  43. g1g = [0.001 0.015 0.5]; %Gain of first Gaussian [min mean max]
  44. g1m = [0.02 0.05 0.1]; %Mean of first Gaussian
  45. g1s = [0.001 0.01 0.1]; %STD of first Gaussian
  46. %second Gaussian
  47. g2g = [0 0.01 0.5]; %Gain of second Gaussian
  48. g2m = [0.04 0.1 0.2]; %Mean of second Gaussian
  49. g2s = [0.001 0.02 0.2]; %STD of second Gaussian
  50. %cumulative gaussian
  51. cg = [0 0.1 0.5]; %Gain of cum. Gauss
  52. cm = [0.05 0.1 0.2]; %Mean of cum. Gauss
  53. cs = [0.001 0.05 1]; %Std of cum. Gauss
  54. else
  55. %Fitting the modulation depends a little on the average shape of the
  56. %modulation. Some monkeys have more oscillatory modulation profiles than
  57. %others. In principle you could get rid of one of the two Gaussians for less
  58. %oscillatory profiles.
  59. %The fits depend a lot on the limits, if you have very similar
  60. %modulation shapes across electrodes then you can use very tight
  61. %limits and get well behaved fits. The more variability you have the
  62. %wider the limits will have to be and the greater the chance that you
  63. %get some weird fits. Check adjusted r-squared values to reject bad fits.
  64. %MODULATION FITTING LIMITS
  65. %1t Gaussian, mean = 50-125ms [100ms]
  66. %2nd Gaussian, mean = 100-200ms [150ms]
  67. %CumGauss, mean = 50-400ms [150ms]
  68. %First Gaussian
  69. g1g = [0 0.004 0.2]; %Gain of first Gaussian [min mean max]
  70. g1m = [0.05 0.1 0.125]; %Mean of first Gaussian
  71. g1s = [0.005 0.03 0.025]; %STD of first Gaussian
  72. %second Gaussian
  73. g2g = [0 0.004 0.3]; %Gain of second Gaussian
  74. g2m = [0.1 0.15 0.2]; %Mean of second Gaussian
  75. g2s = [0.005 0.03 0.025]; %STD of second Gaussian
  76. %cumulative gaussian
  77. cg = [0 0.06 0.5]; %Gain of second Gaussian
  78. cm = [0.05 0.15 0.4]; %Mean of second Gaussian
  79. cs = [0.005 0.05 0.2]; %STD of second Gaussian
  80. end
  81. %Assign to vectors
  82. lower = [g1g(1) g1m(1) g1s(1) g2g(1) g2m(1) g2s(1) cg(1) cm(1) cs(1)];
  83. guess = [g1g(2) g1m(2) g1s(2) g2g(2) g2m(2) g2s(2) cg(2) cm(2) cs(2)];
  84. upper = [g1g(3) g1m(3) g1s(3) g2g(3) g2m(3) g2s(3) cg(3) cm(3) cs(3)];
  85. %Set up the fit
  86. ft = fittype('a.*normpdf(t,b,c) + d.*normpdf(t,e,f) +g.*normcdf(t,h,k);',...
  87. 'independent',{'t'},...
  88. 'coefficients',{'a','b','c','d','e','f','g','h','k'});
  89. fo = fitoptions('method','NonlinearLeastSquares','MaxFunEvals',1000,'Lower',lower,'Upper',upper);
  90. set(fo,'Startpoint',guess);
  91. %Fit the model and get the best fitting parameters
  92. [cfun,gof,output] = fit(t',y',ft,fo);
  93. converge = output.exitflag;
  94. coeff=coeffvalues(cfun);
  95. rs = gof.adjrsquare;
  96. %regenerate best fitting model
  97. yf = coeff(1).*normpdf(t,coeff(2),coeff(3)) + coeff(4).*normpdf(t,coeff(5),coeff(6)) +coeff(7).*normcdf(t,coeff(8),coeff(9));
  98. %Get the latency%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  99. %There are (at least) two approaches that can be used to get the latency, either
  100. %searching forwards from trial onset to find the first point at which the
  101. %fitted curve reaches 33% or searching backwards from the maximum of the fitted data to find
  102. %this point. These SHOULD give the same value, however when fitting
  103. %modulation, the two Gaussians sometimes pick up noise components and the
  104. %second approach can be more robust. If the modulation tends to increase over time
  105. %then the second approach often gives too late latencies and the first approach is preferred.
  106. %generally we use the first approach (Searching from trial onset), and if
  107. %it picks up too many noise components we examine the fitting limits to try
  108. %and avoid this.
  109. %calculate the 33% of maximum point
  110. [mf,mfix] = max(yf);
  111. approach = 1; %1 = search forwards from start, 2 = search backwards from maximum
  112. %Find the first model value that comes within 1% (peak) of the 33% point. As we're fitting a smooth curve, this should
  113. %generally work, to be safe we iterate using progressively larger % values
  114. %until we find something.
  115. ixs = [1:mfix]; %only search before maximum model value
  116. perc = 0;
  117. l33ix = [];
  118. while isempty(l33ix)
  119. perc = perc+0.01;
  120. searchval = perc.*mf;
  121. if approach == 1
  122. l33ix = find(abs(yf(ixs)-mf*0.33)<searchval,1,'first');
  123. else
  124. l33ix = find(abs(yf(ixs)-mf*0.33)<searchval,1,'last');
  125. end
  126. end
  127. lat = t(l33ix);
  128. %Plot out data, fitted model and latency
  129. if fig
  130. figure;area(t,y),hold on,plot(t,yf,'r')
  131. hold on
  132. plot([lat,lat],get(gca,'YLim'),'m')
  133. end
  134. return