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