Mercurial > hg > map
diff MAP/filteredSACF.m @ 38:c2204b18f4a2 tip
End nov big change
author | Ray Meddis <rmeddis@essex.ac.uk> |
---|---|
date | Mon, 28 Nov 2011 13:34:28 +0000 |
parents | f233164f4c86 |
children |
line wrap: on
line diff
--- a/MAP/filteredSACF.m Thu Oct 06 15:43:20 2011 +0100 +++ b/MAP/filteredSACF.m Mon Nov 28 13:34:28 2011 +0000 @@ -1,53 +1,52 @@ -function [P, BFlist, sacf, boundaryValue] = ... - filteredSACF(inputSignalMatrix, method, params) -% UTIL_filteredSACF computes within-channel, running autocorrelations (acfs) -% and finds the sum across channels (sacf). -% The SACF is smoothed to give the 'p function' (P). +function [LP_SACF, BFlist, SACF, ACFboundaryValue] = ... + filteredSACF(inputSignalMatrix, dt, BFlist, params) +% UTIL_filteredSACF computes within-channel, running autocorrelations (ACFs) +% and finds the running sum across channels (SACF). +% The SACF is smoothed to give the 'p function' (LP_SACF). +% (Balaguer-Ballestera, E. Denham, S.L. and Meddis, R. (2008)) +% % % INPUT % inputSignalMatrix: a matrix (channel x time) of AN activity -% method.dt: the signal sampling interval in seconds -% method.segmentNo: -% method.nonlinCF -% +% dt: the signal sampling interval in seconds +% BFlist: channel BFs +% % params: a list of parmeters to guide the computation: -% filteredSACFParams.lags: an array of lags to be computed (seconds) -% filteredSACFParams.acfTau: time constant (sec) of the running acf calculations -% if acfTau>1 it is assumed that Wiegrebe'sacf method +% params.lags: an array of lags to be computed (seconds) +% params.acfTau: time constant (sec) of the running ACF +% if acfTau>1 it is assumed that Wiegrebe'SACF method % for calculating tau is to be used (see below) -% filteredSACFParams.Lambda: time constant for smoothing thsacf to make P -% filteredSACFParams.lagsProcedure identifies a strategy for omitting some lags. -% Options are: 'useAllLags', 'omitShortLags', or 'useBernsteinLagWeights' -% filteredSACFParams.usePressnitzer applies lower weights longer lags -% parafilteredSACFParamsms.plotACFs (=1) creates movie of acf matrix (optional) -% +% params.Lambda: smoothing factor for the SACF +% params.lagsProcedure: strategies for omitting some lags. +% (Options: 'useAllLags' or 'omitShortLags') +% params.usePressnitzer applies lower weights longer lags +% params.plotACFs (=1) creates movie of ACF matrix (optional) % % OUTPUT -% P: P function (time x lags), a low pass filtered version of sacf. -% method: updated version of input method (to include lags used) -% sacf: (time x lags) +% LP_SACF: LP_SACF function (time x lags), a low pass filtered version of SACF. +% method: updated version of input 'method' (to include lags used) +% SACF: (time x lags) +% +% Notes: +% ACFboundaryValue refers to segmented evaluation and is currently not +% supported. However the code may be useful later when this function +% is incorporated into MAP1_14. %% -boundaryValue=[]; +global savedInputSignal + +ACFboundaryValue=[]; + [nChannels inputLength]= size(inputSignalMatrix); -% list of BFs must be repeated is many fiber types used -BFlist=method.nonlinCF; -nfibertypes=nChannels/length(BFlist); -BFlist=repmat(BFlist',2,1)'; -dt=method.dt; -% adjust sample rate, if required -if isfield(params,'dt') - [inputSignalMatrix dt]=UTIL_adjustDT(params.dt, method.dt, inputSignalMatrix); - method.dt=dt; -end - -% create acf movie +% create ACF movie if isfield(params, 'plotACFs') && params.plotACFs==1 plotACF=1; + signalTime=dt:dt:dt*length(savedInputSignal); else plotACF=0; % default end +params.plotACFsInterval=round(params.plotACFsInterval/dt); if isfield(params,'lags') lags=params.lags; @@ -64,11 +63,11 @@ else lagsProcedure='useAllLags'; % default end -% disp(['lag procedure= ''' lagsProcedure '''']) + lagWeights=ones(nChannels,nLags); switch lagsProcedure case 'useAllLags' - % no action required lagWeights set above + % no action required lagWeights set above case 'omitShortLags' % remove lags that are short relative to CF allLags=repmat(lags,nChannels,1); @@ -76,14 +75,12 @@ criterionForOmittingLags=1./(params.criterionForOmittingLags*allCFs); idx= allLags < criterionForOmittingLags; % ignore these lags lagWeights(idx)=0; - case 'useBernsteinLagWeights' - lagWeights=BernsteinLags(BFlist, lags)'; otherwise - error ('acf: params.lagProcedure not recognised') + error ('ACF: params.lagProcedure not recognised') end -% Establish matrix of lag time constants +% Establish matrix of lag time constants % these are all the same if tau<1 % if acfTau>1, it is assumed that we are using the Wiegrebe method % and a different decay factor is applied to each lag @@ -92,7 +89,7 @@ if acfTau<1 % all taus are the same acfTaus=repmat(acfTau, 1, nLags); acfDecayFactors=ones(size(lags)).*exp(-dt/acfTau); -else % use Wiegrebe method: tau= 2*lag (for example) +else % use Wiegrebe method: tau= 2*lag (for example) WiegrebeFactor=acfTau; acfTaus=WiegrebeFactor*lags; idx= acfTaus<0.0025; acfTaus(idx)=0.0025; @@ -101,7 +98,7 @@ % make acfDecayFactors into a (channels x lags) matrix for speedy computation acfDecayFactors=repmat(acfDecayFactors,nChannels, 1); -% P function lowpass filter decay (only one value needed) +% LP_SACF function lowpass filter decay (only one value needed) pDecayFactor=exp(-dt/params.lambda); % ACF @@ -112,124 +109,93 @@ end -P=zeros(nLags,inputLength+1); % P must match segment length +1 -sacf=zeros(nLags,inputLength); +LP_SACF=zeros(nLags,inputLength+1); % LP_SACF must match segment length +1 +SACF=zeros(nLags,inputLength); +method=[]; % legacy programming if ~isfield(method,'segmentNumber') || method.segmentNumber==1 - acf=zeros(nChannels,nLags); + ACF=zeros(nChannels,nLags); % create a runup buffer of signal buffer= zeros(nChannels, max(lagPointers)); else - % boundaryValue picks up from a previous calculation - acf=params.boundaryValue{1}; - P(: , 1)=params.boundaryValue{2}; % NB first value is last value of previous segment - buffer=params.boundaryValue{3}; + % ACFboundaryValue picks up from a previous calculation + ACF=params.ACFboundaryValue{1}; + % NB first value is last value of previous segment + LP_SACF(: , 1)=params.ACFboundaryValue{2}; + buffer=params.ACFboundaryValue{3}; end inputSignalMatrix=[buffer inputSignalMatrix]; [nChannels inputLength]= size(inputSignalMatrix); timeCounter=0; biggestSACF=0; for timePointer= max(lagPointers)+1:inputLength - % acf is a continuously changing channels x lags matrix + % ACF is a continuously changing channels x lags matrix % Only the current value is stored - % sacf is the vertical summary of acf ( a vector) and all values are kept and returned - % P is the smoothed version of sacf and all values are kept and returned + % SACF is the vertical sum of ACFs; all values are kept and returned + % LP_SACF is the smoothed version of SACF:all values are kept and returned % lagWeights emphasise some BF/lag combinations and ignore others % NB time now begins at the longest lag. - % E.g. if max(lags) is .04 then this is when the ACf will begin. - % AN AN delayed weights filtering - + % E.g. if max(lags) is .04 then this is when the ACf will begin (?). + % This is the ACF calculation timeCounter=timeCounter+1; - acf= (repmat(inputSignalMatrix(:, timePointer), 1, nLags) .* inputSignalMatrix(:, timePointer-lagPointers)).*lagWeights *dt + acf.* acfDecayFactors; - x=(mean(acf,1)./acfTaus)'; -% disp(num2str(x')) - sacf(:,timeCounter)=x; - P(:,timeCounter+1)=sacf(:,timeCounter)*(1-pDecayFactor)+P(:,timeCounter)*pDecayFactor; + ACF= (repmat(inputSignalMatrix(:, timePointer), 1, nLags) .* ... + inputSignalMatrix(:, timePointer-lagPointers)).*... + lagWeights *dt + ACF.* acfDecayFactors; + x=(mean(ACF,1)./acfTaus)'; + SACF(:,timeCounter)=x; - % plot at intervals of 200 points - if plotACF && ~mod(timePointer,params.plotACFsInterval) - % mark cursor on chart to signal progress - % this assumes that the user has already plotted - % the signal in subplot(2,1,1) of figure (13) - figure(13) - hold on - subplot(4,1,1) + % smoothed version of SACF + LP_SACF(:,timeCounter+1)=SACF(:,timeCounter)* (1-pDecayFactor) + ... + LP_SACF(:,timeCounter)* pDecayFactor; + + % plot ACF at intervals if requested to do so + if plotACF && ~mod(timePointer,params.plotACFsInterval) && ... + timePointer*dt>3*max(lags) + figure(89), clf + % plot ACFs one per channel + subplot(2,1,1) + UTIL_cascadePlot(ACF, lags) + title(['running ACF at ' num2str(dt*timePointer,'%5.3f') ' s']) + ylabel('channel BF'), xlabel('period (lag, ms)') + set(gca,'ytickLabel',[]) + + % plot SACF + subplot(4,1,3), cla + plotSACF=SACF(:,timeCounter)-min(SACF(:,timeCounter)); + plot(lags*1000, plotSACF, 'k') + biggestSACF=max(biggestSACF, max(plotSACF)); + if biggestSACF>0, ylim([0 biggestSACF]), else ylim([0 1]), end + ylabel('SACF'), set(gca,'ytickLabel',[]) +% xlim([min(lags*1000) max(lags*1000)]) + + % plot signal + subplot(4,1,4) + plot(signalTime, savedInputSignal, 'k'), hold on + xlim([0 max(signalTime)]) + a= ylim; + % mark cursor on chart to indicate progress time=timePointer*dt; - a =ylim; - plot([time time], [a(1) a(1)+(a(2)-a(1))/4]) % current signal point marker - - % plot ACFs one per channel - subplot(2,1,2), cla - cascadePlot(acf, lags, BFlist) - xlim([min(lags) max(lags)]) - % set(gca,'xscale','log') - title(num2str(method.dt*timePointer)) - ylabel('BF'), xlabel('period (lag)') - - % plot SACF - subplot(4,1,2), hold off - plot(lags,sacf(:,timeCounter)-min(sacf(:,timeCounter))) - biggestSACF=max(biggestSACF, max(sacf(:,timeCounter))); - if biggestSACF>0, ylim([0 biggestSACF]), end - % set(gca,'xscale','log') - title('SACF') + plot([time time], [a(1) a(1)+(a(2)-a(1))/4], 'r', 'linewidth', 5) pause(params.plotMoviePauses) end end -P=P(:,1:end-1); % correction for speed up above +LP_SACF=LP_SACF(:,1:end-1); % correction for speed up above % Pressnitzer weights if ~isfield(params, 'usePressnitzer'), params.usePressnitzer=0; end if params.usePressnitzer - [a nTimePoints]=size(P); + [a nTimePoints]=size(LP_SACF); % higher pitches get higher weights % PressnitzerWeights=repmat(min(lags)./lags,nTimePoints,1); % weaker weighting PressnitzerWeights=repmat((min(lags)./lags).^0.5, nTimePoints,1); - P=P.*PressnitzerWeights'; - sacf=sacf.*PressnitzerWeights'; + LP_SACF=LP_SACF.*PressnitzerWeights'; + SACF=SACF.*PressnitzerWeights'; end % wrap up -method.acfLags=lags; -method.filteredSACFdt=dt; - -boundaryValue{1}=acf(:,end-nLags+1:end); -boundaryValue{2}=P(:,end); +% BoundaryValue is legacy programming used in segmented model (keep) +ACFboundaryValue{1}=ACF(:,end-nLags+1:end); +ACFboundaryValue{2}=LP_SACF(:,end); % save signal buffer for next segment -boundaryValue{3} = inputSignalMatrix(:, end-max(lagPointers)+1 : end); - -method.displaydt=method.filteredSACFdt; - -% if ~isfield(params, 'plotUnflteredSACF'), params.plotUnflteredSACF=0; end -% if method.plotGraphs -% method.plotUnflteredSACF=params.plotUnflteredSACF; -% if ~method.plotUnflteredSACF -% method=filteredSACFPlot(P,method); -% else -% method=filteredSACFPlot(SACF,method); -% end -% end - - -% ------------------------------------------------ plotting ACFs -function cascadePlot(toPlot, lags, BFs) -% % useful code -[nChannels nLags]=size(toPlot); - -% cunning code to represent channels as parallel lines -[nRows nCols]=size(toPlot); -if nChannels>1 - % max(toPlot) defines the spacing between lines - a=max(max(toPlot))*(0:nRows-1)'; - % a is the height to be added to each channel - peakGain=10; - % peakGain emphasises the peak height - x=peakGain*toPlot+repmat(a,1,nCols); - x=nRows*x/max(max(x)); -else - x=toPlot; % used when only the stimulus is returned -end -plot(lags, x','k') -ylim([0 nRows]) - +ACFboundaryValue{3} = inputSignalMatrix(:, end-max(lagPointers)+1 : end);