From 8ef03a7557d699edd10be6f3ae2346e3863c6665 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Tue, 23 Aug 2016 19:33:31 -0700 Subject: [PATCH 01/44] Created model template and modified pRFFit to make calls to pRFModelTemplate --- mrLoadRet/Plugin/pRF/pRFFit.m | 181 +++++++++++++----------- mrLoadRet/Plugin/pRF/pRFModelTemplate.m | 118 +++++++++++++++ 2 files changed, 215 insertions(+), 84 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRFModelTemplate.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index e81a57df7..0dc05df6c 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -253,46 +253,51 @@ if ~isfield(fitParams,'initParams') % check the rfType to get the correct min/max arrays - switch (fitParams.rfType) - case 'gaussian' - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {'x','y','rfWidth'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; - fitParams.paramIncDec = [1 1 1]; - fitParams.paramMin = [-inf -inf 0]; - fitParams.paramMax = [inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; - fitParams.initParams = [0 0 4]; - case 'gaussian-hdr' - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; - fitParams.paramIncDec = [1 1 1 0.1 0.5]; - fitParams.paramMin = [-inf -inf 0 0 0]; - fitParams.paramMax = [inf inf inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; - fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; - % add on parameters for difference of gamma - if fitParams.diffOfGamma - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; - fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; - fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; - fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; - fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.minParams 0 0 0]; - fitParams.maxParams = [fitParams.maxParams inf 6 inf]; - fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; - end - otherwise - disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); - return - end + + %%%%%%%%%%%%%%%%%%% + fitParams = pRFModelTemplate('setParams', fitParams) + %%%%%%%%%%%%%%%%%%% + + % switch (fitParams.rfType) + % case 'gaussian' + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {'x','y','rfWidth'}; + % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + % fitParams.paramIncDec = [1 1 1]; + % fitParams.paramMin = [-inf -inf 0]; + % fitParams.paramMax = [inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + % fitParams.initParams = [0 0 4]; + % case 'gaussian-hdr' + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; + % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; + % fitParams.paramIncDec = [1 1 1 0.1 0.5]; + % fitParams.paramMin = [-inf -inf 0 0 0]; + % fitParams.paramMax = [inf inf inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; + % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; + % fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; + % % add on parameters for difference of gamma + % if fitParams.diffOfGamma + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; + % fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; + % fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; + % fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; + % fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.minParams 0 0 0]; + % fitParams.maxParams = [fitParams.maxParams inf 6 inf]; + % fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; + % end + % otherwise + % disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); + % return + % end % round constraints fitParams.minParams = round(fitParams.minParams*10)/10; @@ -372,17 +377,21 @@ % create the model for each concat for i = 1:fitParams.concatInfo.n % get model response - nFrames = fitParams.concatInfo.runTransition(i,2); - thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + %nFrames = fitParams.concatInfo.runTransition(i,2); + %thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); % get a model hrf hrf = getCanonicalHRF(p.canonical,fitParams.framePeriod); % and convolve in time. - thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + %thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + %%%%%%%%%%%%%%%%%%% + thisModelResponse = pRFModelTemplate('getModelResponse', fitParams, rfModel, hrf, i); + %%%%%%%%%%%%%%%%%%% % apply concat filtering if isfield(fitParams,'applyFiltering') && fitParams.applyFiltering @@ -502,46 +511,50 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) p.rfType = fitParams.rfType; -switch (fitParams.rfType) - case 'gaussian' - p.x = params(1); - p.y = params(2); - p.std = params(3); - % use a fixed single gaussian - p.canonical.type = 'gamma'; - p.canonical.lengthInSeconds = 25; - p.canonical.timelag = fitParams.timelag; - p.canonical.tau = fitParams.tau; - p.canonical.exponent = fitParams.exponent; - p.canonical.offset = 0; - p.canonical.diffOfGamma = fitParams.diffOfGamma; - p.canonical.amplitudeRatio = fitParams.amplitudeRatio; - p.canonical.timelag2 = fitParams.timelag2; - p.canonical.tau2 = fitParams.tau2; - p.canonical.exponent2 = fitParams.exponent2; - p.canonical.offset2 = 0; - case 'gaussian-hdr' - p.x = params(1); - p.y = params(2); - p.std = params(3); - % use a fixed single gaussian - p.canonical.type = 'gamma'; - p.canonical.lengthInSeconds = 25; - p.canonical.timelag = params(4); - p.canonical.tau = params(5); - p.canonical.exponent = fitParams.exponent; - p.canonical.offset = 0; - p.canonical.diffOfGamma = fitParams.diffOfGamma; - if fitParams.diffOfGamma - p.canonical.amplitudeRatio = params(6); - p.canonical.timelag2 = params(7); - p.canonical.tau2 = params(8); - p.canonical.exponent2 = fitParams.exponent2; - p.canonical.offset2 = 0; - end -otherwise - disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); -end +%%%%%%%%%%%%%%%%%%% +p = pRFModelTemplate('getFitParams', fitParams, params); +%%%%%%%%%%%%%%%%%%% + +% switch (fitParams.rfType) +% case 'gaussian' +% p.x = params(1); +% p.y = params(2); +% p.std = params(3); +% % use a fixed single gaussian +% p.canonical.type = 'gamma'; +% p.canonical.lengthInSeconds = 25; +% p.canonical.timelag = fitParams.timelag; +% p.canonical.tau = fitParams.tau; +% p.canonical.exponent = fitParams.exponent; +% p.canonical.offset = 0; +% p.canonical.diffOfGamma = fitParams.diffOfGamma; +% p.canonical.amplitudeRatio = fitParams.amplitudeRatio; +% p.canonical.timelag2 = fitParams.timelag2; +% p.canonical.tau2 = fitParams.tau2; +% p.canonical.exponent2 = fitParams.exponent2; +% p.canonical.offset2 = 0; +% case 'gaussian-hdr' +% p.x = params(1); +% p.y = params(2); +% p.std = params(3); +% % use a fixed single gaussian +% p.canonical.type = 'gamma'; +% p.canonical.lengthInSeconds = 25; +% p.canonical.timelag = params(4); +% p.canonical.tau = params(5); +% p.canonical.exponent = fitParams.exponent; +% p.canonical.offset = 0; +% p.canonical.diffOfGamma = fitParams.diffOfGamma; +% if fitParams.diffOfGamma +% p.canonical.amplitudeRatio = params(6); +% p.canonical.timelag2 = params(7); +% p.canonical.tau2 = params(8); +% p.canonical.exponent2 = fitParams.exponent2; +% p.canonical.offset2 = 0; +% end +% otherwise +% disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); +% end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m new file mode 100644 index 000000000..03577474b --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m @@ -0,0 +1,118 @@ +% pRFModelTemplate.m +% +% $Id:$ +% usage: pRFModelTemplate(varargin) +% by: akshay jagadeesh +% date: 08/23/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRFModelTemplate(varargin) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams)%%%%% +%%%% Called from getModelResidual %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + fitParams.paramIncDec = [1 1 1]; + fitParams.paramMin = [-inf -inf 0]; + fitParams.paramMax = [inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + fitParams.initParams = [0 0 4]; + + % return fitParams with modified values + output = fitParams; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From b6d9bc56fe233113e29bab09c1d987481d425261 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 2 Sep 2016 19:20:03 -0700 Subject: [PATCH 02/44] Plugging in exponent model --- mrLoadRet/Plugin/pRF/pRFFit.m | 9 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 2 +- mrLoadRet/Plugin/pRF/pRFModelTemplate.m | 11 +- mrLoadRet/Plugin/pRF/pRF_exp.m | 133 ++++++++++++++++++++++++ mrLoadRet/Plugin/pRF/pRF_gaussian.m | 121 +++++++++++++++++++++ 5 files changed, 269 insertions(+), 7 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_exp.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_gaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 0dc05df6c..685598805 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -42,6 +42,9 @@ end end +% specify the model file here (e.g. pRFModelTemplate) +prfModel = @pRF_exp + % get the stimulus movie if it wasn't passed in if ~isfield(fitParams,'stim') || isempty(fitParams.stim) fitParams.stim = getStim(v,scanNum,fitParams); @@ -255,7 +258,7 @@ % check the rfType to get the correct min/max arrays %%%%%%%%%%%%%%%%%%% - fitParams = pRFModelTemplate('setParams', fitParams) + fitParams = prfModel('setParams', fitParams) %%%%%%%%%%%%%%%%%%% % switch (fitParams.rfType) @@ -390,7 +393,7 @@ %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); %%%%%%%%%%%%%%%%%%% - thisModelResponse = pRFModelTemplate('getModelResponse', fitParams, rfModel, hrf, i); + thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, i); %%%%%%%%%%%%%%%%%%% % apply concat filtering @@ -512,7 +515,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) p.rfType = fitParams.rfType; %%%%%%%%%%%%%%%%%%% -p = pRFModelTemplate('getFitParams', fitParams, params); +p = prfModel('getFitParams', fitParams, params); %%%%%%%%%%%%%%%%%%% % switch (fitParams.rfType) diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index 9d8d101e2..606fd3850 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,7 +116,7 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below.'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m index 03577474b..3e1cc9ca0 100644 --- a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m +++ b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m @@ -15,6 +15,11 @@ function output = pRFModelTemplate(varargin) +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams, rfModel, hrf, i)%%%%% %%%% Called from getModelResidual %%%%% @@ -36,11 +41,11 @@ % return the calculated model response output = thisModelResponse; -end +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams)%%%%% -%%%% Called from getModelResidual %%%%% +%%%% Called from setFitParams %%%%% elseif strcmp(varargin{1}, 'setParams') @@ -58,7 +63,7 @@ % return fitParams with modified values output = fitParams; -end +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams, params)%%%%% diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m new file mode 100644 index 000000000..29a411eea --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -0,0 +1,133 @@ +% pRF_exp.m +% +% $Id:$ +% usage: pRF_exp(varargin) +% by: akshay jagadeesh +% date: 09/01/16 +% purpose: Model file to specify a new rftype +% +% +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_exp(varargin) + +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_exp(command, fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % FOR GAUSSIAN-EXP ONLY: include exponent non-linearity + if strcmp(fitParams.rfType, 'gaussian-exp') + thisModelResponse = power(thisModelResponse, p.exp); + end + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + + disp(sprintf('fitParams.rfType is %s', fitParams.rfType)); + +%end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_exp(command, fitParams)%%%%% +%%%% Called from getModelResidual %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth','exp'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Spatial summation exponent'}; + fitParams.paramIncDec = [1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0]; + fitParams.paramMax = [inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf]; + fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) + + % return fitParams with modified values + output = fitParams; +%end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.exp = params(4); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + +else + disp(sprintf('Function did not execute properly')); + return +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m new file mode 100644 index 000000000..4dbcae878 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -0,0 +1,121 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_gaussian(varargin) + +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('setParams', fitParams)%%%%% +%%%% Called from setParams %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + fitParams.paramIncDec = [1 1 1]; + fitParams.paramMin = [-inf -inf 0]; + fitParams.paramMax = [inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + fitParams.initParams = [0 0 4]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From b1a1d6b37b2d2bcb1dea04a306eb97b0e22c4d3b Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 8 Sep 2016 15:23:37 -0700 Subject: [PATCH 03/44] Completed new file structure for models --- mrLoadRet/Plugin/pRF/pRFFit.m | 122 ++++------------------ mrLoadRet/Plugin/pRF/pRF_exp.m | 14 +-- mrLoadRet/Plugin/pRF/pRF_gaussian.m | 18 ++-- mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m | 135 +++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 685598805..e06cfa5cb 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -42,9 +42,6 @@ end end -% specify the model file here (e.g. pRFModelTemplate) -prfModel = @pRF_exp - % get the stimulus movie if it wasn't passed in if ~isfield(fitParams,'stim') || isempty(fitParams.stim) fitParams.stim = getStim(v,scanNum,fitParams); @@ -229,6 +226,7 @@ % display if fitParams.verbose disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); + disp(sprintf('Params: exp is %f', fit.exp)); end %%%%%%%%%%%%%%%%%%%%%% @@ -258,50 +256,9 @@ % check the rfType to get the correct min/max arrays %%%%%%%%%%%%%%%%%%% - fitParams = prfModel('setParams', fitParams) + fitParams = prfModel('setParams', fitParams); %%%%%%%%%%%%%%%%%%% - % switch (fitParams.rfType) - % case 'gaussian' - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {'x','y','rfWidth'}; - % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; - % fitParams.paramIncDec = [1 1 1]; - % fitParams.paramMin = [-inf -inf 0]; - % fitParams.paramMax = [inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; - % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; - % fitParams.initParams = [0 0 4]; - % case 'gaussian-hdr' - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; - % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; - % fitParams.paramIncDec = [1 1 1 0.1 0.5]; - % fitParams.paramMin = [-inf -inf 0 0 0]; - % fitParams.paramMax = [inf inf inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; - % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; - % fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; - % % add on parameters for difference of gamma - % if fitParams.diffOfGamma - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; - % fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; - % fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; - % fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; - % fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.minParams 0 0 0]; - % fitParams.maxParams = [fitParams.maxParams inf 6 inf]; - % fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; - % end - % otherwise - % disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); - % return - % end - % round constraints fitParams.minParams = round(fitParams.minParams*10)/10; fitParams.maxParams = round(fitParams.maxParams*10)/10; @@ -379,21 +336,12 @@ % create the model for each concat for i = 1:fitParams.concatInfo.n - % get model response - %nFrames = fitParams.concatInfo.runTransition(i,2); - %thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); - % get a model hrf hrf = getCanonicalHRF(p.canonical,fitParams.framePeriod); - % and convolve in time. - %thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); - - % drop junk frames here - %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - %%%%%%%%%%%%%%%%%%% - thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, i); + % Get model response, which involves convolving model with stimulus, and with HRF and dropping junk frames. + thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, p, i); %%%%%%%%%%%%%%%%%%% % apply concat filtering @@ -513,51 +461,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) function p = getFitParams(params,fitParams) p.rfType = fitParams.rfType; - -%%%%%%%%%%%%%%%%%%% p = prfModel('getFitParams', fitParams, params); -%%%%%%%%%%%%%%%%%%% - -% switch (fitParams.rfType) -% case 'gaussian' -% p.x = params(1); -% p.y = params(2); -% p.std = params(3); -% % use a fixed single gaussian -% p.canonical.type = 'gamma'; -% p.canonical.lengthInSeconds = 25; -% p.canonical.timelag = fitParams.timelag; -% p.canonical.tau = fitParams.tau; -% p.canonical.exponent = fitParams.exponent; -% p.canonical.offset = 0; -% p.canonical.diffOfGamma = fitParams.diffOfGamma; -% p.canonical.amplitudeRatio = fitParams.amplitudeRatio; -% p.canonical.timelag2 = fitParams.timelag2; -% p.canonical.tau2 = fitParams.tau2; -% p.canonical.exponent2 = fitParams.exponent2; -% p.canonical.offset2 = 0; -% case 'gaussian-hdr' -% p.x = params(1); -% p.y = params(2); -% p.std = params(3); -% % use a fixed single gaussian -% p.canonical.type = 'gamma'; -% p.canonical.lengthInSeconds = 25; -% p.canonical.timelag = params(4); -% p.canonical.tau = params(5); -% p.canonical.exponent = fitParams.exponent; -% p.canonical.offset = 0; -% p.canonical.diffOfGamma = fitParams.diffOfGamma; -% if fitParams.diffOfGamma -% p.canonical.amplitudeRatio = params(6); -% p.canonical.timelag2 = params(7); -% p.canonical.tau2 = params(8); -% p.canonical.exponent2 = fitParams.exponent2; -% p.canonical.offset2 = 0; -% end -% otherwise -% disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); -% end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% @@ -635,12 +539,28 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); end +%%%%%%%%%%%%%%%%%%% +%% prfModel %% +%%%%%%%%%%%%%%%%%%% +function output = prfModel(varargin) + +fitParams = varargin{2}; +switch (fitParams.rfType) + case 'gaussian' + output = pRF_gaussian(varargin); + case 'gaussian-hdr' + output = pRF_gaussianhdr(varargin); + otherwise + testModel = @pRF_exp; %%% Only need to change this line to specify a new model. + output = testModel(varargin); +end + %%%%%%%%%%%%%%%%%%%%%%%% %% makeRFGaussian %% diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m index 29a411eea..b7201f2a4 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -12,7 +12,7 @@ function output = pRF_exp(varargin) -if nargin <=2 +if nargin < 2 disp(sprintf('Not enough arguments')); return end @@ -25,7 +25,8 @@ fitParams = varargin{2}; rfModel = varargin{3}; hrf = varargin{4}; - i = varargin{5}; + p = varargin{5}; + i = varargin{6}; nFrames = fitParams.concatInfo.runTransition(i,2); thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); @@ -43,14 +44,11 @@ % return the calculated model response output = thisModelResponse; - - disp(sprintf('fitParams.rfType is %s', fitParams.rfType)); - %end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRF_exp(command, fitParams)%%%%% -%%%% Called from getModelResidual %%%%% +%%%% Called from setFitParams %%%%% elseif strcmp(varargin{1}, 'setParams') @@ -67,7 +65,7 @@ fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) % return fitParams with modified values - output = fitParams; + output = struct(fitParams); %end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -100,6 +98,8 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; + output = struct(p); + else disp(sprintf('Function did not execute properly')); diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 4dbcae878..3ae874d95 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -15,20 +15,21 @@ function output = pRF_gaussian(varargin) -if nargin <=2 +if nargin < 2 disp(sprintf('Not enough arguments')); return end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, i)%%%%% -%%%% Called from getModelResidual %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% if strcmp(varargin{1}, 'getModelResponse') fitParams = varargin{2}; rfModel = varargin{3}; hrf = varargin{4}; - i = varargin{5}; + p = varargin{5}; + i = varargin{6}; nFrames = fitParams.concatInfo.runTransition(i,2); thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); @@ -43,8 +44,8 @@ output = thisModelResponse; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian('setParams', fitParams)%%%%% -%%%% Called from setParams %%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% elseif strcmp(varargin{1}, 'setParams') @@ -64,7 +65,7 @@ output = fitParams; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian(command, fitParams, params)%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% %%%% Called from getFitParams %%%%% elseif strcmp(varargin{1}, 'getFitParams') @@ -94,7 +95,6 @@ end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m new file mode 100644 index 000000000..0627d2f1c --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m @@ -0,0 +1,135 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussianhdr(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_gaussianhdr(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussianhdr('getModelResponse', fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('setParams', fitParams)%%%%% +%%%% Called from setParams %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'timelag', 'tau'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Time before start of rise of hemodynamic function', 'Width of the hemodynamic function (tau parameter of gamma)'}; + fitParams.paramIncDec = [1 1 1 0.1 0.5]; + fitParams.paramMin = [-inf -inf 0 0 0]; + fitParams.paramMax = [inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; + fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; + % add on parameters for difference of gamma + if fitParams.diffOfGamma + % parameter names/descriptions and other information for allowing user to set them + fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; + fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; + fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; + fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; + fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.minParams 0 0 0]; + fitParams.maxParams = [fitParams.maxParams inf 6 inf]; + fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; + end + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%0%%%%% +%%%% pRF_gaussianhdr(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = params(4); + p.canonical.tau = params(5); + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + if fitParams.diffOfGamma + p.canonical.amplitudeRatio = params(6); + p.canonical.timelag2 = params(7); + p.canonical.tau2 = params(8); + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From 2f176babf5164aa8d9455c07d8a9174885876fe4 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 26 Sep 2016 15:33:37 -0700 Subject: [PATCH 04/44] temp commit --- mrLoadRet/Plugin/pRF/getR2Overlay.m | 13 +++++++++++++ mrLoadRet/Plugin/pRF/pRFFit.m | 15 ++++++++------- mrLoadRet/Plugin/pRF/pRF_exp.m | 8 ++++++-- mrLoadRet/Plugin/pRF/pRF_gaussian.m | 4 ++++ mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m | 1 + 5 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/getR2Overlay.m diff --git a/mrLoadRet/Plugin/pRF/getR2Overlay.m b/mrLoadRet/Plugin/pRF/getR2Overlay.m new file mode 100644 index 000000000..aa7f7d04e --- /dev/null +++ b/mrLoadRet/Plugin/pRF/getR2Overlay.m @@ -0,0 +1,13 @@ +function r2Overlay = getR2Overlay(modelName) + +v = newView; +v = viewSet(v, 'curGroup', 'Averages'); +v = viewSet(v, 'curScan', 1); +prfModel = sprintf('pRFAnal/%s', modelName); +v = loadAnalysis(v, prfModel); +r2OverlayNum = find(strcmp('r2', viewGet(v, 'overlayNames'))); +v = viewSet(v, 'curOverlay', r2OverlayNum); +r2Overlay = viewGet(v, 'overlayData', 1); + +validR2 = r2Overlay(~isnan(r2Overlay)); +fprintf('Mean r2 for well-defined voxels: %d', mean(validR2)); diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index e06cfa5cb..c0d2820f5 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -224,9 +224,10 @@ [fit.polarAngle fit.eccentricity] = cart2pol(fit.x,fit.y); % display -if fitParams.verbose - disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); - disp(sprintf('Params: exp is %f', fit.exp)); +if fitParams.verbose && strcmp(fitParams.rfType, 'gaussian-exp') + disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f exp=%f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std, fit.exp)); +elseif fitParams.verbose + disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f', fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); end %%%%%%%%%%%%%%%%%%%%%% @@ -446,7 +447,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) designMatrix(:,2) = 1; % get beta weight for the modelResponse -if ~any(isnan(modelResponse)) +if ~any(isnan(modelResponse)) && ~any(isinf(modelResponse)) beta = pinv(designMatrix)*tSeries; beta(1) = max(beta(1),0); modelResponse = designMatrix*beta; @@ -553,12 +554,12 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) fitParams = varargin{2}; switch (fitParams.rfType) case 'gaussian' - output = pRF_gaussian(varargin); + output = pRF_gaussian(varargin{:}); case 'gaussian-hdr' - output = pRF_gaussianhdr(varargin); + output = pRF_gaussianhdr(varargin{:}); otherwise testModel = @pRF_exp; %%% Only need to change this line to specify a new model. - output = testModel(varargin); + output = testModel(varargin{:}); end diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m index b7201f2a4..99c4c5d48 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -14,6 +14,8 @@ if nargin < 2 disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) return end @@ -33,7 +35,9 @@ % FOR GAUSSIAN-EXP ONLY: include exponent non-linearity if strcmp(fitParams.rfType, 'gaussian-exp') - thisModelResponse = power(thisModelResponse, p.exp); + if ~isnan(thisModelResponse) + thisModelResponse = power(thisModelResponse, p.exp); + end end % and convolve in time. @@ -61,7 +65,7 @@ fitParams.paramMax = [inf inf inf inf]; % set min/max and init fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 5]; % Set max exponent to 5 fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) % return fitParams with modified values diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 3ae874d95..07cef5144 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -17,6 +17,8 @@ if nargin < 2 disp(sprintf('Not enough arguments')); + disp(sprintf('Number of argumnets: %d', nargin)); + celldisp(varargin) return end @@ -93,6 +95,8 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; + output = struct(p); + end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m index 0627d2f1c..3fbb58366 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m @@ -107,6 +107,7 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; end + output = struct(p); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 4c7ec7e6969e5db855875cff13afce1da67afbc6 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 7 Oct 2016 18:59:58 -0700 Subject: [PATCH 05/44] Adding files for cross-validation pipeline. --- mrLoadRet/Plugin/pRF/pRFNoise.m | 57 +++++++++++++++++++++++ mrLoadRet/Plugin/pRF/testPRF.m | 18 ++++++++ mrLoadRet/Plugin/pRF/trainPRF.m | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/pRFNoise.m create mode 100644 mrLoadRet/Plugin/pRF/testPRF.m create mode 100644 mrLoadRet/Plugin/pRF/trainPRF.m diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m new file mode 100644 index 000000000..1ef1c8ddf --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFNoise.m @@ -0,0 +1,57 @@ +function [residual, covMat, tSeries, modelResponse] = pRFNoise(v,scanNum,coordinates, analysisFileName) + +% coordinates = [53,61,25; 53,59,24; 51,57,24; 51,56,22; 52,55,20]; +% scanNum = 1; + +if ieNotDefined('v') + v = newView; +end + +v = viewSet(v, 'currentGroup', 'Averages'); +analysisFile = dir(sprintf('Averages/pRFAnal/%s', analysisFileName)); + +% get the analysis structure +analysis = viewGet(v,'analysis'); +if ~isfield(analysis,'d') || (length(analysis.d) < scanNum) || isempty(analysis.d) + v = loadAnalysis(v, ['pRFAnal/' analysisFile.name]); + analysis = viewGet(v,'analysis'); + +end + +d = viewGet(v,'d',scanNum); +if isempty(d),disp(sprintf('Could not find d structure for this scan'));return,end + +numVoxels = size(coordinates, 1); + +figure; +for voxel = 1:numVoxels + [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); + subplot(numVoxels,1,voxel) + plot(tSeries(voxel,:), 'k.-'); + hold on; + plot(modelResponse(voxel,:), 'r-'); + plot(residual(voxel,:), 'b-'); + title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); +end +covMat = residual*residual'; + +function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) + +% get the params that have been run +scanDims = viewGet(v,'scanDims',scanNum); +whichVoxel = find(d.linearCoords == sub2ind(scanDims,x,y,z)); +r = d.r(whichVoxel,:); + +params = d.params(:,whichVoxel); +if isfield(d,'paramsInfo') + paramsInfo = d.paramsInfo; +else + paramsInfo = []; +end + +% get params +m = pRFFit(v,scanNum,x,y,z,'stim',d.stim,'getModelResponse=1','params',params,'concatInfo',d.concatInfo,'fitTypeParams',a.params.pRFFit,'paramsInfo',paramsInfo); + +residual = m.tSeries - m.modelResponse; +tSeries = m.tSeries; +modelResponse = m.modelResponse; diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m new file mode 100644 index 000000000..e73f577f2 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -0,0 +1,18 @@ +% testPRF.m +% +% usage: testPRF( ) +% by: akshay jagadeesh +% date: 10/07/16 +% purpose: Computes the probability of seeing the model response, +% given the observed data, and the computed covariance (noise). +% + +function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) + +%use mvnpdf to compute the probability density function + + +%compute log likelihood of the data and sum + + + diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m new file mode 100644 index 000000000..66e6edaed --- /dev/null +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -0,0 +1,81 @@ +% trainPRF.m +% +% $Id:$ +% usage: trainPRF(view, roiName) +% by: akshay jagadeesh +% date: 10/04/16 +% purpose: Given n MotionComp runs, this function computes a n-fold +% cross validation, running the pRF analysis n times. +% It generates and saves time series, model response, residuals, +% and covariance matrices for each fold. +% + +function trainPRF(view, roiName) + +% Currently hardcoding number and names of scan. +numScans = 6 +roiName = 'xVal' + +for i = 1:numScans + v = newView; + + %Get all but the i'th scan + scanList = [1:i-1 i+1:numScans] + + %Average the other n-1 scans together + v = viewSet(v, 'currentGroup', 'MotionComp'); + scanstr = sprintf('scanList=%s', mat2str(scanList)); + [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) + %Filename of averaged scan is: tseries-avg-.nii + scanListStr = mat2str(scanList); scanListStr = scanListStr(2:end-1); scanListStr=scanListStr(find(~isspace(scanListStr))); + %params.fileName = sprintf('tseries-avg-%s.nii', fileName) + %params = averageTSeriesGUI('groupName', 'MotionComp'); + averageTSeries(v, params) + + %Get group info about the average we just created + gInfo = groupInfo; + gAverageInfo = groupInfo('Averages'); + numAverageScans = gInfo(3).numScans; + sInfo = scanInfo(numAverageScans, 'Averages'); + %% sInfo.description --> contains info about which scans were averaged + %% sInfo.Filename --> contains filename in which this average is saved + %% sInfo.OriginalN --> contains filename of original (replace N with 1 - 5) + + v = newView; + v = viewSet(v, 'currentGroup', 'Averages'); + + % Two ways of calculating ROI coordinates + % Method 1: loadROI.coords + v = loadROI(v, sprintf('%s.mat', roiName)) + roiCoords = v.ROIs(1).coords.' + roiCoords = roiCoords(:, 1:3) + + % Method 2: loadROITSeries.scancoords + roiCoords2 = loadROITSeries(v, 'xVal') + roiCoords2 = roiCoords2.scanCoords.' + + %Run pRF Analysis on average of n-1 scans + %pRF(v, params) + [v, params] = pRF(v, [], 'justGetParams=1'); + %%set dispStimScan to the last most recently computed scan + %%set saveName to pRF_ROINAME_SCANLIST + %%select diffOfGamma + pRF(v, params) + + % Load analysis by filename + analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr) + v = loadAnalysis(v, ['pRFAnal/' analysisFileName]) + scanNum = v.analyses{1}.params.scanNum; + + %Get the residual and covariance matrix + %%% scanNum: scan number on which analysis was conducted + [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) + + %Save residual, covariance matrix, time series, and model response into a structure + save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') + %Test pRF Analysis on the left-out scan + +end + + +function test From 3cbc3b6deabaa457e17bb64b20a9c6beb637423a Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 7 Oct 2016 19:18:25 -0700 Subject: [PATCH 06/44] Adding documentation for cross-val pipeline --- mrLoadRet/Plugin/pRF/testPRF.m | 11 ++++++++++- mrLoadRet/Plugin/pRF/trainPRF.m | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m index e73f577f2..ac5e5ec14 100644 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -6,10 +6,19 @@ % purpose: Computes the probability of seeing the model response, % given the observed data, and the computed covariance (noise). % +% +% Input variables: +% observe: true voxel response for the left-out scan at a single timepoint +% modelResp: expected voxel response trained on other n-1 scans +% covarMat: Covariance matrix (size: m x m, where m is # of voxels) +% roiVoxels: list of voxels in this ROI (length m) function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) -%use mvnpdf to compute the probability density function +% Y = MVNPDF(X,MU,SIGMA) %returns the density of the multivariate normal +% distribution with mean MU and covariance SIGMA, evaluated at each row +% of X. +mvnpdf(testResponse, modelResponse, covarMat) %compute log likelihood of the data and sum diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m index 66e6edaed..f0266cb20 100644 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -71,9 +71,12 @@ function trainPRF(view, roiName) %%% scanNum: scan number on which analysis was conducted [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) + %% + %% TO DO: Get the time series data for the left-out scan + %% + %Save residual, covariance matrix, time series, and model response into a structure save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') - %Test pRF Analysis on the left-out scan end From 98712ff8c844c8bbaecad0dbcacdde9b880561e9 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 27 Oct 2016 12:47:00 -0700 Subject: [PATCH 07/44] Modifying trainPRF and testPRF --- mrLoadRet/Plugin/pRF/pRFNoise.m | 21 +++++++++-------- mrLoadRet/Plugin/pRF/testPRF.m | 40 +++++++++++++++++++++++--------- mrLoadRet/Plugin/pRF/trainPRF.m | 41 ++++++++++++++++----------------- 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m index 1ef1c8ddf..457b0b765 100644 --- a/mrLoadRet/Plugin/pRF/pRFNoise.m +++ b/mrLoadRet/Plugin/pRF/pRFNoise.m @@ -7,8 +7,8 @@ v = newView; end -v = viewSet(v, 'currentGroup', 'Averages'); -analysisFile = dir(sprintf('Averages/pRFAnal/%s', analysisFileName)); +v = viewSet(v, 'currentGroup', 'Concatenation'); +analysisFile = dir(sprintf('Concatenation/pRFAnal/%s', analysisFileName)); % get the analysis structure analysis = viewGet(v,'analysis'); @@ -23,16 +23,19 @@ numVoxels = size(coordinates, 1); -figure; +%figure; +disppercent(-inf, '(pRFNoise) Calculating residuals'); for voxel = 1:numVoxels [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); - subplot(numVoxels,1,voxel) - plot(tSeries(voxel,:), 'k.-'); - hold on; - plot(modelResponse(voxel,:), 'r-'); - plot(residual(voxel,:), 'b-'); - title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); + %subplot(numVoxels,1,voxel) + %plot(tSeries(voxel,:), 'k.-'); + %hold on; + %plot(modelResponse(voxel,:), 'r-'); + %plot(residual(voxel,:), 'b-'); + %title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); + disppercent(voxel/numVoxels); end +disppercent(inf); covMat = residual*residual'; function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m index ac5e5ec14..8723e15d0 100644 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -8,20 +8,38 @@ % % % Input variables: -% observe: true voxel response for the left-out scan at a single timepoint +% testTSeries: true voxel response for the left-out scan at a single timepoint % modelResp: expected voxel response trained on other n-1 scans % covarMat: Covariance matrix (size: m x m, where m is # of voxels) -% roiVoxels: list of voxels in this ROI (length m) - -function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) - -% Y = MVNPDF(X,MU,SIGMA) %returns the density of the multivariate normal -% distribution with mean MU and covariance SIGMA, evaluated at each row -% of X. -mvnpdf(testResponse, modelResponse, covarMat) - +% +% Output variables: +% logLikelihood: total likelihood of all the observed tSeries given model response +% probTable: value at (i, j) is the probability that i'th timepoint in tseries is +% explained by j'th timepoint in model response. -%compute log likelihood of the data and sum +function probTable = testPRF(testTSeries, modelResponse, covarMat) +numTimePoints = size(modelResponse, 2); +probTable = zeros(numTimePoints, numTimePoints); +logprobTable = zeros(numTimePoints, numTimePoints); +disppercent(-inf,'(testPRF) Calculating likelihoods'); +for i = 1:numTimePoints + model_i = modelResponse(:, i); + tSeries_i = testTSeries(:, i); + for j = 1:numTimePoints + tSeries_j = testTSeries(:, j); + probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); + if probTable(j, i) == 0 + disp(sprintf('\n(testPRF) mvnpdf at index (%i, %i) returning 0; Exiting...', j, i)); + return; + end + logProbTable(j, i) = log(probTable(j,i)); + end + + %modelLikelihood(i) = mvnpdf(tSeries_i, model_i, covarMat); + %logLikelihood = logLikelihood + log(modelLikelihood(i)); + disppercent(i/numTimePoints); +end +disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m index f0266cb20..c0197bda9 100644 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -9,12 +9,16 @@ % It generates and saves time series, model response, residuals, % and covariance matrices for each fold. % +% +% input: roiName - Name of the ROI we want to run this analysis on +% analysis - Name of analysis file to load +% - This must be the Concat of Average of N scans -function trainPRF(view, roiName) +function trainPRF(view, roiName, analysis) % Currently hardcoding number and names of scan. numScans = 6 -roiName = 'xVal' +roiName = 'lV1' for i = 1:numScans v = newView; @@ -23,7 +27,7 @@ function trainPRF(view, roiName) scanList = [1:i-1 i+1:numScans] %Average the other n-1 scans together - v = viewSet(v, 'currentGroup', 'MotionComp'); + v = viewSet(v, 'currentGroup', 'Concatenation'); scanstr = sprintf('scanList=%s', mat2str(scanList)); [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) %Filename of averaged scan is: tseries-avg-.nii @@ -44,15 +48,11 @@ function trainPRF(view, roiName) v = newView; v = viewSet(v, 'currentGroup', 'Averages'); - % Two ways of calculating ROI coordinates + % Two ways of calculating ROI coordinates --> neither work right now. % Method 1: loadROI.coords v = loadROI(v, sprintf('%s.mat', roiName)) - roiCoords = v.ROIs(1).coords.' - roiCoords = roiCoords(:, 1:3) - - % Method 2: loadROITSeries.scancoords - roiCoords2 = loadROITSeries(v, 'xVal') - roiCoords2 = roiCoords2.scanCoords.' + % roiCoords = v.ROIs(1).coords.' + % roiCoords = roiCoords(:, 1:3) %Run pRF Analysis on average of n-1 scans %pRF(v, params) @@ -63,22 +63,21 @@ function trainPRF(view, roiName) pRF(v, params) % Load analysis by filename - analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr) - v = loadAnalysis(v, ['pRFAnal/' analysisFileName]) + analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr); + v = loadAnalysis(v, ['pRFAnal/' analysisFileName]); scanNum = v.analyses{1}.params.scanNum; + + % Get the time series data for the left-out scan + v2 = newView; + testTSeries = loadROITSeries(v2, roiName, i, 2, 'straightXform=1'); + roiCoords = testTSeries.scanCoords.'; + testTSeries = testTSeries.tSeries; %Get the residual and covariance matrix %%% scanNum: scan number on which analysis was conducted - [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) - - %% - %% TO DO: Get the time series data for the left-out scan - %% + [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, roiCoords, analysisFileName); %Save residual, covariance matrix, time series, and model response into a structure - save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') + save(sprintf('SaveData/pRF_fold%i_%s_%s', i, scanListStr, roiName), 'residual', 'covMat', 'modelResponse', 'testScanCoords', 'testTSeries') end - - -function test From fb1d1992513f8eafb10fec0161b21293ed1546fd Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 27 Oct 2016 12:48:41 -0700 Subject: [PATCH 08/44] Adding new on-the-fly cross validation, and grabbed applyConcatFiltering function from elsewhere. Finally dispModel creates a GUI for comparing two voxels. --- mrLoadRet/Plugin/pRF/applyConcatFiltering.m | 24 +++ mrLoadRet/Plugin/pRF/dispModel.m | 194 ++++++++++++++++++++ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 134 ++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/applyConcatFiltering.m create mode 100644 mrLoadRet/Plugin/pRF/dispModel.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_crossValidate.m diff --git a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m new file mode 100644 index 000000000..9838e8e37 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m @@ -0,0 +1,24 @@ +function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) + +tSeries = tSeries(:); + +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) + projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; + tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; +end + +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/dispModel.m new file mode 100644 index 000000000..ec83041dc --- /dev/null +++ b/mrLoadRet/Plugin/pRF/dispModel.m @@ -0,0 +1,194 @@ +function display = dispModel(voxels) + +% +voxels = [47 74 24; 37 67 25]; +analysis = 'pRF_lV1_123456.mat'; +scanNum = 7; + +% Set curr group to Concat and load the Analysis +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' analysis]); +a = viewGet(v, 'Analysis'); +d = viewGet(v, 'd', scanNum); + +% Create new figure +f = figure; + +%%% (1) Voxel 1 Receptive Field %%% +rf1 = subplot(2, 3, 1); + + %Get params +x=voxels(1,1); y=voxels(1,2); z=voxels(1,3); +whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); +r = d.r(whichVoxel, :); +params = d.params(:, whichVoxel); + + %get model fit for this voxel +m = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); + + %plot voxel RF +imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m.rfModel')); +set(rf1,'Box','off'); +set(rf1,'Color',[0.8 0.8 0.8]); +set(rf1,'TickDir','out'); +axis equal +axis tight +hold on +hline(0,'w:');vline(0,'w:'); +title('Voxel 1 Receptive Field Position'); + +%% (2) Voxel 2 Receptive Field +rf2 = subplot(2, 3, 4); +x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); +whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); +params = d.params(:, whichVoxel); +m2 = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); + +imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m2.rfModel')); +set(rf2,'Box','off'); +set(rf2,'Color',[0.8 0.8 0.8]); +set(rf2,'TickDir','out'); +axis equal +axis tight +hold on +hline(0, 'w:');vline(0,'w:'); +title('Voxel 2 Receptive Field Position'); + +%% (3) Stimulus position + +[thisT, modelT] = makeStim(100, 50); + +function [thisT, modelT] = makeStim(time, modelTime) + stP = subplot(2, 3, 2); + %clf(stP); + cla(stP); + im = []; + thisT = time; + thisScan = d.concatInfo.whichScan(thisT); + thisVolume = d.concatInfo.whichVolume(thisT); + + modelT = modelTime; + modelScan = d.concatInfo.whichScan(modelT); + modelVol = d.concatInfo.whichVolume(modelT); + + im(:, :, 3) = flipud(0.7*d.stim{thisScan}.im(:, :, thisVolume)'); + im(:, :, 2) = flipud(0.7*d.stim{modelScan}.im(:, :, modelVol)'); + im(:, :, 1) = 0.30*m.rfModel' + 0.30*m2.rfModel'; + image(d.stimX(:, 1), d.stimY(1, :), im); + axis image + hold on + hline(0, 'w:'); vline(0, 'w:'); + title(sprintf('timeT=%i, modelT=%i', thisT, modelT)); +end + + % Get covariance matrix +residual(1, :) = m.tSeries - m.modelResponse; +residual(2, :) = m2.tSeries - m2.modelResponse; +covMat = residual*residual.'; +radius = covMat(1, 2); + +%%%% (3) and (6): Plot voxels' model response time course and time series +% Plot voxel 1 model timecourse and timeseries +subplot(2, 3, 3); +plot((1:477), m.modelResponse, 'r'); +hold on; plot((1:477), m.tSeries, 'black'); +hold on; vl1m = vline(1); tl1m = text(0,0,''); +hold on; vl1t = vline(1); tl1t = text(0,0,''); +title('Voxel 1 Model Response and Time Series'); + +% Plot voxel 2 model timecourse and timeseries +subplot(2, 3, 6); +plot((1:477), m2.modelResponse, 'r'); +hold on; plot((1:477), m2.tSeries, 'black'); +hold on; vl2m = vline(1); tl2m = text(0,0,''); +hold on; vl2t = vline(1); tl2t = text(0,0,''); +title('Voxel 2 model response and time series'); + + +%% (4) 2D Gaussian model + tSeries +p4 = subplot(2, 3, 5); + +timepoint = 100; +modelTime = 50; + +x1 = m.tSeries(timepoint); +y1 = m2.tSeries(timepoint); + +x2 = m.modelResponse(modelTime); +y2 = m2.modelResponse(modelTime); + +timePlot = plot(x1, y1, '*c'); +hold on +cPlot = circle(x2, y2); +xlim([min(m.tSeries), max(m.tSeries)]); +ylim([min(m2.tSeries), max(m2.tSeries)]); +xlabel(sprintf('Voxel 1: (%d, %d, %d)', voxels(1,1), voxels(1,2), voxels(1,3))); +ylabel(sprintf('Voxel 2: (%d, %d, %d)', voxels(2,1), voxels(2,2), voxels(2,3))); +title('Voxel 1 vs Voxel 2: Percent Signal Change'); + +timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... + 'SliderStep', [1/477, 10/477],... + 'Value', timepoint, 'Callback', @slider1Callback,... + 'Parent', f, 'Position', [.05, .05, .5, .1], 'Units', 'normalized'); +function slider1Callback(hObject, eventdata) + newVal = round(get(hObject, 'Value')); + % Move the * around + subplot(2, 3, 5); + delete(timePlot); + x1 = m.tSeries(newVal); + y1 = m2.tSeries(newVal); + timePlot = plot(x1, y1, '*b'); + + % Move stim bar + [thisT, modelT] = makeStim(newVal, modelT); + + % Move cyan line around time series course + subplot(2, 3, 3); + delete([vl1t tl1t]); + vl1t = vline(newVal, '-b'); + tl1t = text(newVal, 0.92, sprintf('time t: %d', newVal), 'color', 'b'); + subplot(2, 3, 6); + delete([vl2t tl2t]); + vl2t = vline(newVal, '-b'); + tl2t = text(newVal, 0.96, sprintf('time t: %d', newVal), 'color', 'b'); +end + +modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... + 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... + 'Parent', f, 'Units', 'normalized', 'Position', [.05, .15, .5, .1]); +function slider2Callback(hObject, eventdata) + newVal = round(get(hObject, 'Value')); + % Move the circle around + subplot(2, 3, 5); + delete(cPlot); + x2 = m.modelResponse(newVal); + y2 = m2.modelResponse(newVal); + cPlot = circle(x2, y2); + + % Move the stimulus bar + [thisT, modelT] = makeStim(thisT, newVal); + + % Move green line around model time course + subplot(2, 3, 3); + delete([vl1m tl1m]); + vl1m = vline(newVal, '-g'); + tl1m = text(newVal, 0.95, sprintf('Model t: %d', newVal), 'color', 'g'); + subplot(2, 3, 6); + delete([vl2m tl2m]); + vl2m = vline(newVal, '-g'); + tl2m = text(newVal, 0.97, sprintf('Model t: %d', newVal), 'color', 'g'); +end + +align([timeSlider, modelSlider, f], 'center', 'distribute'); + + +function cPlot = circle(x, y) + r = radius; + ang = 0:0.01:2*pi; + xp = r*cos(ang); + yp = r*sin(ang); + cPlot = plot(x+xp, y+yp, 'g'); +end + +end diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m new file mode 100644 index 000000000..63e62c400 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -0,0 +1,134 @@ +%% pRF_crossValidate.m +%% +%% $Id:$ +%% usage: pRF_crossValidate(view, roiName, analysis) +%% by: akshay jagadeesh +%% date: 10/04/16 +%% purpose: Given n MotionComp runs, this function computes a n-fold +%% cross validation, running the pRF analysis n times. +%% It generates and saves time series, model response, residuals, +%% and covariance matrices for each fold. +%% +%% +%% input: roiName - Name of the ROI we want to run this analysis on +%% analysis - Name of analysis file to load +%% - This must be the Concat of Average of N scans + +function fit = pRF_crossValidate(roiName, analysis) + +%roiName = 'lV1'; +%roiName = 'xVal'; +%roiName = 'lineV1'; +analysis = 'pRF_lV1_123456.mat'; + +% Set current group to Concat and load the Analysis file +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' analysis]); +analParams = v.analyses{1}.params; +analScanNum = analParams.scanNum; + +ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan +osn = viewGet(v, 'originalscannum', analScanNum); +ogn2 = viewGet(v, 'originalgroupname', osn, ogn{1}); % Get the motioncomp scans +osn2 = viewGet(v, 'originalscannum', osn, ogn{1}); + +% Get analysis params for pRFFit +concatInfo = viewGet(v, 'concatinfo', analScanNum); +d = viewGet(v, 'd', analScanNum); + +% Get the N original scans & their tSeries +scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); + +for i=1:1 + + % Initialize vars for use later + avg = zeros(size(scans{1}.tSeries)); + leftOut = scans{i}.tSeries; + numVoxels = size(leftOut, 1); + modelResponse = zeros(numVoxels, size(leftOut, 2)); + residual = zeros(numVoxels, size(leftOut, 2)); + + % compute average time series across N-1 scans + for j = 1:length(scans) + if i ~= j + avg = avg + scans{j}.tSeries; + end + end + avg = avg / (length(scans)-1); + + % Apply Concat Filtering to averages & left out + for k = 1:numVoxels + filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); + leftOut(k, :) = applyConcatFiltering(leftOut(k, :), concatInfo, 1); + end + + disppercent(-inf, '(crossVal) Fitting pRF to voxels'); + % run pRFFit on the averaged tSeries + coords = scans{i}.scanCoords.'; + for h = 1:numVoxels + x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, h), 'concatInfo', d.concatInfo, 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); + modelResponse(h, :) = modelFit.modelResponse; + residual(h, :) = modelFit.tSeries - modelFit.modelResponse; + + disppercent(h/numVoxels); + end + disppercent(inf); + + %Calculate covariance matrix of voxels on our calculated residual + covMat = residual*residual'; + + % Calculate covariance matrix of voxels using pRFNoise's method + %[residual, covMat, tSeries, modelResponse] = pRFNoise(v, analysisScanNum, coordinates, analysis); + %[resid, covMat2, tS, modResp] = pRFNoise([], analScanNum, coords, analysis); + %noise.resid = resid; + %noise.covMat = covMat2; + %noise.tSeries = tS; + %noise.modelResponse = modResp; + + % Compare model response to left-out timeseries + probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); +end +fit.modelResponse = modelResponse; +fit.residual = residual; +fit.leftOut = leftOut; +fit.covMat = covMat; +fit.probTable = probTable; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% applyConcatFiltering % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) + +% apply the same filter as original data +% check for what filtering was done +tSeries = tSeries(:); + +% apply detrending (either if concatInfo does not say what it did or if +% the filterType field has detrend in it) +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + % check for length match + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +% project out the mean vector +if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) + projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; + tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; +end + +% now remove mean +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +% make back into the right dimensions +tSeries = tSeries(:)'; From 0b12c197ccdd13d4aaace02d2c2b8d490311f500 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:16:10 -0800 Subject: [PATCH 09/44] Adding difference of gaussians (DoG) model --- mrLoadRet/Plugin/pRF/pRFFit.m | 4 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 2 +- mrLoadRet/Plugin/pRF/pRF_diffGaussian.m | 134 ++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_diffGaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index c0d2820f5..16e0f6a35 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -540,7 +540,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); @@ -557,6 +557,8 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) output = pRF_gaussian(varargin{:}); case 'gaussian-hdr' output = pRF_gaussianhdr(varargin{:}); + case 'gaussian-diffs' + output = pRF_diffGaussian(varargin{:}); otherwise testModel = @pRF_exp; %%% Only need to change this line to specify a new model. output = testModel(varargin{:}); diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index 606fd3850..afa44e70a 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,7 +116,7 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; diff --git a/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m new file mode 100644 index 000000000..9157aa743 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m @@ -0,0 +1,134 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_diffGaussian(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % and convolve in time. + pPlus = convolveModelResponseWithHRF(rPlus,hrf); + pMinus = convolveModelResponseWithHRF(rMinus,hrf); + + % Model response is the difference of Gaussians, weighted by Beta amplitudes + thisModelResponse = pPlus*p.B1 + pMinus*p.B2; + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 -inf -inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; + fitParams.initParams = [0 0 4 4 1 0]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.std2 = params(4); + p.B1 = params(5); + p.B2 = params(6); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From 82d741956c9870edc0989e130872018a341bd18f Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:20:37 -0800 Subject: [PATCH 10/44] Adding scripts to get best N voxels, and to plot model prediction accuracy --- mrLoadRet/Plugin/pRF/getBestVoxels.m | 33 +++++++ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 118 +++++++++++++++++++---- mrLoadRet/Plugin/pRF/plotFigs.m | 83 ++++++++++++++++ 3 files changed, 213 insertions(+), 21 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/getBestVoxels.m create mode 100644 mrLoadRet/Plugin/pRF/plotFigs.m diff --git a/mrLoadRet/Plugin/pRF/getBestVoxels.m b/mrLoadRet/Plugin/pRF/getBestVoxels.m new file mode 100644 index 000000000..801f3b146 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/getBestVoxels.m @@ -0,0 +1,33 @@ +function cords = getBestVoxels(scanNum, bestN, roiName, analysis) + +if(ieNotDefined('scanNum')) + disp(sprintf('(getBestVoxels) No inputs given, using preset defaults')); + scanNum = 1; + bestN = 90; + roiName = 'both_pRF'; + analysis = 'pRF.mat' +end + +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +groupNum = viewGet(v, 'currentGroup'); +%v = viewSet(v, 'currentGroup', 'Averages'); +lV1 = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); + +v = loadAnalysis(v, ['pRFAnal/' analysis]); + +r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); +lV1 = getSortIndex(v, lV1, r2); + +sortIndex = lV1{1}.sortindex; +r2 = lV1{1}.r2; +scanLinCoords = lV1{1}.scanLinearCoords; + +scanDims = viewGet(v, 'scanDims'); + +[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); +cords = [i;j;k;ones(1,bestN)]; + +%fits = pRF_crossValidate(cords); +%fit.cords = cords; +end diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m index 63e62c400..95c0918a4 100644 --- a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -13,17 +13,21 @@ %% input: roiName - Name of the ROI we want to run this analysis on %% analysis - Name of analysis file to load %% - This must be the Concat of Average of N scans +%% newCoords - in the form [x1 y1 z1 1; x2 y2 z2 1].' -function fit = pRF_crossValidate(roiName, analysis) +function fits = pRF_crossValidate(newCoords, roiName, analysis) -%roiName = 'lV1'; -%roiName = 'xVal'; -%roiName = 'lineV1'; -analysis = 'pRF_lV1_123456.mat'; +%% Plot Figures flag (set to [] if you don't want to plot) +plotFigs = 1; + +roiName = 'V1'; +%analysis = 'pRF_lV1_123456.mat'; +analysis = 'pRF.mat'; % Set current group to Concat and load the Analysis file v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); +%v = viewSet(v, 'currentGroup', 'Averages'); v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; @@ -36,18 +40,40 @@ % Get analysis params for pRFFit concatInfo = viewGet(v, 'concatinfo', analScanNum); d = viewGet(v, 'd', analScanNum); +scanDims = viewGet(v, 'scanDims'); % Get the N original scans & their tSeries -scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); +%keyboard +if ~ieNotDefined('newCoords') + if(strmatch(newCoords, 'best')) + disp(sprintf('(crossValidate) Getting 90 best defined voxels in ROI %s', roiName)); + coords = getBestVoxels(analScanNum, 85, roiName, analysis); + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + tempRoi.coords = coords; + else + disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + tempRoi.coords = newCoords; + end + scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); +elseif ~ieNotDefined('roiName') + disp(sprintf('(crossValidate) Coordinates not given, getting tSeries for ROI %s', roiName)); + scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); +else + disp(sprintf('(crossValidate) Neither ROI name nor coordinates provided. Exiting.')); + return +end -for i=1:1 - +numFolds = length(scans); +for i=1:numFolds; + disp(sprintf('(crossValidate) Fold %d of %d', i, numFolds)); % Initialize vars for use later + fit = []; avg = zeros(size(scans{1}.tSeries)); - leftOut = scans{i}.tSeries; - numVoxels = size(leftOut, 1); - modelResponse = zeros(numVoxels, size(leftOut, 2)); - residual = zeros(numVoxels, size(leftOut, 2)); + unfilteredLeftOut = scans{i}.tSeries; + numVoxels = size(unfilteredLeftOut, 1); + modelResponse = zeros(numVoxels, size(unfilteredLeftOut, 2)); + residual = zeros(numVoxels, size(unfilteredLeftOut, 2)); % compute average time series across N-1 scans for j = 1:length(scans) @@ -58,22 +84,34 @@ avg = avg / (length(scans)-1); % Apply Concat Filtering to averages & left out + %keyboard for k = 1:numVoxels filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); - leftOut(k, :) = applyConcatFiltering(leftOut(k, :), concatInfo, 1); + leftOut(k, :) = applyConcatFiltering(unfilteredLeftOut(k, :), concatInfo, 1); end - disppercent(-inf, '(crossVal) Fitting pRF to voxels'); + disppercent(-inf, sprintf('\t(crossVal) Fitting pRF to %d voxels', numVoxels)); % run pRFFit on the averaged tSeries coords = scans{i}.scanCoords.'; for h = 1:numVoxels x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, h), 'concatInfo', d.concatInfo, 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); + linCoords = sub2ind(scanDims, x, y, z); + linVox = find(d.linearCoords == linCoords); + if isempty(linVox) + disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); + continue + end + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo, 'concatInfo', concatInfo); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; disppercent(h/numVoxels); end + leftOut(all(modelResponse==0, 2), :) = []; + modelResponse(all(modelResponse==0, 2), :) = []; + residual(all(residual==0,2), :) = []; + numSuccess = size(modelResponse, 1); + disp(sprintf('(crossVal) Successfully fit model to %d voxels', numSuccess)); disppercent(inf); %Calculate covariance matrix of voxels on our calculated residual @@ -89,13 +127,50 @@ % Compare model response to left-out timeseries probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); + fit.modelResponse = modelResponse; + fit.residual = residual; + fit.leftOut = leftOut; + fit.covMat = covMat; + fit.probTable = probTable; + fit.fitParams = fitParams; + + eval(sprintf('fits(%d)=fit;', i)) + timeLen = size(fit.modelResponse, 2); + if ~ieNotDefined('plotFigs') + figure; subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); + subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); + hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); + end + end -fit.modelResponse = modelResponse; -fit.residual = residual; -fit.leftOut = leftOut; -fit.covMat = covMat; -fit.probTable = probTable; +% Average together probability tables +pTable = zeros(timeLen, timeLen); +modResp = zeros(numSuccess, timeLen); +resid = zeros(numSuccess, timeLen); +leftOut = zeros(numSuccess, timeLen); +covMat = zeros(numSuccess, numSuccess); +fp = zeros( +for i = 1:length(fits) + fit = fits(i); + pTable = pTable + fit.probTable; + modResp = modResp + fit.modelResponse; + leftOut = leftOut + fit.leftOut; + covMat = covMat + fit.covMat; + resid = resid + fit.residual; +end +fit = []; +fit.modelResponse = modResp / length(fits); +fit.residual = resid / length(fits); +fit.leftOut = leftOut / length(fits); +fit.covMat = covMat / length(fits); +fit.probTable = pTable / length(fits); +fit.fitParams = []; +eval(sprintf('fits(%d)=fit;', numFolds+1)); +%if ~ieNotDefined('plotFigs') + %fit = fits(numFolds+1); + %plotFigs(fit, d); +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % applyConcatFiltering % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -108,6 +183,7 @@ % apply detrending (either if concatInfo does not say what it did or if % the filterType field has detrend in it) if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + %disp(sprintf('(pRFFit:applyConcatFiltering) Apply detrending')); tSeries = eventRelatedDetrend(tSeries); end diff --git a/mrLoadRet/Plugin/pRF/plotFigs.m b/mrLoadRet/Plugin/pRF/plotFigs.m new file mode 100644 index 000000000..ffe2dc52d --- /dev/null +++ b/mrLoadRet/Plugin/pRF/plotFigs.m @@ -0,0 +1,83 @@ +function plotFigs(fits, d) + +numFolds = length(fits)-1; +fit = fits(numFolds+1); + +timeLen = size(fit.modelResponse, 2); + +%%% 1. Plot prediction probability chart (batik) +f=figure; subplot(2, 2, 1); imagesc(log(fit.probTable)); axis ij; colorbar; +xlabel('Model Time Series'); ylabel('Observed Time series'); +hold on; hl = hline(200, '-b'); +hold on; pt = plot(0,0,'*g'); + % Plot best predicted points +count = 0; +for i = 1:timeLen + tS = fit.probTable(i,:); + [~, mI] = max(tS); + maxInd(i) = mI; + if( abs(mI - i) <= 5) + count = count + 1; + end +end +hold on; plot(maxInd, (1:timeLen), '*g', 'MarkerSize', 1); +title(sprintf('Avg Model Prediction Probability:\n %d / %d timepoints (%0.1f %%) correctly predicted within 5 using Max Likelihood', count, timeLen, 100*count/timeLen)); + +%%% 3. Plot observed and model response time course +subplot(2, 2, 3); plot((1:timeLen), fit.leftOut, 'k'); +hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model Response'); +hold on; vl1 = vline(0, 'k'); hold on; vl2 = vline(0, 'k'); + +%%% 4. Plot voxel receptive fields +%rf = subplot(2,2,4); plot(fits(1).fitParams(:,4), fits(1).fitParams(:,5), '*'); +%title('Voxel Receptive Field positions'); +%set(rf, 'Box', 'off'); set(rf, 'Color', [.8 .8 .8]); set(rf,'TickDir','out'); +%axis equal; axis tight; xlim([-30 30]); ylim([-20 20]); hold on; hline(0, 'w:'); vline(0,'w:'); + +timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(fit.modelResponse),... + 'SliderStep', [1/timeLen 10/timeLen], 'Value', 200, 'Callback', @timeSliderCallback,... + 'Parent',f, 'Units', 'normalized', 'Position', [.25, -.05,.5,.1]); +function timeSliderCallback(hObject, evendata) + newVal = round(get(hObject, 'Value')); + + %plot the stimulus predicted by the model time point with highest posterior probability + timeSeries = fit.probTable(newVal, :); + [maxVal, maxIndex] = max(timeSeries); + stimPl = subplot(2, 2, [2 4]); + cla(stimPl); + im = []; + predScan = d.concatInfo.whichScan(maxIndex); + predVol = d.concatInfo.whichVolume(maxIndex); + trueScan = d.concatInfo.whichScan(newVal); + trueVol = d.concatInfo.whichVolume(newVal); + im(:, :, 3) = flipud(0.7*d.stim{trueScan}.im(:,:,trueVol)'); + im(:, :, 2) = flipud(0.7*d.stim{predScan}.im(:,:,predVol)'); + im(:, :, 1) = 0; + image(d.stimX(:,1), d.stimY(1,:), im); + axis image; hold on; + hline(0, 'w:'); vline(0, 'w:'); + hold on; plot(fits(1).fitParams(:, 4), fits(1).fitParams(:, 5), '*w', 'MarkerSize', 1); + title(sprintf('Stim predictions: Timepoint %i is best predicted by Modelpoint %i', newVal, maxIndex)); + + % Plot line and point of highest prediction + subplot(2,2,1); + delete([hl pt]); + hl = hline(newVal, '-b'); + set(hl, 'LineWidth', 5); + pt = plot(maxIndex, newVal, '*g'); + + % Plot vertical line on time series plots + subplot(2, 2, 3); + delete([vl1 vl2]); + vl1 = vline(newVal, '-b'); + set(vl1, 'LineWidth', 5); + hold on; + vl2 = vline(maxIndex, '-g'); + set(vl2, 'LineWidth', 5); + title(sprintf('Time Series: %d; Model Time: %d', newVal, maxIndex)); +end + +bl3 = uicontrol('Parent',f,'Style','text','Units', 'normalized', 'Position', [.45, .05 ,.1,.015],... + 'String', sprintf('Time Slider (blue)')); + +end From 1f97d4bc82a889097f38596728a8de4cf786c100 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:21:41 -0800 Subject: [PATCH 11/44] minor changes to dispModel, which compares 2 voxels --- mrLoadRet/Plugin/pRF/dispModel.m | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/dispModel.m index ec83041dc..0f78d513b 100644 --- a/mrLoadRet/Plugin/pRF/dispModel.m +++ b/mrLoadRet/Plugin/pRF/dispModel.m @@ -1,7 +1,8 @@ -function display = dispModel(voxels) +function display = dispModel(fit, voxels) -% -voxels = [47 74 24; 37 67 25]; +if ieNotDefined('voxels') + voxels = [47 74 24; 37 67 25]; +end analysis = 'pRF_lV1_123456.mat'; scanNum = 7; @@ -38,7 +39,7 @@ hline(0,'w:');vline(0,'w:'); title('Voxel 1 Receptive Field Position'); -%% (2) Voxel 2 Receptive Field +%% (4) Voxel 2 Receptive Field rf2 = subplot(2, 3, 4); x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); @@ -55,7 +56,7 @@ hline(0, 'w:');vline(0,'w:'); title('Voxel 2 Receptive Field Position'); -%% (3) Stimulus position +%% (2) Stimulus position [thisT, modelT] = makeStim(100, 50); @@ -95,6 +96,7 @@ hold on; plot((1:477), m.tSeries, 'black'); hold on; vl1m = vline(1); tl1m = text(0,0,''); hold on; vl1t = vline(1); tl1t = text(0,0,''); +xlim([1 477]) title('Voxel 1 Model Response and Time Series'); % Plot voxel 2 model timecourse and timeseries @@ -103,10 +105,11 @@ hold on; plot((1:477), m2.tSeries, 'black'); hold on; vl2m = vline(1); tl2m = text(0,0,''); hold on; vl2t = vline(1); tl2t = text(0,0,''); +xlim([1 477]) title('Voxel 2 model response and time series'); -%% (4) 2D Gaussian model + tSeries +%% (5) 2D Gaussian model + tSeries p4 = subplot(2, 3, 5); timepoint = 100; @@ -130,7 +133,7 @@ timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... 'SliderStep', [1/477, 10/477],... 'Value', timepoint, 'Callback', @slider1Callback,... - 'Parent', f, 'Position', [.05, .05, .5, .1], 'Units', 'normalized'); + 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); function slider1Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); % Move the * around @@ -156,7 +159,7 @@ function slider1Callback(hObject, eventdata) modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.05, .15, .5, .1]); + 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); function slider2Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); % Move the circle around @@ -191,4 +194,14 @@ function slider2Callback(hObject, eventdata) cPlot = plot(x+xp, y+yp, 'g'); end + + +figure; subplot(3, 1, 1); +plot((1:477), m.tSeries, 'black'); +hold on; plot((1:477), m.modelResponse, 'blue'); +subplot(3, 1, 2); plot((1:477), m2.tSeries, 'red'); hold on; plot((1:477), m2.modelResponse, 'magenta') +xlim([1 477]) +if ~ieNotDefined('fit') + subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; +end end From 45edd8ead1539a53fefb84c77bb50f3c0a465e3c Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 20:58:00 -0800 Subject: [PATCH 12/44] Cleaning up old files, reorganizing subprocedures into crossVal, renamed a few files --- mrLoadRet/Plugin/pRF/applyConcatFiltering.m | 24 --- mrLoadRet/Plugin/pRF/getBestVoxels.m | 33 ---- mrLoadRet/Plugin/pRF/getR2Overlay.m | 13 -- mrLoadRet/Plugin/pRF/pRFNoise.m | 60 ------ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 178 +++++++++++------- .../Plugin/pRF/{dispModel.m => plot2voxels.m} | 45 +++-- .../pRF/{plotFigs.m => predictStimulus.m} | 22 ++- mrLoadRet/Plugin/pRF/testPRF.m | 45 ----- mrLoadRet/Plugin/pRF/trainPRF.m | 83 -------- 9 files changed, 159 insertions(+), 344 deletions(-) delete mode 100644 mrLoadRet/Plugin/pRF/applyConcatFiltering.m delete mode 100644 mrLoadRet/Plugin/pRF/getBestVoxels.m delete mode 100644 mrLoadRet/Plugin/pRF/getR2Overlay.m delete mode 100644 mrLoadRet/Plugin/pRF/pRFNoise.m rename mrLoadRet/Plugin/pRF/{dispModel.m => plot2voxels.m} (83%) rename mrLoadRet/Plugin/pRF/{plotFigs.m => predictStimulus.m} (81%) delete mode 100644 mrLoadRet/Plugin/pRF/testPRF.m delete mode 100644 mrLoadRet/Plugin/pRF/trainPRF.m diff --git a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m deleted file mode 100644 index 9838e8e37..000000000 --- a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m +++ /dev/null @@ -1,24 +0,0 @@ -function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) - -tSeries = tSeries(:); - -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) - projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; - tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; -end - -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/getBestVoxels.m b/mrLoadRet/Plugin/pRF/getBestVoxels.m deleted file mode 100644 index 801f3b146..000000000 --- a/mrLoadRet/Plugin/pRF/getBestVoxels.m +++ /dev/null @@ -1,33 +0,0 @@ -function cords = getBestVoxels(scanNum, bestN, roiName, analysis) - -if(ieNotDefined('scanNum')) - disp(sprintf('(getBestVoxels) No inputs given, using preset defaults')); - scanNum = 1; - bestN = 90; - roiName = 'both_pRF'; - analysis = 'pRF.mat' -end - -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -groupNum = viewGet(v, 'currentGroup'); -%v = viewSet(v, 'currentGroup', 'Averages'); -lV1 = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); - -v = loadAnalysis(v, ['pRFAnal/' analysis]); - -r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); -lV1 = getSortIndex(v, lV1, r2); - -sortIndex = lV1{1}.sortindex; -r2 = lV1{1}.r2; -scanLinCoords = lV1{1}.scanLinearCoords; - -scanDims = viewGet(v, 'scanDims'); - -[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); -cords = [i;j;k;ones(1,bestN)]; - -%fits = pRF_crossValidate(cords); -%fit.cords = cords; -end diff --git a/mrLoadRet/Plugin/pRF/getR2Overlay.m b/mrLoadRet/Plugin/pRF/getR2Overlay.m deleted file mode 100644 index aa7f7d04e..000000000 --- a/mrLoadRet/Plugin/pRF/getR2Overlay.m +++ /dev/null @@ -1,13 +0,0 @@ -function r2Overlay = getR2Overlay(modelName) - -v = newView; -v = viewSet(v, 'curGroup', 'Averages'); -v = viewSet(v, 'curScan', 1); -prfModel = sprintf('pRFAnal/%s', modelName); -v = loadAnalysis(v, prfModel); -r2OverlayNum = find(strcmp('r2', viewGet(v, 'overlayNames'))); -v = viewSet(v, 'curOverlay', r2OverlayNum); -r2Overlay = viewGet(v, 'overlayData', 1); - -validR2 = r2Overlay(~isnan(r2Overlay)); -fprintf('Mean r2 for well-defined voxels: %d', mean(validR2)); diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m deleted file mode 100644 index 457b0b765..000000000 --- a/mrLoadRet/Plugin/pRF/pRFNoise.m +++ /dev/null @@ -1,60 +0,0 @@ -function [residual, covMat, tSeries, modelResponse] = pRFNoise(v,scanNum,coordinates, analysisFileName) - -% coordinates = [53,61,25; 53,59,24; 51,57,24; 51,56,22; 52,55,20]; -% scanNum = 1; - -if ieNotDefined('v') - v = newView; -end - -v = viewSet(v, 'currentGroup', 'Concatenation'); -analysisFile = dir(sprintf('Concatenation/pRFAnal/%s', analysisFileName)); - -% get the analysis structure -analysis = viewGet(v,'analysis'); -if ~isfield(analysis,'d') || (length(analysis.d) < scanNum) || isempty(analysis.d) - v = loadAnalysis(v, ['pRFAnal/' analysisFile.name]); - analysis = viewGet(v,'analysis'); - -end - -d = viewGet(v,'d',scanNum); -if isempty(d),disp(sprintf('Could not find d structure for this scan'));return,end - -numVoxels = size(coordinates, 1); - -%figure; -disppercent(-inf, '(pRFNoise) Calculating residuals'); -for voxel = 1:numVoxels - [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); - %subplot(numVoxels,1,voxel) - %plot(tSeries(voxel,:), 'k.-'); - %hold on; - %plot(modelResponse(voxel,:), 'r-'); - %plot(residual(voxel,:), 'b-'); - %title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); - disppercent(voxel/numVoxels); -end -disppercent(inf); -covMat = residual*residual'; - -function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) - -% get the params that have been run -scanDims = viewGet(v,'scanDims',scanNum); -whichVoxel = find(d.linearCoords == sub2ind(scanDims,x,y,z)); -r = d.r(whichVoxel,:); - -params = d.params(:,whichVoxel); -if isfield(d,'paramsInfo') - paramsInfo = d.paramsInfo; -else - paramsInfo = []; -end - -% get params -m = pRFFit(v,scanNum,x,y,z,'stim',d.stim,'getModelResponse=1','params',params,'concatInfo',d.concatInfo,'fitTypeParams',a.params.pRFFit,'paramsInfo',paramsInfo); - -residual = m.tSeries - m.modelResponse; -tSeries = m.tSeries; -modelResponse = m.modelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m index 95c0918a4..aa4af2eda 100644 --- a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -1,33 +1,35 @@ %% pRF_crossValidate.m %% -%% $Id:$ -%% usage: pRF_crossValidate(view, roiName, analysis) +%% usage: fits = pRF_crossValidate(newCoords, [], analysis) --> run on specified coordinates +%% fits = pRF_crossValidate([], roiName, analysis) --> run on specified ROI +%% fits = pRF_crossValidate('best', roiName, analysis) --> run on best N voxels in specified ROI %% by: akshay jagadeesh %% date: 10/04/16 -%% purpose: Given n MotionComp runs, this function computes a n-fold -%% cross validation, running the pRF analysis n times. -%% It generates and saves time series, model response, residuals, -%% and covariance matrices for each fold. +%% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF +%% analysis n times. It generates and saves time series, model response, residuals, and covariance +%% matrices for each fold. +%% We then calculate the probability that each point in the observed time series is predicted +%% by the pRF model response. %% %% %% input: roiName - Name of the ROI we want to run this analysis on %% analysis - Name of analysis file to load %% - This must be the Concat of Average of N scans -%% newCoords - in the form [x1 y1 z1 1; x2 y2 z2 1].' +%% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' function fits = pRF_crossValidate(newCoords, roiName, analysis) -%% Plot Figures flag (set to [] if you don't want to plot) -plotFigs = 1; +%%%%%%% Default inputs %%%%%%%%% +newCoords = 'best'; +roiName = 'bothV1'; +analysis = 'pRF_v1.mat'; +nBest = 5; +plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots -roiName = 'V1'; -%analysis = 'pRF_lV1_123456.mat'; -analysis = 'pRF.mat'; % Set current group to Concat and load the Analysis file v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); -%v = viewSet(v, 'currentGroup', 'Averages'); v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; @@ -43,16 +45,14 @@ scanDims = viewGet(v, 'scanDims'); % Get the N original scans & their tSeries -%keyboard if ~ieNotDefined('newCoords') + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); if(strmatch(newCoords, 'best')) - disp(sprintf('(crossValidate) Getting 90 best defined voxels in ROI %s', roiName)); - coords = getBestVoxels(analScanNum, 85, roiName, analysis); - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + disp(sprintf('(crossValidate) Getting %d best defined voxels in ROI %s', nBest, roiName)); + coords = getBestVoxels(v, analScanNum, nBest, roiName, analysis); tempRoi.coords = coords; else disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); tempRoi.coords = newCoords; end scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); @@ -101,7 +101,9 @@ disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); continue end - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo, 'concatInfo', concatInfo); + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... + 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... + d.paramsInfo, 'concatInfo', concatInfo); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; @@ -111,22 +113,14 @@ modelResponse(all(modelResponse==0, 2), :) = []; residual(all(residual==0,2), :) = []; numSuccess = size(modelResponse, 1); - disp(sprintf('(crossVal) Successfully fit model to %d voxels', numSuccess)); disppercent(inf); + disp(sprintf('\t(crossVal) Successfully fit model to %d voxels', numSuccess)); %Calculate covariance matrix of voxels on our calculated residual covMat = residual*residual'; - % Calculate covariance matrix of voxels using pRFNoise's method - %[residual, covMat, tSeries, modelResponse] = pRFNoise(v, analysisScanNum, coordinates, analysis); - %[resid, covMat2, tS, modResp] = pRFNoise([], analScanNum, coords, analysis); - %noise.resid = resid; - %noise.covMat = covMat2; - %noise.tSeries = tS; - %noise.modelResponse = modResp; - % Compare model response to left-out timeseries - probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); + probTable = calcProb(leftOut, modelResponse, diag(diag(covMat))); fit.modelResponse = modelResponse; fit.residual = residual; fit.leftOut = leftOut; @@ -137,61 +131,66 @@ eval(sprintf('fits(%d)=fit;', i)) timeLen = size(fit.modelResponse, 2); if ~ieNotDefined('plotFigs') - figure; subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); - subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); - hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); + figure; + subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); + subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); hold on; + plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); end end -% Average together probability tables -pTable = zeros(timeLen, timeLen); -modResp = zeros(numSuccess, timeLen); -resid = zeros(numSuccess, timeLen); -leftOut = zeros(numSuccess, timeLen); -covMat = zeros(numSuccess, numSuccess); -fp = zeros( -for i = 1:length(fits) - fit = fits(i); - pTable = pTable + fit.probTable; - modResp = modResp + fit.modelResponse; - leftOut = leftOut + fit.leftOut; - covMat = covMat + fit.covMat; - resid = resid + fit.residual; -end +% Average across folds and store in fits struct array fit = []; -fit.modelResponse = modResp / length(fits); -fit.residual = resid / length(fits); -fit.leftOut = leftOut / length(fits); -fit.covMat = covMat / length(fits); -fit.probTable = pTable / length(fits); -fit.fitParams = []; -eval(sprintf('fits(%d)=fit;', numFolds+1)); -%if ~ieNotDefined('plotFigs') - %fit = fits(numFolds+1); - %plotFigs(fit, d); -%end +fit.modelResponse = meanStruct(fits, 'modelResponse'); +fit.residual = meanStruct(fits, 'residual'); +fit.leftOut = meanStruct(fits, 'leftOut'); +fit.covMat = meanStruct(fits, 'covMat'); +fit.probTable = meanStruct(fits, 'probTable'); +fit.fitParams = meanStruct(fits, 'fitParams'); +fits(numFolds+1) = fit; + + + % -- end main program -- % + + +%%%%%%%%%%%%%%%%%%%%%% Helper Methods %%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% applyConcatFiltering % +% meanStruct % +% % +function avg = meanStruct(structArr, field, notI) + +if(ieNotDefined('notI')) + notI = -1; +else + disp(sprintf('Averaging across all but the %d th fold', notI)); +end +eval(sprintf('avg = zeros(size(structArr(1).%s));', field)); + +for i = 1:length(structArr) + if i~=notI + avg = avg + eval(sprintf('structArr(i).%s', field)); + end +end +avg = avg / length(structArr); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% applyConcatFiltering % +% % function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) -% apply the same filter as original data -% check for what filtering was done tSeries = tSeries(:); -% apply detrending (either if concatInfo does not say what it did or if -% the filterType field has detrend in it) +% apply detrending if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - %disp(sprintf('(pRFFit:applyConcatFiltering) Apply detrending')); tSeries = eventRelatedDetrend(tSeries); end % apply hipass filter if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - % check for length match if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); else tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); end @@ -205,6 +204,49 @@ % now remove mean tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -% make back into the right dimensions tSeries = tSeries(:)'; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% getBestVoxels % +% % +function cords = getBestVoxels(v, scanNum, bestN, roiName, analysis) + +groupNum = viewGet(v, 'currentGroup'); +roi = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); + +r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); +roi = getSortIndex(v, roi, r2); + +% Get sort index based on r2 and list of linear coords +sortIndex = roi{1}.sortindex; +scanLinCoords = roi{1}.scanLinearCoords; +scanDims = viewGet(v, 'scanDims'); +% get the linear coords with highest sortIndex and convert to 3d coords +[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); +cords = [i;j;k;ones(1, bestN)]; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% calcProb % + +function probTable = calcProb(testTSeries, modelResponse, covarMat) + +numTimePoints = size(modelResponse, 2); +probTable = zeros(numTimePoints, numTimePoints); + +disppercent(-inf, sprintf('\t(calcProb) Calculating prediction likelihoods')); +for i = 1:numTimePoints + model_i = modelResponse(:, i); + tSeries_i = testTSeries(:, i); + + for j = 1:numTimePoints + tSeries_j = testTSeries(:, j); + probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); + if probTable(j, i) == 0 + disp(sprintf('\n(calcProb) mvnpdf at index(%i, %i) returning 0; Exiting.', j, i)); + return; + end + end + disppercent(i/numTimePoints); +end +disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/plot2voxels.m similarity index 83% rename from mrLoadRet/Plugin/pRF/dispModel.m rename to mrLoadRet/Plugin/pRF/plot2voxels.m index 0f78d513b..53e0a8a7b 100644 --- a/mrLoadRet/Plugin/pRF/dispModel.m +++ b/mrLoadRet/Plugin/pRF/plot2voxels.m @@ -1,15 +1,27 @@ -function display = dispModel(fit, voxels) +%% plot2voxels.m +%% +%% usage: plot2voxels(fit, voxels) +%% purpose: plots 2 voxels' receptive fields and time courses +%% +%% input: analysis - filename of analysis file +%% fit - struct containing fields to plot probTable +%% voxels - list of two voxels in format [x1 y1 z1; x2 y2 z2] +%% + +function display = plot2voxels(analysis, voxels, fit) if ieNotDefined('voxels') - voxels = [47 74 24; 37 67 25]; + voxels = [44 74 21; 43 74 21]; +end +if ieNotDefined('analysis') + analysis = 'pRF_lV1_123456.mat'; end -analysis = 'pRF_lV1_123456.mat'; -scanNum = 7; % Set curr group to Concat and load the Analysis v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); v = loadAnalysis(v, ['pRFAnal/' analysis]); +scanNum = v.analyses{1}.params.scanNum; a = viewGet(v, 'Analysis'); d = viewGet(v, 'd', scanNum); @@ -91,21 +103,22 @@ %%%% (3) and (6): Plot voxels' model response time course and time series % Plot voxel 1 model timecourse and timeseries +tLen = length(m.modelResponse); subplot(2, 3, 3); -plot((1:477), m.modelResponse, 'r'); -hold on; plot((1:477), m.tSeries, 'black'); +plot((1:tLen), m.modelResponse, 'r'); +hold on; plot((1:tLen), m.tSeries, 'black'); hold on; vl1m = vline(1); tl1m = text(0,0,''); hold on; vl1t = vline(1); tl1t = text(0,0,''); -xlim([1 477]) +xlim([1 tLen]) title('Voxel 1 Model Response and Time Series'); % Plot voxel 2 model timecourse and timeseries subplot(2, 3, 6); -plot((1:477), m2.modelResponse, 'r'); -hold on; plot((1:477), m2.tSeries, 'black'); +plot((1:tLen), m2.modelResponse, 'r'); +hold on; plot((1:tLen), m2.tSeries, 'black'); hold on; vl2m = vline(1); tl2m = text(0,0,''); hold on; vl2t = vline(1); tl2t = text(0,0,''); -xlim([1 477]) +xlim([1 tLen]) title('Voxel 2 model response and time series'); @@ -131,7 +144,7 @@ title('Voxel 1 vs Voxel 2: Percent Signal Change'); timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... - 'SliderStep', [1/477, 10/477],... + 'SliderStep', [1/tLen, 10/tLen],... 'Value', timepoint, 'Callback', @slider1Callback,... 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); function slider1Callback(hObject, eventdata) @@ -158,7 +171,7 @@ function slider1Callback(hObject, eventdata) end modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... - 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... + 'SliderStep', [1/tLen 10/tLen], 'Value', modelTime, 'Callback', @slider2Callback,... 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); function slider2Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); @@ -197,10 +210,10 @@ function slider2Callback(hObject, eventdata) figure; subplot(3, 1, 1); -plot((1:477), m.tSeries, 'black'); -hold on; plot((1:477), m.modelResponse, 'blue'); -subplot(3, 1, 2); plot((1:477), m2.tSeries, 'red'); hold on; plot((1:477), m2.modelResponse, 'magenta') -xlim([1 477]) +plot((1:tLen), m.tSeries, 'black'); +hold on; plot((1:tLen), m.modelResponse, 'blue'); +subplot(3, 1, 2); plot((1:tLen), m2.tSeries, 'red'); hold on; plot((1:tLen), m2.modelResponse, 'magenta') +xlim([1 tLen]) if ~ieNotDefined('fit') subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; end diff --git a/mrLoadRet/Plugin/pRF/plotFigs.m b/mrLoadRet/Plugin/pRF/predictStimulus.m similarity index 81% rename from mrLoadRet/Plugin/pRF/plotFigs.m rename to mrLoadRet/Plugin/pRF/predictStimulus.m index ffe2dc52d..d730ea135 100644 --- a/mrLoadRet/Plugin/pRF/plotFigs.m +++ b/mrLoadRet/Plugin/pRF/predictStimulus.m @@ -1,7 +1,25 @@ -function plotFigs(fits, d) +%% predictStimulus.m +%% +%% +%% usage: predictStimulus(fits, d) --> plot figs for avg (last element of fits) +%% predictStimulus(fits, d, index) --> plot figs for i'th fold in fits +%% by: akshay jagadeesh +%% date: 11/20/2016 +%% purpose: Given model fits, this function predicts the stimulus most likely to have elicited +%% the given model response and compares this to the actual observed stimulus. Outputs the +%% percentage of timepoints that are correctly predicted (within 5) using maximum likelihood. +%% + + +function predictStimulus(fits, d, index) numFolds = length(fits)-1; -fit = fits(numFolds+1); +if(ieNotDefined('index')) + fit = fits(numFolds+1); +else + disp(sprintf('getting %d th fit', index)); + fit = fits(index); +end timeLen = size(fit.modelResponse, 2); diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m deleted file mode 100644 index 8723e15d0..000000000 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ /dev/null @@ -1,45 +0,0 @@ -% testPRF.m -% -% usage: testPRF( ) -% by: akshay jagadeesh -% date: 10/07/16 -% purpose: Computes the probability of seeing the model response, -% given the observed data, and the computed covariance (noise). -% -% -% Input variables: -% testTSeries: true voxel response for the left-out scan at a single timepoint -% modelResp: expected voxel response trained on other n-1 scans -% covarMat: Covariance matrix (size: m x m, where m is # of voxels) -% -% Output variables: -% logLikelihood: total likelihood of all the observed tSeries given model response -% probTable: value at (i, j) is the probability that i'th timepoint in tseries is -% explained by j'th timepoint in model response. - -function probTable = testPRF(testTSeries, modelResponse, covarMat) - -numTimePoints = size(modelResponse, 2); -probTable = zeros(numTimePoints, numTimePoints); -logprobTable = zeros(numTimePoints, numTimePoints); - -disppercent(-inf,'(testPRF) Calculating likelihoods'); -for i = 1:numTimePoints - model_i = modelResponse(:, i); - tSeries_i = testTSeries(:, i); - - for j = 1:numTimePoints - tSeries_j = testTSeries(:, j); - probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); - if probTable(j, i) == 0 - disp(sprintf('\n(testPRF) mvnpdf at index (%i, %i) returning 0; Exiting...', j, i)); - return; - end - logProbTable(j, i) = log(probTable(j,i)); - end - - %modelLikelihood(i) = mvnpdf(tSeries_i, model_i, covarMat); - %logLikelihood = logLikelihood + log(modelLikelihood(i)); - disppercent(i/numTimePoints); -end -disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m deleted file mode 100644 index c0197bda9..000000000 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ /dev/null @@ -1,83 +0,0 @@ -% trainPRF.m -% -% $Id:$ -% usage: trainPRF(view, roiName) -% by: akshay jagadeesh -% date: 10/04/16 -% purpose: Given n MotionComp runs, this function computes a n-fold -% cross validation, running the pRF analysis n times. -% It generates and saves time series, model response, residuals, -% and covariance matrices for each fold. -% -% -% input: roiName - Name of the ROI we want to run this analysis on -% analysis - Name of analysis file to load -% - This must be the Concat of Average of N scans - -function trainPRF(view, roiName, analysis) - -% Currently hardcoding number and names of scan. -numScans = 6 -roiName = 'lV1' - -for i = 1:numScans - v = newView; - - %Get all but the i'th scan - scanList = [1:i-1 i+1:numScans] - - %Average the other n-1 scans together - v = viewSet(v, 'currentGroup', 'Concatenation'); - scanstr = sprintf('scanList=%s', mat2str(scanList)); - [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) - %Filename of averaged scan is: tseries-avg-.nii - scanListStr = mat2str(scanList); scanListStr = scanListStr(2:end-1); scanListStr=scanListStr(find(~isspace(scanListStr))); - %params.fileName = sprintf('tseries-avg-%s.nii', fileName) - %params = averageTSeriesGUI('groupName', 'MotionComp'); - averageTSeries(v, params) - - %Get group info about the average we just created - gInfo = groupInfo; - gAverageInfo = groupInfo('Averages'); - numAverageScans = gInfo(3).numScans; - sInfo = scanInfo(numAverageScans, 'Averages'); - %% sInfo.description --> contains info about which scans were averaged - %% sInfo.Filename --> contains filename in which this average is saved - %% sInfo.OriginalN --> contains filename of original (replace N with 1 - 5) - - v = newView; - v = viewSet(v, 'currentGroup', 'Averages'); - - % Two ways of calculating ROI coordinates --> neither work right now. - % Method 1: loadROI.coords - v = loadROI(v, sprintf('%s.mat', roiName)) - % roiCoords = v.ROIs(1).coords.' - % roiCoords = roiCoords(:, 1:3) - - %Run pRF Analysis on average of n-1 scans - %pRF(v, params) - [v, params] = pRF(v, [], 'justGetParams=1'); - %%set dispStimScan to the last most recently computed scan - %%set saveName to pRF_ROINAME_SCANLIST - %%select diffOfGamma - pRF(v, params) - - % Load analysis by filename - analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr); - v = loadAnalysis(v, ['pRFAnal/' analysisFileName]); - scanNum = v.analyses{1}.params.scanNum; - - % Get the time series data for the left-out scan - v2 = newView; - testTSeries = loadROITSeries(v2, roiName, i, 2, 'straightXform=1'); - roiCoords = testTSeries.scanCoords.'; - testTSeries = testTSeries.tSeries; - - %Get the residual and covariance matrix - %%% scanNum: scan number on which analysis was conducted - [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, roiCoords, analysisFileName); - - %Save residual, covariance matrix, time series, and model response into a structure - save(sprintf('SaveData/pRF_fold%i_%s_%s', i, scanListStr, roiName), 'residual', 'covMat', 'modelResponse', 'testScanCoords', 'testTSeries') - -end From 45603a6c4619e6aa9002cae6313034e728c7daea Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 21:07:55 -0800 Subject: [PATCH 13/44] rename pRF_crossValidate to pRFCrossVal --- mrLoadRet/Plugin/pRF/{pRF_crossValidate.m => pRFCrossVal.m} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mrLoadRet/Plugin/pRF/{pRF_crossValidate.m => pRFCrossVal.m} (100%) diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_crossValidate.m rename to mrLoadRet/Plugin/pRF/pRFCrossVal.m From 8774530954ea69e62a9b7af484c02b930468f712 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 21:08:18 -0800 Subject: [PATCH 14/44] rename pRF_crossValidate to pRFCrossVal --- mrLoadRet/Plugin/pRF/pRFCrossVal.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m index aa4af2eda..13e17ee21 100644 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ b/mrLoadRet/Plugin/pRF/pRFCrossVal.m @@ -1,8 +1,8 @@ -%% pRF_crossValidate.m +%% pRFCrossVal.m %% -%% usage: fits = pRF_crossValidate(newCoords, [], analysis) --> run on specified coordinates -%% fits = pRF_crossValidate([], roiName, analysis) --> run on specified ROI -%% fits = pRF_crossValidate('best', roiName, analysis) --> run on best N voxels in specified ROI +%% usage: fits = pRFCrossVal(newCoords, [], analysis) --> run on specified coordinates +%% fits = pRFCrossVal([], roiName, analysis) --> run on specified ROI +%% fits = pRFCrossVal('best', roiName, analysis) --> run on best N voxels in specified ROI %% by: akshay jagadeesh %% date: 10/04/16 %% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF @@ -17,7 +17,7 @@ %% - This must be the Concat of Average of N scans %% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' -function fits = pRF_crossValidate(newCoords, roiName, analysis) +function fits = pRFCrossVal(newCoords, roiName, analysis) %%%%%%% Default inputs %%%%%%%%% newCoords = 'best'; From e7f4d6dbaf04d4ac1a7ca5e9423cdd3c38516299 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 12 Dec 2016 14:15:37 -0800 Subject: [PATCH 15/44] Adding new models (ratio of gaussians) and bounded fminsearch methods --- .../Plugin/pRF/fminsearch/fminsearchbnd.m | 307 ++++++++++++++++++ mrLoadRet/Plugin/pRF/pRFCrossVal.m | 29 +- mrLoadRet/Plugin/pRF/pRFFit.m | 21 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 4 +- mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m | 135 ++++++++ mrLoadRet/Plugin/pRF/pRF_divGaussian.m | 135 ++++++++ 6 files changed, 614 insertions(+), 17 deletions(-) create mode 100755 mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_divGaussian.m diff --git a/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m b/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m new file mode 100755 index 000000000..0448eae0f --- /dev/null +++ b/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m @@ -0,0 +1,307 @@ +function [x,fval,exitflag,output] = fminsearchbnd(fun,x0,LB,UB,options,varargin) +% FMINSEARCHBND: FMINSEARCH, but with bound constraints by transformation +% usage: x=FMINSEARCHBND(fun,x0) +% usage: x=FMINSEARCHBND(fun,x0,LB) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options,p1,p2,...) +% usage: [x,fval,exitflag,output]=FMINSEARCHBND(fun,x0,...) +% +% arguments: +% fun, x0, options - see the help for FMINSEARCH +% +% LB - lower bound vector or array, must be the same size as x0 +% +% If no lower bounds exist for one of the variables, then +% supply -inf for that variable. +% +% If no lower bounds at all, then LB may be left empty. +% +% Variables may be fixed in value by setting the corresponding +% lower and upper bounds to exactly the same value. +% +% UB - upper bound vector or array, must be the same size as x0 +% +% If no upper bounds exist for one of the variables, then +% supply +inf for that variable. +% +% If no upper bounds at all, then UB may be left empty. +% +% Variables may be fixed in value by setting the corresponding +% lower and upper bounds to exactly the same value. +% +% Notes: +% +% If options is supplied, then TolX will apply to the transformed +% variables. All other FMINSEARCH parameters should be unaffected. +% +% Variables which are constrained by both a lower and an upper +% bound will use a sin transformation. Those constrained by +% only a lower or an upper bound will use a quadratic +% transformation, and unconstrained variables will be left alone. +% +% Variables may be fixed by setting their respective bounds equal. +% In this case, the problem will be reduced in size for FMINSEARCH. +% +% The bounds are inclusive inequalities, which admit the +% boundary values themselves, but will not permit ANY function +% evaluations outside the bounds. These constraints are strictly +% followed. +% +% If your problem has an EXCLUSIVE (strict) constraint which will +% not admit evaluation at the bound itself, then you must provide +% a slightly offset bound. An example of this is a function which +% contains the log of one of its parameters. If you constrain the +% variable to have a lower bound of zero, then FMINSEARCHBND may +% try to evaluate the function exactly at zero. +% +% +% Example usage: +% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2; +% +% fminsearch(rosen,[3 3]) % unconstrained +% ans = +% 1.0000 1.0000 +% +% fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained +% ans = +% 2.0000 4.0000 +% +% See test_main.m for other examples of use. +% +% +% See also: fminsearch, fminspleas +% +% +% Author: John D'Errico +% E-mail: woodchips@rochester.rr.com +% Release: 4 +% Release date: 7/23/06 + +% size checks +xsize = size(x0); +x0 = x0(:); +n=length(x0); + +if (nargin<3) || isempty(LB) + LB = repmat(-inf,n,1); +else + LB = LB(:); +end +if (nargin<4) || isempty(UB) + UB = repmat(inf,n,1); +else + UB = UB(:); +end + +if (n~=length(LB)) || (n~=length(UB)) + error 'x0 is incompatible in size with either LB or UB.' +end + +% set default options if necessary +if (nargin<5) || isempty(options) + options = optimset('fminsearch'); +end + +% stuff into a struct to pass around +params.args = varargin; +params.LB = LB; +params.UB = UB; +params.fun = fun; +params.n = n; +% note that the number of parameters may actually vary if +% a user has chosen to fix one or more parameters +params.xsize = xsize; +params.OutputFcn = []; + +% 0 --> unconstrained variable +% 1 --> lower bound only +% 2 --> upper bound only +% 3 --> dual finite bounds +% 4 --> fixed variable +params.BoundClass = zeros(n,1); +for i=1:n + k = isfinite(LB(i)) + 2*isfinite(UB(i)); + params.BoundClass(i) = k; + if (k==3) && (LB(i)==UB(i)) + params.BoundClass(i) = 4; + end +end + +% transform starting values into their unconstrained +% surrogates. Check for infeasible starting guesses. +x0u = x0; +k=1; +for i = 1:n + switch params.BoundClass(i) + case 1 + % lower bound only + if x0(i)<=LB(i) + % infeasible starting value. Use bound. + x0u(k) = 0; + else + x0u(k) = sqrt(x0(i) - LB(i)); + end + + % increment k + k=k+1; + case 2 + % upper bound only + if x0(i)>=UB(i) + % infeasible starting value. use bound. + x0u(k) = 0; + else + x0u(k) = sqrt(UB(i) - x0(i)); + end + + % increment k + k=k+1; + case 3 + % lower and upper bounds + if x0(i)<=LB(i) + % infeasible starting value + x0u(k) = -pi/2; + elseif x0(i)>=UB(i) + % infeasible starting value + x0u(k) = pi/2; + else + x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1; + % shift by 2*pi to avoid problems at zero in fminsearch + % otherwise, the initial simplex is vanishingly small + x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k)))); + end + + % increment k + k=k+1; + case 0 + % unconstrained variable. x0u(i) is set. + x0u(k) = x0(i); + + % increment k + k=k+1; + case 4 + % fixed variable. drop it before fminsearch sees it. + % k is not incremented for this variable. + end + +end +% if any of the unknowns were fixed, then we need to shorten +% x0u now. +if k<=n + x0u(k:n) = []; +end + +% were all the variables fixed? +if isempty(x0u) + % All variables were fixed. quit immediately, setting the + % appropriate parameters, then return. + + % undo the variable transformations into the original space + x = xtransform(x0u,params); + + % final reshape + x = reshape(x,xsize); + + % stuff fval with the final value + fval = feval(params.fun,x,params.args{:}); + + % fminsearchbnd was not called + exitflag = 0; + + output.iterations = 0; + output.funcCount = 1; + output.algorithm = 'fminsearch'; + output.message = 'All variables were held fixed by the applied bounds'; + + % return with no call at all to fminsearch + return +end + +% Check for an outputfcn. If there is any, then substitute my +% own wrapper function. +if ~isempty(options.OutputFcn) + params.OutputFcn = options.OutputFcn; + options.OutputFcn = @outfun_wrapper; +end + +% now we can call fminsearch, but with our own +% intra-objective function. +[xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params); + +% undo the variable transformations into the original space +x = xtransform(xu,params); + +% final reshape to make sure the result has the proper shape +x = reshape(x,xsize); + +% Use a nested function as the OutputFcn wrapper + function stop = outfun_wrapper(x,varargin); + % we need to transform x first + xtrans = xtransform(x,params); + + % then call the user supplied OutputFcn + stop = params.OutputFcn(xtrans,varargin{1:(end-1)}); + + end + +end % mainline end + +% ====================================== +% ========= begin subfunctions ========= +% ====================================== +function fval = intrafun(x,params) +% transform variables, then call original function + +% transform +xtrans = xtransform(x,params); + +% and call fun +fval = feval(params.fun,reshape(xtrans,params.xsize),params.args{:}); + +end % sub function intrafun end + +% ====================================== +function xtrans = xtransform(x,params) +% converts unconstrained variables into their original domains + +xtrans = zeros(params.xsize); +% k allows some variables to be fixed, thus dropped from the +% optimization. +k=1; +for i = 1:params.n + switch params.BoundClass(i) + case 1 + % lower bound only + xtrans(i) = params.LB(i) + x(k).^2; + + k=k+1; + case 2 + % upper bound only + xtrans(i) = params.UB(i) - x(k).^2; + + k=k+1; + case 3 + % lower and upper bounds + xtrans(i) = (sin(x(k))+1)/2; + xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i); + % just in case of any floating point problems + xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i))); + + k=k+1; + case 4 + % fixed variable, bounds are equal, set it at either bound + xtrans(i) = params.LB(i); + case 0 + % unconstrained variable. + xtrans(i) = x(k); + + k=k+1; + end +end + +end % sub function xtransform end + + + + + diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m index 13e17ee21..0ffe58f56 100644 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ b/mrLoadRet/Plugin/pRF/pRFCrossVal.m @@ -17,15 +17,16 @@ %% - This must be the Concat of Average of N scans %% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' -function fits = pRFCrossVal(newCoords, roiName, analysis) +function [fits, d] = pRFCrossVal(newCoords, roiName, analysis) %%%%%%% Default inputs %%%%%%%%% newCoords = 'best'; -roiName = 'bothV1'; -analysis = 'pRF_v1.mat'; -nBest = 5; +roiName = 'goodV1'; +analysis = 'pRF_gV1_RoG.mat'; % change to pRF_v1_DoG.mat to run for Diff of Gaussians model +nBest = 85; plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots - +%rfType = 'gaussian-exp'; +algorithm = 'nelder-mead-bnd'; % Set current group to Concat and load the Analysis file v = newView; @@ -33,6 +34,8 @@ v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; +rfType = analParams.pRFFit.rfType; +disp(sprintf('(pRFCrossVal) Using model %s, with fitting algorithm %s', rfType, algorithm)); ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan osn = viewGet(v, 'originalscannum', analScanNum); @@ -103,10 +106,18 @@ end modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... - d.paramsInfo, 'concatInfo', concatInfo); + d.paramsInfo, 'concatInfo', concatInfo, 'rfType', rfType); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; + if strmatch(rfType, 'gaussian-diffs') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2]; + elseif strmatch(rfType, 'gaussian-exp') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.exp]; + elseif strmatch(rfType, 'gaussian-DoG-CSS') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2, modelFit.p.exp]; + else + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; + end disppercent(h/numVoxels); end leftOut(all(modelResponse==0, 2), :) = []; @@ -148,8 +159,7 @@ fit.probTable = meanStruct(fits, 'probTable'); fit.fitParams = meanStruct(fits, 'fitParams'); fits(numFolds+1) = fit; - - +return % -- end main program -- % @@ -206,6 +216,7 @@ tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); tSeries = tSeries(:)'; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % getBestVoxels % % % diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 16e0f6a35..f57fa049d 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -202,6 +202,8 @@ [params resnorm residual exitflag output lambda jacobian] = lsqnonlin(@getModelResidual,fitParams.initParams,fitParams.minParams,fitParams.maxParams,fitParams.optimParams,tSeries,fitParams); elseif strcmp(lower(fitParams.algorithm),'nelder-mead') [params fval exitflag] = fminsearch(@getModelResidual,fitParams.initParams,fitParams.optimParams,(tSeries-mean(tSeries))/var(tSeries.^2),fitParams); +elseif strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') + [params fval exitflag] = fminsearchbnd(@getModelResidual, fitParams.initParams, fitParams.minParams, fitParams.maxParams, fitParams.optimParams, (tSeries-mean(tSeries))/var(tSeries.^2), fitParams); else disp(sprintf('(pRFFit) Unknown optimization algorithm: %s',fitParams.algorithm)); return @@ -218,6 +220,8 @@ fit.r2 = 1-sum((residual-mean(residual)).^2)/sum((tSeries-mean(tSeries)).^2); elseif strcmp(lower(fitParams.algorithm),'nelder-mead') fit.r2 = residual^2; +elseif strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') + fit.r2 = residual^2; end % compute polar coordinates @@ -266,7 +270,7 @@ % handle constraints here % Check if fit algorithm is one that allows constraints - algorithmsWithConstraints = {'levenberg-marquardt'}; + algorithmsWithConstraints = {'levenberg-marquardt', 'nelder-mead-bnd'}; if any(strcmp(fitParams.algorithm,algorithmsWithConstraints)) % if constraints allowed then allow user to adjust them here (if they set defaultConstraints) if isfield(fitParams,'defaultConstraints') && ~fitParams.defaultConstraints @@ -302,7 +306,8 @@ % optimization parameters if ~isfield(fitParams,'algorithm') || isempty(fitParams.algorithm) - fitParams.algorithm = 'nelder-mead'; + fitParams.algorithm = 'nelder-mead-bnd'; + disp('(pRFFit) No algorithm provided. Using Default: Nelder-Mead-Bnd'); end fitParams.optimParams = optimset('MaxIter',inf,'Display',fitParams.optimDisplay); @@ -396,7 +401,7 @@ end % for nelder-mead just compute correlation and return 1-4 -if strcmp(lower(fitParams.algorithm),'nelder-mead') +if strcmp(lower(fitParams.algorithm),'nelder-mead') || strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') residual = -corr(modelResponse,tSeries); % disp(sprintf('(pRFFit:getModelResidual) r: %f',residual)); end @@ -540,7 +545,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs', 'gaussian-divs', 'gaussian-DoG-CSS'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); @@ -559,8 +564,12 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) output = pRF_gaussianhdr(varargin{:}); case 'gaussian-diffs' output = pRF_diffGaussian(varargin{:}); - otherwise - testModel = @pRF_exp; %%% Only need to change this line to specify a new model. + case 'gaussian-divs' + output = pRF_divGaussian(varargin{:}); + case 'gaussian-exp' + output = pRF_exp(varargin{:}); + otherwise % 'gaussian-DoG-CSS' + testModel = @pRF_DoG_CSS; %%% Only need to change this line to specify a new model. output = testModel(varargin{:}); end diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index afa44e70a..703fc162e 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,9 +116,9 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs', 'gaussian-divs', 'gaussian-DoG-CSS'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians. gaussian-divs takes the quotient of center and surround gaussians.'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; -paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; +paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt', 'nelder-mead-bnd'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; paramsInfo{end+1} = {'prefitOnly',false,'type=checkbox','Check this if you want to ONLY do a prefit and not optimize further. The prefit computes a preset set of model parameters (x,y,rfHalfWidth) and picks the one that produces a mdoel with the highest correlation with the time series. You may want to do this to get a quick but accurate fit so that you can draw a set of ROIs for a full analysis'}; paramsInfo{end+1} = {'quickPrefit',false,'type=checkbox','Check this if you want to do a quick prefit - this samples fewer x,y and rfWidth points. It is faster (especially if coupled with prefitOnly for a fast check), but the optimization routines may be more likely to get trapped into local minima or have to search a long time for the minimum'}; diff --git a/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m b/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m new file mode 100644 index 000000000..d0407f21b --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m @@ -0,0 +1,135 @@ +% pRF_DoG_CSS.m +% +% $Id:$ +% usage: pRF_DoG_CSS(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Model of Difference of Gaussians with Compressive Static Non linearity +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_DoG_CSS(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % and convolve in time. + pPlus = convolveModelResponseWithHRF(rPlus,hrf); + pMinus = convolveModelResponseWithHRF(rMinus,hrf); + + % Model response is the difference of Gaussians, weighted by Beta amplitudes + thisModelResponse = power(pPlus*p.B1 + pMinus*p.B2, p.exp); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude', 'exponent'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian', 'Exponent static nonlinearity'}; + fitParams.paramIncDec = [1 1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0 -inf -5]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf 0 5]; + fitParams.initParams = [0 0 4 4 1 0 1]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.std2 = params(4); + p.B1 = params(5); + p.B2 = params(6); + p.exp = params(7); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m new file mode 100644 index 000000000..634aa0a81 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m @@ -0,0 +1,135 @@ +% pRF_divGaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_divGaussian(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*((p.std*p.stdRatio)^2))+((fitParams.stimY-p.y).^2)/(2*((p.std*p.stdRatio)^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + + % Convolve model with stimulus + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % Apply divisive normalization + resp = p.b1*rPlus ./ (1 + p.b2*rMinus); + + % Convolve response with hemodynamic response function + thisModelResponse = convolveModelResponseWithHRF(resp, hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf -inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 -inf -inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; + fitParams.initParams = [0 0 4 2 1 1]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.stdRatio = params(4); + p.b1 = params(5); + p.b2 = params(6); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From 0c4058f8fffb639224875722ec5c8b751c5eb078 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Wed, 25 Jan 2017 03:49:40 -0800 Subject: [PATCH 16/44] Adding pRFSimulate script --- mrLoadRet/Plugin/pRF/pRFSimulate.m | 206 +++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/pRFSimulate.m diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m new file mode 100644 index 000000000..b54d9acf8 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFSimulate.m @@ -0,0 +1,206 @@ +% pRFSimulate +% +% simulates N v1 voxels given 2 rf types and outputs expected time series given stimImage +% +% - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) +% - numVox: number of voxels we want to simulate +% +function [simulation, fits_gauss,fits_norm, r2_gauss, r2_norm] = pRFSimulate(stim) + +% stimImage = stim.im; +% numVols = size(stimImage, 2); +% [myscreen, stimImage] = +modelType = 'gaussian-divs'; +plotFigs = 0; + +%%% Preset Model Parameters %%% +modelParams.rfRatio = 0.1; +modelParams.normRatio = 1.5; % set norm pool width to be 1.5x the rf width +modelParams.cssExp = 0.75; +modelParams.noiseAmplitude = 0.1; + +% Get canonical hemodynamic response function +hrf = getCanonicalHRF(); + +%%% Create voxels in simulation +% Num voxels: 196 --> same as in prefit +xVals = -32.5:5:32.5; xVals = repmat(xVals, 1, 14); +yVals = -32.5:5:32.5; yVals = repmat(yVals, 14, 1); yVals = yVals(:); + +if(length(xVals) == length(yVals)) + numVox = length(xVals); + disp(sprintf('Number of voxels in simulation: %d', numVox)); +end +if(plotFigs == 1); plot(xVals, yVals, '*'); end + +simulation = []; +for i=1:numVox + + x_sim = xVals(i); y_sim = yVals(i); + eccentricity = sqrt(x_sim^2 + y_sim^2); + rfWidth = modelParams.rfRatio*eccentricity; + + % Calculate the Gaussian-derived RF from Dumoulin & Wandell 2008 + rfModel = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(rfWidth^2))); + if(mod(i,10)==0 && plotFigs == 1) + disp(i); figure; + subplot(1,2,1); plot(x_sim, y_sim, '*'); xlim([-50,50]); ylim([-50,50]); + subplot(1,2,2); imagesc(rfModel'); axis xy; xlim([0,192]); ylim([0,108]); + end + + % Calculate simulated time series using the Ratio-of-Gaussians model + resp = convolveModelWithStimulus(rfModel, stim.im); + suppFieldWidth = modelParams.normRatio*rfWidth; + beta1 = 1; beta2 = 1; + % Calculate suppressive field model + rfModel2 = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(suppFieldWidth^2))); + resp2 = convolveModelWithStimulus(rfModel2, stim.im); + % Estimate model response as the ratio of the 2 gaussian RF + modelResponse = beta1*resp ./ (1 + beta2*resp2); + + % Convolve with HRF + modelHRF = convolveModelResponseWithHRF(modelResponse, hrf); + + % Then add white noise and save the simulated time series data. + simulation(i,:) = addWhiteNoise(modelHRF, modelParams.noiseAmplitude); + %noiseless(i,:) = modelHRF; + %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); + %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); + %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); +end + +%%% To Do: +% 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) +% a. DONE -- figure out why mglDoubleBars framegrab is acting up. +% 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels +% -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); +% so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 + +%%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' 'pRF_v1.mat']); +analParams = v.analyses{1}.params; +analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 +analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing +analParams.pRFFit.prefitOnly=1; +analParams2 = analParams; +analParams2.pRFFit.rfType='gaussian-divs'; +d = viewGet(v, 'd', analParams.scanNum); +concatInfo = viewGet(v, 'concatInfo', 1); +v = newView; + +stimA{1} = stim; +numVoxels = numVox; + +% Compute prefit for all voxels +disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); +for i = 1:numVoxels + tSeries = applyConcatFiltering(simulation(i,:), concatInfo); + disp(sprintf('Voxel %d', i)); + + % Run for gaussian model + fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); + r2_gauss(i) = fit.r2; + fits_gauss{i} = fit; + + % Run for normalization model + fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); + r2_norm(i) = fit2.r2; + fits_norm{i} = fit2; + disppercent(i/numVoxels); +end +disppercent(inf); +disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); + +%keyboard + +return + +%% Do full pRFFits +%for i = 1:numVoxels +% fit = pRFFit(v, [], [], [], [], 'fitTypeParams', analParams.pRFFit, 'returnPrefit', true); +% keyboard +% modelFit1(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian',... +% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); +% modelFit2(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian_divs',... +% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); +%end + +%-------------------------------------------- +% addWhiteNoise +% adds gaussian white noise to the signal +function response = addWhiteNoise(signal, noiseAmplitude) +response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); + +%---------------------------------------------- +% getCanonicalHRF +% Gets the canonical hrf given params and sample rate +function hrf = getCanonicalHRF() + +offset = 0; +timelag = 1; +tau = 0.6; +exponent = 6; +sampleRate = 0.5; +amplitude = 1; + +hrf.time = 0:sampleRate:25; + +exponent = round(exponent); +gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); +gammafun(find((hrf.time-timelag) <0)) = 0; + +if (max(gammafun)-min(gammafun))~=0 + gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); +end +gammafun = (amplitude*gammafun+offset); + +hrf.hrf = gammafun; +hrf.hrf = hrf.hrf / max(hrf.hrf); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ~~~ convolveModelWithStimulus ~~~ %% + +function modelResponse = convolveModelWithStimulus(rfModel, stim) + +nStimFrames = size(stim, 3); +modelResponse = zeros(1,nStimFrames); +for frameNum = 1:nStimFrames + modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% convolveModelResponseWithHRF %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + +%--------------------------------------- +% applyConcatFiltering +% applies detrending, hipassfilter, projection, removes mean. +%---------------------------------------- +function tSeries = applyConcatFiltering(tSeries, concatInfo) +runnum=1; + +tSeries = tSeries(:); + +% apply detrending +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +% project out the mean vector From ec6a1f2737a28fa6ec993f6e4ebe64587d71d762 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 3 Feb 2017 21:27:16 -0800 Subject: [PATCH 17/44] Adding analysis script and updating simulator --- mrLoadRet/Plugin/pRF/pRFSimulate.m | 61 +++--- mrLoadRet/Plugin/pRF/plotFig.m | 336 +++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+), 28 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/plotFig.m diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m index b54d9acf8..a2b55b230 100644 --- a/mrLoadRet/Plugin/pRF/pRFSimulate.m +++ b/mrLoadRet/Plugin/pRF/pRFSimulate.m @@ -5,7 +5,7 @@ % - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) % - numVox: number of voxels we want to simulate % -function [simulation, fits_gauss,fits_norm, r2_gauss, r2_norm] = pRFSimulate(stim) +function [sim, fits_gauss,fits_norm] = pRFSimulate(stim) % stimImage = stim.im; % numVols = size(stimImage, 2); @@ -34,6 +34,7 @@ if(plotFigs == 1); plot(xVals, yVals, '*'); end simulation = []; +disppercent(-inf, sprintf('Creating simulation receptive fields for %d voxels', numVox)); for i=1:numVox x_sim = xVals(i); y_sim = yVals(i); @@ -67,7 +68,13 @@ %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); + + disppercent(i/numVox); end +disppercent(inf); +sim.x = xVals; sim.y = yVals; +sim.rfWidth = rfWidth; +sim.tSeries = simulation; %%% To Do: % 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) @@ -75,7 +82,6 @@ % 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels % -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); % so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 - %%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); @@ -83,7 +89,7 @@ analParams = v.analyses{1}.params; analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing -analParams.pRFFit.prefitOnly=1; +analParams.pRFFit.prefitOnly=0; analParams2 = analParams; analParams2.pRFFit.rfType='gaussian-divs'; d = viewGet(v, 'd', analParams.scanNum); @@ -92,23 +98,21 @@ stimA{1} = stim; numVoxels = numVox; +%numVoxels = 20; % Compute prefit for all voxels disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); for i = 1:numVoxels tSeries = applyConcatFiltering(simulation(i,:), concatInfo); - disp(sprintf('Voxel %d', i)); - + sim.filteredTSeries(i,:) = tSeries; % Run for gaussian model fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); - r2_gauss(i) = fit.r2; fits_gauss{i} = fit; % Run for normalization model fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); - r2_norm(i) = fit2.r2; fits_norm{i} = fit2; - disppercent(i/numVoxels); + disppercent(i/numVoxels, sprintf('Voxel %d', i)); end disppercent(inf); disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); @@ -117,25 +121,20 @@ return -%% Do full pRFFits -%for i = 1:numVoxels -% fit = pRFFit(v, [], [], [], [], 'fitTypeParams', analParams.pRFFit, 'returnPrefit', true); -% keyboard -% modelFit1(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian',... -% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); -% modelFit2(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian_divs',... -% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); -%end - -%-------------------------------------------- +%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%---------------------------------------- % addWhiteNoise % adds gaussian white noise to the signal +%--------------------------------------- function response = addWhiteNoise(signal, noiseAmplitude) response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); -%---------------------------------------------- -% getCanonicalHRF +%--------------------------------------- +% getCanonicalHRF % Gets the canonical hrf given params and sample rate +%--------------------------------------- function hrf = getCanonicalHRF() offset = 0; @@ -159,9 +158,10 @@ hrf.hrf = gammafun; hrf.hrf = hrf.hrf / max(hrf.hrf); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% ~~~ convolveModelWithStimulus ~~~ %% - +%--------------------------------------- +% convolveModelWithStimulus +% convolve the model response with the stimulus +%---------------------------------------- function modelResponse = convolveModelWithStimulus(rfModel, stim) nStimFrames = size(stim, 3); @@ -170,10 +170,10 @@ modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% convolveModelResponseWithHRF %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +%--------------------------------------- +% convolveModelResponseWithHRF +% convolve the model response with the HRF +%---------------------------------------- function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) n = length(modelTimecourse); @@ -204,3 +204,8 @@ end % project out the mean vector + +% remove the mean +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +%tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m new file mode 100644 index 000000000..d9862c7d2 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/plotFig.m @@ -0,0 +1,336 @@ +% plotFig +% +% does analysis given struct of fits for two models +% - fitsGauss, fitsNorm: struct +% +% +function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) + +if any(num==1) % draw true rf's + dispTrueRFs = 1; +end +if any(num==1.5) + linkRFs = 1; +end +if any(num==2) % draw model predicted rf's + dispModelRFs = 1; +end +if any(num==3) + dispModelR2 = 1; +end +if any(num==4) + drawR2 = 1; +end +if any(num==5) + dispBestModelResponse = 1; +end +if any(num==6) + dispSuppFieldSize = 1; +end +if any(num==7) + dispWorstModelResponse = 1; +end + +paramsG = getFieldArrFromStruct(fitsGauss, 'params'); +paramsN = getFieldArrFromStruct(fitsNorm, 'params'); +r2G = getFieldArrFromStruct(fitsGauss, 'r2'); +r2N = getFieldArrFromStruct(fitsNorm, 'r2'); + +if ~ieNotDefined('dispTrueRFs') + figure; + for i = 1:196 + simRFWidth = sqrt(sim.x(i)^2 + sim.y(i)^2)*0.1; + circle(sim.x(i), sim.y(i), simRFWidth, 'b'); hold on; + text(sim.x(i), sim.y(i), num2str(i)); + end + title('True Voxel Receptive Fields (Simulation)'); + hline(0, ':'); vline(0,':'); + +end +if ~ieNotDefined('linkRFs') + figure; + plot(sim.x, sim.y, '*k'); hold on; + plot(paramsG(:,1), paramsG(:,2), '*b'); hold on + for i = 1:196 + plot([paramsG(i,1); sim.x(i)], [paramsG(i,2); sim.y(i)], 'k'); hold on + end + legend('True RFs', 'Gaussian RFs'); + title('Mapping of Gaussian Model RFs to true RFs'); hline(0,':'); vline(0,':'); + + figure; + plot(sim.x, sim.y, '*k'); hold on; + plot(paramsN(:,1), paramsN(:,2), '*g'); hold on + for i = 1:196 + plot([paramsN(i,1); sim.x(i)], [paramsN(i,2); sim.y(i)], 'k'); hold on + end + legend('True RFs', 'Normalization RFs'); + title('Mapping of Normalization Model RFs to true RFs'); hline(0,':'); vline(0,':'); +end +if ~ieNotDefined('dispModelRFs') + figure; + for i = 1:196 + rfWidth = sqrt(paramsG(i,1)^2 + paramsG(i,2)^2)*0.1; + circle(paramsG(i,1), paramsG(i,2), paramsG(i,3), 'b'); hold on; + text(paramsG(i,1), paramsG(i,2), num2str(i)); + end + title('Gaussian Model Predicted Receptive Fields'); + hline(0, ':'); vline(0,':'); + + figure; + for i = 1:196 + rfWidth = sqrt(paramsN(i,1)^2 + paramsN(i,2)^2)*0.1; + circle(paramsN(i,1), paramsN(i,2), paramsN(i,3), 'b'); + circle(paramsN(i,1), paramsN(i,2), paramsN(i,3)*paramsN(i,4), 'g'); + text(paramsN(i,1), paramsN(i,2), num2str(i)); + end + title('Normalization Model Predicted Receptive & Suppressive Fields'); + hline(0,':'), vline(0,':'); +end +if ~ieNotDefined('dispModelR2') + % Plot model RF predictions colored by r2 + figure; + scatter(paramsG(:,1), paramsG(:,2), 20, r2G); + title('Gaussian model RF predictions, colored by R2'); + hline(0,':'); vline(0,':'); colorbar; + + figure; + scatter(paramsN(:,1), paramsN(:,2), 20, r2N); + title('Normalization model RF predictions, colored by R2'); + hline(0,':'); vline(0,':'); colorbar; +end +if ~ieNotDefined('drawR2') + % Draw R2 by voxel for each model + figure; + plot(r2G, 'b'); hold on; plot(r2N, 'g'); + title('Model r2 plotted by voxel'); + xlabel('Voxel Number'); ylabel('R-squared'); +end +if ~ieNotDefined('dispBestModelResponse') || ~ieNotDefined('dispWorstModelResponse') + if ieNotDefined('stim') || ieNotDefined('concatInfo') + disp('Either stimulus or concatInfo not provided. Quitting...'); + return + end + + [bestR2N bestVoxN] = max(r2N); bestN = fitsNorm{bestVoxN}; + [bestR2G bestVoxG] = max(r2G); bestG = fitsGauss{bestVoxG}; + + G = @(x,y,sigma) exp(-(((stim.x - x).^2) + ((stim.y - y).^2))/(2*sigma^2)); + respNorm = @(c, x, y, sigma, stdRatio, b1, b2) (b1*c*G(x,y,sigma))./(1+ b2*c*G(x,y,stdRatio*sigma)); + Rx = 0:.05:1; + Ry = []; + + modelResponseG = []; + modelResponseN = []; + tSeries = []; + hrf = getCanonicalHRF(); + disppercent(-inf, 'Computing model response based on model params for 196 voxels'); + for i = 1:196 + gParams(i,:) = fitsGauss{i}.params; + rfModel = exp(-(((stim.x - gParams(i,1)).^2) + ((stim.y - gParams(i,2)).^2))/(2*(gParams(i,3)^2))); + rfModel = convolveModelWithStimulus(rfModel, stim.im); + modelGwithHRF = convolveModelResponseWithHRF(rfModel, hrf); + modelResponseG(i,:) = applyConcatFiltering(modelGwithHRF/std(modelGwithHRF), concatInfo); + + nParams(i,:) = fitsNorm{i}.params; + rfModel = exp(-(((stim.x - nParams(i,1)).^2) + ((stim.y - nParams(i,2)).^2))/(2*(nParams(i,3)^2))); + rfModel = convolveModelWithStimulus(rfModel, stim.im); + rfModel2 = exp(-(((stim.x - nParams(i,1)).^2) + ((stim.y-nParams(i,2)).^2))/(2*((nParams(i,4)*nParams(i,3))^2))); + rfModel2 = convolveModelWithStimulus(rfModel2, stim.im); + modelNwithHRF = convolveModelResponseWithHRF((nParams(i,5)*rfModel)./(nParams(i,6)*rfModel2), hrf); + modelResponseN(i,:) = applyConcatFiltering(modelNwithHRF, concatInfo); + + tSeries(i,:) = applyConcatFiltering(sim.tSeries(i,:), concatInfo); + disppercent(i/196); + end + disppercent(inf); + + if ~ieNotDefined('dispBestModelResponse') + figure; + plot(sim.filteredTSeries(bestVoxN,:), 'k'); hold on; + plot(modelResponseN(bestVoxN,:), 'g'); hold on; + plot(modelResponseG(bestVoxN,:), 'b'); + title('Model response and true time series for well-fit voxel'); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization', 'gaussian'); + end + if ~ieNotDefined('dispWorstModelResponse') + figure; + plot(sim.filteredTSeries(194,:), 'k'); hold on; + plot(modelResponseN(194,:), 'g'); hold on; + title(sprintf('Voxel 194 model response vs time series (R2: %d)', r2N(194))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + + figure; + plot(sim.filteredTSeries(189,:), 'k'); hold on; + plot(modelResponseN(189,:), 'g'); hold on; + title(sprintf('Voxel 189 model response vs time series (R2:%d)', r2N(189))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + + figure; + plot(sim.filteredTSeries(1,:), 'k'); hold on; + plot(modelResponseN(1,:), 'g'); hold on; + title(sprintf('Voxel 1 model response vs time series (R2:%d)', r2N(1))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + end +end +if ~ieNotDefined('dispSuppFieldSize') + + figure; + rfWidthN = paramsN(:,3); + suppWidthN = paramsN(:,4).*rfWidthN; + eccN = sqrt(paramsN(:,1).^2 + paramsN(:,2).^2); + plot(eccN, suppWidthN, '*g'); hold on; + fit = polyfit(eccN, suppWidthN, 1); + line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccN)], [line(min(eccN)) line(max(eccN))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between suppressive field size and eccentricity'); + xlabel('Eccentricity'); ylabel('Suppressive field width'); + + figure; + plot(eccN, rfWidthN, '*g'); hold on; + fit = polyfit(eccN, rfWidthN, 1); line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccN)], [line(min(eccN)) line(max(eccN))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between RF field size and eccentricity (normalization model)'); + xlabel('Eccentricity'); ylabel('RF Field Width'); + + figure; + eccG = sqrt(paramsG(:,1).^2 + paramsG(:,2).^2); + rfWidthG = paramsG(:,3); + plot(eccG, rfWidthG, '*b'); hold on; + fit = polyfit(eccG, rfWidthG, 1); line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccG)], [line(min(eccG)) line(max(eccG))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between RF field size and eccentricity (gaussian model)'); + xlabel('Eccentricity'); ylabel('RF Field Width'); + + keyboard +end +if num == -1 + %%%% + % Plot model RFs and true RFs using circle tool + f = figure; + for i = 1:196 + %% Plot true RF's + plot(sim.x(i), sim.y(i), '*r', 'MarkerSize', 10); hold on; + %simRFWidth = sqrt(sim.x(i)^2 + sim.y(i)^2)*0.1; + %circle(sim.x(i), sim.y(i), simRFWidth, 'r'); hold on; + + %% Plot gaussian model RF's + fit = fitsGauss{i}; + %circle(fit.x, fit.y, fit.std, 'b'); + + %% Plot normalization model rf's + fit2 = fitsNorm{i}; + circle(fit2.x, fit2.y, fit2.std, 'g'); + circle(fit2.x, fit2.y, fit2.params(4)*fit2.std, 'c') + + %% Plot Lines connecting model rf center to true rf center + %plot([fit.x; sim.x(i)], [fit.y; sim.y(i)],'-b','MarkerSize',3); hold on + plot([fit2.x; sim.x(i)], [fit2.y; sim.y(i)], '-g', 'MarkerSize', 3); hold on + end + xlim([-100 100]); ylim([-100 100]); +end + +return + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%-------------------------------------- +% getFieldArrFromStruct(structure, fieldNameStr, +%-------------------------------------- +function fieldArray = getFieldArrFromStruct(structure, fieldNameStr) + +fieldArray = []; +for i = 1:length(structure) + fieldArray(i,:) = structure{i}.(fieldNameStr); +end + +%--------------------------------------- +% circle +% draw a circle given center (x,y), radius and color +%---------------------------------------- +function circle(x,y,r, color) +%x and y are the coordinates of the center of the circle +%r is the radius of the circle +%0.01 is the angle step, bigger values will draw the circle faster but +%you might notice imperfections (not very smooth) +ang=0:0.01:2*pi; +xp=r*cos(ang); +yp=r*sin(ang); +plot(x+xp,y+yp, color, 'MarkerSize', 4); +hold on + + +%--------------------------------------- +% getCanonicalHRF() +% get the canonical hemodnamic response function +%---------------------------------------- +function hrf = getCanonicalHRF() +offset = 0; +timelag = 1; +tau = 0.6; +exponent = 6; +sampleRate = 0.5; +amplitude = 1; +hrf.time = 0:sampleRate:25; + +exponent = round(exponent); +gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); +gammafun(find((hrf.time-timelag) <0)) = 0; + +if (max(gammafun)-min(gammafun))~=0 + gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); +end +gammafun = (amplitude*gammafun+offset); + +hrf.hrf = gammafun; +hrf.hrf = hrf.hrf / max(hrf.hrf); + + +%--------------------------------------- +% convolveModelWithStimulus +% convolve the model response with the stimulus +%---------------------------------------- +function modelResponse = convolveModelWithStimulus(rfModel, stim) +nStimFrames = size(stim, 3); +modelResponse = zeros(1,nStimFrames); +for frameNum = 1:nStimFrames + modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); +end + +%--------------------------------------- +% convolveModelResponseWithHRF +% convolve the model response with the HRF +%---------------------------------------- +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + +%--------------------------------------- +% applyConcatFiltering +% applies detrending, hipassfilter, projection, removes mean. +%---------------------------------------- +function tSeries = applyConcatFiltering(tSeries, concatInfo) +runnum=1; +tSeries = tSeries(:); + +% apply detrending + +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); +tSeries = tSeries(:)'; From 7317239833ecb8aa74cc64b16af6b7db2231e4af Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 23 Feb 2017 13:14:17 -0800 Subject: [PATCH 18/44] Making changes to get pRF to run with double bars --- mrLoadRet/Plugin/pRF/pRFFit.m | 22 ++++++++++++++----- .../Plugin/pRF/pRFGetStimImageFromStimfile.m | 12 +++++++--- mrLoadRet/Plugin/pRF/pRF_divGaussian.m | 2 +- mrLoadRet/Plugin/pRF/plotFig.m | 20 +++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index f57fa049d..8fa36859d 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -54,7 +54,6 @@ fit = fitParams.stim; return end - % get the tSeries if ~isempty(x) % if tSeries was not passed in then load it @@ -67,7 +66,7 @@ % but useful for raw/motionCorrected time series. Also, it is very important that % the tSeries is properly mean subtracted if ~isfield(fitParams.concatInfo,'hipassfilter') - tSeries = percentTSeries(tSeries,'detrend','Linear','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); + tSeries = percentTSeries(tSeries,'detrend','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); end % if there are any nans in the tSeries then don't fit @@ -80,7 +79,6 @@ else tSeries = []; end - % handle junk frames (i.e. ones that have not already been junked) if ~isempty(fitParams.junkFrames) && ~isequal(fitParams.junkFrames,0) % drop junk frames @@ -143,7 +141,9 @@ if ~isfield(fitParams.prefit,'modelResponse') % get number of workers nProcessors = mlrNumWorkers; - disppercent(-inf,sprintf('(pRFFit) Computing %i prefit model responses using %i processors',fitParams.prefit.n,nProcessors)); + if fitParams.verbose==1 + disppercent(-inf,sprintf('(pRFFit) Computing %i prefit model responses using %i processors',fitParams.prefit.n,nProcessors)); + end % first convert the x/y and width parameters into sizes % on the actual screen fitParams.prefit.x = fitParams.prefit.x*fitParams.stimWidth; @@ -184,10 +184,13 @@ if fitParams.prefitOnly % return if we are just doing a prefit fit = getFitParams(fitParams.initParams,fitParams); + fit.modelResponse = fitParams.prefit.modelResponse; + fit.tSeries = tSeries; fit.rfType = fitParams.rfType; fit.params = fitParams.initParams; fit.r2 = maxr^2; fit.r = maxr; + fit.bestFitVoxel = bestModel; [fit.polarAngle fit.eccentricity] = cart2pol(fit.x,fit.y); % display if fitParams.verbose @@ -298,7 +301,9 @@ end else % no constraints allowed - disp(sprintf('(pRFFit) !!! Fit constraints ignored for algorithm: %s (if you want to constrain the fits, then use: %s) !!!',fitParams.algorithm,cell2mat(algorithmsWithConstraints))); + if fitParams.verbose==1 + disp(sprintf('(pRFFit) !!! Fit constraints ignored for algorithm: %s (if you want to constrain the fits, then use: %s) !!!',fitParams.algorithm,cell2mat(algorithmsWithConstraints))); + end end end @@ -350,6 +355,11 @@ thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, p, i); %%%%%%%%%%%%%%%%%%% + %~~~~~~~~~~ + %keyboard + %~~~~~~~~~~ + + % apply concat filtering if isfield(fitParams,'applyFiltering') && fitParams.applyFiltering thisModelResponse = applyConcatFiltering(thisModelResponse,fitParams.concatInfo,i); @@ -478,7 +488,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m index bba7b545b..baba6ea08 100644 --- a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m +++ b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m @@ -451,7 +451,7 @@ % have a task which is mglRetinotopy taskNum = []; for iTask = 1:2 - if (length(thiss.task) >= iTask) && (isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename,'gruRetinotopy.m')) + if (length(thiss.task) >= iTask) && (isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename,'gruRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename, 'mglDoubleBars.m')) taskNum = iTask; end end @@ -467,7 +467,7 @@ if ~isfield(thiss.task{taskNum}{1},'randVars') missing = 'randVars';end if ~isfield(thiss.task{taskNum}{1},'parameter') missing = 'parameter';end if ~any(strcmp('maskPhase',thiss.myscreen.traceNames)) missing = 'maskPhase';end - if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end + %if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end if ~isempty(missing) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) Stimfile: %s',dispstr)); disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) The stimfile does not appear to have been created by the latest version of mglRetinotopy which contains the field %s necessary for reconstructing the stimulus. Consider running a dummy run with a newer version of mglRetinotpy with the same parameters (see mglSimulateRun to simulate backticks) and then use that stimfile instead of this one.',missing)); @@ -480,6 +480,9 @@ % now check for each variable that we need varnames = {'blank'}; + if isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') % mglDoubleBars doesn't use blanks + varnames = {}; + end for i = 1:length(varnames) varval = getVarFromParameters(varnames{i},e); if isempty(varval) @@ -494,12 +497,15 @@ if ~isempty(stimulusType) && (stimulusType ~= thiss.stimulusType) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! Have you averaged together scans with different stimulus conditions?')); end - if any(thiss.stimulus.stimulusType == [3 4]) + if ~isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') && any(thiss.stimulus.stimulusType == [3 4]) varval = getVarFromParameters('barAngle',e); if ~isempty(barAngle) && ~isequal(varval,barAngle) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! The barAngles are different! Have you averaged together scans with different stimulus conditions?')); end barAngle = varval; + elseif isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') + varval = getVarFromParameters('conditionNum', e); + barAngle = thiss.stimulus.conditions(varval, 3:4); else if ~isempty(direction) && (thiss.stimulus.direction ~= direction) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! The directions are different! Have you averaged together scans with different stimulus conditions?')); diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m index 634aa0a81..2cdac8a8e 100644 --- a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m @@ -117,7 +117,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m index d9862c7d2..055b3dcef 100644 --- a/mrLoadRet/Plugin/pRF/plotFig.m +++ b/mrLoadRet/Plugin/pRF/plotFig.m @@ -30,12 +30,32 @@ function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) if any(num==7) dispWorstModelResponse = 1; end +if any(num==8) + drawR2excludingoffscreen = 1; +end paramsG = getFieldArrFromStruct(fitsGauss, 'params'); paramsN = getFieldArrFromStruct(fitsNorm, 'params'); r2G = getFieldArrFromStruct(fitsGauss, 'r2'); r2N = getFieldArrFromStruct(fitsNorm, 'r2'); +if ~ieNotDefined('drawR2excludingoffscreen') + xMin = min(stim.x(:)); + xMax = max(stim.x(:)); + yMin = min(stim.y(:)); + yMax = max(stim.y(:)); + r2g_1 = []; r2n_1 = []; + for i = 1:196 + if fitsGauss{i}.x > xMin && fitsGauss{i}.x < xMax && fitsGauss{i}.y > yMin && fitsGauss{i}.y xMin && fitsNorm{i}.x < xMax && fitsNorm{i}.y > yMin && fitsNorm{i}.y Date: Sun, 5 Mar 2017 15:09:37 -0800 Subject: [PATCH 19/44] temp commit --- mrLoadRet/Plugin/pRF/pRFFit.m | 1 + mrLoadRet/Plugin/pRF/pRF_gaussian.m | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 8fa36859d..d68ee4f9a 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -236,6 +236,7 @@ elseif fitParams.verbose disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f', fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); end +%keyboard %%%%%%%%%%%%%%%%%%%%%% % setFitParams % diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 07cef5144..698e30c26 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -107,7 +107,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel From 151ed67f12b843fa341704e40212b5043133322e Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 10 Mar 2017 14:21:09 -0800 Subject: [PATCH 20/44] Reorganizing git directories. Moving models into models folder and moved normalization related scripts to its own git repository --- .../pRF/{ => models}/pRFModelTemplate.m | 0 .../Plugin/pRF/{ => models}/pRF_DoG_CSS.m | 0 .../pRF/{ => models}/pRF_diffGaussian.m | 0 .../Plugin/pRF/{ => models}/pRF_divGaussian.m | 23 +- mrLoadRet/Plugin/pRF/{ => models}/pRF_exp.m | 3 +- .../Plugin/pRF/{ => models}/pRF_gaussian.m | 4 +- .../Plugin/pRF/{ => models}/pRF_gaussianhdr.m | 0 mrLoadRet/Plugin/pRF/pRFCrossVal.m | 263 ------------- mrLoadRet/Plugin/pRF/pRFSimulate.m | 211 ----------- mrLoadRet/Plugin/pRF/plot2voxels.m | 220 ----------- mrLoadRet/Plugin/pRF/plotFig.m | 356 ------------------ mrLoadRet/Plugin/pRF/predictStimulus.m | 101 ----- 12 files changed, 17 insertions(+), 1164 deletions(-) rename mrLoadRet/Plugin/pRF/{ => models}/pRFModelTemplate.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_DoG_CSS.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_diffGaussian.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_divGaussian.m (87%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_exp.m (95%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_gaussian.m (94%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_gaussianhdr.m (100%) delete mode 100644 mrLoadRet/Plugin/pRF/pRFCrossVal.m delete mode 100644 mrLoadRet/Plugin/pRF/pRFSimulate.m delete mode 100644 mrLoadRet/Plugin/pRF/plot2voxels.m delete mode 100644 mrLoadRet/Plugin/pRF/plotFig.m delete mode 100644 mrLoadRet/Plugin/pRF/predictStimulus.m diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/models/pRFModelTemplate.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRFModelTemplate.m rename to mrLoadRet/Plugin/pRF/models/pRFModelTemplate.m diff --git a/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m b/mrLoadRet/Plugin/pRF/models/pRF_DoG_CSS.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m rename to mrLoadRet/Plugin/pRF/models/pRF_DoG_CSS.m diff --git a/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_diffGaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m similarity index 87% rename from mrLoadRet/Plugin/pRF/pRF_divGaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m index 2cdac8a8e..1e5b0c05c 100644 --- a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m @@ -41,13 +41,14 @@ rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); % Apply divisive normalization - resp = p.b1*rPlus ./ (1 + p.b2*rMinus); + resp = rPlus ./ (1 + p.b1*rMinus); % Convolve response with hemodynamic response function thisModelResponse = convolveModelResponseWithHRF(resp, hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); % return the calculated model response output = thisModelResponse; @@ -60,15 +61,15 @@ fitParams = varargin{2}; - fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; - fitParams.paramIncDec = [1 1 1 1 1 1]; - fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; - fitParams.paramMax = [inf inf inf inf inf -inf]; + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf]; + fitParams.paramMax = [inf inf inf inf -inf]; % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 -inf -inf]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; - fitParams.initParams = [0 0 4 2 1 1]; + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf]; + fitParams.initParams = [0 0 4 2 1]; % return fitParams with modified values output = fitParams; @@ -90,7 +91,7 @@ p.std = params(3); p.stdRatio = params(4); p.b1 = params(5); - p.b2 = params(6); + %p.b2 = params(6); % use a fixed single gaussian p.canonical.type = 'gamma'; p.canonical.lengthInSeconds = 25; diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/models/pRF_exp.m similarity index 95% rename from mrLoadRet/Plugin/pRF/pRF_exp.m rename to mrLoadRet/Plugin/pRF/models/pRF_exp.m index 99c4c5d48..35696a30f 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_exp.m @@ -44,7 +44,8 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); % return the calculated model response output = thisModelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m similarity index 94% rename from mrLoadRet/Plugin/pRF/pRF_gaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_gaussian.m index 698e30c26..b669a8b83 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m @@ -40,7 +40,9 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + %%%% Maybe uncomment this later: + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); % return the calculated model response output = thisModelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussianhdr.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m rename to mrLoadRet/Plugin/pRF/models/pRF_gaussianhdr.m diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m deleted file mode 100644 index 0ffe58f56..000000000 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ /dev/null @@ -1,263 +0,0 @@ -%% pRFCrossVal.m -%% -%% usage: fits = pRFCrossVal(newCoords, [], analysis) --> run on specified coordinates -%% fits = pRFCrossVal([], roiName, analysis) --> run on specified ROI -%% fits = pRFCrossVal('best', roiName, analysis) --> run on best N voxels in specified ROI -%% by: akshay jagadeesh -%% date: 10/04/16 -%% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF -%% analysis n times. It generates and saves time series, model response, residuals, and covariance -%% matrices for each fold. -%% We then calculate the probability that each point in the observed time series is predicted -%% by the pRF model response. -%% -%% -%% input: roiName - Name of the ROI we want to run this analysis on -%% analysis - Name of analysis file to load -%% - This must be the Concat of Average of N scans -%% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' - -function [fits, d] = pRFCrossVal(newCoords, roiName, analysis) - -%%%%%%% Default inputs %%%%%%%%% -newCoords = 'best'; -roiName = 'goodV1'; -analysis = 'pRF_gV1_RoG.mat'; % change to pRF_v1_DoG.mat to run for Diff of Gaussians model -nBest = 85; -plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots -%rfType = 'gaussian-exp'; -algorithm = 'nelder-mead-bnd'; - -% Set current group to Concat and load the Analysis file -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' analysis]); -analParams = v.analyses{1}.params; -analScanNum = analParams.scanNum; -rfType = analParams.pRFFit.rfType; -disp(sprintf('(pRFCrossVal) Using model %s, with fitting algorithm %s', rfType, algorithm)); - -ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan -osn = viewGet(v, 'originalscannum', analScanNum); -ogn2 = viewGet(v, 'originalgroupname', osn, ogn{1}); % Get the motioncomp scans -osn2 = viewGet(v, 'originalscannum', osn, ogn{1}); - -% Get analysis params for pRFFit -concatInfo = viewGet(v, 'concatinfo', analScanNum); -d = viewGet(v, 'd', analScanNum); -scanDims = viewGet(v, 'scanDims'); - -% Get the N original scans & their tSeries -if ~ieNotDefined('newCoords') - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); - if(strmatch(newCoords, 'best')) - disp(sprintf('(crossValidate) Getting %d best defined voxels in ROI %s', nBest, roiName)); - coords = getBestVoxels(v, analScanNum, nBest, roiName, analysis); - tempRoi.coords = coords; - else - disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); - tempRoi.coords = newCoords; - end - scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); -elseif ~ieNotDefined('roiName') - disp(sprintf('(crossValidate) Coordinates not given, getting tSeries for ROI %s', roiName)); - scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); -else - disp(sprintf('(crossValidate) Neither ROI name nor coordinates provided. Exiting.')); - return -end - -numFolds = length(scans); -for i=1:numFolds; - disp(sprintf('(crossValidate) Fold %d of %d', i, numFolds)); - % Initialize vars for use later - fit = []; - avg = zeros(size(scans{1}.tSeries)); - unfilteredLeftOut = scans{i}.tSeries; - numVoxels = size(unfilteredLeftOut, 1); - modelResponse = zeros(numVoxels, size(unfilteredLeftOut, 2)); - residual = zeros(numVoxels, size(unfilteredLeftOut, 2)); - - % compute average time series across N-1 scans - for j = 1:length(scans) - if i ~= j - avg = avg + scans{j}.tSeries; - end - end - avg = avg / (length(scans)-1); - - % Apply Concat Filtering to averages & left out - %keyboard - for k = 1:numVoxels - filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); - leftOut(k, :) = applyConcatFiltering(unfilteredLeftOut(k, :), concatInfo, 1); - end - - disppercent(-inf, sprintf('\t(crossVal) Fitting pRF to %d voxels', numVoxels)); - % run pRFFit on the averaged tSeries - coords = scans{i}.scanCoords.'; - for h = 1:numVoxels - x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); - linCoords = sub2ind(scanDims, x, y, z); - linVox = find(d.linearCoords == linCoords); - if isempty(linVox) - disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); - continue - end - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... - 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... - d.paramsInfo, 'concatInfo', concatInfo, 'rfType', rfType); - modelResponse(h, :) = modelFit.modelResponse; - residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - if strmatch(rfType, 'gaussian-diffs') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2]; - elseif strmatch(rfType, 'gaussian-exp') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.exp]; - elseif strmatch(rfType, 'gaussian-DoG-CSS') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2, modelFit.p.exp]; - else - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; - end - disppercent(h/numVoxels); - end - leftOut(all(modelResponse==0, 2), :) = []; - modelResponse(all(modelResponse==0, 2), :) = []; - residual(all(residual==0,2), :) = []; - numSuccess = size(modelResponse, 1); - disppercent(inf); - disp(sprintf('\t(crossVal) Successfully fit model to %d voxels', numSuccess)); - - %Calculate covariance matrix of voxels on our calculated residual - covMat = residual*residual'; - - % Compare model response to left-out timeseries - probTable = calcProb(leftOut, modelResponse, diag(diag(covMat))); - fit.modelResponse = modelResponse; - fit.residual = residual; - fit.leftOut = leftOut; - fit.covMat = covMat; - fit.probTable = probTable; - fit.fitParams = fitParams; - - eval(sprintf('fits(%d)=fit;', i)) - timeLen = size(fit.modelResponse, 2); - if ~ieNotDefined('plotFigs') - figure; - subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); - subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); hold on; - plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); - end - -end - -% Average across folds and store in fits struct array -fit = []; -fit.modelResponse = meanStruct(fits, 'modelResponse'); -fit.residual = meanStruct(fits, 'residual'); -fit.leftOut = meanStruct(fits, 'leftOut'); -fit.covMat = meanStruct(fits, 'covMat'); -fit.probTable = meanStruct(fits, 'probTable'); -fit.fitParams = meanStruct(fits, 'fitParams'); -fits(numFolds+1) = fit; -return - % -- end main program -- % - - -%%%%%%%%%%%%%%%%%%%%%% Helper Methods %%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% meanStruct % -% % -function avg = meanStruct(structArr, field, notI) - -if(ieNotDefined('notI')) - notI = -1; -else - disp(sprintf('Averaging across all but the %d th fold', notI)); -end -eval(sprintf('avg = zeros(size(structArr(1).%s));', field)); - -for i = 1:length(structArr) - if i~=notI - avg = avg + eval(sprintf('structArr(i).%s', field)); - end -end -avg = avg / length(structArr); - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% applyConcatFiltering % -% % -function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) - -tSeries = tSeries(:); - -% apply detrending -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -% project out the mean vector -if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) - projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; - tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; -end - -% now remove mean -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); -tSeries = tSeries(:)'; - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% getBestVoxels % -% % -function cords = getBestVoxels(v, scanNum, bestN, roiName, analysis) - -groupNum = viewGet(v, 'currentGroup'); -roi = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); - -r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); -roi = getSortIndex(v, roi, r2); - -% Get sort index based on r2 and list of linear coords -sortIndex = roi{1}.sortindex; -scanLinCoords = roi{1}.scanLinearCoords; -scanDims = viewGet(v, 'scanDims'); -% get the linear coords with highest sortIndex and convert to 3d coords -[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); -cords = [i;j;k;ones(1, bestN)]; - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% calcProb % - -function probTable = calcProb(testTSeries, modelResponse, covarMat) - -numTimePoints = size(modelResponse, 2); -probTable = zeros(numTimePoints, numTimePoints); - -disppercent(-inf, sprintf('\t(calcProb) Calculating prediction likelihoods')); -for i = 1:numTimePoints - model_i = modelResponse(:, i); - tSeries_i = testTSeries(:, i); - - for j = 1:numTimePoints - tSeries_j = testTSeries(:, j); - probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); - if probTable(j, i) == 0 - disp(sprintf('\n(calcProb) mvnpdf at index(%i, %i) returning 0; Exiting.', j, i)); - return; - end - end - disppercent(i/numTimePoints); -end -disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m deleted file mode 100644 index a2b55b230..000000000 --- a/mrLoadRet/Plugin/pRF/pRFSimulate.m +++ /dev/null @@ -1,211 +0,0 @@ -% pRFSimulate -% -% simulates N v1 voxels given 2 rf types and outputs expected time series given stimImage -% -% - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) -% - numVox: number of voxels we want to simulate -% -function [sim, fits_gauss,fits_norm] = pRFSimulate(stim) - -% stimImage = stim.im; -% numVols = size(stimImage, 2); -% [myscreen, stimImage] = -modelType = 'gaussian-divs'; -plotFigs = 0; - -%%% Preset Model Parameters %%% -modelParams.rfRatio = 0.1; -modelParams.normRatio = 1.5; % set norm pool width to be 1.5x the rf width -modelParams.cssExp = 0.75; -modelParams.noiseAmplitude = 0.1; - -% Get canonical hemodynamic response function -hrf = getCanonicalHRF(); - -%%% Create voxels in simulation -% Num voxels: 196 --> same as in prefit -xVals = -32.5:5:32.5; xVals = repmat(xVals, 1, 14); -yVals = -32.5:5:32.5; yVals = repmat(yVals, 14, 1); yVals = yVals(:); - -if(length(xVals) == length(yVals)) - numVox = length(xVals); - disp(sprintf('Number of voxels in simulation: %d', numVox)); -end -if(plotFigs == 1); plot(xVals, yVals, '*'); end - -simulation = []; -disppercent(-inf, sprintf('Creating simulation receptive fields for %d voxels', numVox)); -for i=1:numVox - - x_sim = xVals(i); y_sim = yVals(i); - eccentricity = sqrt(x_sim^2 + y_sim^2); - rfWidth = modelParams.rfRatio*eccentricity; - - % Calculate the Gaussian-derived RF from Dumoulin & Wandell 2008 - rfModel = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(rfWidth^2))); - if(mod(i,10)==0 && plotFigs == 1) - disp(i); figure; - subplot(1,2,1); plot(x_sim, y_sim, '*'); xlim([-50,50]); ylim([-50,50]); - subplot(1,2,2); imagesc(rfModel'); axis xy; xlim([0,192]); ylim([0,108]); - end - - % Calculate simulated time series using the Ratio-of-Gaussians model - resp = convolveModelWithStimulus(rfModel, stim.im); - suppFieldWidth = modelParams.normRatio*rfWidth; - beta1 = 1; beta2 = 1; - % Calculate suppressive field model - rfModel2 = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(suppFieldWidth^2))); - resp2 = convolveModelWithStimulus(rfModel2, stim.im); - % Estimate model response as the ratio of the 2 gaussian RF - modelResponse = beta1*resp ./ (1 + beta2*resp2); - - % Convolve with HRF - modelHRF = convolveModelResponseWithHRF(modelResponse, hrf); - - % Then add white noise and save the simulated time series data. - simulation(i,:) = addWhiteNoise(modelHRF, modelParams.noiseAmplitude); - %noiseless(i,:) = modelHRF; - %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); - %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); - %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); - - disppercent(i/numVox); -end -disppercent(inf); -sim.x = xVals; sim.y = yVals; -sim.rfWidth = rfWidth; -sim.tSeries = simulation; - -%%% To Do: -% 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) -% a. DONE -- figure out why mglDoubleBars framegrab is acting up. -% 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels -% -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); -% so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 -%%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' 'pRF_v1.mat']); -analParams = v.analyses{1}.params; -analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 -analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing -analParams.pRFFit.prefitOnly=0; -analParams2 = analParams; -analParams2.pRFFit.rfType='gaussian-divs'; -d = viewGet(v, 'd', analParams.scanNum); -concatInfo = viewGet(v, 'concatInfo', 1); -v = newView; - -stimA{1} = stim; -numVoxels = numVox; -%numVoxels = 20; - -% Compute prefit for all voxels -disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); -for i = 1:numVoxels - tSeries = applyConcatFiltering(simulation(i,:), concatInfo); - sim.filteredTSeries(i,:) = tSeries; - % Run for gaussian model - fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); - fits_gauss{i} = fit; - - % Run for normalization model - fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); - fits_norm{i} = fit2; - disppercent(i/numVoxels, sprintf('Voxel %d', i)); -end -disppercent(inf); -disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); - -%keyboard - -return - -%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%---------------------------------------- -% addWhiteNoise -% adds gaussian white noise to the signal -%--------------------------------------- -function response = addWhiteNoise(signal, noiseAmplitude) -response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); - -%--------------------------------------- -% getCanonicalHRF -% Gets the canonical hrf given params and sample rate -%--------------------------------------- -function hrf = getCanonicalHRF() - -offset = 0; -timelag = 1; -tau = 0.6; -exponent = 6; -sampleRate = 0.5; -amplitude = 1; - -hrf.time = 0:sampleRate:25; - -exponent = round(exponent); -gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); -gammafun(find((hrf.time-timelag) <0)) = 0; - -if (max(gammafun)-min(gammafun))~=0 - gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); -end -gammafun = (amplitude*gammafun+offset); - -hrf.hrf = gammafun; -hrf.hrf = hrf.hrf / max(hrf.hrf); - -%--------------------------------------- -% convolveModelWithStimulus -% convolve the model response with the stimulus -%---------------------------------------- -function modelResponse = convolveModelWithStimulus(rfModel, stim) - -nStimFrames = size(stim, 3); -modelResponse = zeros(1,nStimFrames); -for frameNum = 1:nStimFrames - modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); -end - -%--------------------------------------- -% convolveModelResponseWithHRF -% convolve the model response with the HRF -%---------------------------------------- -function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) - -n = length(modelTimecourse); -modelTimecourse = conv(modelTimecourse,hrf.hrf); -modelTimecourse = modelTimecourse(1:n); - -%--------------------------------------- -% applyConcatFiltering -% applies detrending, hipassfilter, projection, removes mean. -%---------------------------------------- -function tSeries = applyConcatFiltering(tSeries, concatInfo) -runnum=1; - -tSeries = tSeries(:); - -% apply detrending -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -% project out the mean vector - -% remove the mean -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -%tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/plot2voxels.m b/mrLoadRet/Plugin/pRF/plot2voxels.m deleted file mode 100644 index 53e0a8a7b..000000000 --- a/mrLoadRet/Plugin/pRF/plot2voxels.m +++ /dev/null @@ -1,220 +0,0 @@ -%% plot2voxels.m -%% -%% usage: plot2voxels(fit, voxels) -%% purpose: plots 2 voxels' receptive fields and time courses -%% -%% input: analysis - filename of analysis file -%% fit - struct containing fields to plot probTable -%% voxels - list of two voxels in format [x1 y1 z1; x2 y2 z2] -%% - -function display = plot2voxels(analysis, voxels, fit) - -if ieNotDefined('voxels') - voxels = [44 74 21; 43 74 21]; -end -if ieNotDefined('analysis') - analysis = 'pRF_lV1_123456.mat'; -end - -% Set curr group to Concat and load the Analysis -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' analysis]); -scanNum = v.analyses{1}.params.scanNum; -a = viewGet(v, 'Analysis'); -d = viewGet(v, 'd', scanNum); - -% Create new figure -f = figure; - -%%% (1) Voxel 1 Receptive Field %%% -rf1 = subplot(2, 3, 1); - - %Get params -x=voxels(1,1); y=voxels(1,2); z=voxels(1,3); -whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); -r = d.r(whichVoxel, :); -params = d.params(:, whichVoxel); - - %get model fit for this voxel -m = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); - - %plot voxel RF -imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m.rfModel')); -set(rf1,'Box','off'); -set(rf1,'Color',[0.8 0.8 0.8]); -set(rf1,'TickDir','out'); -axis equal -axis tight -hold on -hline(0,'w:');vline(0,'w:'); -title('Voxel 1 Receptive Field Position'); - -%% (4) Voxel 2 Receptive Field -rf2 = subplot(2, 3, 4); -x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); -whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); -params = d.params(:, whichVoxel); -m2 = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); - -imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m2.rfModel')); -set(rf2,'Box','off'); -set(rf2,'Color',[0.8 0.8 0.8]); -set(rf2,'TickDir','out'); -axis equal -axis tight -hold on -hline(0, 'w:');vline(0,'w:'); -title('Voxel 2 Receptive Field Position'); - -%% (2) Stimulus position - -[thisT, modelT] = makeStim(100, 50); - -function [thisT, modelT] = makeStim(time, modelTime) - stP = subplot(2, 3, 2); - %clf(stP); - cla(stP); - im = []; - thisT = time; - thisScan = d.concatInfo.whichScan(thisT); - thisVolume = d.concatInfo.whichVolume(thisT); - - modelT = modelTime; - modelScan = d.concatInfo.whichScan(modelT); - modelVol = d.concatInfo.whichVolume(modelT); - - im(:, :, 3) = flipud(0.7*d.stim{thisScan}.im(:, :, thisVolume)'); - im(:, :, 2) = flipud(0.7*d.stim{modelScan}.im(:, :, modelVol)'); - im(:, :, 1) = 0.30*m.rfModel' + 0.30*m2.rfModel'; - image(d.stimX(:, 1), d.stimY(1, :), im); - axis image - hold on - hline(0, 'w:'); vline(0, 'w:'); - title(sprintf('timeT=%i, modelT=%i', thisT, modelT)); -end - - % Get covariance matrix -residual(1, :) = m.tSeries - m.modelResponse; -residual(2, :) = m2.tSeries - m2.modelResponse; -covMat = residual*residual.'; -radius = covMat(1, 2); - -%%%% (3) and (6): Plot voxels' model response time course and time series -% Plot voxel 1 model timecourse and timeseries -tLen = length(m.modelResponse); -subplot(2, 3, 3); -plot((1:tLen), m.modelResponse, 'r'); -hold on; plot((1:tLen), m.tSeries, 'black'); -hold on; vl1m = vline(1); tl1m = text(0,0,''); -hold on; vl1t = vline(1); tl1t = text(0,0,''); -xlim([1 tLen]) -title('Voxel 1 Model Response and Time Series'); - -% Plot voxel 2 model timecourse and timeseries -subplot(2, 3, 6); -plot((1:tLen), m2.modelResponse, 'r'); -hold on; plot((1:tLen), m2.tSeries, 'black'); -hold on; vl2m = vline(1); tl2m = text(0,0,''); -hold on; vl2t = vline(1); tl2t = text(0,0,''); -xlim([1 tLen]) -title('Voxel 2 model response and time series'); - - -%% (5) 2D Gaussian model + tSeries -p4 = subplot(2, 3, 5); - -timepoint = 100; -modelTime = 50; - -x1 = m.tSeries(timepoint); -y1 = m2.tSeries(timepoint); - -x2 = m.modelResponse(modelTime); -y2 = m2.modelResponse(modelTime); - -timePlot = plot(x1, y1, '*c'); -hold on -cPlot = circle(x2, y2); -xlim([min(m.tSeries), max(m.tSeries)]); -ylim([min(m2.tSeries), max(m2.tSeries)]); -xlabel(sprintf('Voxel 1: (%d, %d, %d)', voxels(1,1), voxels(1,2), voxels(1,3))); -ylabel(sprintf('Voxel 2: (%d, %d, %d)', voxels(2,1), voxels(2,2), voxels(2,3))); -title('Voxel 1 vs Voxel 2: Percent Signal Change'); - -timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... - 'SliderStep', [1/tLen, 10/tLen],... - 'Value', timepoint, 'Callback', @slider1Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); -function slider1Callback(hObject, eventdata) - newVal = round(get(hObject, 'Value')); - % Move the * around - subplot(2, 3, 5); - delete(timePlot); - x1 = m.tSeries(newVal); - y1 = m2.tSeries(newVal); - timePlot = plot(x1, y1, '*b'); - - % Move stim bar - [thisT, modelT] = makeStim(newVal, modelT); - - % Move cyan line around time series course - subplot(2, 3, 3); - delete([vl1t tl1t]); - vl1t = vline(newVal, '-b'); - tl1t = text(newVal, 0.92, sprintf('time t: %d', newVal), 'color', 'b'); - subplot(2, 3, 6); - delete([vl2t tl2t]); - vl2t = vline(newVal, '-b'); - tl2t = text(newVal, 0.96, sprintf('time t: %d', newVal), 'color', 'b'); -end - -modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... - 'SliderStep', [1/tLen 10/tLen], 'Value', modelTime, 'Callback', @slider2Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); -function slider2Callback(hObject, eventdata) - newVal = round(get(hObject, 'Value')); - % Move the circle around - subplot(2, 3, 5); - delete(cPlot); - x2 = m.modelResponse(newVal); - y2 = m2.modelResponse(newVal); - cPlot = circle(x2, y2); - - % Move the stimulus bar - [thisT, modelT] = makeStim(thisT, newVal); - - % Move green line around model time course - subplot(2, 3, 3); - delete([vl1m tl1m]); - vl1m = vline(newVal, '-g'); - tl1m = text(newVal, 0.95, sprintf('Model t: %d', newVal), 'color', 'g'); - subplot(2, 3, 6); - delete([vl2m tl2m]); - vl2m = vline(newVal, '-g'); - tl2m = text(newVal, 0.97, sprintf('Model t: %d', newVal), 'color', 'g'); -end - -align([timeSlider, modelSlider, f], 'center', 'distribute'); - - -function cPlot = circle(x, y) - r = radius; - ang = 0:0.01:2*pi; - xp = r*cos(ang); - yp = r*sin(ang); - cPlot = plot(x+xp, y+yp, 'g'); -end - - - -figure; subplot(3, 1, 1); -plot((1:tLen), m.tSeries, 'black'); -hold on; plot((1:tLen), m.modelResponse, 'blue'); -subplot(3, 1, 2); plot((1:tLen), m2.tSeries, 'red'); hold on; plot((1:tLen), m2.modelResponse, 'magenta') -xlim([1 tLen]) -if ~ieNotDefined('fit') - subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; -end -end diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m deleted file mode 100644 index 055b3dcef..000000000 --- a/mrLoadRet/Plugin/pRF/plotFig.m +++ /dev/null @@ -1,356 +0,0 @@ -% plotFig -% -% does analysis given struct of fits for two models -% - fitsGauss, fitsNorm: struct -% -% -function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) - -if any(num==1) % draw true rf's - dispTrueRFs = 1; -end -if any(num==1.5) - linkRFs = 1; -end -if any(num==2) % draw model predicted rf's - dispModelRFs = 1; -end -if any(num==3) - dispModelR2 = 1; -end -if any(num==4) - drawR2 = 1; -end -if any(num==5) - dispBestModelResponse = 1; -end -if any(num==6) - dispSuppFieldSize = 1; -end -if any(num==7) - dispWorstModelResponse = 1; -end -if any(num==8) - drawR2excludingoffscreen = 1; -end - -paramsG = getFieldArrFromStruct(fitsGauss, 'params'); -paramsN = getFieldArrFromStruct(fitsNorm, 'params'); -r2G = getFieldArrFromStruct(fitsGauss, 'r2'); -r2N = getFieldArrFromStruct(fitsNorm, 'r2'); - -if ~ieNotDefined('drawR2excludingoffscreen') - xMin = min(stim.x(:)); - xMax = max(stim.x(:)); - yMin = min(stim.y(:)); - yMax = max(stim.y(:)); - r2g_1 = []; r2n_1 = []; - for i = 1:196 - if fitsGauss{i}.x > xMin && fitsGauss{i}.x < xMax && fitsGauss{i}.y > yMin && fitsGauss{i}.y xMin && fitsNorm{i}.x < xMax && fitsNorm{i}.y > yMin && fitsNorm{i}.y %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%-------------------------------------- -% getFieldArrFromStruct(structure, fieldNameStr, -%-------------------------------------- -function fieldArray = getFieldArrFromStruct(structure, fieldNameStr) - -fieldArray = []; -for i = 1:length(structure) - fieldArray(i,:) = structure{i}.(fieldNameStr); -end - -%--------------------------------------- -% circle -% draw a circle given center (x,y), radius and color -%---------------------------------------- -function circle(x,y,r, color) -%x and y are the coordinates of the center of the circle -%r is the radius of the circle -%0.01 is the angle step, bigger values will draw the circle faster but -%you might notice imperfections (not very smooth) -ang=0:0.01:2*pi; -xp=r*cos(ang); -yp=r*sin(ang); -plot(x+xp,y+yp, color, 'MarkerSize', 4); -hold on - - -%--------------------------------------- -% getCanonicalHRF() -% get the canonical hemodnamic response function -%---------------------------------------- -function hrf = getCanonicalHRF() -offset = 0; -timelag = 1; -tau = 0.6; -exponent = 6; -sampleRate = 0.5; -amplitude = 1; -hrf.time = 0:sampleRate:25; - -exponent = round(exponent); -gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); -gammafun(find((hrf.time-timelag) <0)) = 0; - -if (max(gammafun)-min(gammafun))~=0 - gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); -end -gammafun = (amplitude*gammafun+offset); - -hrf.hrf = gammafun; -hrf.hrf = hrf.hrf / max(hrf.hrf); - - -%--------------------------------------- -% convolveModelWithStimulus -% convolve the model response with the stimulus -%---------------------------------------- -function modelResponse = convolveModelWithStimulus(rfModel, stim) -nStimFrames = size(stim, 3); -modelResponse = zeros(1,nStimFrames); -for frameNum = 1:nStimFrames - modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); -end - -%--------------------------------------- -% convolveModelResponseWithHRF -% convolve the model response with the HRF -%---------------------------------------- -function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) -n = length(modelTimecourse); -modelTimecourse = conv(modelTimecourse,hrf.hrf); -modelTimecourse = modelTimecourse(1:n); - -%--------------------------------------- -% applyConcatFiltering -% applies detrending, hipassfilter, projection, removes mean. -%---------------------------------------- -function tSeries = applyConcatFiltering(tSeries, concatInfo) -runnum=1; -tSeries = tSeries(:); - -% apply detrending - -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); -tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/predictStimulus.m b/mrLoadRet/Plugin/pRF/predictStimulus.m deleted file mode 100644 index d730ea135..000000000 --- a/mrLoadRet/Plugin/pRF/predictStimulus.m +++ /dev/null @@ -1,101 +0,0 @@ -%% predictStimulus.m -%% -%% -%% usage: predictStimulus(fits, d) --> plot figs for avg (last element of fits) -%% predictStimulus(fits, d, index) --> plot figs for i'th fold in fits -%% by: akshay jagadeesh -%% date: 11/20/2016 -%% purpose: Given model fits, this function predicts the stimulus most likely to have elicited -%% the given model response and compares this to the actual observed stimulus. Outputs the -%% percentage of timepoints that are correctly predicted (within 5) using maximum likelihood. -%% - - -function predictStimulus(fits, d, index) - -numFolds = length(fits)-1; -if(ieNotDefined('index')) - fit = fits(numFolds+1); -else - disp(sprintf('getting %d th fit', index)); - fit = fits(index); -end - -timeLen = size(fit.modelResponse, 2); - -%%% 1. Plot prediction probability chart (batik) -f=figure; subplot(2, 2, 1); imagesc(log(fit.probTable)); axis ij; colorbar; -xlabel('Model Time Series'); ylabel('Observed Time series'); -hold on; hl = hline(200, '-b'); -hold on; pt = plot(0,0,'*g'); - % Plot best predicted points -count = 0; -for i = 1:timeLen - tS = fit.probTable(i,:); - [~, mI] = max(tS); - maxInd(i) = mI; - if( abs(mI - i) <= 5) - count = count + 1; - end -end -hold on; plot(maxInd, (1:timeLen), '*g', 'MarkerSize', 1); -title(sprintf('Avg Model Prediction Probability:\n %d / %d timepoints (%0.1f %%) correctly predicted within 5 using Max Likelihood', count, timeLen, 100*count/timeLen)); - -%%% 3. Plot observed and model response time course -subplot(2, 2, 3); plot((1:timeLen), fit.leftOut, 'k'); -hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model Response'); -hold on; vl1 = vline(0, 'k'); hold on; vl2 = vline(0, 'k'); - -%%% 4. Plot voxel receptive fields -%rf = subplot(2,2,4); plot(fits(1).fitParams(:,4), fits(1).fitParams(:,5), '*'); -%title('Voxel Receptive Field positions'); -%set(rf, 'Box', 'off'); set(rf, 'Color', [.8 .8 .8]); set(rf,'TickDir','out'); -%axis equal; axis tight; xlim([-30 30]); ylim([-20 20]); hold on; hline(0, 'w:'); vline(0,'w:'); - -timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(fit.modelResponse),... - 'SliderStep', [1/timeLen 10/timeLen], 'Value', 200, 'Callback', @timeSliderCallback,... - 'Parent',f, 'Units', 'normalized', 'Position', [.25, -.05,.5,.1]); -function timeSliderCallback(hObject, evendata) - newVal = round(get(hObject, 'Value')); - - %plot the stimulus predicted by the model time point with highest posterior probability - timeSeries = fit.probTable(newVal, :); - [maxVal, maxIndex] = max(timeSeries); - stimPl = subplot(2, 2, [2 4]); - cla(stimPl); - im = []; - predScan = d.concatInfo.whichScan(maxIndex); - predVol = d.concatInfo.whichVolume(maxIndex); - trueScan = d.concatInfo.whichScan(newVal); - trueVol = d.concatInfo.whichVolume(newVal); - im(:, :, 3) = flipud(0.7*d.stim{trueScan}.im(:,:,trueVol)'); - im(:, :, 2) = flipud(0.7*d.stim{predScan}.im(:,:,predVol)'); - im(:, :, 1) = 0; - image(d.stimX(:,1), d.stimY(1,:), im); - axis image; hold on; - hline(0, 'w:'); vline(0, 'w:'); - hold on; plot(fits(1).fitParams(:, 4), fits(1).fitParams(:, 5), '*w', 'MarkerSize', 1); - title(sprintf('Stim predictions: Timepoint %i is best predicted by Modelpoint %i', newVal, maxIndex)); - - % Plot line and point of highest prediction - subplot(2,2,1); - delete([hl pt]); - hl = hline(newVal, '-b'); - set(hl, 'LineWidth', 5); - pt = plot(maxIndex, newVal, '*g'); - - % Plot vertical line on time series plots - subplot(2, 2, 3); - delete([vl1 vl2]); - vl1 = vline(newVal, '-b'); - set(vl1, 'LineWidth', 5); - hold on; - vl2 = vline(maxIndex, '-g'); - set(vl2, 'LineWidth', 5); - title(sprintf('Time Series: %d; Model Time: %d', newVal, maxIndex)); -end - -bl3 = uicontrol('Parent',f,'Style','text','Units', 'normalized', 'Position', [.45, .05 ,.1,.015],... - 'String', sprintf('Time Slider (blue)')); - -end From 5aaa19a4e31d3f868887ff192f9d6e36603041bd Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 10 Mar 2017 14:22:08 -0800 Subject: [PATCH 21/44] Updated to reverse old changes and make compatible with mglDoubleBars --- mrLoadRet/Plugin/pRF/pRFFit.m | 2 +- mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index d68ee4f9a..4d9899f12 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -66,7 +66,7 @@ % but useful for raw/motionCorrected time series. Also, it is very important that % the tSeries is properly mean subtracted if ~isfield(fitParams.concatInfo,'hipassfilter') - tSeries = percentTSeries(tSeries,'detrend','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); + tSeries = percentTSeries(tSeries,'detrend','Linear', 'spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); end % if there are any nans in the tSeries then don't fit diff --git a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m index baba6ea08..8a7b0528e 100644 --- a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m +++ b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m @@ -467,7 +467,7 @@ if ~isfield(thiss.task{taskNum}{1},'randVars') missing = 'randVars';end if ~isfield(thiss.task{taskNum}{1},'parameter') missing = 'parameter';end if ~any(strcmp('maskPhase',thiss.myscreen.traceNames)) missing = 'maskPhase';end - %if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end + if ~any(strcmp('blank',thiss.myscreen.traceNames)) && isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') missing = 'blank';end if ~isempty(missing) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) Stimfile: %s',dispstr)); disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) The stimfile does not appear to have been created by the latest version of mglRetinotopy which contains the field %s necessary for reconstructing the stimulus. Consider running a dummy run with a newer version of mglRetinotpy with the same parameters (see mglSimulateRun to simulate backticks) and then use that stimfile instead of this one.',missing)); From d29c658262ae58ba1866a9e6863cd04308bdce08 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Tue, 20 Jun 2017 15:37:44 -0700 Subject: [PATCH 22/44] Bug fixes for models code --- .../Plugin/pRF/models/pRF_diffGaussian.m | 30 ++++++++++++------- mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m | 7 +++-- mrLoadRet/Plugin/pRF/models/pRF_exp.m | 7 +++-- mrLoadRet/Plugin/pRF/models/pRF_gaussian.m | 4 ++- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m index 9157aa743..5436bb88c 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m @@ -33,20 +33,27 @@ p = varargin{5}; i = varargin{6}; - rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*((p.std*p.stdRatio)^2))+((fitParams.stimY-p.y).^2)/(2*((p.std*p.stdRatio)^2)))); nFrames = fitParams.concatInfo.runTransition(i,2); rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + thisModelResponse = rPlus*p.B1 - rMinus*p.B2; + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse, hrf); + % and convolve in time. - pPlus = convolveModelResponseWithHRF(rPlus,hrf); - pMinus = convolveModelResponseWithHRF(rMinus,hrf); + %pPlus = convolveModelResponseWithHRF(rPlus,hrf); + %pMinus = convolveModelResponseWithHRF(rMinus,hrf); % Model response is the difference of Gaussians, weighted by Beta amplitudes - thisModelResponse = pPlus*p.B1 + pMinus*p.B2; + %thisModelResponse = pPlus*p.B1 + pMinus*p.B2; % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end + % return the calculated model response output = thisModelResponse; @@ -59,15 +66,16 @@ fitParams = varargin{2}; - fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian'}; + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; fitParams.paramMax = [inf inf inf inf inf inf]; % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 -inf -inf]; + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 0 0]; fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; - fitParams.initParams = [0 0 4 4 1 0]; + fitParams.initParams = [0 0 4 2 1 1]; % return fitParams with modified values output = fitParams; @@ -87,7 +95,7 @@ p.x = params(1); p.y = params(2); p.std = params(3); - p.std2 = params(4); + p.stdRatio = params(4); p.B1 = params(5); p.B2 = params(6); % use a fixed single gaussian @@ -116,7 +124,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m index 1e5b0c05c..691aab70c 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m @@ -48,8 +48,9 @@ % drop junk frames here %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); - + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end % return the calculated model response output = thisModelResponse; @@ -91,7 +92,7 @@ p.std = params(3); p.stdRatio = params(4); p.b1 = params(5); - %p.b2 = params(6); + p.b2 = params(6); % use a fixed single gaussian p.canonical.type = 'gamma'; p.canonical.lengthInSeconds = 25; diff --git a/mrLoadRet/Plugin/pRF/models/pRF_exp.m b/mrLoadRet/Plugin/pRF/models/pRF_exp.m index 35696a30f..a83043dca 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_exp.m @@ -45,8 +45,9 @@ % drop junk frames here %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); - + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end % return the calculated model response output = thisModelResponse; %end @@ -120,7 +121,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m index b669a8b83..12e3dc7c4 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m @@ -40,7 +40,9 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end %%%% Maybe uncomment this later: %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); From b25a0903820e6bca537fda68ad9a64aaf8b216d0 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Tue, 23 Aug 2016 19:33:31 -0700 Subject: [PATCH 23/44] Created model template and modified pRFFit to make calls to pRFModelTemplate --- mrLoadRet/Plugin/pRF/pRFFit.m | 181 +++++++++++++----------- mrLoadRet/Plugin/pRF/pRFModelTemplate.m | 118 +++++++++++++++ 2 files changed, 215 insertions(+), 84 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRFModelTemplate.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index e81a57df7..0dc05df6c 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -253,46 +253,51 @@ if ~isfield(fitParams,'initParams') % check the rfType to get the correct min/max arrays - switch (fitParams.rfType) - case 'gaussian' - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {'x','y','rfWidth'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; - fitParams.paramIncDec = [1 1 1]; - fitParams.paramMin = [-inf -inf 0]; - fitParams.paramMax = [inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; - fitParams.initParams = [0 0 4]; - case 'gaussian-hdr' - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; - fitParams.paramIncDec = [1 1 1 0.1 0.5]; - fitParams.paramMin = [-inf -inf 0 0 0]; - fitParams.paramMax = [inf inf inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; - fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; - % add on parameters for difference of gamma - if fitParams.diffOfGamma - % parameter names/descriptions and other information for allowing user to set them - fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; - fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; - fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; - fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; - fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; - % set min/max and init - fitParams.minParams = [fitParams.minParams 0 0 0]; - fitParams.maxParams = [fitParams.maxParams inf 6 inf]; - fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; - end - otherwise - disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); - return - end + + %%%%%%%%%%%%%%%%%%% + fitParams = pRFModelTemplate('setParams', fitParams) + %%%%%%%%%%%%%%%%%%% + + % switch (fitParams.rfType) + % case 'gaussian' + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {'x','y','rfWidth'}; + % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + % fitParams.paramIncDec = [1 1 1]; + % fitParams.paramMin = [-inf -inf 0]; + % fitParams.paramMax = [inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + % fitParams.initParams = [0 0 4]; + % case 'gaussian-hdr' + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; + % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; + % fitParams.paramIncDec = [1 1 1 0.1 0.5]; + % fitParams.paramMin = [-inf -inf 0 0 0]; + % fitParams.paramMax = [inf inf inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; + % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; + % fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; + % % add on parameters for difference of gamma + % if fitParams.diffOfGamma + % % parameter names/descriptions and other information for allowing user to set them + % fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; + % fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; + % fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; + % fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; + % fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; + % % set min/max and init + % fitParams.minParams = [fitParams.minParams 0 0 0]; + % fitParams.maxParams = [fitParams.maxParams inf 6 inf]; + % fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; + % end + % otherwise + % disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); + % return + % end % round constraints fitParams.minParams = round(fitParams.minParams*10)/10; @@ -372,17 +377,21 @@ % create the model for each concat for i = 1:fitParams.concatInfo.n % get model response - nFrames = fitParams.concatInfo.runTransition(i,2); - thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + %nFrames = fitParams.concatInfo.runTransition(i,2); + %thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); % get a model hrf hrf = getCanonicalHRF(p.canonical,fitParams.framePeriod); % and convolve in time. - thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + %thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + %%%%%%%%%%%%%%%%%%% + thisModelResponse = pRFModelTemplate('getModelResponse', fitParams, rfModel, hrf, i); + %%%%%%%%%%%%%%%%%%% % apply concat filtering if isfield(fitParams,'applyFiltering') && fitParams.applyFiltering @@ -502,46 +511,50 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) p.rfType = fitParams.rfType; -switch (fitParams.rfType) - case 'gaussian' - p.x = params(1); - p.y = params(2); - p.std = params(3); - % use a fixed single gaussian - p.canonical.type = 'gamma'; - p.canonical.lengthInSeconds = 25; - p.canonical.timelag = fitParams.timelag; - p.canonical.tau = fitParams.tau; - p.canonical.exponent = fitParams.exponent; - p.canonical.offset = 0; - p.canonical.diffOfGamma = fitParams.diffOfGamma; - p.canonical.amplitudeRatio = fitParams.amplitudeRatio; - p.canonical.timelag2 = fitParams.timelag2; - p.canonical.tau2 = fitParams.tau2; - p.canonical.exponent2 = fitParams.exponent2; - p.canonical.offset2 = 0; - case 'gaussian-hdr' - p.x = params(1); - p.y = params(2); - p.std = params(3); - % use a fixed single gaussian - p.canonical.type = 'gamma'; - p.canonical.lengthInSeconds = 25; - p.canonical.timelag = params(4); - p.canonical.tau = params(5); - p.canonical.exponent = fitParams.exponent; - p.canonical.offset = 0; - p.canonical.diffOfGamma = fitParams.diffOfGamma; - if fitParams.diffOfGamma - p.canonical.amplitudeRatio = params(6); - p.canonical.timelag2 = params(7); - p.canonical.tau2 = params(8); - p.canonical.exponent2 = fitParams.exponent2; - p.canonical.offset2 = 0; - end -otherwise - disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); -end +%%%%%%%%%%%%%%%%%%% +p = pRFModelTemplate('getFitParams', fitParams, params); +%%%%%%%%%%%%%%%%%%% + +% switch (fitParams.rfType) +% case 'gaussian' +% p.x = params(1); +% p.y = params(2); +% p.std = params(3); +% % use a fixed single gaussian +% p.canonical.type = 'gamma'; +% p.canonical.lengthInSeconds = 25; +% p.canonical.timelag = fitParams.timelag; +% p.canonical.tau = fitParams.tau; +% p.canonical.exponent = fitParams.exponent; +% p.canonical.offset = 0; +% p.canonical.diffOfGamma = fitParams.diffOfGamma; +% p.canonical.amplitudeRatio = fitParams.amplitudeRatio; +% p.canonical.timelag2 = fitParams.timelag2; +% p.canonical.tau2 = fitParams.tau2; +% p.canonical.exponent2 = fitParams.exponent2; +% p.canonical.offset2 = 0; +% case 'gaussian-hdr' +% p.x = params(1); +% p.y = params(2); +% p.std = params(3); +% % use a fixed single gaussian +% p.canonical.type = 'gamma'; +% p.canonical.lengthInSeconds = 25; +% p.canonical.timelag = params(4); +% p.canonical.tau = params(5); +% p.canonical.exponent = fitParams.exponent; +% p.canonical.offset = 0; +% p.canonical.diffOfGamma = fitParams.diffOfGamma; +% if fitParams.diffOfGamma +% p.canonical.amplitudeRatio = params(6); +% p.canonical.timelag2 = params(7); +% p.canonical.tau2 = params(8); +% p.canonical.exponent2 = fitParams.exponent2; +% p.canonical.offset2 = 0; +% end +% otherwise +% disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); +% end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m new file mode 100644 index 000000000..03577474b --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m @@ -0,0 +1,118 @@ +% pRFModelTemplate.m +% +% $Id:$ +% usage: pRFModelTemplate(varargin) +% by: akshay jagadeesh +% date: 08/23/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRFModelTemplate(varargin) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams)%%%%% +%%%% Called from getModelResidual %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + fitParams.paramIncDec = [1 1 1]; + fitParams.paramMin = [-inf -inf 0]; + fitParams.paramMax = [inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + fitParams.initParams = [0 0 4]; + + % return fitParams with modified values + output = fitParams; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From b38e84f00afe87b9bb7b2fe4ee0d4e4d6adc314c Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 2 Sep 2016 19:20:03 -0700 Subject: [PATCH 24/44] Plugging in exponent model --- mrLoadRet/Plugin/pRF/pRFFit.m | 9 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 2 +- mrLoadRet/Plugin/pRF/pRFModelTemplate.m | 11 +- mrLoadRet/Plugin/pRF/pRF_exp.m | 133 ++++++++++++++++++++++++ mrLoadRet/Plugin/pRF/pRF_gaussian.m | 121 +++++++++++++++++++++ 5 files changed, 269 insertions(+), 7 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_exp.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_gaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 0dc05df6c..685598805 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -42,6 +42,9 @@ end end +% specify the model file here (e.g. pRFModelTemplate) +prfModel = @pRF_exp + % get the stimulus movie if it wasn't passed in if ~isfield(fitParams,'stim') || isempty(fitParams.stim) fitParams.stim = getStim(v,scanNum,fitParams); @@ -255,7 +258,7 @@ % check the rfType to get the correct min/max arrays %%%%%%%%%%%%%%%%%%% - fitParams = pRFModelTemplate('setParams', fitParams) + fitParams = prfModel('setParams', fitParams) %%%%%%%%%%%%%%%%%%% % switch (fitParams.rfType) @@ -390,7 +393,7 @@ %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); %%%%%%%%%%%%%%%%%%% - thisModelResponse = pRFModelTemplate('getModelResponse', fitParams, rfModel, hrf, i); + thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, i); %%%%%%%%%%%%%%%%%%% % apply concat filtering @@ -512,7 +515,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) p.rfType = fitParams.rfType; %%%%%%%%%%%%%%%%%%% -p = pRFModelTemplate('getFitParams', fitParams, params); +p = prfModel('getFitParams', fitParams, params); %%%%%%%%%%%%%%%%%%% % switch (fitParams.rfType) diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index 9d8d101e2..606fd3850 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,7 +116,7 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below.'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m index 03577474b..3e1cc9ca0 100644 --- a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m +++ b/mrLoadRet/Plugin/pRF/pRFModelTemplate.m @@ -15,6 +15,11 @@ function output = pRFModelTemplate(varargin) +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams, rfModel, hrf, i)%%%%% %%%% Called from getModelResidual %%%%% @@ -36,11 +41,11 @@ % return the calculated model response output = thisModelResponse; -end +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams)%%%%% -%%%% Called from getModelResidual %%%%% +%%%% Called from setFitParams %%%%% elseif strcmp(varargin{1}, 'setParams') @@ -58,7 +63,7 @@ % return fitParams with modified values output = fitParams; -end +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRFModelTemplate(command, fitParams, params)%%%%% diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m new file mode 100644 index 000000000..29a411eea --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -0,0 +1,133 @@ +% pRF_exp.m +% +% $Id:$ +% usage: pRF_exp(varargin) +% by: akshay jagadeesh +% date: 09/01/16 +% purpose: Model file to specify a new rftype +% +% +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_exp(varargin) + +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_exp(command, fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % FOR GAUSSIAN-EXP ONLY: include exponent non-linearity + if strcmp(fitParams.rfType, 'gaussian-exp') + thisModelResponse = power(thisModelResponse, p.exp); + end + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + + disp(sprintf('fitParams.rfType is %s', fitParams.rfType)); + +%end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_exp(command, fitParams)%%%%% +%%%% Called from getModelResidual %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth','exp'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Spatial summation exponent'}; + fitParams.paramIncDec = [1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0]; + fitParams.paramMax = [inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf]; + fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) + + % return fitParams with modified values + output = fitParams; +%end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRFModelTemplate(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.exp = params(4); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + +else + disp(sprintf('Function did not execute properly')); + return +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m new file mode 100644 index 000000000..4dbcae878 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -0,0 +1,121 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_gaussian(varargin) + +if nargin <=2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + i = varargin{5}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('setParams', fitParams)%%%%% +%%%% Called from setParams %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; + fitParams.paramIncDec = [1 1 1]; + fitParams.paramMin = [-inf -inf 0]; + fitParams.paramMax = [inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; + fitParams.initParams = [0 0 4]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From 4f0f9086086d450e0fe43a244fda24671fa5a4d7 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 8 Sep 2016 15:23:37 -0700 Subject: [PATCH 25/44] Completed new file structure for models --- mrLoadRet/Plugin/pRF/pRFFit.m | 122 ++++------------------ mrLoadRet/Plugin/pRF/pRF_exp.m | 14 +-- mrLoadRet/Plugin/pRF/pRF_gaussian.m | 18 ++-- mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m | 135 +++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 685598805..e06cfa5cb 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -42,9 +42,6 @@ end end -% specify the model file here (e.g. pRFModelTemplate) -prfModel = @pRF_exp - % get the stimulus movie if it wasn't passed in if ~isfield(fitParams,'stim') || isempty(fitParams.stim) fitParams.stim = getStim(v,scanNum,fitParams); @@ -229,6 +226,7 @@ % display if fitParams.verbose disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); + disp(sprintf('Params: exp is %f', fit.exp)); end %%%%%%%%%%%%%%%%%%%%%% @@ -258,50 +256,9 @@ % check the rfType to get the correct min/max arrays %%%%%%%%%%%%%%%%%%% - fitParams = prfModel('setParams', fitParams) + fitParams = prfModel('setParams', fitParams); %%%%%%%%%%%%%%%%%%% - % switch (fitParams.rfType) - % case 'gaussian' - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {'x','y','rfWidth'}; - % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)'}; - % fitParams.paramIncDec = [1 1 1]; - % fitParams.paramMin = [-inf -inf 0]; - % fitParams.paramMax = [inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0]; - % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf]; - % fitParams.initParams = [0 0 4]; - % case 'gaussian-hdr' - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {'x','y','rfWidth','timelag','tau'}; - % fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)','Time before start of rise of hemodynamic function','Width of the hemodynamic function (tau parameter of gamma)'}; - % fitParams.paramIncDec = [1 1 1 0.1 0.5]; - % fitParams.paramMin = [-inf -inf 0 0 0]; - % fitParams.paramMax = [inf inf inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; - % fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; - % fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; - % % add on parameters for difference of gamma - % if fitParams.diffOfGamma - % % parameter names/descriptions and other information for allowing user to set them - % fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; - % fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; - % fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; - % fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; - % fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; - % % set min/max and init - % fitParams.minParams = [fitParams.minParams 0 0 0]; - % fitParams.maxParams = [fitParams.maxParams inf 6 inf]; - % fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; - % end - % otherwise - % disp(sprintf('(pRFFit:setFitParams) Unknown rfType %s',rfType)); - % return - % end - % round constraints fitParams.minParams = round(fitParams.minParams*10)/10; fitParams.maxParams = round(fitParams.maxParams*10)/10; @@ -379,21 +336,12 @@ % create the model for each concat for i = 1:fitParams.concatInfo.n - % get model response - %nFrames = fitParams.concatInfo.runTransition(i,2); - %thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); - % get a model hrf hrf = getCanonicalHRF(p.canonical,fitParams.framePeriod); - % and convolve in time. - %thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); - - % drop junk frames here - %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - %%%%%%%%%%%%%%%%%%% - thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, i); + % Get model response, which involves convolving model with stimulus, and with HRF and dropping junk frames. + thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, p, i); %%%%%%%%%%%%%%%%%%% % apply concat filtering @@ -513,51 +461,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) function p = getFitParams(params,fitParams) p.rfType = fitParams.rfType; - -%%%%%%%%%%%%%%%%%%% p = prfModel('getFitParams', fitParams, params); -%%%%%%%%%%%%%%%%%%% - -% switch (fitParams.rfType) -% case 'gaussian' -% p.x = params(1); -% p.y = params(2); -% p.std = params(3); -% % use a fixed single gaussian -% p.canonical.type = 'gamma'; -% p.canonical.lengthInSeconds = 25; -% p.canonical.timelag = fitParams.timelag; -% p.canonical.tau = fitParams.tau; -% p.canonical.exponent = fitParams.exponent; -% p.canonical.offset = 0; -% p.canonical.diffOfGamma = fitParams.diffOfGamma; -% p.canonical.amplitudeRatio = fitParams.amplitudeRatio; -% p.canonical.timelag2 = fitParams.timelag2; -% p.canonical.tau2 = fitParams.tau2; -% p.canonical.exponent2 = fitParams.exponent2; -% p.canonical.offset2 = 0; -% case 'gaussian-hdr' -% p.x = params(1); -% p.y = params(2); -% p.std = params(3); -% % use a fixed single gaussian -% p.canonical.type = 'gamma'; -% p.canonical.lengthInSeconds = 25; -% p.canonical.timelag = params(4); -% p.canonical.tau = params(5); -% p.canonical.exponent = fitParams.exponent; -% p.canonical.offset = 0; -% p.canonical.diffOfGamma = fitParams.diffOfGamma; -% if fitParams.diffOfGamma -% p.canonical.amplitudeRatio = params(6); -% p.canonical.timelag2 = params(7); -% p.canonical.tau2 = params(8); -% p.canonical.exponent2 = fitParams.exponent2; -% p.canonical.offset2 = 0; -% end -% otherwise -% disp(sprintf('(pRFFit) Unknown rfType %s',rfType)); -% end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% @@ -635,12 +539,28 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); end +%%%%%%%%%%%%%%%%%%% +%% prfModel %% +%%%%%%%%%%%%%%%%%%% +function output = prfModel(varargin) + +fitParams = varargin{2}; +switch (fitParams.rfType) + case 'gaussian' + output = pRF_gaussian(varargin); + case 'gaussian-hdr' + output = pRF_gaussianhdr(varargin); + otherwise + testModel = @pRF_exp; %%% Only need to change this line to specify a new model. + output = testModel(varargin); +end + %%%%%%%%%%%%%%%%%%%%%%%% %% makeRFGaussian %% diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m index 29a411eea..b7201f2a4 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -12,7 +12,7 @@ function output = pRF_exp(varargin) -if nargin <=2 +if nargin < 2 disp(sprintf('Not enough arguments')); return end @@ -25,7 +25,8 @@ fitParams = varargin{2}; rfModel = varargin{3}; hrf = varargin{4}; - i = varargin{5}; + p = varargin{5}; + i = varargin{6}; nFrames = fitParams.concatInfo.runTransition(i,2); thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); @@ -43,14 +44,11 @@ % return the calculated model response output = thisModelResponse; - - disp(sprintf('fitParams.rfType is %s', fitParams.rfType)); - %end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%pRF_exp(command, fitParams)%%%%% -%%%% Called from getModelResidual %%%%% +%%%% Called from setFitParams %%%%% elseif strcmp(varargin{1}, 'setParams') @@ -67,7 +65,7 @@ fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) % return fitParams with modified values - output = fitParams; + output = struct(fitParams); %end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -100,6 +98,8 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; + output = struct(p); + else disp(sprintf('Function did not execute properly')); diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 4dbcae878..3ae874d95 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -15,20 +15,21 @@ function output = pRF_gaussian(varargin) -if nargin <=2 +if nargin < 2 disp(sprintf('Not enough arguments')); return end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, i)%%%%% -%%%% Called from getModelResidual %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% if strcmp(varargin{1}, 'getModelResponse') fitParams = varargin{2}; rfModel = varargin{3}; hrf = varargin{4}; - i = varargin{5}; + p = varargin{5}; + i = varargin{6}; nFrames = fitParams.concatInfo.runTransition(i,2); thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); @@ -43,8 +44,8 @@ output = thisModelResponse; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian('setParams', fitParams)%%%%% -%%%% Called from setParams %%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% elseif strcmp(varargin{1}, 'setParams') @@ -64,7 +65,7 @@ output = fitParams; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%pRF_gaussian(command, fitParams, params)%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% %%%% Called from getFitParams %%%%% elseif strcmp(varargin{1}, 'getFitParams') @@ -94,7 +95,6 @@ end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% convolveModelWithStimulus %% function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m new file mode 100644 index 000000000..0627d2f1c --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m @@ -0,0 +1,135 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussianhdr(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_gaussianhdr(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussianhdr('getModelResponse', fitParams, rfModel, hrf, i)%%%%% +%%%% Called from getModelResidual %%%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + nFrames = fitParams.concatInfo.runTransition(i,2); + thisModelResponse = convolveModelWithStimulus(rfModel,fitParams.stim{i},nFrames); + + % and convolve in time. + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%pRF_gaussian('setParams', fitParams)%%%%% +%%%% Called from setParams %%%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'timelag', 'tau'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Time before start of rise of hemodynamic function', 'Width of the hemodynamic function (tau parameter of gamma)'}; + fitParams.paramIncDec = [1 1 1 0.1 0.5]; + fitParams.paramMin = [-inf -inf 0 0 0]; + fitParams.paramMax = [inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 3 inf]; + fitParams.initParams = [0 0 4 fitParams.timelag fitParams.tau]; + % add on parameters for difference of gamma + if fitParams.diffOfGamma + % parameter names/descriptions and other information for allowing user to set them + fitParams.paramNames = {fitParams.paramNames{:} 'amp2' 'timelag2','tau2'}; + fitParams.paramDescriptions = {fitParams.paramDescriptions{:} 'Amplitude of second gamma for HDR' 'Timelag for second gamma for HDR','tau for second gamma for HDR'}; + fitParams.paramIncDec = [fitParams.paramIncDec(:)' 0.1 0.1 0.5]; + fitParams.paramMin = [fitParams.paramMin(:)' 0 0 0]; + fitParams.paramMax = [fitParams.paramMax(:)' inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.minParams 0 0 0]; + fitParams.maxParams = [fitParams.maxParams inf 6 inf]; + fitParams.initParams = [fitParams.initParams fitParams.amplitudeRatio fitParams.timelag2 fitParams.tau2]; + end + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%0%%%%% +%%%% pRF_gaussianhdr(command, fitParams, params)%%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = params(4); + p.canonical.tau = params(5); + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + if fitParams.diffOfGamma + p.canonical.amplitudeRatio = params(6); + p.canonical.timelag2 = params(7); + p.canonical.tau2 = params(8); + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From 4ce8d99f5f477d6d06d62ad42fa2beb56ea832b9 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 26 Sep 2016 15:33:37 -0700 Subject: [PATCH 26/44] temp commit --- mrLoadRet/Plugin/pRF/getR2Overlay.m | 13 +++++++++++++ mrLoadRet/Plugin/pRF/pRFFit.m | 15 ++++++++------- mrLoadRet/Plugin/pRF/pRF_exp.m | 8 ++++++-- mrLoadRet/Plugin/pRF/pRF_gaussian.m | 4 ++++ mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m | 1 + 5 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/getR2Overlay.m diff --git a/mrLoadRet/Plugin/pRF/getR2Overlay.m b/mrLoadRet/Plugin/pRF/getR2Overlay.m new file mode 100644 index 000000000..aa7f7d04e --- /dev/null +++ b/mrLoadRet/Plugin/pRF/getR2Overlay.m @@ -0,0 +1,13 @@ +function r2Overlay = getR2Overlay(modelName) + +v = newView; +v = viewSet(v, 'curGroup', 'Averages'); +v = viewSet(v, 'curScan', 1); +prfModel = sprintf('pRFAnal/%s', modelName); +v = loadAnalysis(v, prfModel); +r2OverlayNum = find(strcmp('r2', viewGet(v, 'overlayNames'))); +v = viewSet(v, 'curOverlay', r2OverlayNum); +r2Overlay = viewGet(v, 'overlayData', 1); + +validR2 = r2Overlay(~isnan(r2Overlay)); +fprintf('Mean r2 for well-defined voxels: %d', mean(validR2)); diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index e06cfa5cb..c0d2820f5 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -224,9 +224,10 @@ [fit.polarAngle fit.eccentricity] = cart2pol(fit.x,fit.y); % display -if fitParams.verbose - disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); - disp(sprintf('Params: exp is %f', fit.exp)); +if fitParams.verbose && strcmp(fitParams.rfType, 'gaussian-exp') + disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f exp=%f',fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std, fit.exp)); +elseif fitParams.verbose + disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f', fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); end %%%%%%%%%%%%%%%%%%%%%% @@ -446,7 +447,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) designMatrix(:,2) = 1; % get beta weight for the modelResponse -if ~any(isnan(modelResponse)) +if ~any(isnan(modelResponse)) && ~any(isinf(modelResponse)) beta = pinv(designMatrix)*tSeries; beta(1) = max(beta(1),0); modelResponse = designMatrix*beta; @@ -553,12 +554,12 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) fitParams = varargin{2}; switch (fitParams.rfType) case 'gaussian' - output = pRF_gaussian(varargin); + output = pRF_gaussian(varargin{:}); case 'gaussian-hdr' - output = pRF_gaussianhdr(varargin); + output = pRF_gaussianhdr(varargin{:}); otherwise testModel = @pRF_exp; %%% Only need to change this line to specify a new model. - output = testModel(varargin); + output = testModel(varargin{:}); end diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/pRF_exp.m index b7201f2a4..99c4c5d48 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/pRF_exp.m @@ -14,6 +14,8 @@ if nargin < 2 disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) return end @@ -33,7 +35,9 @@ % FOR GAUSSIAN-EXP ONLY: include exponent non-linearity if strcmp(fitParams.rfType, 'gaussian-exp') - thisModelResponse = power(thisModelResponse, p.exp); + if ~isnan(thisModelResponse) + thisModelResponse = power(thisModelResponse, p.exp); + end end % and convolve in time. @@ -61,7 +65,7 @@ fitParams.paramMax = [inf inf inf inf]; % set min/max and init fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf 5]; % Set max exponent to 5 fitParams.initParams = [0 0 4 1]; %Initialize exponent to 1 (linear) % return fitParams with modified values diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 3ae874d95..07cef5144 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -17,6 +17,8 @@ if nargin < 2 disp(sprintf('Not enough arguments')); + disp(sprintf('Number of argumnets: %d', nargin)); + celldisp(varargin) return end @@ -93,6 +95,8 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; + output = struct(p); + end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m index 0627d2f1c..3fbb58366 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m @@ -107,6 +107,7 @@ p.canonical.exponent2 = fitParams.exponent2; p.canonical.offset2 = 0; end + output = struct(p); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From de5e2c35a5be1b5b6fc3861fe63d2dfefa71d5e7 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 7 Oct 2016 18:59:58 -0700 Subject: [PATCH 27/44] Adding files for cross-validation pipeline. --- mrLoadRet/Plugin/pRF/pRFNoise.m | 57 +++++++++++++++++++++++ mrLoadRet/Plugin/pRF/testPRF.m | 18 ++++++++ mrLoadRet/Plugin/pRF/trainPRF.m | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/pRFNoise.m create mode 100644 mrLoadRet/Plugin/pRF/testPRF.m create mode 100644 mrLoadRet/Plugin/pRF/trainPRF.m diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m new file mode 100644 index 000000000..1ef1c8ddf --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFNoise.m @@ -0,0 +1,57 @@ +function [residual, covMat, tSeries, modelResponse] = pRFNoise(v,scanNum,coordinates, analysisFileName) + +% coordinates = [53,61,25; 53,59,24; 51,57,24; 51,56,22; 52,55,20]; +% scanNum = 1; + +if ieNotDefined('v') + v = newView; +end + +v = viewSet(v, 'currentGroup', 'Averages'); +analysisFile = dir(sprintf('Averages/pRFAnal/%s', analysisFileName)); + +% get the analysis structure +analysis = viewGet(v,'analysis'); +if ~isfield(analysis,'d') || (length(analysis.d) < scanNum) || isempty(analysis.d) + v = loadAnalysis(v, ['pRFAnal/' analysisFile.name]); + analysis = viewGet(v,'analysis'); + +end + +d = viewGet(v,'d',scanNum); +if isempty(d),disp(sprintf('Could not find d structure for this scan'));return,end + +numVoxels = size(coordinates, 1); + +figure; +for voxel = 1:numVoxels + [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); + subplot(numVoxels,1,voxel) + plot(tSeries(voxel,:), 'k.-'); + hold on; + plot(modelResponse(voxel,:), 'r-'); + plot(residual(voxel,:), 'b-'); + title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); +end +covMat = residual*residual'; + +function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) + +% get the params that have been run +scanDims = viewGet(v,'scanDims',scanNum); +whichVoxel = find(d.linearCoords == sub2ind(scanDims,x,y,z)); +r = d.r(whichVoxel,:); + +params = d.params(:,whichVoxel); +if isfield(d,'paramsInfo') + paramsInfo = d.paramsInfo; +else + paramsInfo = []; +end + +% get params +m = pRFFit(v,scanNum,x,y,z,'stim',d.stim,'getModelResponse=1','params',params,'concatInfo',d.concatInfo,'fitTypeParams',a.params.pRFFit,'paramsInfo',paramsInfo); + +residual = m.tSeries - m.modelResponse; +tSeries = m.tSeries; +modelResponse = m.modelResponse; diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m new file mode 100644 index 000000000..e73f577f2 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -0,0 +1,18 @@ +% testPRF.m +% +% usage: testPRF( ) +% by: akshay jagadeesh +% date: 10/07/16 +% purpose: Computes the probability of seeing the model response, +% given the observed data, and the computed covariance (noise). +% + +function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) + +%use mvnpdf to compute the probability density function + + +%compute log likelihood of the data and sum + + + diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m new file mode 100644 index 000000000..66e6edaed --- /dev/null +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -0,0 +1,81 @@ +% trainPRF.m +% +% $Id:$ +% usage: trainPRF(view, roiName) +% by: akshay jagadeesh +% date: 10/04/16 +% purpose: Given n MotionComp runs, this function computes a n-fold +% cross validation, running the pRF analysis n times. +% It generates and saves time series, model response, residuals, +% and covariance matrices for each fold. +% + +function trainPRF(view, roiName) + +% Currently hardcoding number and names of scan. +numScans = 6 +roiName = 'xVal' + +for i = 1:numScans + v = newView; + + %Get all but the i'th scan + scanList = [1:i-1 i+1:numScans] + + %Average the other n-1 scans together + v = viewSet(v, 'currentGroup', 'MotionComp'); + scanstr = sprintf('scanList=%s', mat2str(scanList)); + [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) + %Filename of averaged scan is: tseries-avg-.nii + scanListStr = mat2str(scanList); scanListStr = scanListStr(2:end-1); scanListStr=scanListStr(find(~isspace(scanListStr))); + %params.fileName = sprintf('tseries-avg-%s.nii', fileName) + %params = averageTSeriesGUI('groupName', 'MotionComp'); + averageTSeries(v, params) + + %Get group info about the average we just created + gInfo = groupInfo; + gAverageInfo = groupInfo('Averages'); + numAverageScans = gInfo(3).numScans; + sInfo = scanInfo(numAverageScans, 'Averages'); + %% sInfo.description --> contains info about which scans were averaged + %% sInfo.Filename --> contains filename in which this average is saved + %% sInfo.OriginalN --> contains filename of original (replace N with 1 - 5) + + v = newView; + v = viewSet(v, 'currentGroup', 'Averages'); + + % Two ways of calculating ROI coordinates + % Method 1: loadROI.coords + v = loadROI(v, sprintf('%s.mat', roiName)) + roiCoords = v.ROIs(1).coords.' + roiCoords = roiCoords(:, 1:3) + + % Method 2: loadROITSeries.scancoords + roiCoords2 = loadROITSeries(v, 'xVal') + roiCoords2 = roiCoords2.scanCoords.' + + %Run pRF Analysis on average of n-1 scans + %pRF(v, params) + [v, params] = pRF(v, [], 'justGetParams=1'); + %%set dispStimScan to the last most recently computed scan + %%set saveName to pRF_ROINAME_SCANLIST + %%select diffOfGamma + pRF(v, params) + + % Load analysis by filename + analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr) + v = loadAnalysis(v, ['pRFAnal/' analysisFileName]) + scanNum = v.analyses{1}.params.scanNum; + + %Get the residual and covariance matrix + %%% scanNum: scan number on which analysis was conducted + [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) + + %Save residual, covariance matrix, time series, and model response into a structure + save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') + %Test pRF Analysis on the left-out scan + +end + + +function test From 20caf9a993b262447c2f8f28246b03a445f43c63 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 7 Oct 2016 19:18:25 -0700 Subject: [PATCH 28/44] Adding documentation for cross-val pipeline --- mrLoadRet/Plugin/pRF/testPRF.m | 11 ++++++++++- mrLoadRet/Plugin/pRF/trainPRF.m | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m index e73f577f2..ac5e5ec14 100644 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -6,10 +6,19 @@ % purpose: Computes the probability of seeing the model response, % given the observed data, and the computed covariance (noise). % +% +% Input variables: +% observe: true voxel response for the left-out scan at a single timepoint +% modelResp: expected voxel response trained on other n-1 scans +% covarMat: Covariance matrix (size: m x m, where m is # of voxels) +% roiVoxels: list of voxels in this ROI (length m) function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) -%use mvnpdf to compute the probability density function +% Y = MVNPDF(X,MU,SIGMA) %returns the density of the multivariate normal +% distribution with mean MU and covariance SIGMA, evaluated at each row +% of X. +mvnpdf(testResponse, modelResponse, covarMat) %compute log likelihood of the data and sum diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m index 66e6edaed..f0266cb20 100644 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -71,9 +71,12 @@ function trainPRF(view, roiName) %%% scanNum: scan number on which analysis was conducted [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) + %% + %% TO DO: Get the time series data for the left-out scan + %% + %Save residual, covariance matrix, time series, and model response into a structure save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') - %Test pRF Analysis on the left-out scan end From d34d738d0dce638ee757541a577d5a74cbfd77d2 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 27 Oct 2016 12:47:00 -0700 Subject: [PATCH 29/44] Modifying trainPRF and testPRF --- mrLoadRet/Plugin/pRF/pRFNoise.m | 21 +++++++++-------- mrLoadRet/Plugin/pRF/testPRF.m | 40 +++++++++++++++++++++++--------- mrLoadRet/Plugin/pRF/trainPRF.m | 41 ++++++++++++++++----------------- 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m index 1ef1c8ddf..457b0b765 100644 --- a/mrLoadRet/Plugin/pRF/pRFNoise.m +++ b/mrLoadRet/Plugin/pRF/pRFNoise.m @@ -7,8 +7,8 @@ v = newView; end -v = viewSet(v, 'currentGroup', 'Averages'); -analysisFile = dir(sprintf('Averages/pRFAnal/%s', analysisFileName)); +v = viewSet(v, 'currentGroup', 'Concatenation'); +analysisFile = dir(sprintf('Concatenation/pRFAnal/%s', analysisFileName)); % get the analysis structure analysis = viewGet(v,'analysis'); @@ -23,16 +23,19 @@ numVoxels = size(coordinates, 1); -figure; +%figure; +disppercent(-inf, '(pRFNoise) Calculating residuals'); for voxel = 1:numVoxels [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); - subplot(numVoxels,1,voxel) - plot(tSeries(voxel,:), 'k.-'); - hold on; - plot(modelResponse(voxel,:), 'r-'); - plot(residual(voxel,:), 'b-'); - title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); + %subplot(numVoxels,1,voxel) + %plot(tSeries(voxel,:), 'k.-'); + %hold on; + %plot(modelResponse(voxel,:), 'r-'); + %plot(residual(voxel,:), 'b-'); + %title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); + disppercent(voxel/numVoxels); end +disppercent(inf); covMat = residual*residual'; function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m index ac5e5ec14..8723e15d0 100644 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ b/mrLoadRet/Plugin/pRF/testPRF.m @@ -8,20 +8,38 @@ % % % Input variables: -% observe: true voxel response for the left-out scan at a single timepoint +% testTSeries: true voxel response for the left-out scan at a single timepoint % modelResp: expected voxel response trained on other n-1 scans % covarMat: Covariance matrix (size: m x m, where m is # of voxels) -% roiVoxels: list of voxels in this ROI (length m) - -function testPRF(voxelList, tSeries, residual, modelResponse, covarMat) - -% Y = MVNPDF(X,MU,SIGMA) %returns the density of the multivariate normal -% distribution with mean MU and covariance SIGMA, evaluated at each row -% of X. -mvnpdf(testResponse, modelResponse, covarMat) - +% +% Output variables: +% logLikelihood: total likelihood of all the observed tSeries given model response +% probTable: value at (i, j) is the probability that i'th timepoint in tseries is +% explained by j'th timepoint in model response. -%compute log likelihood of the data and sum +function probTable = testPRF(testTSeries, modelResponse, covarMat) +numTimePoints = size(modelResponse, 2); +probTable = zeros(numTimePoints, numTimePoints); +logprobTable = zeros(numTimePoints, numTimePoints); +disppercent(-inf,'(testPRF) Calculating likelihoods'); +for i = 1:numTimePoints + model_i = modelResponse(:, i); + tSeries_i = testTSeries(:, i); + for j = 1:numTimePoints + tSeries_j = testTSeries(:, j); + probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); + if probTable(j, i) == 0 + disp(sprintf('\n(testPRF) mvnpdf at index (%i, %i) returning 0; Exiting...', j, i)); + return; + end + logProbTable(j, i) = log(probTable(j,i)); + end + + %modelLikelihood(i) = mvnpdf(tSeries_i, model_i, covarMat); + %logLikelihood = logLikelihood + log(modelLikelihood(i)); + disppercent(i/numTimePoints); +end +disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m index f0266cb20..c0197bda9 100644 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ b/mrLoadRet/Plugin/pRF/trainPRF.m @@ -9,12 +9,16 @@ % It generates and saves time series, model response, residuals, % and covariance matrices for each fold. % +% +% input: roiName - Name of the ROI we want to run this analysis on +% analysis - Name of analysis file to load +% - This must be the Concat of Average of N scans -function trainPRF(view, roiName) +function trainPRF(view, roiName, analysis) % Currently hardcoding number and names of scan. numScans = 6 -roiName = 'xVal' +roiName = 'lV1' for i = 1:numScans v = newView; @@ -23,7 +27,7 @@ function trainPRF(view, roiName) scanList = [1:i-1 i+1:numScans] %Average the other n-1 scans together - v = viewSet(v, 'currentGroup', 'MotionComp'); + v = viewSet(v, 'currentGroup', 'Concatenation'); scanstr = sprintf('scanList=%s', mat2str(scanList)); [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) %Filename of averaged scan is: tseries-avg-.nii @@ -44,15 +48,11 @@ function trainPRF(view, roiName) v = newView; v = viewSet(v, 'currentGroup', 'Averages'); - % Two ways of calculating ROI coordinates + % Two ways of calculating ROI coordinates --> neither work right now. % Method 1: loadROI.coords v = loadROI(v, sprintf('%s.mat', roiName)) - roiCoords = v.ROIs(1).coords.' - roiCoords = roiCoords(:, 1:3) - - % Method 2: loadROITSeries.scancoords - roiCoords2 = loadROITSeries(v, 'xVal') - roiCoords2 = roiCoords2.scanCoords.' + % roiCoords = v.ROIs(1).coords.' + % roiCoords = roiCoords(:, 1:3) %Run pRF Analysis on average of n-1 scans %pRF(v, params) @@ -63,22 +63,21 @@ function trainPRF(view, roiName) pRF(v, params) % Load analysis by filename - analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr) - v = loadAnalysis(v, ['pRFAnal/' analysisFileName]) + analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr); + v = loadAnalysis(v, ['pRFAnal/' analysisFileName]); scanNum = v.analyses{1}.params.scanNum; + + % Get the time series data for the left-out scan + v2 = newView; + testTSeries = loadROITSeries(v2, roiName, i, 2, 'straightXform=1'); + roiCoords = testTSeries.scanCoords.'; + testTSeries = testTSeries.tSeries; %Get the residual and covariance matrix %%% scanNum: scan number on which analysis was conducted - [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, coordinates, analysisFileName) - - %% - %% TO DO: Get the time series data for the left-out scan - %% + [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, roiCoords, analysisFileName); %Save residual, covariance matrix, time series, and model response into a structure - save(sprintf('SaveData/pRF_fold%i_%s', i, scanListStr), 'residual', 'covMat', 'tSeries', 'modelResponse') + save(sprintf('SaveData/pRF_fold%i_%s_%s', i, scanListStr, roiName), 'residual', 'covMat', 'modelResponse', 'testScanCoords', 'testTSeries') end - - -function test From de1b57e127c2625c1e541c270aa8ca17753f3ea4 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 27 Oct 2016 12:48:41 -0700 Subject: [PATCH 30/44] Adding new on-the-fly cross validation, and grabbed applyConcatFiltering function from elsewhere. Finally dispModel creates a GUI for comparing two voxels. --- mrLoadRet/Plugin/pRF/applyConcatFiltering.m | 24 +++ mrLoadRet/Plugin/pRF/dispModel.m | 194 ++++++++++++++++++++ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 134 ++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/applyConcatFiltering.m create mode 100644 mrLoadRet/Plugin/pRF/dispModel.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_crossValidate.m diff --git a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m new file mode 100644 index 000000000..9838e8e37 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m @@ -0,0 +1,24 @@ +function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) + +tSeries = tSeries(:); + +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) + projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; + tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; +end + +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/dispModel.m new file mode 100644 index 000000000..ec83041dc --- /dev/null +++ b/mrLoadRet/Plugin/pRF/dispModel.m @@ -0,0 +1,194 @@ +function display = dispModel(voxels) + +% +voxels = [47 74 24; 37 67 25]; +analysis = 'pRF_lV1_123456.mat'; +scanNum = 7; + +% Set curr group to Concat and load the Analysis +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' analysis]); +a = viewGet(v, 'Analysis'); +d = viewGet(v, 'd', scanNum); + +% Create new figure +f = figure; + +%%% (1) Voxel 1 Receptive Field %%% +rf1 = subplot(2, 3, 1); + + %Get params +x=voxels(1,1); y=voxels(1,2); z=voxels(1,3); +whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); +r = d.r(whichVoxel, :); +params = d.params(:, whichVoxel); + + %get model fit for this voxel +m = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); + + %plot voxel RF +imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m.rfModel')); +set(rf1,'Box','off'); +set(rf1,'Color',[0.8 0.8 0.8]); +set(rf1,'TickDir','out'); +axis equal +axis tight +hold on +hline(0,'w:');vline(0,'w:'); +title('Voxel 1 Receptive Field Position'); + +%% (2) Voxel 2 Receptive Field +rf2 = subplot(2, 3, 4); +x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); +whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); +params = d.params(:, whichVoxel); +m2 = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); + +imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m2.rfModel')); +set(rf2,'Box','off'); +set(rf2,'Color',[0.8 0.8 0.8]); +set(rf2,'TickDir','out'); +axis equal +axis tight +hold on +hline(0, 'w:');vline(0,'w:'); +title('Voxel 2 Receptive Field Position'); + +%% (3) Stimulus position + +[thisT, modelT] = makeStim(100, 50); + +function [thisT, modelT] = makeStim(time, modelTime) + stP = subplot(2, 3, 2); + %clf(stP); + cla(stP); + im = []; + thisT = time; + thisScan = d.concatInfo.whichScan(thisT); + thisVolume = d.concatInfo.whichVolume(thisT); + + modelT = modelTime; + modelScan = d.concatInfo.whichScan(modelT); + modelVol = d.concatInfo.whichVolume(modelT); + + im(:, :, 3) = flipud(0.7*d.stim{thisScan}.im(:, :, thisVolume)'); + im(:, :, 2) = flipud(0.7*d.stim{modelScan}.im(:, :, modelVol)'); + im(:, :, 1) = 0.30*m.rfModel' + 0.30*m2.rfModel'; + image(d.stimX(:, 1), d.stimY(1, :), im); + axis image + hold on + hline(0, 'w:'); vline(0, 'w:'); + title(sprintf('timeT=%i, modelT=%i', thisT, modelT)); +end + + % Get covariance matrix +residual(1, :) = m.tSeries - m.modelResponse; +residual(2, :) = m2.tSeries - m2.modelResponse; +covMat = residual*residual.'; +radius = covMat(1, 2); + +%%%% (3) and (6): Plot voxels' model response time course and time series +% Plot voxel 1 model timecourse and timeseries +subplot(2, 3, 3); +plot((1:477), m.modelResponse, 'r'); +hold on; plot((1:477), m.tSeries, 'black'); +hold on; vl1m = vline(1); tl1m = text(0,0,''); +hold on; vl1t = vline(1); tl1t = text(0,0,''); +title('Voxel 1 Model Response and Time Series'); + +% Plot voxel 2 model timecourse and timeseries +subplot(2, 3, 6); +plot((1:477), m2.modelResponse, 'r'); +hold on; plot((1:477), m2.tSeries, 'black'); +hold on; vl2m = vline(1); tl2m = text(0,0,''); +hold on; vl2t = vline(1); tl2t = text(0,0,''); +title('Voxel 2 model response and time series'); + + +%% (4) 2D Gaussian model + tSeries +p4 = subplot(2, 3, 5); + +timepoint = 100; +modelTime = 50; + +x1 = m.tSeries(timepoint); +y1 = m2.tSeries(timepoint); + +x2 = m.modelResponse(modelTime); +y2 = m2.modelResponse(modelTime); + +timePlot = plot(x1, y1, '*c'); +hold on +cPlot = circle(x2, y2); +xlim([min(m.tSeries), max(m.tSeries)]); +ylim([min(m2.tSeries), max(m2.tSeries)]); +xlabel(sprintf('Voxel 1: (%d, %d, %d)', voxels(1,1), voxels(1,2), voxels(1,3))); +ylabel(sprintf('Voxel 2: (%d, %d, %d)', voxels(2,1), voxels(2,2), voxels(2,3))); +title('Voxel 1 vs Voxel 2: Percent Signal Change'); + +timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... + 'SliderStep', [1/477, 10/477],... + 'Value', timepoint, 'Callback', @slider1Callback,... + 'Parent', f, 'Position', [.05, .05, .5, .1], 'Units', 'normalized'); +function slider1Callback(hObject, eventdata) + newVal = round(get(hObject, 'Value')); + % Move the * around + subplot(2, 3, 5); + delete(timePlot); + x1 = m.tSeries(newVal); + y1 = m2.tSeries(newVal); + timePlot = plot(x1, y1, '*b'); + + % Move stim bar + [thisT, modelT] = makeStim(newVal, modelT); + + % Move cyan line around time series course + subplot(2, 3, 3); + delete([vl1t tl1t]); + vl1t = vline(newVal, '-b'); + tl1t = text(newVal, 0.92, sprintf('time t: %d', newVal), 'color', 'b'); + subplot(2, 3, 6); + delete([vl2t tl2t]); + vl2t = vline(newVal, '-b'); + tl2t = text(newVal, 0.96, sprintf('time t: %d', newVal), 'color', 'b'); +end + +modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... + 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... + 'Parent', f, 'Units', 'normalized', 'Position', [.05, .15, .5, .1]); +function slider2Callback(hObject, eventdata) + newVal = round(get(hObject, 'Value')); + % Move the circle around + subplot(2, 3, 5); + delete(cPlot); + x2 = m.modelResponse(newVal); + y2 = m2.modelResponse(newVal); + cPlot = circle(x2, y2); + + % Move the stimulus bar + [thisT, modelT] = makeStim(thisT, newVal); + + % Move green line around model time course + subplot(2, 3, 3); + delete([vl1m tl1m]); + vl1m = vline(newVal, '-g'); + tl1m = text(newVal, 0.95, sprintf('Model t: %d', newVal), 'color', 'g'); + subplot(2, 3, 6); + delete([vl2m tl2m]); + vl2m = vline(newVal, '-g'); + tl2m = text(newVal, 0.97, sprintf('Model t: %d', newVal), 'color', 'g'); +end + +align([timeSlider, modelSlider, f], 'center', 'distribute'); + + +function cPlot = circle(x, y) + r = radius; + ang = 0:0.01:2*pi; + xp = r*cos(ang); + yp = r*sin(ang); + cPlot = plot(x+xp, y+yp, 'g'); +end + +end diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m new file mode 100644 index 000000000..63e62c400 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -0,0 +1,134 @@ +%% pRF_crossValidate.m +%% +%% $Id:$ +%% usage: pRF_crossValidate(view, roiName, analysis) +%% by: akshay jagadeesh +%% date: 10/04/16 +%% purpose: Given n MotionComp runs, this function computes a n-fold +%% cross validation, running the pRF analysis n times. +%% It generates and saves time series, model response, residuals, +%% and covariance matrices for each fold. +%% +%% +%% input: roiName - Name of the ROI we want to run this analysis on +%% analysis - Name of analysis file to load +%% - This must be the Concat of Average of N scans + +function fit = pRF_crossValidate(roiName, analysis) + +%roiName = 'lV1'; +%roiName = 'xVal'; +%roiName = 'lineV1'; +analysis = 'pRF_lV1_123456.mat'; + +% Set current group to Concat and load the Analysis file +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' analysis]); +analParams = v.analyses{1}.params; +analScanNum = analParams.scanNum; + +ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan +osn = viewGet(v, 'originalscannum', analScanNum); +ogn2 = viewGet(v, 'originalgroupname', osn, ogn{1}); % Get the motioncomp scans +osn2 = viewGet(v, 'originalscannum', osn, ogn{1}); + +% Get analysis params for pRFFit +concatInfo = viewGet(v, 'concatinfo', analScanNum); +d = viewGet(v, 'd', analScanNum); + +% Get the N original scans & their tSeries +scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); + +for i=1:1 + + % Initialize vars for use later + avg = zeros(size(scans{1}.tSeries)); + leftOut = scans{i}.tSeries; + numVoxels = size(leftOut, 1); + modelResponse = zeros(numVoxels, size(leftOut, 2)); + residual = zeros(numVoxels, size(leftOut, 2)); + + % compute average time series across N-1 scans + for j = 1:length(scans) + if i ~= j + avg = avg + scans{j}.tSeries; + end + end + avg = avg / (length(scans)-1); + + % Apply Concat Filtering to averages & left out + for k = 1:numVoxels + filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); + leftOut(k, :) = applyConcatFiltering(leftOut(k, :), concatInfo, 1); + end + + disppercent(-inf, '(crossVal) Fitting pRF to voxels'); + % run pRFFit on the averaged tSeries + coords = scans{i}.scanCoords.'; + for h = 1:numVoxels + x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, h), 'concatInfo', d.concatInfo, 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); + modelResponse(h, :) = modelFit.modelResponse; + residual(h, :) = modelFit.tSeries - modelFit.modelResponse; + + disppercent(h/numVoxels); + end + disppercent(inf); + + %Calculate covariance matrix of voxels on our calculated residual + covMat = residual*residual'; + + % Calculate covariance matrix of voxels using pRFNoise's method + %[residual, covMat, tSeries, modelResponse] = pRFNoise(v, analysisScanNum, coordinates, analysis); + %[resid, covMat2, tS, modResp] = pRFNoise([], analScanNum, coords, analysis); + %noise.resid = resid; + %noise.covMat = covMat2; + %noise.tSeries = tS; + %noise.modelResponse = modResp; + + % Compare model response to left-out timeseries + probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); +end +fit.modelResponse = modelResponse; +fit.residual = residual; +fit.leftOut = leftOut; +fit.covMat = covMat; +fit.probTable = probTable; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% applyConcatFiltering % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) + +% apply the same filter as original data +% check for what filtering was done +tSeries = tSeries(:); + +% apply detrending (either if concatInfo does not say what it did or if +% the filterType field has detrend in it) +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + % check for length match + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +% project out the mean vector +if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) + projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; + tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; +end + +% now remove mean +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +% make back into the right dimensions +tSeries = tSeries(:)'; From 852a820ce53d77906de1a80e9444d25f60d32afa Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:16:10 -0800 Subject: [PATCH 31/44] Adding difference of gaussians (DoG) model --- mrLoadRet/Plugin/pRF/pRFFit.m | 4 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 2 +- mrLoadRet/Plugin/pRF/pRF_diffGaussian.m | 134 ++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/pRF_diffGaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index c0d2820f5..16e0f6a35 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -540,7 +540,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); @@ -557,6 +557,8 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) output = pRF_gaussian(varargin{:}); case 'gaussian-hdr' output = pRF_gaussianhdr(varargin{:}); + case 'gaussian-diffs' + output = pRF_diffGaussian(varargin{:}); otherwise testModel = @pRF_exp; %%% Only need to change this line to specify a new model. output = testModel(varargin{:}); diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index 606fd3850..afa44e70a 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,7 +116,7 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; diff --git a/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m new file mode 100644 index 000000000..9157aa743 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m @@ -0,0 +1,134 @@ +% pRF_gaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_diffGaussian(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % and convolve in time. + pPlus = convolveModelResponseWithHRF(rPlus,hrf); + pMinus = convolveModelResponseWithHRF(rMinus,hrf); + + % Model response is the difference of Gaussians, weighted by Beta amplitudes + thisModelResponse = pPlus*p.B1 + pMinus*p.B2; + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 -inf -inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; + fitParams.initParams = [0 0 4 4 1 0]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.std2 = params(4); + p.B1 = params(5); + p.B2 = params(6); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From ae9374c5a84534257088c1bad0e520ec78c91258 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:20:37 -0800 Subject: [PATCH 32/44] Adding scripts to get best N voxels, and to plot model prediction accuracy --- mrLoadRet/Plugin/pRF/getBestVoxels.m | 33 +++++++ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 118 +++++++++++++++++++---- mrLoadRet/Plugin/pRF/plotFigs.m | 83 ++++++++++++++++ 3 files changed, 213 insertions(+), 21 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/getBestVoxels.m create mode 100644 mrLoadRet/Plugin/pRF/plotFigs.m diff --git a/mrLoadRet/Plugin/pRF/getBestVoxels.m b/mrLoadRet/Plugin/pRF/getBestVoxels.m new file mode 100644 index 000000000..801f3b146 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/getBestVoxels.m @@ -0,0 +1,33 @@ +function cords = getBestVoxels(scanNum, bestN, roiName, analysis) + +if(ieNotDefined('scanNum')) + disp(sprintf('(getBestVoxels) No inputs given, using preset defaults')); + scanNum = 1; + bestN = 90; + roiName = 'both_pRF'; + analysis = 'pRF.mat' +end + +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +groupNum = viewGet(v, 'currentGroup'); +%v = viewSet(v, 'currentGroup', 'Averages'); +lV1 = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); + +v = loadAnalysis(v, ['pRFAnal/' analysis]); + +r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); +lV1 = getSortIndex(v, lV1, r2); + +sortIndex = lV1{1}.sortindex; +r2 = lV1{1}.r2; +scanLinCoords = lV1{1}.scanLinearCoords; + +scanDims = viewGet(v, 'scanDims'); + +[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); +cords = [i;j;k;ones(1,bestN)]; + +%fits = pRF_crossValidate(cords); +%fit.cords = cords; +end diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m index 63e62c400..95c0918a4 100644 --- a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -13,17 +13,21 @@ %% input: roiName - Name of the ROI we want to run this analysis on %% analysis - Name of analysis file to load %% - This must be the Concat of Average of N scans +%% newCoords - in the form [x1 y1 z1 1; x2 y2 z2 1].' -function fit = pRF_crossValidate(roiName, analysis) +function fits = pRF_crossValidate(newCoords, roiName, analysis) -%roiName = 'lV1'; -%roiName = 'xVal'; -%roiName = 'lineV1'; -analysis = 'pRF_lV1_123456.mat'; +%% Plot Figures flag (set to [] if you don't want to plot) +plotFigs = 1; + +roiName = 'V1'; +%analysis = 'pRF_lV1_123456.mat'; +analysis = 'pRF.mat'; % Set current group to Concat and load the Analysis file v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); +%v = viewSet(v, 'currentGroup', 'Averages'); v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; @@ -36,18 +40,40 @@ % Get analysis params for pRFFit concatInfo = viewGet(v, 'concatinfo', analScanNum); d = viewGet(v, 'd', analScanNum); +scanDims = viewGet(v, 'scanDims'); % Get the N original scans & their tSeries -scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); +%keyboard +if ~ieNotDefined('newCoords') + if(strmatch(newCoords, 'best')) + disp(sprintf('(crossValidate) Getting 90 best defined voxels in ROI %s', roiName)); + coords = getBestVoxels(analScanNum, 85, roiName, analysis); + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + tempRoi.coords = coords; + else + disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + tempRoi.coords = newCoords; + end + scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); +elseif ~ieNotDefined('roiName') + disp(sprintf('(crossValidate) Coordinates not given, getting tSeries for ROI %s', roiName)); + scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); +else + disp(sprintf('(crossValidate) Neither ROI name nor coordinates provided. Exiting.')); + return +end -for i=1:1 - +numFolds = length(scans); +for i=1:numFolds; + disp(sprintf('(crossValidate) Fold %d of %d', i, numFolds)); % Initialize vars for use later + fit = []; avg = zeros(size(scans{1}.tSeries)); - leftOut = scans{i}.tSeries; - numVoxels = size(leftOut, 1); - modelResponse = zeros(numVoxels, size(leftOut, 2)); - residual = zeros(numVoxels, size(leftOut, 2)); + unfilteredLeftOut = scans{i}.tSeries; + numVoxels = size(unfilteredLeftOut, 1); + modelResponse = zeros(numVoxels, size(unfilteredLeftOut, 2)); + residual = zeros(numVoxels, size(unfilteredLeftOut, 2)); % compute average time series across N-1 scans for j = 1:length(scans) @@ -58,22 +84,34 @@ avg = avg / (length(scans)-1); % Apply Concat Filtering to averages & left out + %keyboard for k = 1:numVoxels filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); - leftOut(k, :) = applyConcatFiltering(leftOut(k, :), concatInfo, 1); + leftOut(k, :) = applyConcatFiltering(unfilteredLeftOut(k, :), concatInfo, 1); end - disppercent(-inf, '(crossVal) Fitting pRF to voxels'); + disppercent(-inf, sprintf('\t(crossVal) Fitting pRF to %d voxels', numVoxels)); % run pRFFit on the averaged tSeries coords = scans{i}.scanCoords.'; for h = 1:numVoxels x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, h), 'concatInfo', d.concatInfo, 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); + linCoords = sub2ind(scanDims, x, y, z); + linVox = find(d.linearCoords == linCoords); + if isempty(linVox) + disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); + continue + end + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo, 'concatInfo', concatInfo); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; disppercent(h/numVoxels); end + leftOut(all(modelResponse==0, 2), :) = []; + modelResponse(all(modelResponse==0, 2), :) = []; + residual(all(residual==0,2), :) = []; + numSuccess = size(modelResponse, 1); + disp(sprintf('(crossVal) Successfully fit model to %d voxels', numSuccess)); disppercent(inf); %Calculate covariance matrix of voxels on our calculated residual @@ -89,13 +127,50 @@ % Compare model response to left-out timeseries probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); + fit.modelResponse = modelResponse; + fit.residual = residual; + fit.leftOut = leftOut; + fit.covMat = covMat; + fit.probTable = probTable; + fit.fitParams = fitParams; + + eval(sprintf('fits(%d)=fit;', i)) + timeLen = size(fit.modelResponse, 2); + if ~ieNotDefined('plotFigs') + figure; subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); + subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); + hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); + end + end -fit.modelResponse = modelResponse; -fit.residual = residual; -fit.leftOut = leftOut; -fit.covMat = covMat; -fit.probTable = probTable; +% Average together probability tables +pTable = zeros(timeLen, timeLen); +modResp = zeros(numSuccess, timeLen); +resid = zeros(numSuccess, timeLen); +leftOut = zeros(numSuccess, timeLen); +covMat = zeros(numSuccess, numSuccess); +fp = zeros( +for i = 1:length(fits) + fit = fits(i); + pTable = pTable + fit.probTable; + modResp = modResp + fit.modelResponse; + leftOut = leftOut + fit.leftOut; + covMat = covMat + fit.covMat; + resid = resid + fit.residual; +end +fit = []; +fit.modelResponse = modResp / length(fits); +fit.residual = resid / length(fits); +fit.leftOut = leftOut / length(fits); +fit.covMat = covMat / length(fits); +fit.probTable = pTable / length(fits); +fit.fitParams = []; +eval(sprintf('fits(%d)=fit;', numFolds+1)); +%if ~ieNotDefined('plotFigs') + %fit = fits(numFolds+1); + %plotFigs(fit, d); +%end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % applyConcatFiltering % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -108,6 +183,7 @@ % apply detrending (either if concatInfo does not say what it did or if % the filterType field has detrend in it) if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + %disp(sprintf('(pRFFit:applyConcatFiltering) Apply detrending')); tSeries = eventRelatedDetrend(tSeries); end diff --git a/mrLoadRet/Plugin/pRF/plotFigs.m b/mrLoadRet/Plugin/pRF/plotFigs.m new file mode 100644 index 000000000..ffe2dc52d --- /dev/null +++ b/mrLoadRet/Plugin/pRF/plotFigs.m @@ -0,0 +1,83 @@ +function plotFigs(fits, d) + +numFolds = length(fits)-1; +fit = fits(numFolds+1); + +timeLen = size(fit.modelResponse, 2); + +%%% 1. Plot prediction probability chart (batik) +f=figure; subplot(2, 2, 1); imagesc(log(fit.probTable)); axis ij; colorbar; +xlabel('Model Time Series'); ylabel('Observed Time series'); +hold on; hl = hline(200, '-b'); +hold on; pt = plot(0,0,'*g'); + % Plot best predicted points +count = 0; +for i = 1:timeLen + tS = fit.probTable(i,:); + [~, mI] = max(tS); + maxInd(i) = mI; + if( abs(mI - i) <= 5) + count = count + 1; + end +end +hold on; plot(maxInd, (1:timeLen), '*g', 'MarkerSize', 1); +title(sprintf('Avg Model Prediction Probability:\n %d / %d timepoints (%0.1f %%) correctly predicted within 5 using Max Likelihood', count, timeLen, 100*count/timeLen)); + +%%% 3. Plot observed and model response time course +subplot(2, 2, 3); plot((1:timeLen), fit.leftOut, 'k'); +hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model Response'); +hold on; vl1 = vline(0, 'k'); hold on; vl2 = vline(0, 'k'); + +%%% 4. Plot voxel receptive fields +%rf = subplot(2,2,4); plot(fits(1).fitParams(:,4), fits(1).fitParams(:,5), '*'); +%title('Voxel Receptive Field positions'); +%set(rf, 'Box', 'off'); set(rf, 'Color', [.8 .8 .8]); set(rf,'TickDir','out'); +%axis equal; axis tight; xlim([-30 30]); ylim([-20 20]); hold on; hline(0, 'w:'); vline(0,'w:'); + +timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(fit.modelResponse),... + 'SliderStep', [1/timeLen 10/timeLen], 'Value', 200, 'Callback', @timeSliderCallback,... + 'Parent',f, 'Units', 'normalized', 'Position', [.25, -.05,.5,.1]); +function timeSliderCallback(hObject, evendata) + newVal = round(get(hObject, 'Value')); + + %plot the stimulus predicted by the model time point with highest posterior probability + timeSeries = fit.probTable(newVal, :); + [maxVal, maxIndex] = max(timeSeries); + stimPl = subplot(2, 2, [2 4]); + cla(stimPl); + im = []; + predScan = d.concatInfo.whichScan(maxIndex); + predVol = d.concatInfo.whichVolume(maxIndex); + trueScan = d.concatInfo.whichScan(newVal); + trueVol = d.concatInfo.whichVolume(newVal); + im(:, :, 3) = flipud(0.7*d.stim{trueScan}.im(:,:,trueVol)'); + im(:, :, 2) = flipud(0.7*d.stim{predScan}.im(:,:,predVol)'); + im(:, :, 1) = 0; + image(d.stimX(:,1), d.stimY(1,:), im); + axis image; hold on; + hline(0, 'w:'); vline(0, 'w:'); + hold on; plot(fits(1).fitParams(:, 4), fits(1).fitParams(:, 5), '*w', 'MarkerSize', 1); + title(sprintf('Stim predictions: Timepoint %i is best predicted by Modelpoint %i', newVal, maxIndex)); + + % Plot line and point of highest prediction + subplot(2,2,1); + delete([hl pt]); + hl = hline(newVal, '-b'); + set(hl, 'LineWidth', 5); + pt = plot(maxIndex, newVal, '*g'); + + % Plot vertical line on time series plots + subplot(2, 2, 3); + delete([vl1 vl2]); + vl1 = vline(newVal, '-b'); + set(vl1, 'LineWidth', 5); + hold on; + vl2 = vline(maxIndex, '-g'); + set(vl2, 'LineWidth', 5); + title(sprintf('Time Series: %d; Model Time: %d', newVal, maxIndex)); +end + +bl3 = uicontrol('Parent',f,'Style','text','Units', 'normalized', 'Position', [.45, .05 ,.1,.015],... + 'String', sprintf('Time Slider (blue)')); + +end From 16d70856d16da71128dc00ef0ff225692091dadd Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 18 Nov 2016 21:21:41 -0800 Subject: [PATCH 33/44] minor changes to dispModel, which compares 2 voxels --- mrLoadRet/Plugin/pRF/dispModel.m | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/dispModel.m index ec83041dc..0f78d513b 100644 --- a/mrLoadRet/Plugin/pRF/dispModel.m +++ b/mrLoadRet/Plugin/pRF/dispModel.m @@ -1,7 +1,8 @@ -function display = dispModel(voxels) +function display = dispModel(fit, voxels) -% -voxels = [47 74 24; 37 67 25]; +if ieNotDefined('voxels') + voxels = [47 74 24; 37 67 25]; +end analysis = 'pRF_lV1_123456.mat'; scanNum = 7; @@ -38,7 +39,7 @@ hline(0,'w:');vline(0,'w:'); title('Voxel 1 Receptive Field Position'); -%% (2) Voxel 2 Receptive Field +%% (4) Voxel 2 Receptive Field rf2 = subplot(2, 3, 4); x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); @@ -55,7 +56,7 @@ hline(0, 'w:');vline(0,'w:'); title('Voxel 2 Receptive Field Position'); -%% (3) Stimulus position +%% (2) Stimulus position [thisT, modelT] = makeStim(100, 50); @@ -95,6 +96,7 @@ hold on; plot((1:477), m.tSeries, 'black'); hold on; vl1m = vline(1); tl1m = text(0,0,''); hold on; vl1t = vline(1); tl1t = text(0,0,''); +xlim([1 477]) title('Voxel 1 Model Response and Time Series'); % Plot voxel 2 model timecourse and timeseries @@ -103,10 +105,11 @@ hold on; plot((1:477), m2.tSeries, 'black'); hold on; vl2m = vline(1); tl2m = text(0,0,''); hold on; vl2t = vline(1); tl2t = text(0,0,''); +xlim([1 477]) title('Voxel 2 model response and time series'); -%% (4) 2D Gaussian model + tSeries +%% (5) 2D Gaussian model + tSeries p4 = subplot(2, 3, 5); timepoint = 100; @@ -130,7 +133,7 @@ timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... 'SliderStep', [1/477, 10/477],... 'Value', timepoint, 'Callback', @slider1Callback,... - 'Parent', f, 'Position', [.05, .05, .5, .1], 'Units', 'normalized'); + 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); function slider1Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); % Move the * around @@ -156,7 +159,7 @@ function slider1Callback(hObject, eventdata) modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.05, .15, .5, .1]); + 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); function slider2Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); % Move the circle around @@ -191,4 +194,14 @@ function slider2Callback(hObject, eventdata) cPlot = plot(x+xp, y+yp, 'g'); end + + +figure; subplot(3, 1, 1); +plot((1:477), m.tSeries, 'black'); +hold on; plot((1:477), m.modelResponse, 'blue'); +subplot(3, 1, 2); plot((1:477), m2.tSeries, 'red'); hold on; plot((1:477), m2.modelResponse, 'magenta') +xlim([1 477]) +if ~ieNotDefined('fit') + subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; +end end From 9cdba00bf9fe2f7aed4322bd7b31220b39e67d66 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 20:58:00 -0800 Subject: [PATCH 34/44] Cleaning up old files, reorganizing subprocedures into crossVal, renamed a few files --- mrLoadRet/Plugin/pRF/applyConcatFiltering.m | 24 --- mrLoadRet/Plugin/pRF/getBestVoxels.m | 33 ---- mrLoadRet/Plugin/pRF/getR2Overlay.m | 13 -- mrLoadRet/Plugin/pRF/pRFNoise.m | 60 ------ mrLoadRet/Plugin/pRF/pRF_crossValidate.m | 178 +++++++++++------- .../Plugin/pRF/{dispModel.m => plot2voxels.m} | 45 +++-- .../pRF/{plotFigs.m => predictStimulus.m} | 22 ++- mrLoadRet/Plugin/pRF/testPRF.m | 45 ----- mrLoadRet/Plugin/pRF/trainPRF.m | 83 -------- 9 files changed, 159 insertions(+), 344 deletions(-) delete mode 100644 mrLoadRet/Plugin/pRF/applyConcatFiltering.m delete mode 100644 mrLoadRet/Plugin/pRF/getBestVoxels.m delete mode 100644 mrLoadRet/Plugin/pRF/getR2Overlay.m delete mode 100644 mrLoadRet/Plugin/pRF/pRFNoise.m rename mrLoadRet/Plugin/pRF/{dispModel.m => plot2voxels.m} (83%) rename mrLoadRet/Plugin/pRF/{plotFigs.m => predictStimulus.m} (81%) delete mode 100644 mrLoadRet/Plugin/pRF/testPRF.m delete mode 100644 mrLoadRet/Plugin/pRF/trainPRF.m diff --git a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m b/mrLoadRet/Plugin/pRF/applyConcatFiltering.m deleted file mode 100644 index 9838e8e37..000000000 --- a/mrLoadRet/Plugin/pRF/applyConcatFiltering.m +++ /dev/null @@ -1,24 +0,0 @@ -function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) - -tSeries = tSeries(:); - -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) - projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; - tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; -end - -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/getBestVoxels.m b/mrLoadRet/Plugin/pRF/getBestVoxels.m deleted file mode 100644 index 801f3b146..000000000 --- a/mrLoadRet/Plugin/pRF/getBestVoxels.m +++ /dev/null @@ -1,33 +0,0 @@ -function cords = getBestVoxels(scanNum, bestN, roiName, analysis) - -if(ieNotDefined('scanNum')) - disp(sprintf('(getBestVoxels) No inputs given, using preset defaults')); - scanNum = 1; - bestN = 90; - roiName = 'both_pRF'; - analysis = 'pRF.mat' -end - -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -groupNum = viewGet(v, 'currentGroup'); -%v = viewSet(v, 'currentGroup', 'Averages'); -lV1 = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); - -v = loadAnalysis(v, ['pRFAnal/' analysis]); - -r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); -lV1 = getSortIndex(v, lV1, r2); - -sortIndex = lV1{1}.sortindex; -r2 = lV1{1}.r2; -scanLinCoords = lV1{1}.scanLinearCoords; - -scanDims = viewGet(v, 'scanDims'); - -[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); -cords = [i;j;k;ones(1,bestN)]; - -%fits = pRF_crossValidate(cords); -%fit.cords = cords; -end diff --git a/mrLoadRet/Plugin/pRF/getR2Overlay.m b/mrLoadRet/Plugin/pRF/getR2Overlay.m deleted file mode 100644 index aa7f7d04e..000000000 --- a/mrLoadRet/Plugin/pRF/getR2Overlay.m +++ /dev/null @@ -1,13 +0,0 @@ -function r2Overlay = getR2Overlay(modelName) - -v = newView; -v = viewSet(v, 'curGroup', 'Averages'); -v = viewSet(v, 'curScan', 1); -prfModel = sprintf('pRFAnal/%s', modelName); -v = loadAnalysis(v, prfModel); -r2OverlayNum = find(strcmp('r2', viewGet(v, 'overlayNames'))); -v = viewSet(v, 'curOverlay', r2OverlayNum); -r2Overlay = viewGet(v, 'overlayData', 1); - -validR2 = r2Overlay(~isnan(r2Overlay)); -fprintf('Mean r2 for well-defined voxels: %d', mean(validR2)); diff --git a/mrLoadRet/Plugin/pRF/pRFNoise.m b/mrLoadRet/Plugin/pRF/pRFNoise.m deleted file mode 100644 index 457b0b765..000000000 --- a/mrLoadRet/Plugin/pRF/pRFNoise.m +++ /dev/null @@ -1,60 +0,0 @@ -function [residual, covMat, tSeries, modelResponse] = pRFNoise(v,scanNum,coordinates, analysisFileName) - -% coordinates = [53,61,25; 53,59,24; 51,57,24; 51,56,22; 52,55,20]; -% scanNum = 1; - -if ieNotDefined('v') - v = newView; -end - -v = viewSet(v, 'currentGroup', 'Concatenation'); -analysisFile = dir(sprintf('Concatenation/pRFAnal/%s', analysisFileName)); - -% get the analysis structure -analysis = viewGet(v,'analysis'); -if ~isfield(analysis,'d') || (length(analysis.d) < scanNum) || isempty(analysis.d) - v = loadAnalysis(v, ['pRFAnal/' analysisFile.name]); - analysis = viewGet(v,'analysis'); - -end - -d = viewGet(v,'d',scanNum); -if isempty(d),disp(sprintf('Could not find d structure for this scan'));return,end - -numVoxels = size(coordinates, 1); - -%figure; -disppercent(-inf, '(pRFNoise) Calculating residuals'); -for voxel = 1:numVoxels - [residual(voxel,:), tSeries(voxel,:), modelResponse(voxel,:)] = getResidual(v,analysis, d, scanNum, coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3)); - %subplot(numVoxels,1,voxel) - %plot(tSeries(voxel,:), 'k.-'); - %hold on; - %plot(modelResponse(voxel,:), 'r-'); - %plot(residual(voxel,:), 'b-'); - %title(sprintf('voxel %i %i %i', coordinates(voxel,1), coordinates(voxel,2), coordinates(voxel,3))); - disppercent(voxel/numVoxels); -end -disppercent(inf); -covMat = residual*residual'; - -function [residual, tSeries,modelResponse] = getResidual(v,a,d, scanNum,x,y,z) - -% get the params that have been run -scanDims = viewGet(v,'scanDims',scanNum); -whichVoxel = find(d.linearCoords == sub2ind(scanDims,x,y,z)); -r = d.r(whichVoxel,:); - -params = d.params(:,whichVoxel); -if isfield(d,'paramsInfo') - paramsInfo = d.paramsInfo; -else - paramsInfo = []; -end - -% get params -m = pRFFit(v,scanNum,x,y,z,'stim',d.stim,'getModelResponse=1','params',params,'concatInfo',d.concatInfo,'fitTypeParams',a.params.pRFFit,'paramsInfo',paramsInfo); - -residual = m.tSeries - m.modelResponse; -tSeries = m.tSeries; -modelResponse = m.modelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m index 95c0918a4..aa4af2eda 100644 --- a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m +++ b/mrLoadRet/Plugin/pRF/pRF_crossValidate.m @@ -1,33 +1,35 @@ %% pRF_crossValidate.m %% -%% $Id:$ -%% usage: pRF_crossValidate(view, roiName, analysis) +%% usage: fits = pRF_crossValidate(newCoords, [], analysis) --> run on specified coordinates +%% fits = pRF_crossValidate([], roiName, analysis) --> run on specified ROI +%% fits = pRF_crossValidate('best', roiName, analysis) --> run on best N voxels in specified ROI %% by: akshay jagadeesh %% date: 10/04/16 -%% purpose: Given n MotionComp runs, this function computes a n-fold -%% cross validation, running the pRF analysis n times. -%% It generates and saves time series, model response, residuals, -%% and covariance matrices for each fold. +%% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF +%% analysis n times. It generates and saves time series, model response, residuals, and covariance +%% matrices for each fold. +%% We then calculate the probability that each point in the observed time series is predicted +%% by the pRF model response. %% %% %% input: roiName - Name of the ROI we want to run this analysis on %% analysis - Name of analysis file to load %% - This must be the Concat of Average of N scans -%% newCoords - in the form [x1 y1 z1 1; x2 y2 z2 1].' +%% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' function fits = pRF_crossValidate(newCoords, roiName, analysis) -%% Plot Figures flag (set to [] if you don't want to plot) -plotFigs = 1; +%%%%%%% Default inputs %%%%%%%%% +newCoords = 'best'; +roiName = 'bothV1'; +analysis = 'pRF_v1.mat'; +nBest = 5; +plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots -roiName = 'V1'; -%analysis = 'pRF_lV1_123456.mat'; -analysis = 'pRF.mat'; % Set current group to Concat and load the Analysis file v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); -%v = viewSet(v, 'currentGroup', 'Averages'); v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; @@ -43,16 +45,14 @@ scanDims = viewGet(v, 'scanDims'); % Get the N original scans & their tSeries -%keyboard if ~ieNotDefined('newCoords') + tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); if(strmatch(newCoords, 'best')) - disp(sprintf('(crossValidate) Getting 90 best defined voxels in ROI %s', roiName)); - coords = getBestVoxels(analScanNum, 85, roiName, analysis); - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); + disp(sprintf('(crossValidate) Getting %d best defined voxels in ROI %s', nBest, roiName)); + coords = getBestVoxels(v, analScanNum, nBest, roiName, analysis); tempRoi.coords = coords; else disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); tempRoi.coords = newCoords; end scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); @@ -101,7 +101,9 @@ disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); continue end - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1', 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo, 'concatInfo', concatInfo); + modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... + 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... + d.paramsInfo, 'concatInfo', concatInfo); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; @@ -111,22 +113,14 @@ modelResponse(all(modelResponse==0, 2), :) = []; residual(all(residual==0,2), :) = []; numSuccess = size(modelResponse, 1); - disp(sprintf('(crossVal) Successfully fit model to %d voxels', numSuccess)); disppercent(inf); + disp(sprintf('\t(crossVal) Successfully fit model to %d voxels', numSuccess)); %Calculate covariance matrix of voxels on our calculated residual covMat = residual*residual'; - % Calculate covariance matrix of voxels using pRFNoise's method - %[residual, covMat, tSeries, modelResponse] = pRFNoise(v, analysisScanNum, coordinates, analysis); - %[resid, covMat2, tS, modResp] = pRFNoise([], analScanNum, coords, analysis); - %noise.resid = resid; - %noise.covMat = covMat2; - %noise.tSeries = tS; - %noise.modelResponse = modResp; - % Compare model response to left-out timeseries - probTable = testPRF(leftOut, modelResponse, diag(diag(covMat))); + probTable = calcProb(leftOut, modelResponse, diag(diag(covMat))); fit.modelResponse = modelResponse; fit.residual = residual; fit.leftOut = leftOut; @@ -137,61 +131,66 @@ eval(sprintf('fits(%d)=fit;', i)) timeLen = size(fit.modelResponse, 2); if ~ieNotDefined('plotFigs') - figure; subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); - subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); - hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); + figure; + subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); + subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); hold on; + plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); end end -% Average together probability tables -pTable = zeros(timeLen, timeLen); -modResp = zeros(numSuccess, timeLen); -resid = zeros(numSuccess, timeLen); -leftOut = zeros(numSuccess, timeLen); -covMat = zeros(numSuccess, numSuccess); -fp = zeros( -for i = 1:length(fits) - fit = fits(i); - pTable = pTable + fit.probTable; - modResp = modResp + fit.modelResponse; - leftOut = leftOut + fit.leftOut; - covMat = covMat + fit.covMat; - resid = resid + fit.residual; -end +% Average across folds and store in fits struct array fit = []; -fit.modelResponse = modResp / length(fits); -fit.residual = resid / length(fits); -fit.leftOut = leftOut / length(fits); -fit.covMat = covMat / length(fits); -fit.probTable = pTable / length(fits); -fit.fitParams = []; -eval(sprintf('fits(%d)=fit;', numFolds+1)); -%if ~ieNotDefined('plotFigs') - %fit = fits(numFolds+1); - %plotFigs(fit, d); -%end +fit.modelResponse = meanStruct(fits, 'modelResponse'); +fit.residual = meanStruct(fits, 'residual'); +fit.leftOut = meanStruct(fits, 'leftOut'); +fit.covMat = meanStruct(fits, 'covMat'); +fit.probTable = meanStruct(fits, 'probTable'); +fit.fitParams = meanStruct(fits, 'fitParams'); +fits(numFolds+1) = fit; + + + % -- end main program -- % + + +%%%%%%%%%%%%%%%%%%%%%% Helper Methods %%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% applyConcatFiltering % +% meanStruct % +% % +function avg = meanStruct(structArr, field, notI) + +if(ieNotDefined('notI')) + notI = -1; +else + disp(sprintf('Averaging across all but the %d th fold', notI)); +end +eval(sprintf('avg = zeros(size(structArr(1).%s));', field)); + +for i = 1:length(structArr) + if i~=notI + avg = avg + eval(sprintf('structArr(i).%s', field)); + end +end +avg = avg / length(structArr); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% applyConcatFiltering % +% % function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) -% apply the same filter as original data -% check for what filtering was done tSeries = tSeries(:); -% apply detrending (either if concatInfo does not say what it did or if -% the filterType field has detrend in it) +% apply detrending if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - %disp(sprintf('(pRFFit:applyConcatFiltering) Apply detrending')); tSeries = eventRelatedDetrend(tSeries); end % apply hipass filter if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - % check for length match if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(pRFFit:applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); else tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); end @@ -205,6 +204,49 @@ % now remove mean tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -% make back into the right dimensions tSeries = tSeries(:)'; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% getBestVoxels % +% % +function cords = getBestVoxels(v, scanNum, bestN, roiName, analysis) + +groupNum = viewGet(v, 'currentGroup'); +roi = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); + +r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); +roi = getSortIndex(v, roi, r2); + +% Get sort index based on r2 and list of linear coords +sortIndex = roi{1}.sortindex; +scanLinCoords = roi{1}.scanLinearCoords; +scanDims = viewGet(v, 'scanDims'); +% get the linear coords with highest sortIndex and convert to 3d coords +[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); +cords = [i;j;k;ones(1, bestN)]; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% calcProb % + +function probTable = calcProb(testTSeries, modelResponse, covarMat) + +numTimePoints = size(modelResponse, 2); +probTable = zeros(numTimePoints, numTimePoints); + +disppercent(-inf, sprintf('\t(calcProb) Calculating prediction likelihoods')); +for i = 1:numTimePoints + model_i = modelResponse(:, i); + tSeries_i = testTSeries(:, i); + + for j = 1:numTimePoints + tSeries_j = testTSeries(:, j); + probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); + if probTable(j, i) == 0 + disp(sprintf('\n(calcProb) mvnpdf at index(%i, %i) returning 0; Exiting.', j, i)); + return; + end + end + disppercent(i/numTimePoints); +end +disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/dispModel.m b/mrLoadRet/Plugin/pRF/plot2voxels.m similarity index 83% rename from mrLoadRet/Plugin/pRF/dispModel.m rename to mrLoadRet/Plugin/pRF/plot2voxels.m index 0f78d513b..53e0a8a7b 100644 --- a/mrLoadRet/Plugin/pRF/dispModel.m +++ b/mrLoadRet/Plugin/pRF/plot2voxels.m @@ -1,15 +1,27 @@ -function display = dispModel(fit, voxels) +%% plot2voxels.m +%% +%% usage: plot2voxels(fit, voxels) +%% purpose: plots 2 voxels' receptive fields and time courses +%% +%% input: analysis - filename of analysis file +%% fit - struct containing fields to plot probTable +%% voxels - list of two voxels in format [x1 y1 z1; x2 y2 z2] +%% + +function display = plot2voxels(analysis, voxels, fit) if ieNotDefined('voxels') - voxels = [47 74 24; 37 67 25]; + voxels = [44 74 21; 43 74 21]; +end +if ieNotDefined('analysis') + analysis = 'pRF_lV1_123456.mat'; end -analysis = 'pRF_lV1_123456.mat'; -scanNum = 7; % Set curr group to Concat and load the Analysis v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); v = loadAnalysis(v, ['pRFAnal/' analysis]); +scanNum = v.analyses{1}.params.scanNum; a = viewGet(v, 'Analysis'); d = viewGet(v, 'd', scanNum); @@ -91,21 +103,22 @@ %%%% (3) and (6): Plot voxels' model response time course and time series % Plot voxel 1 model timecourse and timeseries +tLen = length(m.modelResponse); subplot(2, 3, 3); -plot((1:477), m.modelResponse, 'r'); -hold on; plot((1:477), m.tSeries, 'black'); +plot((1:tLen), m.modelResponse, 'r'); +hold on; plot((1:tLen), m.tSeries, 'black'); hold on; vl1m = vline(1); tl1m = text(0,0,''); hold on; vl1t = vline(1); tl1t = text(0,0,''); -xlim([1 477]) +xlim([1 tLen]) title('Voxel 1 Model Response and Time Series'); % Plot voxel 2 model timecourse and timeseries subplot(2, 3, 6); -plot((1:477), m2.modelResponse, 'r'); -hold on; plot((1:477), m2.tSeries, 'black'); +plot((1:tLen), m2.modelResponse, 'r'); +hold on; plot((1:tLen), m2.tSeries, 'black'); hold on; vl2m = vline(1); tl2m = text(0,0,''); hold on; vl2t = vline(1); tl2t = text(0,0,''); -xlim([1 477]) +xlim([1 tLen]) title('Voxel 2 model response and time series'); @@ -131,7 +144,7 @@ title('Voxel 1 vs Voxel 2: Percent Signal Change'); timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... - 'SliderStep', [1/477, 10/477],... + 'SliderStep', [1/tLen, 10/tLen],... 'Value', timepoint, 'Callback', @slider1Callback,... 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); function slider1Callback(hObject, eventdata) @@ -158,7 +171,7 @@ function slider1Callback(hObject, eventdata) end modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... - 'SliderStep', [1/477 10/477], 'Value', modelTime, 'Callback', @slider2Callback,... + 'SliderStep', [1/tLen 10/tLen], 'Value', modelTime, 'Callback', @slider2Callback,... 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); function slider2Callback(hObject, eventdata) newVal = round(get(hObject, 'Value')); @@ -197,10 +210,10 @@ function slider2Callback(hObject, eventdata) figure; subplot(3, 1, 1); -plot((1:477), m.tSeries, 'black'); -hold on; plot((1:477), m.modelResponse, 'blue'); -subplot(3, 1, 2); plot((1:477), m2.tSeries, 'red'); hold on; plot((1:477), m2.modelResponse, 'magenta') -xlim([1 477]) +plot((1:tLen), m.tSeries, 'black'); +hold on; plot((1:tLen), m.modelResponse, 'blue'); +subplot(3, 1, 2); plot((1:tLen), m2.tSeries, 'red'); hold on; plot((1:tLen), m2.modelResponse, 'magenta') +xlim([1 tLen]) if ~ieNotDefined('fit') subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; end diff --git a/mrLoadRet/Plugin/pRF/plotFigs.m b/mrLoadRet/Plugin/pRF/predictStimulus.m similarity index 81% rename from mrLoadRet/Plugin/pRF/plotFigs.m rename to mrLoadRet/Plugin/pRF/predictStimulus.m index ffe2dc52d..d730ea135 100644 --- a/mrLoadRet/Plugin/pRF/plotFigs.m +++ b/mrLoadRet/Plugin/pRF/predictStimulus.m @@ -1,7 +1,25 @@ -function plotFigs(fits, d) +%% predictStimulus.m +%% +%% +%% usage: predictStimulus(fits, d) --> plot figs for avg (last element of fits) +%% predictStimulus(fits, d, index) --> plot figs for i'th fold in fits +%% by: akshay jagadeesh +%% date: 11/20/2016 +%% purpose: Given model fits, this function predicts the stimulus most likely to have elicited +%% the given model response and compares this to the actual observed stimulus. Outputs the +%% percentage of timepoints that are correctly predicted (within 5) using maximum likelihood. +%% + + +function predictStimulus(fits, d, index) numFolds = length(fits)-1; -fit = fits(numFolds+1); +if(ieNotDefined('index')) + fit = fits(numFolds+1); +else + disp(sprintf('getting %d th fit', index)); + fit = fits(index); +end timeLen = size(fit.modelResponse, 2); diff --git a/mrLoadRet/Plugin/pRF/testPRF.m b/mrLoadRet/Plugin/pRF/testPRF.m deleted file mode 100644 index 8723e15d0..000000000 --- a/mrLoadRet/Plugin/pRF/testPRF.m +++ /dev/null @@ -1,45 +0,0 @@ -% testPRF.m -% -% usage: testPRF( ) -% by: akshay jagadeesh -% date: 10/07/16 -% purpose: Computes the probability of seeing the model response, -% given the observed data, and the computed covariance (noise). -% -% -% Input variables: -% testTSeries: true voxel response for the left-out scan at a single timepoint -% modelResp: expected voxel response trained on other n-1 scans -% covarMat: Covariance matrix (size: m x m, where m is # of voxels) -% -% Output variables: -% logLikelihood: total likelihood of all the observed tSeries given model response -% probTable: value at (i, j) is the probability that i'th timepoint in tseries is -% explained by j'th timepoint in model response. - -function probTable = testPRF(testTSeries, modelResponse, covarMat) - -numTimePoints = size(modelResponse, 2); -probTable = zeros(numTimePoints, numTimePoints); -logprobTable = zeros(numTimePoints, numTimePoints); - -disppercent(-inf,'(testPRF) Calculating likelihoods'); -for i = 1:numTimePoints - model_i = modelResponse(:, i); - tSeries_i = testTSeries(:, i); - - for j = 1:numTimePoints - tSeries_j = testTSeries(:, j); - probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); - if probTable(j, i) == 0 - disp(sprintf('\n(testPRF) mvnpdf at index (%i, %i) returning 0; Exiting...', j, i)); - return; - end - logProbTable(j, i) = log(probTable(j,i)); - end - - %modelLikelihood(i) = mvnpdf(tSeries_i, model_i, covarMat); - %logLikelihood = logLikelihood + log(modelLikelihood(i)); - disppercent(i/numTimePoints); -end -disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/trainPRF.m b/mrLoadRet/Plugin/pRF/trainPRF.m deleted file mode 100644 index c0197bda9..000000000 --- a/mrLoadRet/Plugin/pRF/trainPRF.m +++ /dev/null @@ -1,83 +0,0 @@ -% trainPRF.m -% -% $Id:$ -% usage: trainPRF(view, roiName) -% by: akshay jagadeesh -% date: 10/04/16 -% purpose: Given n MotionComp runs, this function computes a n-fold -% cross validation, running the pRF analysis n times. -% It generates and saves time series, model response, residuals, -% and covariance matrices for each fold. -% -% -% input: roiName - Name of the ROI we want to run this analysis on -% analysis - Name of analysis file to load -% - This must be the Concat of Average of N scans - -function trainPRF(view, roiName, analysis) - -% Currently hardcoding number and names of scan. -numScans = 6 -roiName = 'lV1' - -for i = 1:numScans - v = newView; - - %Get all but the i'th scan - scanList = [1:i-1 i+1:numScans] - - %Average the other n-1 scans together - v = viewSet(v, 'currentGroup', 'Concatenation'); - scanstr = sprintf('scanList=%s', mat2str(scanList)); - [v params] = averageTSeries(v, [], 'justGetParams=1', 'defaultParams=1', scanstr) - %Filename of averaged scan is: tseries-avg-.nii - scanListStr = mat2str(scanList); scanListStr = scanListStr(2:end-1); scanListStr=scanListStr(find(~isspace(scanListStr))); - %params.fileName = sprintf('tseries-avg-%s.nii', fileName) - %params = averageTSeriesGUI('groupName', 'MotionComp'); - averageTSeries(v, params) - - %Get group info about the average we just created - gInfo = groupInfo; - gAverageInfo = groupInfo('Averages'); - numAverageScans = gInfo(3).numScans; - sInfo = scanInfo(numAverageScans, 'Averages'); - %% sInfo.description --> contains info about which scans were averaged - %% sInfo.Filename --> contains filename in which this average is saved - %% sInfo.OriginalN --> contains filename of original (replace N with 1 - 5) - - v = newView; - v = viewSet(v, 'currentGroup', 'Averages'); - - % Two ways of calculating ROI coordinates --> neither work right now. - % Method 1: loadROI.coords - v = loadROI(v, sprintf('%s.mat', roiName)) - % roiCoords = v.ROIs(1).coords.' - % roiCoords = roiCoords(:, 1:3) - - %Run pRF Analysis on average of n-1 scans - %pRF(v, params) - [v, params] = pRF(v, [], 'justGetParams=1'); - %%set dispStimScan to the last most recently computed scan - %%set saveName to pRF_ROINAME_SCANLIST - %%select diffOfGamma - pRF(v, params) - - % Load analysis by filename - analysisFileName = sprintf('pRF_%s_%s_.mat', roiName, scanListStr); - v = loadAnalysis(v, ['pRFAnal/' analysisFileName]); - scanNum = v.analyses{1}.params.scanNum; - - % Get the time series data for the left-out scan - v2 = newView; - testTSeries = loadROITSeries(v2, roiName, i, 2, 'straightXform=1'); - roiCoords = testTSeries.scanCoords.'; - testTSeries = testTSeries.tSeries; - - %Get the residual and covariance matrix - %%% scanNum: scan number on which analysis was conducted - [residual, covMat, tSeries, modelResponse] = pRFNoise(v, scanNum, roiCoords, analysisFileName); - - %Save residual, covariance matrix, time series, and model response into a structure - save(sprintf('SaveData/pRF_fold%i_%s_%s', i, scanListStr, roiName), 'residual', 'covMat', 'modelResponse', 'testScanCoords', 'testTSeries') - -end From 6375d4bc25b19d97249af8aea39d7bb882ddedd6 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 21:07:55 -0800 Subject: [PATCH 35/44] rename pRF_crossValidate to pRFCrossVal --- mrLoadRet/Plugin/pRF/{pRF_crossValidate.m => pRFCrossVal.m} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mrLoadRet/Plugin/pRF/{pRF_crossValidate.m => pRFCrossVal.m} (100%) diff --git a/mrLoadRet/Plugin/pRF/pRF_crossValidate.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_crossValidate.m rename to mrLoadRet/Plugin/pRF/pRFCrossVal.m From 262e60cc6580923f0c23760f9d528129d5e745ab Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 21 Nov 2016 21:08:18 -0800 Subject: [PATCH 36/44] rename pRF_crossValidate to pRFCrossVal --- mrLoadRet/Plugin/pRF/pRFCrossVal.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m index aa4af2eda..13e17ee21 100644 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ b/mrLoadRet/Plugin/pRF/pRFCrossVal.m @@ -1,8 +1,8 @@ -%% pRF_crossValidate.m +%% pRFCrossVal.m %% -%% usage: fits = pRF_crossValidate(newCoords, [], analysis) --> run on specified coordinates -%% fits = pRF_crossValidate([], roiName, analysis) --> run on specified ROI -%% fits = pRF_crossValidate('best', roiName, analysis) --> run on best N voxels in specified ROI +%% usage: fits = pRFCrossVal(newCoords, [], analysis) --> run on specified coordinates +%% fits = pRFCrossVal([], roiName, analysis) --> run on specified ROI +%% fits = pRFCrossVal('best', roiName, analysis) --> run on best N voxels in specified ROI %% by: akshay jagadeesh %% date: 10/04/16 %% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF @@ -17,7 +17,7 @@ %% - This must be the Concat of Average of N scans %% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' -function fits = pRF_crossValidate(newCoords, roiName, analysis) +function fits = pRFCrossVal(newCoords, roiName, analysis) %%%%%%% Default inputs %%%%%%%%% newCoords = 'best'; From 36534b531983fc0ec0ef0f2d6327a367c17b7e8e Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Mon, 12 Dec 2016 14:15:37 -0800 Subject: [PATCH 37/44] Adding new models (ratio of gaussians) and bounded fminsearch methods --- .../Plugin/pRF/fminsearch/fminsearchbnd.m | 307 ++++++++++++++++++ mrLoadRet/Plugin/pRF/pRFCrossVal.m | 29 +- mrLoadRet/Plugin/pRF/pRFFit.m | 21 +- mrLoadRet/Plugin/pRF/pRFGUI.m | 4 +- mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m | 135 ++++++++ mrLoadRet/Plugin/pRF/pRF_divGaussian.m | 135 ++++++++ 6 files changed, 614 insertions(+), 17 deletions(-) create mode 100755 mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m create mode 100644 mrLoadRet/Plugin/pRF/pRF_divGaussian.m diff --git a/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m b/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m new file mode 100755 index 000000000..0448eae0f --- /dev/null +++ b/mrLoadRet/Plugin/pRF/fminsearch/fminsearchbnd.m @@ -0,0 +1,307 @@ +function [x,fval,exitflag,output] = fminsearchbnd(fun,x0,LB,UB,options,varargin) +% FMINSEARCHBND: FMINSEARCH, but with bound constraints by transformation +% usage: x=FMINSEARCHBND(fun,x0) +% usage: x=FMINSEARCHBND(fun,x0,LB) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options) +% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options,p1,p2,...) +% usage: [x,fval,exitflag,output]=FMINSEARCHBND(fun,x0,...) +% +% arguments: +% fun, x0, options - see the help for FMINSEARCH +% +% LB - lower bound vector or array, must be the same size as x0 +% +% If no lower bounds exist for one of the variables, then +% supply -inf for that variable. +% +% If no lower bounds at all, then LB may be left empty. +% +% Variables may be fixed in value by setting the corresponding +% lower and upper bounds to exactly the same value. +% +% UB - upper bound vector or array, must be the same size as x0 +% +% If no upper bounds exist for one of the variables, then +% supply +inf for that variable. +% +% If no upper bounds at all, then UB may be left empty. +% +% Variables may be fixed in value by setting the corresponding +% lower and upper bounds to exactly the same value. +% +% Notes: +% +% If options is supplied, then TolX will apply to the transformed +% variables. All other FMINSEARCH parameters should be unaffected. +% +% Variables which are constrained by both a lower and an upper +% bound will use a sin transformation. Those constrained by +% only a lower or an upper bound will use a quadratic +% transformation, and unconstrained variables will be left alone. +% +% Variables may be fixed by setting their respective bounds equal. +% In this case, the problem will be reduced in size for FMINSEARCH. +% +% The bounds are inclusive inequalities, which admit the +% boundary values themselves, but will not permit ANY function +% evaluations outside the bounds. These constraints are strictly +% followed. +% +% If your problem has an EXCLUSIVE (strict) constraint which will +% not admit evaluation at the bound itself, then you must provide +% a slightly offset bound. An example of this is a function which +% contains the log of one of its parameters. If you constrain the +% variable to have a lower bound of zero, then FMINSEARCHBND may +% try to evaluate the function exactly at zero. +% +% +% Example usage: +% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2; +% +% fminsearch(rosen,[3 3]) % unconstrained +% ans = +% 1.0000 1.0000 +% +% fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained +% ans = +% 2.0000 4.0000 +% +% See test_main.m for other examples of use. +% +% +% See also: fminsearch, fminspleas +% +% +% Author: John D'Errico +% E-mail: woodchips@rochester.rr.com +% Release: 4 +% Release date: 7/23/06 + +% size checks +xsize = size(x0); +x0 = x0(:); +n=length(x0); + +if (nargin<3) || isempty(LB) + LB = repmat(-inf,n,1); +else + LB = LB(:); +end +if (nargin<4) || isempty(UB) + UB = repmat(inf,n,1); +else + UB = UB(:); +end + +if (n~=length(LB)) || (n~=length(UB)) + error 'x0 is incompatible in size with either LB or UB.' +end + +% set default options if necessary +if (nargin<5) || isempty(options) + options = optimset('fminsearch'); +end + +% stuff into a struct to pass around +params.args = varargin; +params.LB = LB; +params.UB = UB; +params.fun = fun; +params.n = n; +% note that the number of parameters may actually vary if +% a user has chosen to fix one or more parameters +params.xsize = xsize; +params.OutputFcn = []; + +% 0 --> unconstrained variable +% 1 --> lower bound only +% 2 --> upper bound only +% 3 --> dual finite bounds +% 4 --> fixed variable +params.BoundClass = zeros(n,1); +for i=1:n + k = isfinite(LB(i)) + 2*isfinite(UB(i)); + params.BoundClass(i) = k; + if (k==3) && (LB(i)==UB(i)) + params.BoundClass(i) = 4; + end +end + +% transform starting values into their unconstrained +% surrogates. Check for infeasible starting guesses. +x0u = x0; +k=1; +for i = 1:n + switch params.BoundClass(i) + case 1 + % lower bound only + if x0(i)<=LB(i) + % infeasible starting value. Use bound. + x0u(k) = 0; + else + x0u(k) = sqrt(x0(i) - LB(i)); + end + + % increment k + k=k+1; + case 2 + % upper bound only + if x0(i)>=UB(i) + % infeasible starting value. use bound. + x0u(k) = 0; + else + x0u(k) = sqrt(UB(i) - x0(i)); + end + + % increment k + k=k+1; + case 3 + % lower and upper bounds + if x0(i)<=LB(i) + % infeasible starting value + x0u(k) = -pi/2; + elseif x0(i)>=UB(i) + % infeasible starting value + x0u(k) = pi/2; + else + x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1; + % shift by 2*pi to avoid problems at zero in fminsearch + % otherwise, the initial simplex is vanishingly small + x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k)))); + end + + % increment k + k=k+1; + case 0 + % unconstrained variable. x0u(i) is set. + x0u(k) = x0(i); + + % increment k + k=k+1; + case 4 + % fixed variable. drop it before fminsearch sees it. + % k is not incremented for this variable. + end + +end +% if any of the unknowns were fixed, then we need to shorten +% x0u now. +if k<=n + x0u(k:n) = []; +end + +% were all the variables fixed? +if isempty(x0u) + % All variables were fixed. quit immediately, setting the + % appropriate parameters, then return. + + % undo the variable transformations into the original space + x = xtransform(x0u,params); + + % final reshape + x = reshape(x,xsize); + + % stuff fval with the final value + fval = feval(params.fun,x,params.args{:}); + + % fminsearchbnd was not called + exitflag = 0; + + output.iterations = 0; + output.funcCount = 1; + output.algorithm = 'fminsearch'; + output.message = 'All variables were held fixed by the applied bounds'; + + % return with no call at all to fminsearch + return +end + +% Check for an outputfcn. If there is any, then substitute my +% own wrapper function. +if ~isempty(options.OutputFcn) + params.OutputFcn = options.OutputFcn; + options.OutputFcn = @outfun_wrapper; +end + +% now we can call fminsearch, but with our own +% intra-objective function. +[xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params); + +% undo the variable transformations into the original space +x = xtransform(xu,params); + +% final reshape to make sure the result has the proper shape +x = reshape(x,xsize); + +% Use a nested function as the OutputFcn wrapper + function stop = outfun_wrapper(x,varargin); + % we need to transform x first + xtrans = xtransform(x,params); + + % then call the user supplied OutputFcn + stop = params.OutputFcn(xtrans,varargin{1:(end-1)}); + + end + +end % mainline end + +% ====================================== +% ========= begin subfunctions ========= +% ====================================== +function fval = intrafun(x,params) +% transform variables, then call original function + +% transform +xtrans = xtransform(x,params); + +% and call fun +fval = feval(params.fun,reshape(xtrans,params.xsize),params.args{:}); + +end % sub function intrafun end + +% ====================================== +function xtrans = xtransform(x,params) +% converts unconstrained variables into their original domains + +xtrans = zeros(params.xsize); +% k allows some variables to be fixed, thus dropped from the +% optimization. +k=1; +for i = 1:params.n + switch params.BoundClass(i) + case 1 + % lower bound only + xtrans(i) = params.LB(i) + x(k).^2; + + k=k+1; + case 2 + % upper bound only + xtrans(i) = params.UB(i) - x(k).^2; + + k=k+1; + case 3 + % lower and upper bounds + xtrans(i) = (sin(x(k))+1)/2; + xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i); + % just in case of any floating point problems + xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i))); + + k=k+1; + case 4 + % fixed variable, bounds are equal, set it at either bound + xtrans(i) = params.LB(i); + case 0 + % unconstrained variable. + xtrans(i) = x(k); + + k=k+1; + end +end + +end % sub function xtransform end + + + + + diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m index 13e17ee21..0ffe58f56 100644 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ b/mrLoadRet/Plugin/pRF/pRFCrossVal.m @@ -17,15 +17,16 @@ %% - This must be the Concat of Average of N scans %% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' -function fits = pRFCrossVal(newCoords, roiName, analysis) +function [fits, d] = pRFCrossVal(newCoords, roiName, analysis) %%%%%%% Default inputs %%%%%%%%% newCoords = 'best'; -roiName = 'bothV1'; -analysis = 'pRF_v1.mat'; -nBest = 5; +roiName = 'goodV1'; +analysis = 'pRF_gV1_RoG.mat'; % change to pRF_v1_DoG.mat to run for Diff of Gaussians model +nBest = 85; plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots - +%rfType = 'gaussian-exp'; +algorithm = 'nelder-mead-bnd'; % Set current group to Concat and load the Analysis file v = newView; @@ -33,6 +34,8 @@ v = loadAnalysis(v, ['pRFAnal/' analysis]); analParams = v.analyses{1}.params; analScanNum = analParams.scanNum; +rfType = analParams.pRFFit.rfType; +disp(sprintf('(pRFCrossVal) Using model %s, with fitting algorithm %s', rfType, algorithm)); ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan osn = viewGet(v, 'originalscannum', analScanNum); @@ -103,10 +106,18 @@ end modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... - d.paramsInfo, 'concatInfo', concatInfo); + d.paramsInfo, 'concatInfo', concatInfo, 'rfType', rfType); modelResponse(h, :) = modelFit.modelResponse; residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; + if strmatch(rfType, 'gaussian-diffs') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2]; + elseif strmatch(rfType, 'gaussian-exp') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.exp]; + elseif strmatch(rfType, 'gaussian-DoG-CSS') + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2, modelFit.p.exp]; + else + fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; + end disppercent(h/numVoxels); end leftOut(all(modelResponse==0, 2), :) = []; @@ -148,8 +159,7 @@ fit.probTable = meanStruct(fits, 'probTable'); fit.fitParams = meanStruct(fits, 'fitParams'); fits(numFolds+1) = fit; - - +return % -- end main program -- % @@ -206,6 +216,7 @@ tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); tSeries = tSeries(:)'; + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % getBestVoxels % % % diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 16e0f6a35..f57fa049d 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -202,6 +202,8 @@ [params resnorm residual exitflag output lambda jacobian] = lsqnonlin(@getModelResidual,fitParams.initParams,fitParams.minParams,fitParams.maxParams,fitParams.optimParams,tSeries,fitParams); elseif strcmp(lower(fitParams.algorithm),'nelder-mead') [params fval exitflag] = fminsearch(@getModelResidual,fitParams.initParams,fitParams.optimParams,(tSeries-mean(tSeries))/var(tSeries.^2),fitParams); +elseif strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') + [params fval exitflag] = fminsearchbnd(@getModelResidual, fitParams.initParams, fitParams.minParams, fitParams.maxParams, fitParams.optimParams, (tSeries-mean(tSeries))/var(tSeries.^2), fitParams); else disp(sprintf('(pRFFit) Unknown optimization algorithm: %s',fitParams.algorithm)); return @@ -218,6 +220,8 @@ fit.r2 = 1-sum((residual-mean(residual)).^2)/sum((tSeries-mean(tSeries)).^2); elseif strcmp(lower(fitParams.algorithm),'nelder-mead') fit.r2 = residual^2; +elseif strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') + fit.r2 = residual^2; end % compute polar coordinates @@ -266,7 +270,7 @@ % handle constraints here % Check if fit algorithm is one that allows constraints - algorithmsWithConstraints = {'levenberg-marquardt'}; + algorithmsWithConstraints = {'levenberg-marquardt', 'nelder-mead-bnd'}; if any(strcmp(fitParams.algorithm,algorithmsWithConstraints)) % if constraints allowed then allow user to adjust them here (if they set defaultConstraints) if isfield(fitParams,'defaultConstraints') && ~fitParams.defaultConstraints @@ -302,7 +306,8 @@ % optimization parameters if ~isfield(fitParams,'algorithm') || isempty(fitParams.algorithm) - fitParams.algorithm = 'nelder-mead'; + fitParams.algorithm = 'nelder-mead-bnd'; + disp('(pRFFit) No algorithm provided. Using Default: Nelder-Mead-Bnd'); end fitParams.optimParams = optimset('MaxIter',inf,'Display',fitParams.optimDisplay); @@ -396,7 +401,7 @@ end % for nelder-mead just compute correlation and return 1-4 -if strcmp(lower(fitParams.algorithm),'nelder-mead') +if strcmp(lower(fitParams.algorithm),'nelder-mead') || strcmp(lower(fitParams.algorithm), 'nelder-mead-bnd') residual = -corr(modelResponse,tSeries); % disp(sprintf('(pRFFit:getModelResidual) r: %f',residual)); end @@ -540,7 +545,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) rfModel = []; % now gernerate the rfModel -if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'})) +if any(strcmp(fitParams.rfType,{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs', 'gaussian-divs', 'gaussian-DoG-CSS'})) rfModel = makeRFGaussian(params,fitParams); else disp(sprintf('(pRFFit:getRFModel) Unknown rfType: %s',fitParams.rfType)); @@ -559,8 +564,12 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) output = pRF_gaussianhdr(varargin{:}); case 'gaussian-diffs' output = pRF_diffGaussian(varargin{:}); - otherwise - testModel = @pRF_exp; %%% Only need to change this line to specify a new model. + case 'gaussian-divs' + output = pRF_divGaussian(varargin{:}); + case 'gaussian-exp' + output = pRF_exp(varargin{:}); + otherwise % 'gaussian-DoG-CSS' + testModel = @pRF_DoG_CSS; %%% Only need to change this line to specify a new model. output = testModel(varargin{:}); end diff --git a/mrLoadRet/Plugin/pRF/pRFGUI.m b/mrLoadRet/Plugin/pRF/pRFGUI.m index afa44e70a..703fc162e 100644 --- a/mrLoadRet/Plugin/pRF/pRFGUI.m +++ b/mrLoadRet/Plugin/pRF/pRFGUI.m @@ -116,9 +116,9 @@ end %all of these parameters are for pRFFit -paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians'}; +paramsInfo{end+1} = {'rfType',{'gaussian','gaussian-hdr', 'gaussian-exp', 'gaussian-diffs', 'gaussian-divs', 'gaussian-DoG-CSS'},'Type of pRF fit. Gaussian fits a gaussian with x,y,width as parameters to each voxel. gaussian-hdr fits also the hemodynamic response with the parameters of the hdr as below. gaussian-exp incorporates an exponent non-linearity when calculating neuron response, gaussian-diffs calculates response as the difference between a center and a surround gaussians. gaussian-divs takes the quotient of center and surround gaussians.'}; paramsInfo{end+1} = {'betaEachScan',false,'type=checkbox','Compute a separate beta weight (scaling) for each scan in the concanetation. This may be useful if there is some reason to believe that different scans have different magnitude responses, this will allow the fit to scale the magnitude for each scan'}; -paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; +paramsInfo{end+1} = {'algorithm',{'nelder-mead','levenberg-marquardt', 'nelder-mead-bnd'},'Which algorithm to use for optimization. Levenberg-marquardt seems to get stuck in local minimum, so the default is nelder-mead. However, levenberg-marquardt can set bounds for parameters, so may be better for when you are trying to fit the hdr along with the rf, since the hdr parameters can fly off to strange values.'}; paramsInfo{end+1} = {'defaultConstraints',1,'type=checkbox','Sets how to constrain the search (i.e. what are the allowed range of stimulus parameters). The default is to constrain so that the x,y of the RF has to be within the stimulus extents (other parameter constrains will print to the matlab window). If you click this off a dialog box will come up after the stimulus has been calculated from the stimfiles allowing you to specify the constraints on the parameters of the model. You may want to custom constrain the parameters if you know something about the RFs you are trying to model (like how big they are) to keep the nonlinear fits from finding unlikely parameter estimates. Note that nelder-mead is an unconstrained fit so this will not do anything.'}; paramsInfo{end+1} = {'prefitOnly',false,'type=checkbox','Check this if you want to ONLY do a prefit and not optimize further. The prefit computes a preset set of model parameters (x,y,rfHalfWidth) and picks the one that produces a mdoel with the highest correlation with the time series. You may want to do this to get a quick but accurate fit so that you can draw a set of ROIs for a full analysis'}; paramsInfo{end+1} = {'quickPrefit',false,'type=checkbox','Check this if you want to do a quick prefit - this samples fewer x,y and rfWidth points. It is faster (especially if coupled with prefitOnly for a fast check), but the optimization routines may be more likely to get trapped into local minima or have to search a long time for the minimum'}; diff --git a/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m b/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m new file mode 100644 index 000000000..d0407f21b --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m @@ -0,0 +1,135 @@ +% pRF_DoG_CSS.m +% +% $Id:$ +% usage: pRF_DoG_CSS(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Model of Difference of Gaussians with Compressive Static Non linearity +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_DoG_CSS(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % and convolve in time. + pPlus = convolveModelResponseWithHRF(rPlus,hrf); + pMinus = convolveModelResponseWithHRF(rMinus,hrf); + + % Model response is the difference of Gaussians, weighted by Beta amplitudes + thisModelResponse = power(pPlus*p.B1 + pMinus*p.B2, p.exp); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude', 'exponent'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian', 'Exponent static nonlinearity'}; + fitParams.paramIncDec = [1 1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf inf inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 0 -inf -5]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf 0 5]; + fitParams.initParams = [0 0 4 4 1 0 1]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.std2 = params(4); + p.B1 = params(5); + p.B2 = params(6); + p.exp = params(7); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m new file mode 100644 index 000000000..634aa0a81 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m @@ -0,0 +1,135 @@ +% pRF_divGaussian.m +% +% $Id:$ +% usage: pRF_gaussian(varargin) +% by: akshay jagadeesh +% date: 09/02/16 +% purpose: Template file to create new models +% +% - Allows you to create a new model type +% - Simply add the model type to pRFGUI and create a +% file like this one for your model with the appropriate +% methods filled in. +% +% This model template is set up for the standard Gaussian model. + +function output = pRF_divGaussian(varargin) + +if nargin < 2 + disp(sprintf('Not enough arguments')); + disp(sprintf('Number of arguments: %d', nargin)); + celldisp(varargin) + return +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('getModelResponse', fitParams, rfModel, hrf, p, i) %%%% +%%% Called from getModelResidual %%%% +if strcmp(varargin{1}, 'getModelResponse') + + fitParams = varargin{2}; + rfModel1 = varargin{3}; + hrf = varargin{4}; + p = varargin{5}; + i = varargin{6}; + + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*((p.std*p.stdRatio)^2))+((fitParams.stimY-p.y).^2)/(2*((p.std*p.stdRatio)^2)))); + nFrames = fitParams.concatInfo.runTransition(i,2); + + % Convolve model with stimulus + rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); + rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + + % Apply divisive normalization + resp = p.b1*rPlus ./ (1 + p.b2*rMinus); + + % Convolve response with hemodynamic response function + thisModelResponse = convolveModelResponseWithHRF(resp, hrf); + + % drop junk frames here + thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + + % return the calculated model response + output = thisModelResponse; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% pRF_gaussian('setParams', fitParams) %%%% +%%% Called from setParams %%%% + +elseif strcmp(varargin{1}, 'setParams') + + fitParams = varargin{2}; + + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; + fitParams.paramMax = [inf inf inf inf inf -inf]; + % set min/max and init + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 -inf -inf]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; + fitParams.initParams = [0 0 4 2 1 1]; + + % return fitParams with modified values + output = fitParams; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% pRF_gaussian(command, fitParams, params) %%%%% +%%%% Called from getFitParams %%%%% + +elseif strcmp(varargin{1}, 'getFitParams') + + fitParams = varargin{2}; + params = varargin{3}; + + p.rfType = fitParams.rfType; + + % Define your parameters here + p.x = params(1); + p.y = params(2); + p.std = params(3); + p.stdRatio = params(4); + p.b1 = params(5); + p.b2 = params(6); + % use a fixed single gaussian + p.canonical.type = 'gamma'; + p.canonical.lengthInSeconds = 25; + p.canonical.timelag = fitParams.timelag; + p.canonical.tau = fitParams.tau; + p.canonical.exponent = fitParams.exponent; + p.canonical.offset = 0; + p.canonical.diffOfGamma = fitParams.diffOfGamma; + p.canonical.amplitudeRatio = fitParams.amplitudeRatio; + p.canonical.timelag2 = fitParams.timelag2; + p.canonical.tau2 = fitParams.tau2; + p.canonical.exponent2 = fitParams.exponent2; + p.canonical.offset2 = 0; + + output = struct(p); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelWithStimulus %% +function modelResponse = convolveModelWithStimulus(rfModel,stim,nFrames) + +% get number of frames +nStimFrames = size(stim.im,3); + +% preallocate memory +modelResponse = zeros(1,nFrames); + +for frameNum = 1:nStimFrames + % multipy the stimulus frame by frame with the rfModel + % and take the sum + modelResponse(frameNum) = sum(sum(rfModel.*stim.im(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% convolveModelResponseWithHRF %% +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + From e82ba663f49ac192a4fe2f7f8cfd99db58f8d87f Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Wed, 25 Jan 2017 03:49:40 -0800 Subject: [PATCH 38/44] Adding pRFSimulate script --- mrLoadRet/Plugin/pRF/pRFSimulate.m | 206 +++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 mrLoadRet/Plugin/pRF/pRFSimulate.m diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m new file mode 100644 index 000000000..b54d9acf8 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/pRFSimulate.m @@ -0,0 +1,206 @@ +% pRFSimulate +% +% simulates N v1 voxels given 2 rf types and outputs expected time series given stimImage +% +% - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) +% - numVox: number of voxels we want to simulate +% +function [simulation, fits_gauss,fits_norm, r2_gauss, r2_norm] = pRFSimulate(stim) + +% stimImage = stim.im; +% numVols = size(stimImage, 2); +% [myscreen, stimImage] = +modelType = 'gaussian-divs'; +plotFigs = 0; + +%%% Preset Model Parameters %%% +modelParams.rfRatio = 0.1; +modelParams.normRatio = 1.5; % set norm pool width to be 1.5x the rf width +modelParams.cssExp = 0.75; +modelParams.noiseAmplitude = 0.1; + +% Get canonical hemodynamic response function +hrf = getCanonicalHRF(); + +%%% Create voxels in simulation +% Num voxels: 196 --> same as in prefit +xVals = -32.5:5:32.5; xVals = repmat(xVals, 1, 14); +yVals = -32.5:5:32.5; yVals = repmat(yVals, 14, 1); yVals = yVals(:); + +if(length(xVals) == length(yVals)) + numVox = length(xVals); + disp(sprintf('Number of voxels in simulation: %d', numVox)); +end +if(plotFigs == 1); plot(xVals, yVals, '*'); end + +simulation = []; +for i=1:numVox + + x_sim = xVals(i); y_sim = yVals(i); + eccentricity = sqrt(x_sim^2 + y_sim^2); + rfWidth = modelParams.rfRatio*eccentricity; + + % Calculate the Gaussian-derived RF from Dumoulin & Wandell 2008 + rfModel = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(rfWidth^2))); + if(mod(i,10)==0 && plotFigs == 1) + disp(i); figure; + subplot(1,2,1); plot(x_sim, y_sim, '*'); xlim([-50,50]); ylim([-50,50]); + subplot(1,2,2); imagesc(rfModel'); axis xy; xlim([0,192]); ylim([0,108]); + end + + % Calculate simulated time series using the Ratio-of-Gaussians model + resp = convolveModelWithStimulus(rfModel, stim.im); + suppFieldWidth = modelParams.normRatio*rfWidth; + beta1 = 1; beta2 = 1; + % Calculate suppressive field model + rfModel2 = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(suppFieldWidth^2))); + resp2 = convolveModelWithStimulus(rfModel2, stim.im); + % Estimate model response as the ratio of the 2 gaussian RF + modelResponse = beta1*resp ./ (1 + beta2*resp2); + + % Convolve with HRF + modelHRF = convolveModelResponseWithHRF(modelResponse, hrf); + + % Then add white noise and save the simulated time series data. + simulation(i,:) = addWhiteNoise(modelHRF, modelParams.noiseAmplitude); + %noiseless(i,:) = modelHRF; + %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); + %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); + %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); +end + +%%% To Do: +% 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) +% a. DONE -- figure out why mglDoubleBars framegrab is acting up. +% 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels +% -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); +% so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 + +%%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) +v = newView; +v = viewSet(v, 'currentGroup', 'Concatenation'); +v = loadAnalysis(v, ['pRFAnal/' 'pRF_v1.mat']); +analParams = v.analyses{1}.params; +analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 +analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing +analParams.pRFFit.prefitOnly=1; +analParams2 = analParams; +analParams2.pRFFit.rfType='gaussian-divs'; +d = viewGet(v, 'd', analParams.scanNum); +concatInfo = viewGet(v, 'concatInfo', 1); +v = newView; + +stimA{1} = stim; +numVoxels = numVox; + +% Compute prefit for all voxels +disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); +for i = 1:numVoxels + tSeries = applyConcatFiltering(simulation(i,:), concatInfo); + disp(sprintf('Voxel %d', i)); + + % Run for gaussian model + fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); + r2_gauss(i) = fit.r2; + fits_gauss{i} = fit; + + % Run for normalization model + fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); + r2_norm(i) = fit2.r2; + fits_norm{i} = fit2; + disppercent(i/numVoxels); +end +disppercent(inf); +disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); + +%keyboard + +return + +%% Do full pRFFits +%for i = 1:numVoxels +% fit = pRFFit(v, [], [], [], [], 'fitTypeParams', analParams.pRFFit, 'returnPrefit', true); +% keyboard +% modelFit1(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian',... +% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); +% modelFit2(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian_divs',... +% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); +%end + +%-------------------------------------------- +% addWhiteNoise +% adds gaussian white noise to the signal +function response = addWhiteNoise(signal, noiseAmplitude) +response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); + +%---------------------------------------------- +% getCanonicalHRF +% Gets the canonical hrf given params and sample rate +function hrf = getCanonicalHRF() + +offset = 0; +timelag = 1; +tau = 0.6; +exponent = 6; +sampleRate = 0.5; +amplitude = 1; + +hrf.time = 0:sampleRate:25; + +exponent = round(exponent); +gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); +gammafun(find((hrf.time-timelag) <0)) = 0; + +if (max(gammafun)-min(gammafun))~=0 + gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); +end +gammafun = (amplitude*gammafun+offset); + +hrf.hrf = gammafun; +hrf.hrf = hrf.hrf / max(hrf.hrf); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ~~~ convolveModelWithStimulus ~~~ %% + +function modelResponse = convolveModelWithStimulus(rfModel, stim) + +nStimFrames = size(stim, 3); +modelResponse = zeros(1,nStimFrames); +for frameNum = 1:nStimFrames + modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% convolveModelResponseWithHRF %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) + +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + +%--------------------------------------- +% applyConcatFiltering +% applies detrending, hipassfilter, projection, removes mean. +%---------------------------------------- +function tSeries = applyConcatFiltering(tSeries, concatInfo) +runnum=1; + +tSeries = tSeries(:); + +% apply detrending +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +% project out the mean vector From 2e1bd373ae3bb52c757365d9d997e7f57a1b4345 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 3 Feb 2017 21:27:16 -0800 Subject: [PATCH 39/44] Adding analysis script and updating simulator --- mrLoadRet/Plugin/pRF/pRFSimulate.m | 61 +++--- mrLoadRet/Plugin/pRF/plotFig.m | 336 +++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+), 28 deletions(-) create mode 100644 mrLoadRet/Plugin/pRF/plotFig.m diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m index b54d9acf8..a2b55b230 100644 --- a/mrLoadRet/Plugin/pRF/pRFSimulate.m +++ b/mrLoadRet/Plugin/pRF/pRFSimulate.m @@ -5,7 +5,7 @@ % - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) % - numVox: number of voxels we want to simulate % -function [simulation, fits_gauss,fits_norm, r2_gauss, r2_norm] = pRFSimulate(stim) +function [sim, fits_gauss,fits_norm] = pRFSimulate(stim) % stimImage = stim.im; % numVols = size(stimImage, 2); @@ -34,6 +34,7 @@ if(plotFigs == 1); plot(xVals, yVals, '*'); end simulation = []; +disppercent(-inf, sprintf('Creating simulation receptive fields for %d voxels', numVox)); for i=1:numVox x_sim = xVals(i); y_sim = yVals(i); @@ -67,7 +68,13 @@ %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); + + disppercent(i/numVox); end +disppercent(inf); +sim.x = xVals; sim.y = yVals; +sim.rfWidth = rfWidth; +sim.tSeries = simulation; %%% To Do: % 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) @@ -75,7 +82,6 @@ % 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels % -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); % so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 - %%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) v = newView; v = viewSet(v, 'currentGroup', 'Concatenation'); @@ -83,7 +89,7 @@ analParams = v.analyses{1}.params; analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing -analParams.pRFFit.prefitOnly=1; +analParams.pRFFit.prefitOnly=0; analParams2 = analParams; analParams2.pRFFit.rfType='gaussian-divs'; d = viewGet(v, 'd', analParams.scanNum); @@ -92,23 +98,21 @@ stimA{1} = stim; numVoxels = numVox; +%numVoxels = 20; % Compute prefit for all voxels disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); for i = 1:numVoxels tSeries = applyConcatFiltering(simulation(i,:), concatInfo); - disp(sprintf('Voxel %d', i)); - + sim.filteredTSeries(i,:) = tSeries; % Run for gaussian model fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); - r2_gauss(i) = fit.r2; fits_gauss{i} = fit; % Run for normalization model fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); - r2_norm(i) = fit2.r2; fits_norm{i} = fit2; - disppercent(i/numVoxels); + disppercent(i/numVoxels, sprintf('Voxel %d', i)); end disppercent(inf); disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); @@ -117,25 +121,20 @@ return -%% Do full pRFFits -%for i = 1:numVoxels -% fit = pRFFit(v, [], [], [], [], 'fitTypeParams', analParams.pRFFit, 'returnPrefit', true); -% keyboard -% modelFit1(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian',... -% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); -% modelFit2(i,:) = pRFFit(v, [], [],[],[], 'stim', stim, 'tSeries', simulation(i,:), 'getModelResponse=1', 'rfType=gaussian_divs',... -% 'fitTypeParams', analParams.pRFFit, 'paramsInfo', d.paramsInfo); -%end - -%-------------------------------------------- +%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%---------------------------------------- % addWhiteNoise % adds gaussian white noise to the signal +%--------------------------------------- function response = addWhiteNoise(signal, noiseAmplitude) response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); -%---------------------------------------------- -% getCanonicalHRF +%--------------------------------------- +% getCanonicalHRF % Gets the canonical hrf given params and sample rate +%--------------------------------------- function hrf = getCanonicalHRF() offset = 0; @@ -159,9 +158,10 @@ hrf.hrf = gammafun; hrf.hrf = hrf.hrf / max(hrf.hrf); -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% ~~~ convolveModelWithStimulus ~~~ %% - +%--------------------------------------- +% convolveModelWithStimulus +% convolve the model response with the stimulus +%---------------------------------------- function modelResponse = convolveModelWithStimulus(rfModel, stim) nStimFrames = size(stim, 3); @@ -170,10 +170,10 @@ modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% convolveModelResponseWithHRF %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +%--------------------------------------- +% convolveModelResponseWithHRF +% convolve the model response with the HRF +%---------------------------------------- function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) n = length(modelTimecourse); @@ -204,3 +204,8 @@ end % project out the mean vector + +% remove the mean +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); + +%tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m new file mode 100644 index 000000000..d9862c7d2 --- /dev/null +++ b/mrLoadRet/Plugin/pRF/plotFig.m @@ -0,0 +1,336 @@ +% plotFig +% +% does analysis given struct of fits for two models +% - fitsGauss, fitsNorm: struct +% +% +function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) + +if any(num==1) % draw true rf's + dispTrueRFs = 1; +end +if any(num==1.5) + linkRFs = 1; +end +if any(num==2) % draw model predicted rf's + dispModelRFs = 1; +end +if any(num==3) + dispModelR2 = 1; +end +if any(num==4) + drawR2 = 1; +end +if any(num==5) + dispBestModelResponse = 1; +end +if any(num==6) + dispSuppFieldSize = 1; +end +if any(num==7) + dispWorstModelResponse = 1; +end + +paramsG = getFieldArrFromStruct(fitsGauss, 'params'); +paramsN = getFieldArrFromStruct(fitsNorm, 'params'); +r2G = getFieldArrFromStruct(fitsGauss, 'r2'); +r2N = getFieldArrFromStruct(fitsNorm, 'r2'); + +if ~ieNotDefined('dispTrueRFs') + figure; + for i = 1:196 + simRFWidth = sqrt(sim.x(i)^2 + sim.y(i)^2)*0.1; + circle(sim.x(i), sim.y(i), simRFWidth, 'b'); hold on; + text(sim.x(i), sim.y(i), num2str(i)); + end + title('True Voxel Receptive Fields (Simulation)'); + hline(0, ':'); vline(0,':'); + +end +if ~ieNotDefined('linkRFs') + figure; + plot(sim.x, sim.y, '*k'); hold on; + plot(paramsG(:,1), paramsG(:,2), '*b'); hold on + for i = 1:196 + plot([paramsG(i,1); sim.x(i)], [paramsG(i,2); sim.y(i)], 'k'); hold on + end + legend('True RFs', 'Gaussian RFs'); + title('Mapping of Gaussian Model RFs to true RFs'); hline(0,':'); vline(0,':'); + + figure; + plot(sim.x, sim.y, '*k'); hold on; + plot(paramsN(:,1), paramsN(:,2), '*g'); hold on + for i = 1:196 + plot([paramsN(i,1); sim.x(i)], [paramsN(i,2); sim.y(i)], 'k'); hold on + end + legend('True RFs', 'Normalization RFs'); + title('Mapping of Normalization Model RFs to true RFs'); hline(0,':'); vline(0,':'); +end +if ~ieNotDefined('dispModelRFs') + figure; + for i = 1:196 + rfWidth = sqrt(paramsG(i,1)^2 + paramsG(i,2)^2)*0.1; + circle(paramsG(i,1), paramsG(i,2), paramsG(i,3), 'b'); hold on; + text(paramsG(i,1), paramsG(i,2), num2str(i)); + end + title('Gaussian Model Predicted Receptive Fields'); + hline(0, ':'); vline(0,':'); + + figure; + for i = 1:196 + rfWidth = sqrt(paramsN(i,1)^2 + paramsN(i,2)^2)*0.1; + circle(paramsN(i,1), paramsN(i,2), paramsN(i,3), 'b'); + circle(paramsN(i,1), paramsN(i,2), paramsN(i,3)*paramsN(i,4), 'g'); + text(paramsN(i,1), paramsN(i,2), num2str(i)); + end + title('Normalization Model Predicted Receptive & Suppressive Fields'); + hline(0,':'), vline(0,':'); +end +if ~ieNotDefined('dispModelR2') + % Plot model RF predictions colored by r2 + figure; + scatter(paramsG(:,1), paramsG(:,2), 20, r2G); + title('Gaussian model RF predictions, colored by R2'); + hline(0,':'); vline(0,':'); colorbar; + + figure; + scatter(paramsN(:,1), paramsN(:,2), 20, r2N); + title('Normalization model RF predictions, colored by R2'); + hline(0,':'); vline(0,':'); colorbar; +end +if ~ieNotDefined('drawR2') + % Draw R2 by voxel for each model + figure; + plot(r2G, 'b'); hold on; plot(r2N, 'g'); + title('Model r2 plotted by voxel'); + xlabel('Voxel Number'); ylabel('R-squared'); +end +if ~ieNotDefined('dispBestModelResponse') || ~ieNotDefined('dispWorstModelResponse') + if ieNotDefined('stim') || ieNotDefined('concatInfo') + disp('Either stimulus or concatInfo not provided. Quitting...'); + return + end + + [bestR2N bestVoxN] = max(r2N); bestN = fitsNorm{bestVoxN}; + [bestR2G bestVoxG] = max(r2G); bestG = fitsGauss{bestVoxG}; + + G = @(x,y,sigma) exp(-(((stim.x - x).^2) + ((stim.y - y).^2))/(2*sigma^2)); + respNorm = @(c, x, y, sigma, stdRatio, b1, b2) (b1*c*G(x,y,sigma))./(1+ b2*c*G(x,y,stdRatio*sigma)); + Rx = 0:.05:1; + Ry = []; + + modelResponseG = []; + modelResponseN = []; + tSeries = []; + hrf = getCanonicalHRF(); + disppercent(-inf, 'Computing model response based on model params for 196 voxels'); + for i = 1:196 + gParams(i,:) = fitsGauss{i}.params; + rfModel = exp(-(((stim.x - gParams(i,1)).^2) + ((stim.y - gParams(i,2)).^2))/(2*(gParams(i,3)^2))); + rfModel = convolveModelWithStimulus(rfModel, stim.im); + modelGwithHRF = convolveModelResponseWithHRF(rfModel, hrf); + modelResponseG(i,:) = applyConcatFiltering(modelGwithHRF/std(modelGwithHRF), concatInfo); + + nParams(i,:) = fitsNorm{i}.params; + rfModel = exp(-(((stim.x - nParams(i,1)).^2) + ((stim.y - nParams(i,2)).^2))/(2*(nParams(i,3)^2))); + rfModel = convolveModelWithStimulus(rfModel, stim.im); + rfModel2 = exp(-(((stim.x - nParams(i,1)).^2) + ((stim.y-nParams(i,2)).^2))/(2*((nParams(i,4)*nParams(i,3))^2))); + rfModel2 = convolveModelWithStimulus(rfModel2, stim.im); + modelNwithHRF = convolveModelResponseWithHRF((nParams(i,5)*rfModel)./(nParams(i,6)*rfModel2), hrf); + modelResponseN(i,:) = applyConcatFiltering(modelNwithHRF, concatInfo); + + tSeries(i,:) = applyConcatFiltering(sim.tSeries(i,:), concatInfo); + disppercent(i/196); + end + disppercent(inf); + + if ~ieNotDefined('dispBestModelResponse') + figure; + plot(sim.filteredTSeries(bestVoxN,:), 'k'); hold on; + plot(modelResponseN(bestVoxN,:), 'g'); hold on; + plot(modelResponseG(bestVoxN,:), 'b'); + title('Model response and true time series for well-fit voxel'); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization', 'gaussian'); + end + if ~ieNotDefined('dispWorstModelResponse') + figure; + plot(sim.filteredTSeries(194,:), 'k'); hold on; + plot(modelResponseN(194,:), 'g'); hold on; + title(sprintf('Voxel 194 model response vs time series (R2: %d)', r2N(194))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + + figure; + plot(sim.filteredTSeries(189,:), 'k'); hold on; + plot(modelResponseN(189,:), 'g'); hold on; + title(sprintf('Voxel 189 model response vs time series (R2:%d)', r2N(189))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + + figure; + plot(sim.filteredTSeries(1,:), 'k'); hold on; + plot(modelResponseN(1,:), 'g'); hold on; + title(sprintf('Voxel 1 model response vs time series (R2:%d)', r2N(1))); + xlabel('Time (volumes)'); ylabel('Response'); + legend('timeseries', 'normalization'); + end +end +if ~ieNotDefined('dispSuppFieldSize') + + figure; + rfWidthN = paramsN(:,3); + suppWidthN = paramsN(:,4).*rfWidthN; + eccN = sqrt(paramsN(:,1).^2 + paramsN(:,2).^2); + plot(eccN, suppWidthN, '*g'); hold on; + fit = polyfit(eccN, suppWidthN, 1); + line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccN)], [line(min(eccN)) line(max(eccN))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between suppressive field size and eccentricity'); + xlabel('Eccentricity'); ylabel('Suppressive field width'); + + figure; + plot(eccN, rfWidthN, '*g'); hold on; + fit = polyfit(eccN, rfWidthN, 1); line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccN)], [line(min(eccN)) line(max(eccN))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between RF field size and eccentricity (normalization model)'); + xlabel('Eccentricity'); ylabel('RF Field Width'); + + figure; + eccG = sqrt(paramsG(:,1).^2 + paramsG(:,2).^2); + rfWidthG = paramsG(:,3); + plot(eccG, rfWidthG, '*b'); hold on; + fit = polyfit(eccG, rfWidthG, 1); line = @(x) fit(1)*x + fit(2); + plot([min(eccN), max(eccG)], [line(min(eccG)) line(max(eccG))], 'k'); text(5, 7, sprintf('Slope: %d', fit(1))); + title('Relationship between RF field size and eccentricity (gaussian model)'); + xlabel('Eccentricity'); ylabel('RF Field Width'); + + keyboard +end +if num == -1 + %%%% + % Plot model RFs and true RFs using circle tool + f = figure; + for i = 1:196 + %% Plot true RF's + plot(sim.x(i), sim.y(i), '*r', 'MarkerSize', 10); hold on; + %simRFWidth = sqrt(sim.x(i)^2 + sim.y(i)^2)*0.1; + %circle(sim.x(i), sim.y(i), simRFWidth, 'r'); hold on; + + %% Plot gaussian model RF's + fit = fitsGauss{i}; + %circle(fit.x, fit.y, fit.std, 'b'); + + %% Plot normalization model rf's + fit2 = fitsNorm{i}; + circle(fit2.x, fit2.y, fit2.std, 'g'); + circle(fit2.x, fit2.y, fit2.params(4)*fit2.std, 'c') + + %% Plot Lines connecting model rf center to true rf center + %plot([fit.x; sim.x(i)], [fit.y; sim.y(i)],'-b','MarkerSize',3); hold on + plot([fit2.x; sim.x(i)], [fit2.y; sim.y(i)], '-g', 'MarkerSize', 3); hold on + end + xlim([-100 100]); ylim([-100 100]); +end + +return + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%-------------------------------------- +% getFieldArrFromStruct(structure, fieldNameStr, +%-------------------------------------- +function fieldArray = getFieldArrFromStruct(structure, fieldNameStr) + +fieldArray = []; +for i = 1:length(structure) + fieldArray(i,:) = structure{i}.(fieldNameStr); +end + +%--------------------------------------- +% circle +% draw a circle given center (x,y), radius and color +%---------------------------------------- +function circle(x,y,r, color) +%x and y are the coordinates of the center of the circle +%r is the radius of the circle +%0.01 is the angle step, bigger values will draw the circle faster but +%you might notice imperfections (not very smooth) +ang=0:0.01:2*pi; +xp=r*cos(ang); +yp=r*sin(ang); +plot(x+xp,y+yp, color, 'MarkerSize', 4); +hold on + + +%--------------------------------------- +% getCanonicalHRF() +% get the canonical hemodnamic response function +%---------------------------------------- +function hrf = getCanonicalHRF() +offset = 0; +timelag = 1; +tau = 0.6; +exponent = 6; +sampleRate = 0.5; +amplitude = 1; +hrf.time = 0:sampleRate:25; + +exponent = round(exponent); +gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); +gammafun(find((hrf.time-timelag) <0)) = 0; + +if (max(gammafun)-min(gammafun))~=0 + gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); +end +gammafun = (amplitude*gammafun+offset); + +hrf.hrf = gammafun; +hrf.hrf = hrf.hrf / max(hrf.hrf); + + +%--------------------------------------- +% convolveModelWithStimulus +% convolve the model response with the stimulus +%---------------------------------------- +function modelResponse = convolveModelWithStimulus(rfModel, stim) +nStimFrames = size(stim, 3); +modelResponse = zeros(1,nStimFrames); +for frameNum = 1:nStimFrames + modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); +end + +%--------------------------------------- +% convolveModelResponseWithHRF +% convolve the model response with the HRF +%---------------------------------------- +function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) +n = length(modelTimecourse); +modelTimecourse = conv(modelTimecourse,hrf.hrf); +modelTimecourse = modelTimecourse(1:n); + +%--------------------------------------- +% applyConcatFiltering +% applies detrending, hipassfilter, projection, removes mean. +%---------------------------------------- +function tSeries = applyConcatFiltering(tSeries, concatInfo) +runnum=1; +tSeries = tSeries(:); + +% apply detrending + +if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) + tSeries = eventRelatedDetrend(tSeries); +end + +% apply hipass filter +if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) + if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) + disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); + else + tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); + end +end + +tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); +tSeries = tSeries(:)'; From 83f68d932f1832deb51755d5b431a445060014eb Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Thu, 23 Feb 2017 13:14:17 -0800 Subject: [PATCH 40/44] Making changes to get pRF to run with double bars --- mrLoadRet/Plugin/pRF/pRFFit.m | 22 ++++++++++++++----- .../Plugin/pRF/pRFGetStimImageFromStimfile.m | 12 +++++++--- mrLoadRet/Plugin/pRF/pRF_divGaussian.m | 2 +- mrLoadRet/Plugin/pRF/plotFig.m | 20 +++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index f57fa049d..8fa36859d 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -54,7 +54,6 @@ fit = fitParams.stim; return end - % get the tSeries if ~isempty(x) % if tSeries was not passed in then load it @@ -67,7 +66,7 @@ % but useful for raw/motionCorrected time series. Also, it is very important that % the tSeries is properly mean subtracted if ~isfield(fitParams.concatInfo,'hipassfilter') - tSeries = percentTSeries(tSeries,'detrend','Linear','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); + tSeries = percentTSeries(tSeries,'detrend','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); end % if there are any nans in the tSeries then don't fit @@ -80,7 +79,6 @@ else tSeries = []; end - % handle junk frames (i.e. ones that have not already been junked) if ~isempty(fitParams.junkFrames) && ~isequal(fitParams.junkFrames,0) % drop junk frames @@ -143,7 +141,9 @@ if ~isfield(fitParams.prefit,'modelResponse') % get number of workers nProcessors = mlrNumWorkers; - disppercent(-inf,sprintf('(pRFFit) Computing %i prefit model responses using %i processors',fitParams.prefit.n,nProcessors)); + if fitParams.verbose==1 + disppercent(-inf,sprintf('(pRFFit) Computing %i prefit model responses using %i processors',fitParams.prefit.n,nProcessors)); + end % first convert the x/y and width parameters into sizes % on the actual screen fitParams.prefit.x = fitParams.prefit.x*fitParams.stimWidth; @@ -184,10 +184,13 @@ if fitParams.prefitOnly % return if we are just doing a prefit fit = getFitParams(fitParams.initParams,fitParams); + fit.modelResponse = fitParams.prefit.modelResponse; + fit.tSeries = tSeries; fit.rfType = fitParams.rfType; fit.params = fitParams.initParams; fit.r2 = maxr^2; fit.r = maxr; + fit.bestFitVoxel = bestModel; [fit.polarAngle fit.eccentricity] = cart2pol(fit.x,fit.y); % display if fitParams.verbose @@ -298,7 +301,9 @@ end else % no constraints allowed - disp(sprintf('(pRFFit) !!! Fit constraints ignored for algorithm: %s (if you want to constrain the fits, then use: %s) !!!',fitParams.algorithm,cell2mat(algorithmsWithConstraints))); + if fitParams.verbose==1 + disp(sprintf('(pRFFit) !!! Fit constraints ignored for algorithm: %s (if you want to constrain the fits, then use: %s) !!!',fitParams.algorithm,cell2mat(algorithmsWithConstraints))); + end end end @@ -350,6 +355,11 @@ thisModelResponse = prfModel('getModelResponse', fitParams, rfModel, hrf, p, i); %%%%%%%%%%%%%%%%%%% + %~~~~~~~~~~ + %keyboard + %~~~~~~~~~~ + + % apply concat filtering if isfield(fitParams,'applyFiltering') && fitParams.applyFiltering thisModelResponse = applyConcatFiltering(thisModelResponse,fitParams.concatInfo,i); @@ -478,7 +488,7 @@ function dispModelFit(params,fitParams,modelResponse,tSeries,rfModel) nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m index bba7b545b..baba6ea08 100644 --- a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m +++ b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m @@ -451,7 +451,7 @@ % have a task which is mglRetinotopy taskNum = []; for iTask = 1:2 - if (length(thiss.task) >= iTask) && (isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename,'gruRetinotopy.m')) + if (length(thiss.task) >= iTask) && (isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename,'gruRetinotopy.m') || isequal(thiss.task{iTask}{1}.taskFilename, 'mglDoubleBars.m')) taskNum = iTask; end end @@ -467,7 +467,7 @@ if ~isfield(thiss.task{taskNum}{1},'randVars') missing = 'randVars';end if ~isfield(thiss.task{taskNum}{1},'parameter') missing = 'parameter';end if ~any(strcmp('maskPhase',thiss.myscreen.traceNames)) missing = 'maskPhase';end - if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end + %if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end if ~isempty(missing) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) Stimfile: %s',dispstr)); disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) The stimfile does not appear to have been created by the latest version of mglRetinotopy which contains the field %s necessary for reconstructing the stimulus. Consider running a dummy run with a newer version of mglRetinotpy with the same parameters (see mglSimulateRun to simulate backticks) and then use that stimfile instead of this one.',missing)); @@ -480,6 +480,9 @@ % now check for each variable that we need varnames = {'blank'}; + if isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') % mglDoubleBars doesn't use blanks + varnames = {}; + end for i = 1:length(varnames) varval = getVarFromParameters(varnames{i},e); if isempty(varval) @@ -494,12 +497,15 @@ if ~isempty(stimulusType) && (stimulusType ~= thiss.stimulusType) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! Have you averaged together scans with different stimulus conditions?')); end - if any(thiss.stimulus.stimulusType == [3 4]) + if ~isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') && any(thiss.stimulus.stimulusType == [3 4]) varval = getVarFromParameters('barAngle',e); if ~isempty(barAngle) && ~isequal(varval,barAngle) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! The barAngles are different! Have you averaged together scans with different stimulus conditions?')); end barAngle = varval; + elseif isequal(thiss.task{taskNum}{1}.taskFilename, 'mglDoubleBars.m') + varval = getVarFromParameters('conditionNum', e); + barAngle = thiss.stimulus.conditions(varval, 3:4); else if ~isempty(direction) && (thiss.stimulus.direction ~= direction) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) !!! Stimfile %s does not match previous one !!! The directions are different! Have you averaged together scans with different stimulus conditions?')); diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m index 634aa0a81..2cdac8a8e 100644 --- a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_divGaussian.m @@ -117,7 +117,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m index d9862c7d2..055b3dcef 100644 --- a/mrLoadRet/Plugin/pRF/plotFig.m +++ b/mrLoadRet/Plugin/pRF/plotFig.m @@ -30,12 +30,32 @@ function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) if any(num==7) dispWorstModelResponse = 1; end +if any(num==8) + drawR2excludingoffscreen = 1; +end paramsG = getFieldArrFromStruct(fitsGauss, 'params'); paramsN = getFieldArrFromStruct(fitsNorm, 'params'); r2G = getFieldArrFromStruct(fitsGauss, 'r2'); r2N = getFieldArrFromStruct(fitsNorm, 'r2'); +if ~ieNotDefined('drawR2excludingoffscreen') + xMin = min(stim.x(:)); + xMax = max(stim.x(:)); + yMin = min(stim.y(:)); + yMax = max(stim.y(:)); + r2g_1 = []; r2n_1 = []; + for i = 1:196 + if fitsGauss{i}.x > xMin && fitsGauss{i}.x < xMax && fitsGauss{i}.y > yMin && fitsGauss{i}.y xMin && fitsNorm{i}.x < xMax && fitsNorm{i}.y > yMin && fitsNorm{i}.y Date: Sun, 5 Mar 2017 15:09:37 -0800 Subject: [PATCH 41/44] temp commit --- mrLoadRet/Plugin/pRF/pRFFit.m | 1 + mrLoadRet/Plugin/pRF/pRF_gaussian.m | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index 8fa36859d..d68ee4f9a 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -236,6 +236,7 @@ elseif fitParams.verbose disp(sprintf('%s[%2.f %2.f %2.f] r2=%0.2f polarAngle=%6.1f eccentricity=%6.1f rfHalfWidth=%6.1f', fitParams.dispstr,x,y,z,fit.r2,r2d(fit.polarAngle),fit.eccentricity,fit.std)); end +%keyboard %%%%%%%%%%%%%%%%%%%%%% % setFitParams % diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/pRF_gaussian.m index 07cef5144..698e30c26 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/pRF_gaussian.m @@ -107,7 +107,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel From cd9146919f3ad0bbd58f242b5e37fb20a4c05f38 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 10 Mar 2017 14:21:09 -0800 Subject: [PATCH 42/44] Reorganizing git directories. Moving models into models folder and moved normalization related scripts to its own git repository --- .../pRF/{ => models}/pRFModelTemplate.m | 0 .../Plugin/pRF/{ => models}/pRF_DoG_CSS.m | 0 .../pRF/{ => models}/pRF_diffGaussian.m | 0 .../Plugin/pRF/{ => models}/pRF_divGaussian.m | 23 +- mrLoadRet/Plugin/pRF/{ => models}/pRF_exp.m | 3 +- .../Plugin/pRF/{ => models}/pRF_gaussian.m | 4 +- .../Plugin/pRF/{ => models}/pRF_gaussianhdr.m | 0 mrLoadRet/Plugin/pRF/pRFCrossVal.m | 263 ------------- mrLoadRet/Plugin/pRF/pRFSimulate.m | 211 ----------- mrLoadRet/Plugin/pRF/plot2voxels.m | 220 ----------- mrLoadRet/Plugin/pRF/plotFig.m | 356 ------------------ mrLoadRet/Plugin/pRF/predictStimulus.m | 101 ----- 12 files changed, 17 insertions(+), 1164 deletions(-) rename mrLoadRet/Plugin/pRF/{ => models}/pRFModelTemplate.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_DoG_CSS.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_diffGaussian.m (100%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_divGaussian.m (87%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_exp.m (95%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_gaussian.m (94%) rename mrLoadRet/Plugin/pRF/{ => models}/pRF_gaussianhdr.m (100%) delete mode 100644 mrLoadRet/Plugin/pRF/pRFCrossVal.m delete mode 100644 mrLoadRet/Plugin/pRF/pRFSimulate.m delete mode 100644 mrLoadRet/Plugin/pRF/plot2voxels.m delete mode 100644 mrLoadRet/Plugin/pRF/plotFig.m delete mode 100644 mrLoadRet/Plugin/pRF/predictStimulus.m diff --git a/mrLoadRet/Plugin/pRF/pRFModelTemplate.m b/mrLoadRet/Plugin/pRF/models/pRFModelTemplate.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRFModelTemplate.m rename to mrLoadRet/Plugin/pRF/models/pRFModelTemplate.m diff --git a/mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m b/mrLoadRet/Plugin/pRF/models/pRF_DoG_CSS.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_DoG_CSS.m rename to mrLoadRet/Plugin/pRF/models/pRF_DoG_CSS.m diff --git a/mrLoadRet/Plugin/pRF/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_diffGaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m diff --git a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m similarity index 87% rename from mrLoadRet/Plugin/pRF/pRF_divGaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m index 2cdac8a8e..1e5b0c05c 100644 --- a/mrLoadRet/Plugin/pRF/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m @@ -41,13 +41,14 @@ rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); % Apply divisive normalization - resp = p.b1*rPlus ./ (1 + p.b2*rMinus); + resp = rPlus ./ (1 + p.b1*rMinus); % Convolve response with hemodynamic response function thisModelResponse = convolveModelResponseWithHRF(resp, hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); % return the calculated model response output = thisModelResponse; @@ -60,15 +61,15 @@ fitParams = varargin{2}; - fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; - fitParams.paramIncDec = [1 1 1 1 1 1]; - fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; - fitParams.paramMax = [inf inf inf inf inf -inf]; + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1]; + fitParams.paramMin = [-inf -inf 0 0 -inf]; + fitParams.paramMax = [inf inf inf inf -inf]; % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 -inf -inf]; - fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; - fitParams.initParams = [0 0 4 2 1 1]; + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 0]; + fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf]; + fitParams.initParams = [0 0 4 2 1]; % return fitParams with modified values output = fitParams; @@ -90,7 +91,7 @@ p.std = params(3); p.stdRatio = params(4); p.b1 = params(5); - p.b2 = params(6); + %p.b2 = params(6); % use a fixed single gaussian p.canonical.type = 'gamma'; p.canonical.lengthInSeconds = 25; diff --git a/mrLoadRet/Plugin/pRF/pRF_exp.m b/mrLoadRet/Plugin/pRF/models/pRF_exp.m similarity index 95% rename from mrLoadRet/Plugin/pRF/pRF_exp.m rename to mrLoadRet/Plugin/pRF/models/pRF_exp.m index 99c4c5d48..35696a30f 100644 --- a/mrLoadRet/Plugin/pRF/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_exp.m @@ -44,7 +44,8 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); % return the calculated model response output = thisModelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m similarity index 94% rename from mrLoadRet/Plugin/pRF/pRF_gaussian.m rename to mrLoadRet/Plugin/pRF/models/pRF_gaussian.m index 698e30c26..b669a8b83 100644 --- a/mrLoadRet/Plugin/pRF/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m @@ -40,7 +40,9 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + %%%% Maybe uncomment this later: + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); % return the calculated model response output = thisModelResponse; diff --git a/mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussianhdr.m similarity index 100% rename from mrLoadRet/Plugin/pRF/pRF_gaussianhdr.m rename to mrLoadRet/Plugin/pRF/models/pRF_gaussianhdr.m diff --git a/mrLoadRet/Plugin/pRF/pRFCrossVal.m b/mrLoadRet/Plugin/pRF/pRFCrossVal.m deleted file mode 100644 index 0ffe58f56..000000000 --- a/mrLoadRet/Plugin/pRF/pRFCrossVal.m +++ /dev/null @@ -1,263 +0,0 @@ -%% pRFCrossVal.m -%% -%% usage: fits = pRFCrossVal(newCoords, [], analysis) --> run on specified coordinates -%% fits = pRFCrossVal([], roiName, analysis) --> run on specified ROI -%% fits = pRFCrossVal('best', roiName, analysis) --> run on best N voxels in specified ROI -%% by: akshay jagadeesh -%% date: 10/04/16 -%% purpose: Given n MotionComp runs, this function computes a n-fold cross validation, running the pRF -%% analysis n times. It generates and saves time series, model response, residuals, and covariance -%% matrices for each fold. -%% We then calculate the probability that each point in the observed time series is predicted -%% by the pRF model response. -%% -%% -%% input: roiName - Name of the ROI we want to run this analysis on -%% analysis - Name of analysis file to load -%% - This must be the Concat of Average of N scans -%% newCoords - array of scan coordinates in the form [x1 y1 z1 1; x2 y2 z2 1]' - -function [fits, d] = pRFCrossVal(newCoords, roiName, analysis) - -%%%%%%% Default inputs %%%%%%%%% -newCoords = 'best'; -roiName = 'goodV1'; -analysis = 'pRF_gV1_RoG.mat'; % change to pRF_v1_DoG.mat to run for Diff of Gaussians model -nBest = 85; -plotFigs = []; % set to [] to turn off plots, set to 1 to turn on plots -%rfType = 'gaussian-exp'; -algorithm = 'nelder-mead-bnd'; - -% Set current group to Concat and load the Analysis file -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' analysis]); -analParams = v.analyses{1}.params; -analScanNum = analParams.scanNum; -rfType = analParams.pRFFit.rfType; -disp(sprintf('(pRFCrossVal) Using model %s, with fitting algorithm %s', rfType, algorithm)); - -ogn = viewGet(v, 'originalgroupname', analScanNum); % Get the average group scan -osn = viewGet(v, 'originalscannum', analScanNum); -ogn2 = viewGet(v, 'originalgroupname', osn, ogn{1}); % Get the motioncomp scans -osn2 = viewGet(v, 'originalscannum', osn, ogn{1}); - -% Get analysis params for pRFFit -concatInfo = viewGet(v, 'concatinfo', analScanNum); -d = viewGet(v, 'd', analScanNum); -scanDims = viewGet(v, 'scanDims'); - -% Get the N original scans & their tSeries -if ~ieNotDefined('newCoords') - tempRoi = makeEmptyROI(v, sprintf('scanNum=%i',osn2(1)), 'groupNum', ogn2{1}); - if(strmatch(newCoords, 'best')) - disp(sprintf('(crossValidate) Getting %d best defined voxels in ROI %s', nBest, roiName)); - coords = getBestVoxels(v, analScanNum, nBest, roiName, analysis); - tempRoi.coords = coords; - else - disp(sprintf('(crossValidate) Getting tSeries for provided coordinates')); - tempRoi.coords = newCoords; - end - scans = loadROITSeries(v, tempRoi, osn2, ogn2{1}, 'straightXform=1'); -elseif ~ieNotDefined('roiName') - disp(sprintf('(crossValidate) Coordinates not given, getting tSeries for ROI %s', roiName)); - scans = loadROITSeries(v, roiName, osn2, ogn2{1}, 'straightXform=1'); -else - disp(sprintf('(crossValidate) Neither ROI name nor coordinates provided. Exiting.')); - return -end - -numFolds = length(scans); -for i=1:numFolds; - disp(sprintf('(crossValidate) Fold %d of %d', i, numFolds)); - % Initialize vars for use later - fit = []; - avg = zeros(size(scans{1}.tSeries)); - unfilteredLeftOut = scans{i}.tSeries; - numVoxels = size(unfilteredLeftOut, 1); - modelResponse = zeros(numVoxels, size(unfilteredLeftOut, 2)); - residual = zeros(numVoxels, size(unfilteredLeftOut, 2)); - - % compute average time series across N-1 scans - for j = 1:length(scans) - if i ~= j - avg = avg + scans{j}.tSeries; - end - end - avg = avg / (length(scans)-1); - - % Apply Concat Filtering to averages & left out - %keyboard - for k = 1:numVoxels - filteredAvg(k, :) = applyConcatFiltering(avg(k, :), concatInfo, 1); - leftOut(k, :) = applyConcatFiltering(unfilteredLeftOut(k, :), concatInfo, 1); - end - - disppercent(-inf, sprintf('\t(crossVal) Fitting pRF to %d voxels', numVoxels)); - % run pRFFit on the averaged tSeries - coords = scans{i}.scanCoords.'; - for h = 1:numVoxels - x = coords(h, 1); y = coords(h, 2); z = coords(h, 3); - linCoords = sub2ind(scanDims, x, y, z); - linVox = find(d.linearCoords == linCoords); - if isempty(linVox) - disp(sprintf('Encountered voxel, (%d, %d, %d), not included in d.linearCoords', x, y, z)); - continue - end - modelFit = pRFFit(v,[],x,y,z, 'tSeries', filteredAvg(h, :).', 'stim', d.stim, 'getModelResponse=1',... - 'params', d.params(:, linVox), 'fitTypeParams', analParams.pRFFit, 'paramsInfo', ... - d.paramsInfo, 'concatInfo', concatInfo, 'rfType', rfType); - modelResponse(h, :) = modelFit.modelResponse; - residual(h, :) = modelFit.tSeries - modelFit.modelResponse; - if strmatch(rfType, 'gaussian-diffs') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2]; - elseif strmatch(rfType, 'gaussian-exp') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.exp]; - elseif strmatch(rfType, 'gaussian-DoG-CSS') - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std, modelFit.p.std2, modelFit.p.B1, modelFit.p.B2, modelFit.p.exp]; - else - fitParams(h, :) = [x, y, z, modelFit.p.x, modelFit.p.y, modelFit.p.std]; - end - disppercent(h/numVoxels); - end - leftOut(all(modelResponse==0, 2), :) = []; - modelResponse(all(modelResponse==0, 2), :) = []; - residual(all(residual==0,2), :) = []; - numSuccess = size(modelResponse, 1); - disppercent(inf); - disp(sprintf('\t(crossVal) Successfully fit model to %d voxels', numSuccess)); - - %Calculate covariance matrix of voxels on our calculated residual - covMat = residual*residual'; - - % Compare model response to left-out timeseries - probTable = calcProb(leftOut, modelResponse, diag(diag(covMat))); - fit.modelResponse = modelResponse; - fit.residual = residual; - fit.leftOut = leftOut; - fit.covMat = covMat; - fit.probTable = probTable; - fit.fitParams = fitParams; - - eval(sprintf('fits(%d)=fit;', i)) - timeLen = size(fit.modelResponse, 2); - if ~ieNotDefined('plotFigs') - figure; - subplot(2, 1, 1); imagesc(log(fit.probTable)); axis ij; colorbar; title(sprintf('Fold %d of %d', i, numFolds)); - subplot(2, 1, 2); plot((1:timeLen), fit.leftOut, 'k'); hold on; - plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model response'); - end - -end - -% Average across folds and store in fits struct array -fit = []; -fit.modelResponse = meanStruct(fits, 'modelResponse'); -fit.residual = meanStruct(fits, 'residual'); -fit.leftOut = meanStruct(fits, 'leftOut'); -fit.covMat = meanStruct(fits, 'covMat'); -fit.probTable = meanStruct(fits, 'probTable'); -fit.fitParams = meanStruct(fits, 'fitParams'); -fits(numFolds+1) = fit; -return - % -- end main program -- % - - -%%%%%%%%%%%%%%%%%%%%%% Helper Methods %%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% meanStruct % -% % -function avg = meanStruct(structArr, field, notI) - -if(ieNotDefined('notI')) - notI = -1; -else - disp(sprintf('Averaging across all but the %d th fold', notI)); -end -eval(sprintf('avg = zeros(size(structArr(1).%s));', field)); - -for i = 1:length(structArr) - if i~=notI - avg = avg + eval(sprintf('structArr(i).%s', field)); - end -end -avg = avg / length(structArr); - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% applyConcatFiltering % -% % -function tSeries = applyConcatFiltering(tSeries,concatInfo,runnum) - -tSeries = tSeries(:); - -% apply detrending -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -% project out the mean vector -if isfield(concatInfo,'projection') && ~isempty(concatInfo.projection{runnum}) - projectionWeight = concatInfo.projection{runnum}.sourceMeanVector * tSeries; - tSeries = tSeries - concatInfo.projection{runnum}.sourceMeanVector'*projectionWeight; -end - -% now remove mean -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); -tSeries = tSeries(:)'; - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% getBestVoxels % -% % -function cords = getBestVoxels(v, scanNum, bestN, roiName, analysis) - -groupNum = viewGet(v, 'currentGroup'); -roi = loadROITSeries(v, roiName, scanNum, groupNum, 'straightXform=1', 'loadType=none'); - -r2 = viewGet(v, 'overlaydata', scanNum, 1, 1); -roi = getSortIndex(v, roi, r2); - -% Get sort index based on r2 and list of linear coords -sortIndex = roi{1}.sortindex; -scanLinCoords = roi{1}.scanLinearCoords; -scanDims = viewGet(v, 'scanDims'); -% get the linear coords with highest sortIndex and convert to 3d coords -[i,j,k] = ind2sub(scanDims, scanLinCoords(sortIndex(1:bestN))); -cords = [i;j;k;ones(1, bestN)]; - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% calcProb % - -function probTable = calcProb(testTSeries, modelResponse, covarMat) - -numTimePoints = size(modelResponse, 2); -probTable = zeros(numTimePoints, numTimePoints); - -disppercent(-inf, sprintf('\t(calcProb) Calculating prediction likelihoods')); -for i = 1:numTimePoints - model_i = modelResponse(:, i); - tSeries_i = testTSeries(:, i); - - for j = 1:numTimePoints - tSeries_j = testTSeries(:, j); - probTable(j, i) = mvnpdf(tSeries_j, model_i, covarMat); - if probTable(j, i) == 0 - disp(sprintf('\n(calcProb) mvnpdf at index(%i, %i) returning 0; Exiting.', j, i)); - return; - end - end - disppercent(i/numTimePoints); -end -disppercent(inf); diff --git a/mrLoadRet/Plugin/pRF/pRFSimulate.m b/mrLoadRet/Plugin/pRF/pRFSimulate.m deleted file mode 100644 index a2b55b230..000000000 --- a/mrLoadRet/Plugin/pRF/pRFSimulate.m +++ /dev/null @@ -1,211 +0,0 @@ -% pRFSimulate -% -% simulates N v1 voxels given 2 rf types and outputs expected time series given stimImage -% -% - stim: struct containing fields x (192x108), y (192x108), and im (192x108x time) -% - numVox: number of voxels we want to simulate -% -function [sim, fits_gauss,fits_norm] = pRFSimulate(stim) - -% stimImage = stim.im; -% numVols = size(stimImage, 2); -% [myscreen, stimImage] = -modelType = 'gaussian-divs'; -plotFigs = 0; - -%%% Preset Model Parameters %%% -modelParams.rfRatio = 0.1; -modelParams.normRatio = 1.5; % set norm pool width to be 1.5x the rf width -modelParams.cssExp = 0.75; -modelParams.noiseAmplitude = 0.1; - -% Get canonical hemodynamic response function -hrf = getCanonicalHRF(); - -%%% Create voxels in simulation -% Num voxels: 196 --> same as in prefit -xVals = -32.5:5:32.5; xVals = repmat(xVals, 1, 14); -yVals = -32.5:5:32.5; yVals = repmat(yVals, 14, 1); yVals = yVals(:); - -if(length(xVals) == length(yVals)) - numVox = length(xVals); - disp(sprintf('Number of voxels in simulation: %d', numVox)); -end -if(plotFigs == 1); plot(xVals, yVals, '*'); end - -simulation = []; -disppercent(-inf, sprintf('Creating simulation receptive fields for %d voxels', numVox)); -for i=1:numVox - - x_sim = xVals(i); y_sim = yVals(i); - eccentricity = sqrt(x_sim^2 + y_sim^2); - rfWidth = modelParams.rfRatio*eccentricity; - - % Calculate the Gaussian-derived RF from Dumoulin & Wandell 2008 - rfModel = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(rfWidth^2))); - if(mod(i,10)==0 && plotFigs == 1) - disp(i); figure; - subplot(1,2,1); plot(x_sim, y_sim, '*'); xlim([-50,50]); ylim([-50,50]); - subplot(1,2,2); imagesc(rfModel'); axis xy; xlim([0,192]); ylim([0,108]); - end - - % Calculate simulated time series using the Ratio-of-Gaussians model - resp = convolveModelWithStimulus(rfModel, stim.im); - suppFieldWidth = modelParams.normRatio*rfWidth; - beta1 = 1; beta2 = 1; - % Calculate suppressive field model - rfModel2 = exp(-(((stim.x - x_sim).^2) + ((stim.y - y_sim).^2))/(2*(suppFieldWidth^2))); - resp2 = convolveModelWithStimulus(rfModel2, stim.im); - % Estimate model response as the ratio of the 2 gaussian RF - modelResponse = beta1*resp ./ (1 + beta2*resp2); - - % Convolve with HRF - modelHRF = convolveModelResponseWithHRF(modelResponse, hrf); - - % Then add white noise and save the simulated time series data. - simulation(i,:) = addWhiteNoise(modelHRF, modelParams.noiseAmplitude); - %noiseless(i,:) = modelHRF; - %gaussian(i,:) = convolveModelResponseWithHRF(resp, hrf); - %simulation(i,:) = addWhiteNoise(convolveModelResponseWithHRF(resp./(max(resp) - min(resp)), hrf)); - %simulation(i,:) = convolveModelResponseWithHRF(resp./(max(resp) - min(resp)),hrf); - - disppercent(i/numVox); -end -disppercent(inf); -sim.x = xVals; sim.y = yVals; -sim.rfWidth = rfWidth; -sim.tSeries = simulation; - -%%% To Do: -% 1. Compute stimulus image with 464 volumes (equal to s0315 retinotopy) -% a. DONE -- figure out why mglDoubleBars framegrab is acting up. -% 2. Figure out how to map the huge number of prefit computed voxels to my simulated voxels -% -- Prefit computes 7623 (33x33x7) voxels using [prefitx prefity prefitrfHalfWidth] = ndgrid(-0.4:0.025:0.4,-0.4:0.025:0.4,[0.0125 0.025 0.05 0.1 0.25 0.5 0.75]); -% so just map my simulated voxels to values from -0.4 to +0.4 in intervals of 0.025 -%%% Model Fit: now fit the pRF model to the simulation using 2 different models (rftypes) -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' 'pRF_v1.mat']); -analParams = v.analyses{1}.params; -analParams.pRFFit.quickPrefit=1; % Use quick prefit for 196 voxels instead of 7623 -analParams.pRFFit.verbose = 0; %set verbose to 0 to silence all that annoying printing -analParams.pRFFit.prefitOnly=0; -analParams2 = analParams; -analParams2.pRFFit.rfType='gaussian-divs'; -d = viewGet(v, 'd', analParams.scanNum); -concatInfo = viewGet(v, 'concatInfo', 1); -v = newView; - -stimA{1} = stim; -numVoxels = numVox; -%numVoxels = 20; - -% Compute prefit for all voxels -disppercent(-inf, sprintf('(pRFSimulate) Computing fits for %d simulated voxels', numVoxels)); -for i = 1:numVoxels - tSeries = applyConcatFiltering(simulation(i,:), concatInfo); - sim.filteredTSeries(i,:) = tSeries; - % Run for gaussian model - fit = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams.pRFFit, 'quickPrefit', true, 'verbose=0'); - fits_gauss{i} = fit; - - % Run for normalization model - fit2 = pRFFit(v, [], 1, [], [], 'stim', stimA, 'tSeries', tSeries, 'concatInfo', concatInfo, 'fitTypeParams', analParams2.pRFFit, 'quickPrefit', true, 'verbose=0'); - fits_norm{i} = fit2; - disppercent(i/numVoxels, sprintf('Voxel %d', i)); -end -disppercent(inf); -disp(sprintf('(pRFSimulate) Successfully fit model to %d simulated voxels', numVoxels)); - -%keyboard - -return - -%%%%%%%%%%%%%%%%%%%%%%%%%%%% < end of main section > %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%---------------------------------------- -% addWhiteNoise -% adds gaussian white noise to the signal -%--------------------------------------- -function response = addWhiteNoise(signal, noiseAmplitude) -response=signal+sqrt(noiseAmplitude).*randn(1,size(signal,2)); - -%--------------------------------------- -% getCanonicalHRF -% Gets the canonical hrf given params and sample rate -%--------------------------------------- -function hrf = getCanonicalHRF() - -offset = 0; -timelag = 1; -tau = 0.6; -exponent = 6; -sampleRate = 0.5; -amplitude = 1; - -hrf.time = 0:sampleRate:25; - -exponent = round(exponent); -gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); -gammafun(find((hrf.time-timelag) <0)) = 0; - -if (max(gammafun)-min(gammafun))~=0 - gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); -end -gammafun = (amplitude*gammafun+offset); - -hrf.hrf = gammafun; -hrf.hrf = hrf.hrf / max(hrf.hrf); - -%--------------------------------------- -% convolveModelWithStimulus -% convolve the model response with the stimulus -%---------------------------------------- -function modelResponse = convolveModelWithStimulus(rfModel, stim) - -nStimFrames = size(stim, 3); -modelResponse = zeros(1,nStimFrames); -for frameNum = 1:nStimFrames - modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); -end - -%--------------------------------------- -% convolveModelResponseWithHRF -% convolve the model response with the HRF -%---------------------------------------- -function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) - -n = length(modelTimecourse); -modelTimecourse = conv(modelTimecourse,hrf.hrf); -modelTimecourse = modelTimecourse(1:n); - -%--------------------------------------- -% applyConcatFiltering -% applies detrending, hipassfilter, projection, removes mean. -%---------------------------------------- -function tSeries = applyConcatFiltering(tSeries, concatInfo) -runnum=1; - -tSeries = tSeries(:); - -% apply detrending -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -% project out the mean vector - -% remove the mean -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); - -%tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/plot2voxels.m b/mrLoadRet/Plugin/pRF/plot2voxels.m deleted file mode 100644 index 53e0a8a7b..000000000 --- a/mrLoadRet/Plugin/pRF/plot2voxels.m +++ /dev/null @@ -1,220 +0,0 @@ -%% plot2voxels.m -%% -%% usage: plot2voxels(fit, voxels) -%% purpose: plots 2 voxels' receptive fields and time courses -%% -%% input: analysis - filename of analysis file -%% fit - struct containing fields to plot probTable -%% voxels - list of two voxels in format [x1 y1 z1; x2 y2 z2] -%% - -function display = plot2voxels(analysis, voxels, fit) - -if ieNotDefined('voxels') - voxels = [44 74 21; 43 74 21]; -end -if ieNotDefined('analysis') - analysis = 'pRF_lV1_123456.mat'; -end - -% Set curr group to Concat and load the Analysis -v = newView; -v = viewSet(v, 'currentGroup', 'Concatenation'); -v = loadAnalysis(v, ['pRFAnal/' analysis]); -scanNum = v.analyses{1}.params.scanNum; -a = viewGet(v, 'Analysis'); -d = viewGet(v, 'd', scanNum); - -% Create new figure -f = figure; - -%%% (1) Voxel 1 Receptive Field %%% -rf1 = subplot(2, 3, 1); - - %Get params -x=voxels(1,1); y=voxels(1,2); z=voxels(1,3); -whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); -r = d.r(whichVoxel, :); -params = d.params(:, whichVoxel); - - %get model fit for this voxel -m = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); - - %plot voxel RF -imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m.rfModel')); -set(rf1,'Box','off'); -set(rf1,'Color',[0.8 0.8 0.8]); -set(rf1,'TickDir','out'); -axis equal -axis tight -hold on -hline(0,'w:');vline(0,'w:'); -title('Voxel 1 Receptive Field Position'); - -%% (4) Voxel 2 Receptive Field -rf2 = subplot(2, 3, 4); -x=voxels(2,1); y=voxels(2,2); z=voxels(2,3); -whichVoxel = find(d.linearCoords == sub2ind(viewGet(v, 'scanDims', scanNum), x, y, z)); -params = d.params(:, whichVoxel); -m2 = pRFFit(v, scanNum, x,y,z, 'stim', d.stim, 'getModelResponse=1', 'params', params, 'concatInfo', d.concatInfo, 'fitTypeParams', a.params.pRFFit, 'paramsInfo', d.paramsInfo); - -imagesc(d.stimX(:,1),d.stimY(1,:),flipud(m2.rfModel')); -set(rf2,'Box','off'); -set(rf2,'Color',[0.8 0.8 0.8]); -set(rf2,'TickDir','out'); -axis equal -axis tight -hold on -hline(0, 'w:');vline(0,'w:'); -title('Voxel 2 Receptive Field Position'); - -%% (2) Stimulus position - -[thisT, modelT] = makeStim(100, 50); - -function [thisT, modelT] = makeStim(time, modelTime) - stP = subplot(2, 3, 2); - %clf(stP); - cla(stP); - im = []; - thisT = time; - thisScan = d.concatInfo.whichScan(thisT); - thisVolume = d.concatInfo.whichVolume(thisT); - - modelT = modelTime; - modelScan = d.concatInfo.whichScan(modelT); - modelVol = d.concatInfo.whichVolume(modelT); - - im(:, :, 3) = flipud(0.7*d.stim{thisScan}.im(:, :, thisVolume)'); - im(:, :, 2) = flipud(0.7*d.stim{modelScan}.im(:, :, modelVol)'); - im(:, :, 1) = 0.30*m.rfModel' + 0.30*m2.rfModel'; - image(d.stimX(:, 1), d.stimY(1, :), im); - axis image - hold on - hline(0, 'w:'); vline(0, 'w:'); - title(sprintf('timeT=%i, modelT=%i', thisT, modelT)); -end - - % Get covariance matrix -residual(1, :) = m.tSeries - m.modelResponse; -residual(2, :) = m2.tSeries - m2.modelResponse; -covMat = residual*residual.'; -radius = covMat(1, 2); - -%%%% (3) and (6): Plot voxels' model response time course and time series -% Plot voxel 1 model timecourse and timeseries -tLen = length(m.modelResponse); -subplot(2, 3, 3); -plot((1:tLen), m.modelResponse, 'r'); -hold on; plot((1:tLen), m.tSeries, 'black'); -hold on; vl1m = vline(1); tl1m = text(0,0,''); -hold on; vl1t = vline(1); tl1t = text(0,0,''); -xlim([1 tLen]) -title('Voxel 1 Model Response and Time Series'); - -% Plot voxel 2 model timecourse and timeseries -subplot(2, 3, 6); -plot((1:tLen), m2.modelResponse, 'r'); -hold on; plot((1:tLen), m2.tSeries, 'black'); -hold on; vl2m = vline(1); tl2m = text(0,0,''); -hold on; vl2t = vline(1); tl2t = text(0,0,''); -xlim([1 tLen]) -title('Voxel 2 model response and time series'); - - -%% (5) 2D Gaussian model + tSeries -p4 = subplot(2, 3, 5); - -timepoint = 100; -modelTime = 50; - -x1 = m.tSeries(timepoint); -y1 = m2.tSeries(timepoint); - -x2 = m.modelResponse(modelTime); -y2 = m2.modelResponse(modelTime); - -timePlot = plot(x1, y1, '*c'); -hold on -cPlot = circle(x2, y2); -xlim([min(m.tSeries), max(m.tSeries)]); -ylim([min(m2.tSeries), max(m2.tSeries)]); -xlabel(sprintf('Voxel 1: (%d, %d, %d)', voxels(1,1), voxels(1,2), voxels(1,3))); -ylabel(sprintf('Voxel 2: (%d, %d, %d)', voxels(2,1), voxels(2,2), voxels(2,3))); -title('Voxel 1 vs Voxel 2: Percent Signal Change'); - -timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.tSeries),... - 'SliderStep', [1/tLen, 10/tLen],... - 'Value', timepoint, 'Callback', @slider1Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.25, .45, .5, .1]); -function slider1Callback(hObject, eventdata) - newVal = round(get(hObject, 'Value')); - % Move the * around - subplot(2, 3, 5); - delete(timePlot); - x1 = m.tSeries(newVal); - y1 = m2.tSeries(newVal); - timePlot = plot(x1, y1, '*b'); - - % Move stim bar - [thisT, modelT] = makeStim(newVal, modelT); - - % Move cyan line around time series course - subplot(2, 3, 3); - delete([vl1t tl1t]); - vl1t = vline(newVal, '-b'); - tl1t = text(newVal, 0.92, sprintf('time t: %d', newVal), 'color', 'b'); - subplot(2, 3, 6); - delete([vl2t tl2t]); - vl2t = vline(newVal, '-b'); - tl2t = text(newVal, 0.96, sprintf('time t: %d', newVal), 'color', 'b'); -end - -modelSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(m.modelResponse),... - 'SliderStep', [1/tLen 10/tLen], 'Value', modelTime, 'Callback', @slider2Callback,... - 'Parent', f, 'Units', 'normalized', 'Position', [.25, -.05, .5, .1]); -function slider2Callback(hObject, eventdata) - newVal = round(get(hObject, 'Value')); - % Move the circle around - subplot(2, 3, 5); - delete(cPlot); - x2 = m.modelResponse(newVal); - y2 = m2.modelResponse(newVal); - cPlot = circle(x2, y2); - - % Move the stimulus bar - [thisT, modelT] = makeStim(thisT, newVal); - - % Move green line around model time course - subplot(2, 3, 3); - delete([vl1m tl1m]); - vl1m = vline(newVal, '-g'); - tl1m = text(newVal, 0.95, sprintf('Model t: %d', newVal), 'color', 'g'); - subplot(2, 3, 6); - delete([vl2m tl2m]); - vl2m = vline(newVal, '-g'); - tl2m = text(newVal, 0.97, sprintf('Model t: %d', newVal), 'color', 'g'); -end - -align([timeSlider, modelSlider, f], 'center', 'distribute'); - - -function cPlot = circle(x, y) - r = radius; - ang = 0:0.01:2*pi; - xp = r*cos(ang); - yp = r*sin(ang); - cPlot = plot(x+xp, y+yp, 'g'); -end - - - -figure; subplot(3, 1, 1); -plot((1:tLen), m.tSeries, 'black'); -hold on; plot((1:tLen), m.modelResponse, 'blue'); -subplot(3, 1, 2); plot((1:tLen), m2.tSeries, 'red'); hold on; plot((1:tLen), m2.modelResponse, 'magenta') -xlim([1 tLen]) -if ~ieNotDefined('fit') - subplot(3, 1, 3); imagesc(log(fit.probTable)); axis ij; -end -end diff --git a/mrLoadRet/Plugin/pRF/plotFig.m b/mrLoadRet/Plugin/pRF/plotFig.m deleted file mode 100644 index 055b3dcef..000000000 --- a/mrLoadRet/Plugin/pRF/plotFig.m +++ /dev/null @@ -1,356 +0,0 @@ -% plotFig -% -% does analysis given struct of fits for two models -% - fitsGauss, fitsNorm: struct -% -% -function plotFig(fitsGauss, fitsNorm, sim, num, stim, concatInfo) - -if any(num==1) % draw true rf's - dispTrueRFs = 1; -end -if any(num==1.5) - linkRFs = 1; -end -if any(num==2) % draw model predicted rf's - dispModelRFs = 1; -end -if any(num==3) - dispModelR2 = 1; -end -if any(num==4) - drawR2 = 1; -end -if any(num==5) - dispBestModelResponse = 1; -end -if any(num==6) - dispSuppFieldSize = 1; -end -if any(num==7) - dispWorstModelResponse = 1; -end -if any(num==8) - drawR2excludingoffscreen = 1; -end - -paramsG = getFieldArrFromStruct(fitsGauss, 'params'); -paramsN = getFieldArrFromStruct(fitsNorm, 'params'); -r2G = getFieldArrFromStruct(fitsGauss, 'r2'); -r2N = getFieldArrFromStruct(fitsNorm, 'r2'); - -if ~ieNotDefined('drawR2excludingoffscreen') - xMin = min(stim.x(:)); - xMax = max(stim.x(:)); - yMin = min(stim.y(:)); - yMax = max(stim.y(:)); - r2g_1 = []; r2n_1 = []; - for i = 1:196 - if fitsGauss{i}.x > xMin && fitsGauss{i}.x < xMax && fitsGauss{i}.y > yMin && fitsGauss{i}.y xMin && fitsNorm{i}.x < xMax && fitsNorm{i}.y > yMin && fitsNorm{i}.y %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper methods below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%-------------------------------------- -% getFieldArrFromStruct(structure, fieldNameStr, -%-------------------------------------- -function fieldArray = getFieldArrFromStruct(structure, fieldNameStr) - -fieldArray = []; -for i = 1:length(structure) - fieldArray(i,:) = structure{i}.(fieldNameStr); -end - -%--------------------------------------- -% circle -% draw a circle given center (x,y), radius and color -%---------------------------------------- -function circle(x,y,r, color) -%x and y are the coordinates of the center of the circle -%r is the radius of the circle -%0.01 is the angle step, bigger values will draw the circle faster but -%you might notice imperfections (not very smooth) -ang=0:0.01:2*pi; -xp=r*cos(ang); -yp=r*sin(ang); -plot(x+xp,y+yp, color, 'MarkerSize', 4); -hold on - - -%--------------------------------------- -% getCanonicalHRF() -% get the canonical hemodnamic response function -%---------------------------------------- -function hrf = getCanonicalHRF() -offset = 0; -timelag = 1; -tau = 0.6; -exponent = 6; -sampleRate = 0.5; -amplitude = 1; -hrf.time = 0:sampleRate:25; - -exponent = round(exponent); -gammafun = (((hrf.time - timelag)/tau).^(exponent-1).*exp(-(hrf.time-timelag)/tau))./(tau*factorial(exponent-1)); -gammafun(find((hrf.time-timelag) <0)) = 0; - -if (max(gammafun)-min(gammafun))~=0 - gammafun = (gammafun-min(gammafun)) ./ (max(gammafun)-min(gammafun)); -end -gammafun = (amplitude*gammafun+offset); - -hrf.hrf = gammafun; -hrf.hrf = hrf.hrf / max(hrf.hrf); - - -%--------------------------------------- -% convolveModelWithStimulus -% convolve the model response with the stimulus -%---------------------------------------- -function modelResponse = convolveModelWithStimulus(rfModel, stim) -nStimFrames = size(stim, 3); -modelResponse = zeros(1,nStimFrames); -for frameNum = 1:nStimFrames - modelResponse(frameNum) = sum(sum(rfModel.*stim(:,:,frameNum))); -end - -%--------------------------------------- -% convolveModelResponseWithHRF -% convolve the model response with the HRF -%---------------------------------------- -function modelTimecourse = convolveModelResponseWithHRF(modelTimecourse,hrf) -n = length(modelTimecourse); -modelTimecourse = conv(modelTimecourse,hrf.hrf); -modelTimecourse = modelTimecourse(1:n); - -%--------------------------------------- -% applyConcatFiltering -% applies detrending, hipassfilter, projection, removes mean. -%---------------------------------------- -function tSeries = applyConcatFiltering(tSeries, concatInfo) -runnum=1; -tSeries = tSeries(:); - -% apply detrending - -if ~isfield(concatInfo,'filterType') || ~isempty(findstr('detrend',lower(concatInfo.filterType))) - tSeries = eventRelatedDetrend(tSeries); -end - -% apply hipass filter -if isfield(concatInfo,'hipassfilter') && ~isempty(concatInfo.hipassfilter{runnum}) - if ~isequal(length(tSeries),length(concatInfo.hipassfilter{runnum})) - disp(sprintf('(applyConcatFiltering) Mismatch dimensions of tSeries (length: %i) and concat filter (length: %i)',length(tSeries),length(concatInfo.hipassfilter{runnum}))); - else - tSeries = real(ifft(fft(tSeries) .* repmat(concatInfo.hipassfilter{runnum}', 1, size(tSeries,2)) )); - end -end - -tSeries = tSeries-repmat(mean(tSeries,1),size(tSeries,1),1); -tSeries = tSeries(:)'; diff --git a/mrLoadRet/Plugin/pRF/predictStimulus.m b/mrLoadRet/Plugin/pRF/predictStimulus.m deleted file mode 100644 index d730ea135..000000000 --- a/mrLoadRet/Plugin/pRF/predictStimulus.m +++ /dev/null @@ -1,101 +0,0 @@ -%% predictStimulus.m -%% -%% -%% usage: predictStimulus(fits, d) --> plot figs for avg (last element of fits) -%% predictStimulus(fits, d, index) --> plot figs for i'th fold in fits -%% by: akshay jagadeesh -%% date: 11/20/2016 -%% purpose: Given model fits, this function predicts the stimulus most likely to have elicited -%% the given model response and compares this to the actual observed stimulus. Outputs the -%% percentage of timepoints that are correctly predicted (within 5) using maximum likelihood. -%% - - -function predictStimulus(fits, d, index) - -numFolds = length(fits)-1; -if(ieNotDefined('index')) - fit = fits(numFolds+1); -else - disp(sprintf('getting %d th fit', index)); - fit = fits(index); -end - -timeLen = size(fit.modelResponse, 2); - -%%% 1. Plot prediction probability chart (batik) -f=figure; subplot(2, 2, 1); imagesc(log(fit.probTable)); axis ij; colorbar; -xlabel('Model Time Series'); ylabel('Observed Time series'); -hold on; hl = hline(200, '-b'); -hold on; pt = plot(0,0,'*g'); - % Plot best predicted points -count = 0; -for i = 1:timeLen - tS = fit.probTable(i,:); - [~, mI] = max(tS); - maxInd(i) = mI; - if( abs(mI - i) <= 5) - count = count + 1; - end -end -hold on; plot(maxInd, (1:timeLen), '*g', 'MarkerSize', 1); -title(sprintf('Avg Model Prediction Probability:\n %d / %d timepoints (%0.1f %%) correctly predicted within 5 using Max Likelihood', count, timeLen, 100*count/timeLen)); - -%%% 3. Plot observed and model response time course -subplot(2, 2, 3); plot((1:timeLen), fit.leftOut, 'k'); -hold on; plot((1:timeLen), fit.modelResponse, 'r'); xlim([1 timeLen]); title('Left out time series + Model Response'); -hold on; vl1 = vline(0, 'k'); hold on; vl2 = vline(0, 'k'); - -%%% 4. Plot voxel receptive fields -%rf = subplot(2,2,4); plot(fits(1).fitParams(:,4), fits(1).fitParams(:,5), '*'); -%title('Voxel Receptive Field positions'); -%set(rf, 'Box', 'off'); set(rf, 'Color', [.8 .8 .8]); set(rf,'TickDir','out'); -%axis equal; axis tight; xlim([-30 30]); ylim([-20 20]); hold on; hline(0, 'w:'); vline(0,'w:'); - -timeSlider = uicontrol('Style', 'slider', 'Min', 1, 'Max', length(fit.modelResponse),... - 'SliderStep', [1/timeLen 10/timeLen], 'Value', 200, 'Callback', @timeSliderCallback,... - 'Parent',f, 'Units', 'normalized', 'Position', [.25, -.05,.5,.1]); -function timeSliderCallback(hObject, evendata) - newVal = round(get(hObject, 'Value')); - - %plot the stimulus predicted by the model time point with highest posterior probability - timeSeries = fit.probTable(newVal, :); - [maxVal, maxIndex] = max(timeSeries); - stimPl = subplot(2, 2, [2 4]); - cla(stimPl); - im = []; - predScan = d.concatInfo.whichScan(maxIndex); - predVol = d.concatInfo.whichVolume(maxIndex); - trueScan = d.concatInfo.whichScan(newVal); - trueVol = d.concatInfo.whichVolume(newVal); - im(:, :, 3) = flipud(0.7*d.stim{trueScan}.im(:,:,trueVol)'); - im(:, :, 2) = flipud(0.7*d.stim{predScan}.im(:,:,predVol)'); - im(:, :, 1) = 0; - image(d.stimX(:,1), d.stimY(1,:), im); - axis image; hold on; - hline(0, 'w:'); vline(0, 'w:'); - hold on; plot(fits(1).fitParams(:, 4), fits(1).fitParams(:, 5), '*w', 'MarkerSize', 1); - title(sprintf('Stim predictions: Timepoint %i is best predicted by Modelpoint %i', newVal, maxIndex)); - - % Plot line and point of highest prediction - subplot(2,2,1); - delete([hl pt]); - hl = hline(newVal, '-b'); - set(hl, 'LineWidth', 5); - pt = plot(maxIndex, newVal, '*g'); - - % Plot vertical line on time series plots - subplot(2, 2, 3); - delete([vl1 vl2]); - vl1 = vline(newVal, '-b'); - set(vl1, 'LineWidth', 5); - hold on; - vl2 = vline(maxIndex, '-g'); - set(vl2, 'LineWidth', 5); - title(sprintf('Time Series: %d; Model Time: %d', newVal, maxIndex)); -end - -bl3 = uicontrol('Parent',f,'Style','text','Units', 'normalized', 'Position', [.45, .05 ,.1,.015],... - 'String', sprintf('Time Slider (blue)')); - -end From 5df0fa232ec15c82af95ec166ca42ad808e71ab0 Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Fri, 10 Mar 2017 14:22:08 -0800 Subject: [PATCH 43/44] Updated to reverse old changes and make compatible with mglDoubleBars --- mrLoadRet/Plugin/pRF/pRFFit.m | 2 +- mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/pRFFit.m b/mrLoadRet/Plugin/pRF/pRFFit.m index d68ee4f9a..4d9899f12 100644 --- a/mrLoadRet/Plugin/pRF/pRFFit.m +++ b/mrLoadRet/Plugin/pRF/pRFFit.m @@ -66,7 +66,7 @@ % but useful for raw/motionCorrected time series. Also, it is very important that % the tSeries is properly mean subtracted if ~isfield(fitParams.concatInfo,'hipassfilter') - tSeries = percentTSeries(tSeries,'detrend','spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); + tSeries = percentTSeries(tSeries,'detrend','Linear', 'spatialNormalization','Divide by mean','subtractMean', 'Yes', 'temporalNormalization', 'No'); end % if there are any nans in the tSeries then don't fit diff --git a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m index baba6ea08..8a7b0528e 100644 --- a/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m +++ b/mrLoadRet/Plugin/pRF/pRFGetStimImageFromStimfile.m @@ -467,7 +467,7 @@ if ~isfield(thiss.task{taskNum}{1},'randVars') missing = 'randVars';end if ~isfield(thiss.task{taskNum}{1},'parameter') missing = 'parameter';end if ~any(strcmp('maskPhase',thiss.myscreen.traceNames)) missing = 'maskPhase';end - %if ~any(strcmp('blank',thiss.myscreen.traceNames)) missing = 'blank';end + if ~any(strcmp('blank',thiss.myscreen.traceNames)) && isequal(thiss.task{iTask}{1}.taskFilename,'mglRetinotopy.m') missing = 'blank';end if ~isempty(missing) disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) Stimfile: %s',dispstr)); disp(sprintf('(pRFGetStimImageFromStimfile:checkStimfile) The stimfile does not appear to have been created by the latest version of mglRetinotopy which contains the field %s necessary for reconstructing the stimulus. Consider running a dummy run with a newer version of mglRetinotpy with the same parameters (see mglSimulateRun to simulate backticks) and then use that stimfile instead of this one.',missing)); From 960ed603524f14fea05a7af7f5b3cd2a150e90fb Mon Sep 17 00:00:00 2001 From: Akshay Jagadeesh Date: Tue, 20 Jun 2017 15:37:44 -0700 Subject: [PATCH 44/44] Bug fixes for models code --- .../Plugin/pRF/models/pRF_diffGaussian.m | 30 ++++++++++++------- mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m | 7 +++-- mrLoadRet/Plugin/pRF/models/pRF_exp.m | 7 +++-- mrLoadRet/Plugin/pRF/models/pRF_gaussian.m | 4 ++- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m index 9157aa743..5436bb88c 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_diffGaussian.m @@ -33,20 +33,27 @@ p = varargin{5}; i = varargin{6}; - rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*(p.std2^2))+((fitParams.stimY-p.y).^2)/(2*(p.std2^2)))); + rfModel2 = exp(-(((fitParams.stimX - p.x).^2)/(2*((p.std*p.stdRatio)^2))+((fitParams.stimY-p.y).^2)/(2*((p.std*p.stdRatio)^2)))); nFrames = fitParams.concatInfo.runTransition(i,2); rPlus = convolveModelWithStimulus(rfModel1,fitParams.stim{i},nFrames); rMinus = convolveModelWithStimulus(rfModel2, fitParams.stim{i}, nFrames); + thisModelResponse = rPlus*p.B1 - rMinus*p.B2; + thisModelResponse = convolveModelResponseWithHRF(thisModelResponse, hrf); + % and convolve in time. - pPlus = convolveModelResponseWithHRF(rPlus,hrf); - pMinus = convolveModelResponseWithHRF(rMinus,hrf); + %pPlus = convolveModelResponseWithHRF(rPlus,hrf); + %pMinus = convolveModelResponseWithHRF(rMinus,hrf); % Model response is the difference of Gaussians, weighted by Beta amplitudes - thisModelResponse = pPlus*p.B1 + pMinus*p.B2; + %thisModelResponse = pPlus*p.B1 + pMinus*p.B2; % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end + % return the calculated model response output = thisModelResponse; @@ -59,15 +66,16 @@ fitParams = varargin{2}; - fitParams.paramNames = {'x','y','rfWidth', 'surroundWidth', 'centerAmplitude', 'surroundAmplitude'}; - fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'RF width of surround pool', 'Beta weight amplitude of positive Gaussian', 'Beta weight amplitude for negative Gaussian'}; + fitParams.paramNames = {'x','y','rfWidth', 'surroundRatio', 'centerGain', 'surroundGain'}; + fitParams.paramDescriptions = {'RF x position','RF y position','RF width (std of gaussian)', 'Ratio of surround width to center width', 'Center Gain', 'Surround Gain'}; + fitParams.paramIncDec = [1 1 1 1 1 1]; fitParams.paramMin = [-inf -inf 0 0 -inf -inf]; fitParams.paramMax = [inf inf inf inf inf inf]; % set min/max and init - fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 0 -inf -inf]; + fitParams.minParams = [fitParams.stimExtents(1) fitParams.stimExtents(2) 0 1 0 0]; fitParams.maxParams = [fitParams.stimExtents(3) fitParams.stimExtents(4) inf inf inf inf]; - fitParams.initParams = [0 0 4 4 1 0]; + fitParams.initParams = [0 0 4 2 1 1]; % return fitParams with modified values output = fitParams; @@ -87,7 +95,7 @@ p.x = params(1); p.y = params(2); p.std = params(3); - p.std2 = params(4); + p.stdRatio = params(4); p.B1 = params(5); p.B2 = params(6); % use a fixed single gaussian @@ -116,7 +124,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m index 1e5b0c05c..691aab70c 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_divGaussian.m @@ -48,8 +48,9 @@ % drop junk frames here %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); - + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end % return the calculated model response output = thisModelResponse; @@ -91,7 +92,7 @@ p.std = params(3); p.stdRatio = params(4); p.b1 = params(5); - %p.b2 = params(6); + p.b2 = params(6); % use a fixed single gaussian p.canonical.type = 'gamma'; p.canonical.lengthInSeconds = 25; diff --git a/mrLoadRet/Plugin/pRF/models/pRF_exp.m b/mrLoadRet/Plugin/pRF/models/pRF_exp.m index 35696a30f..a83043dca 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_exp.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_exp.m @@ -45,8 +45,9 @@ % drop junk frames here %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end); - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); - + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end % return the calculated model response output = thisModelResponse; %end @@ -120,7 +121,7 @@ nStimFrames = size(stim.im,3); % preallocate memory -modelResponse = zeros(1,nFrames); +modelResponse = zeros(1,nStimFrames); for frameNum = 1:nStimFrames % multipy the stimulus frame by frame with the rfModel diff --git a/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m index b669a8b83..12e3dc7c4 100644 --- a/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m +++ b/mrLoadRet/Plugin/pRF/models/pRF_gaussian.m @@ -40,7 +40,9 @@ thisModelResponse = convolveModelResponseWithHRF(thisModelResponse,hrf); % drop junk frames here - thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + if fitParams.concatInfo.isConcat + thisModelResponse = thisModelResponse(fitParams.concatInfo.junkFrames(i)+1:end); + end %%%% Maybe uncomment this later: %thisModelResponse = thisModelResponse(fitParams.concatInfo.totalJunkedFrames(i)+1:end);