annotate 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
rev   line source
rmeddis@38 1 function [LP_SACF, BFlist, SACF, ACFboundaryValue] = ...
rmeddis@38 2 filteredSACF(inputSignalMatrix, dt, BFlist, params)
rmeddis@38 3 % UTIL_filteredSACF computes within-channel, running autocorrelations (ACFs)
rmeddis@38 4 % and finds the running sum across channels (SACF).
rmeddis@38 5 % The SACF is smoothed to give the 'p function' (LP_SACF).
rmeddis@38 6 % (Balaguer-Ballestera, E. Denham, S.L. and Meddis, R. (2008))
rmeddis@38 7 %
rmeddis@0 8 %
rmeddis@0 9 % INPUT
rmeddis@0 10 % inputSignalMatrix: a matrix (channel x time) of AN activity
rmeddis@38 11 % dt: the signal sampling interval in seconds
rmeddis@38 12 % BFlist: channel BFs
rmeddis@38 13 %
rmeddis@0 14 % params: a list of parmeters to guide the computation:
rmeddis@38 15 % params.lags: an array of lags to be computed (seconds)
rmeddis@38 16 % params.acfTau: time constant (sec) of the running ACF
rmeddis@38 17 % if acfTau>1 it is assumed that Wiegrebe'SACF method
rmeddis@0 18 % for calculating tau is to be used (see below)
rmeddis@38 19 % params.Lambda: smoothing factor for the SACF
rmeddis@38 20 % params.lagsProcedure: strategies for omitting some lags.
rmeddis@38 21 % (Options: 'useAllLags' or 'omitShortLags')
rmeddis@38 22 % params.usePressnitzer applies lower weights longer lags
rmeddis@38 23 % params.plotACFs (=1) creates movie of ACF matrix (optional)
rmeddis@0 24 %
rmeddis@0 25 % OUTPUT
rmeddis@38 26 % LP_SACF: LP_SACF function (time x lags), a low pass filtered version of SACF.
rmeddis@38 27 % method: updated version of input 'method' (to include lags used)
rmeddis@38 28 % SACF: (time x lags)
rmeddis@38 29 %
rmeddis@38 30 % Notes:
rmeddis@38 31 % ACFboundaryValue refers to segmented evaluation and is currently not
rmeddis@38 32 % supported. However the code may be useful later when this function
rmeddis@38 33 % is incorporated into MAP1_14.
rmeddis@0 34
rmeddis@0 35 %%
rmeddis@38 36 global savedInputSignal
rmeddis@38 37
rmeddis@38 38 ACFboundaryValue=[];
rmeddis@38 39
rmeddis@0 40 [nChannels inputLength]= size(inputSignalMatrix);
rmeddis@0 41
rmeddis@38 42 % create ACF movie
rmeddis@0 43 if isfield(params, 'plotACFs') && params.plotACFs==1
rmeddis@0 44 plotACF=1;
rmeddis@38 45 signalTime=dt:dt:dt*length(savedInputSignal);
rmeddis@0 46 else
rmeddis@0 47 plotACF=0; % default
rmeddis@0 48 end
rmeddis@38 49 params.plotACFsInterval=round(params.plotACFsInterval/dt);
rmeddis@0 50
rmeddis@0 51 if isfield(params,'lags')
rmeddis@0 52 lags=params.lags;
rmeddis@0 53 else
rmeddis@0 54 lags=params.minLag:params.lagStep:params.maxLag;
rmeddis@0 55 end
rmeddis@0 56 nLags=length(lags);
rmeddis@0 57
rmeddis@0 58 % Establish lag weightsaccording to params.lagsProcedure
rmeddis@0 59 % lagWeights allow some lag computations to be ignored
rmeddis@0 60 % lagWeights is a (channel x lag) matrix;
rmeddis@0 61 if isfield(params, 'lagsProcedure')
rmeddis@0 62 lagsProcedure=params.lagsProcedure;
rmeddis@0 63 else
rmeddis@0 64 lagsProcedure='useAllLags'; % default
rmeddis@0 65 end
rmeddis@38 66
rmeddis@0 67 lagWeights=ones(nChannels,nLags);
rmeddis@0 68 switch lagsProcedure
rmeddis@0 69 case 'useAllLags'
rmeddis@38 70 % no action required lagWeights set above
rmeddis@0 71 case 'omitShortLags'
rmeddis@0 72 % remove lags that are short relative to CF
rmeddis@0 73 allLags=repmat(lags,nChannels,1);
rmeddis@0 74 allCFs=repmat(BFlist',1,nLags);
rmeddis@0 75 criterionForOmittingLags=1./(params.criterionForOmittingLags*allCFs);
rmeddis@0 76 idx= allLags < criterionForOmittingLags; % ignore these lags
rmeddis@0 77 lagWeights(idx)=0;
rmeddis@0 78 otherwise
rmeddis@38 79 error ('ACF: params.lagProcedure not recognised')
rmeddis@0 80 end
rmeddis@0 81
rmeddis@0 82
rmeddis@38 83 % Establish matrix of lag time constants
rmeddis@0 84 % these are all the same if tau<1
rmeddis@0 85 % if acfTau>1, it is assumed that we are using the Wiegrebe method
rmeddis@0 86 % and a different decay factor is applied to each lag
rmeddis@0 87 % ( i.e., longer lags have longer time constants)
rmeddis@0 88 acfTau=params.acfTau;
rmeddis@0 89 if acfTau<1 % all taus are the same
rmeddis@0 90 acfTaus=repmat(acfTau, 1, nLags);
rmeddis@0 91 acfDecayFactors=ones(size(lags)).*exp(-dt/acfTau);
rmeddis@38 92 else % use Wiegrebe method: tau= 2*lag (for example)
rmeddis@0 93 WiegrebeFactor=acfTau;
rmeddis@0 94 acfTaus=WiegrebeFactor*lags;
rmeddis@0 95 idx= acfTaus<0.0025; acfTaus(idx)=0.0025;
rmeddis@0 96 acfDecayFactors= exp(-dt./(acfTaus));
rmeddis@0 97 end
rmeddis@0 98 % make acfDecayFactors into a (channels x lags) matrix for speedy computation
rmeddis@0 99 acfDecayFactors=repmat(acfDecayFactors,nChannels, 1);
rmeddis@0 100
rmeddis@38 101 % LP_SACF function lowpass filter decay (only one value needed)
rmeddis@0 102 pDecayFactor=exp(-dt/params.lambda);
rmeddis@0 103
rmeddis@0 104 % ACF
rmeddis@0 105 % lagPointers is a list of pointers relative to 'time now'
rmeddis@0 106 lagPointers=round(lags/dt);
rmeddis@0 107 if max(lagPointers)+1>inputLength
rmeddis@0 108 error([' filteredSACF: not enough signal to evaluate ACF. Max(lag)= ' num2str(max(lags))])
rmeddis@0 109 end
rmeddis@0 110
rmeddis@0 111
rmeddis@38 112 LP_SACF=zeros(nLags,inputLength+1); % LP_SACF must match segment length +1
rmeddis@38 113 SACF=zeros(nLags,inputLength);
rmeddis@38 114 method=[]; % legacy programming
rmeddis@0 115 if ~isfield(method,'segmentNumber') || method.segmentNumber==1
rmeddis@38 116 ACF=zeros(nChannels,nLags);
rmeddis@0 117 % create a runup buffer of signal
rmeddis@0 118 buffer= zeros(nChannels, max(lagPointers));
rmeddis@0 119 else
rmeddis@38 120 % ACFboundaryValue picks up from a previous calculation
rmeddis@38 121 ACF=params.ACFboundaryValue{1};
rmeddis@38 122 % NB first value is last value of previous segment
rmeddis@38 123 LP_SACF(: , 1)=params.ACFboundaryValue{2};
rmeddis@38 124 buffer=params.ACFboundaryValue{3};
rmeddis@0 125 end
rmeddis@0 126 inputSignalMatrix=[buffer inputSignalMatrix];
rmeddis@0 127 [nChannels inputLength]= size(inputSignalMatrix);
rmeddis@0 128
rmeddis@0 129 timeCounter=0; biggestSACF=0;
rmeddis@0 130 for timePointer= max(lagPointers)+1:inputLength
rmeddis@38 131 % ACF is a continuously changing channels x lags matrix
rmeddis@0 132 % Only the current value is stored
rmeddis@38 133 % SACF is the vertical sum of ACFs; all values are kept and returned
rmeddis@38 134 % LP_SACF is the smoothed version of SACF:all values are kept and returned
rmeddis@0 135 % lagWeights emphasise some BF/lag combinations and ignore others
rmeddis@0 136 % NB time now begins at the longest lag.
rmeddis@38 137 % E.g. if max(lags) is .04 then this is when the ACf will begin (?).
rmeddis@38 138
rmeddis@0 139 % This is the ACF calculation
rmeddis@0 140 timeCounter=timeCounter+1;
rmeddis@38 141 ACF= (repmat(inputSignalMatrix(:, timePointer), 1, nLags) .* ...
rmeddis@38 142 inputSignalMatrix(:, timePointer-lagPointers)).*...
rmeddis@38 143 lagWeights *dt + ACF.* acfDecayFactors;
rmeddis@38 144 x=(mean(ACF,1)./acfTaus)';
rmeddis@38 145 SACF(:,timeCounter)=x;
rmeddis@0 146
rmeddis@38 147 % smoothed version of SACF
rmeddis@38 148 LP_SACF(:,timeCounter+1)=SACF(:,timeCounter)* (1-pDecayFactor) + ...
rmeddis@38 149 LP_SACF(:,timeCounter)* pDecayFactor;
rmeddis@38 150
rmeddis@38 151 % plot ACF at intervals if requested to do so
rmeddis@38 152 if plotACF && ~mod(timePointer,params.plotACFsInterval) && ...
rmeddis@38 153 timePointer*dt>3*max(lags)
rmeddis@38 154 figure(89), clf
rmeddis@38 155 % plot ACFs one per channel
rmeddis@38 156 subplot(2,1,1)
rmeddis@38 157 UTIL_cascadePlot(ACF, lags)
rmeddis@38 158 title(['running ACF at ' num2str(dt*timePointer,'%5.3f') ' s'])
rmeddis@38 159 ylabel('channel BF'), xlabel('period (lag, ms)')
rmeddis@38 160 set(gca,'ytickLabel',[])
rmeddis@38 161
rmeddis@38 162 % plot SACF
rmeddis@38 163 subplot(4,1,3), cla
rmeddis@38 164 plotSACF=SACF(:,timeCounter)-min(SACF(:,timeCounter));
rmeddis@38 165 plot(lags*1000, plotSACF, 'k')
rmeddis@38 166 biggestSACF=max(biggestSACF, max(plotSACF));
rmeddis@38 167 if biggestSACF>0, ylim([0 biggestSACF]), else ylim([0 1]), end
rmeddis@38 168 ylabel('SACF'), set(gca,'ytickLabel',[])
rmeddis@38 169 % xlim([min(lags*1000) max(lags*1000)])
rmeddis@38 170
rmeddis@38 171 % plot signal
rmeddis@38 172 subplot(4,1,4)
rmeddis@38 173 plot(signalTime, savedInputSignal, 'k'), hold on
rmeddis@38 174 xlim([0 max(signalTime)])
rmeddis@38 175 a= ylim;
rmeddis@38 176 % mark cursor on chart to indicate progress
rmeddis@0 177 time=timePointer*dt;
rmeddis@38 178 plot([time time], [a(1) a(1)+(a(2)-a(1))/4], 'r', 'linewidth', 5)
rmeddis@0 179 pause(params.plotMoviePauses)
rmeddis@0 180 end
rmeddis@0 181 end
rmeddis@38 182 LP_SACF=LP_SACF(:,1:end-1); % correction for speed up above
rmeddis@0 183
rmeddis@0 184 % Pressnitzer weights
rmeddis@0 185 if ~isfield(params, 'usePressnitzer'), params.usePressnitzer=0; end
rmeddis@0 186 if params.usePressnitzer
rmeddis@38 187 [a nTimePoints]=size(LP_SACF);
rmeddis@0 188 % higher pitches get higher weights
rmeddis@0 189 % PressnitzerWeights=repmat(min(lags)./lags,nTimePoints,1);
rmeddis@0 190 % weaker weighting
rmeddis@0 191 PressnitzerWeights=repmat((min(lags)./lags).^0.5, nTimePoints,1);
rmeddis@38 192 LP_SACF=LP_SACF.*PressnitzerWeights';
rmeddis@38 193 SACF=SACF.*PressnitzerWeights';
rmeddis@0 194 end
rmeddis@0 195
rmeddis@0 196 % wrap up
rmeddis@38 197 % BoundaryValue is legacy programming used in segmented model (keep)
rmeddis@38 198 ACFboundaryValue{1}=ACF(:,end-nLags+1:end);
rmeddis@38 199 ACFboundaryValue{2}=LP_SACF(:,end);
rmeddis@0 200 % save signal buffer for next segment
rmeddis@38 201 ACFboundaryValue{3} = inputSignalMatrix(:, end-max(lagPointers)+1 : end);