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 @ 35:25d53244d5c8
History | View | Annotate | Download (8.32 KB)
| 1 |
function [P, BFlist, sacf, boundaryValue] = ... |
|---|---|
| 2 |
filteredSACF(inputSignalMatrix, method, params) |
| 3 |
% UTIL_filteredSACF computes within-channel, running autocorrelations (acfs) |
| 4 |
% and finds the sum across channels (sacf). |
| 5 |
% The SACF is smoothed to give the 'p function' (P). |
| 6 |
% |
| 7 |
% INPUT |
| 8 |
% inputSignalMatrix: a matrix (channel x time) of AN activity |
| 9 |
% method.dt: the signal sampling interval in seconds |
| 10 |
% method.segmentNo: |
| 11 |
% method.nonlinCF |
| 12 |
% |
| 13 |
% params: a list of parmeters to guide the computation: |
| 14 |
% filteredSACFParams.lags: an array of lags to be computed (seconds) |
| 15 |
% filteredSACFParams.acfTau: time constant (sec) of the running acf calculations |
| 16 |
% if acfTau>1 it is assumed that Wiegrebe'sacf method |
| 17 |
% for calculating tau is to be used (see below) |
| 18 |
% filteredSACFParams.Lambda: time constant for smoothing thsacf to make P |
| 19 |
% filteredSACFParams.lagsProcedure identifies a strategy for omitting some lags. |
| 20 |
% Options are: 'useAllLags', 'omitShortLags', or 'useBernsteinLagWeights' |
| 21 |
% filteredSACFParams.usePressnitzer applies lower weights longer lags |
| 22 |
% parafilteredSACFParamsms.plotACFs (=1) creates movie of acf matrix (optional) |
| 23 |
% |
| 24 |
% |
| 25 |
% OUTPUT |
| 26 |
% P: P 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 |
%% |
| 31 |
boundaryValue=[]; |
| 32 |
[nChannels inputLength]= size(inputSignalMatrix); |
| 33 |
% list of BFs must be repeated is many fiber types used |
| 34 |
BFlist=method.nonlinCF; |
| 35 |
nfibertypes=nChannels/length(BFlist); |
| 36 |
BFlist=repmat(BFlist',2,1)'; |
| 37 |
|
| 38 |
dt=method.dt; |
| 39 |
% adjust sample rate, if required |
| 40 |
if isfield(params,'dt') |
| 41 |
[inputSignalMatrix dt]=UTIL_adjustDT(params.dt, method.dt, inputSignalMatrix); |
| 42 |
method.dt=dt; |
| 43 |
end |
| 44 |
|
| 45 |
% create acf movie |
| 46 |
if isfield(params, 'plotACFs') && params.plotACFs==1 |
| 47 |
plotACF=1; |
| 48 |
else |
| 49 |
plotACF=0; % default |
| 50 |
end |
| 51 |
|
| 52 |
if isfield(params,'lags') |
| 53 |
lags=params.lags; |
| 54 |
else |
| 55 |
lags=params.minLag:params.lagStep:params.maxLag; |
| 56 |
end |
| 57 |
nLags=length(lags); |
| 58 |
|
| 59 |
% Establish lag weightsaccording to params.lagsProcedure |
| 60 |
% lagWeights allow some lag computations to be ignored |
| 61 |
% lagWeights is a (channel x lag) matrix; |
| 62 |
if isfield(params, 'lagsProcedure') |
| 63 |
lagsProcedure=params.lagsProcedure; |
| 64 |
else |
| 65 |
lagsProcedure='useAllLags'; % default |
| 66 |
end |
| 67 |
% disp(['lag procedure= ''' lagsProcedure '''']) |
| 68 |
lagWeights=ones(nChannels,nLags); |
| 69 |
switch lagsProcedure |
| 70 |
case 'useAllLags' |
| 71 |
% no action required lagWeights set above |
| 72 |
case 'omitShortLags' |
| 73 |
% remove lags that are short relative to CF |
| 74 |
allLags=repmat(lags,nChannels,1); |
| 75 |
allCFs=repmat(BFlist',1,nLags); |
| 76 |
criterionForOmittingLags=1./(params.criterionForOmittingLags*allCFs); |
| 77 |
idx= allLags < criterionForOmittingLags; % ignore these lags |
| 78 |
lagWeights(idx)=0; |
| 79 |
case 'useBernsteinLagWeights' |
| 80 |
lagWeights=BernsteinLags(BFlist, lags)'; |
| 81 |
otherwise |
| 82 |
error ('acf: params.lagProcedure not recognised')
|
| 83 |
end |
| 84 |
|
| 85 |
|
| 86 |
% Establish matrix of lag time constants |
| 87 |
% these are all the same if tau<1 |
| 88 |
% if acfTau>1, it is assumed that we are using the Wiegrebe method |
| 89 |
% and a different decay factor is applied to each lag |
| 90 |
% ( i.e., longer lags have longer time constants) |
| 91 |
acfTau=params.acfTau; |
| 92 |
if acfTau<1 % all taus are the same |
| 93 |
acfTaus=repmat(acfTau, 1, nLags); |
| 94 |
acfDecayFactors=ones(size(lags)).*exp(-dt/acfTau); |
| 95 |
else % use Wiegrebe method: tau= 2*lag (for example) |
| 96 |
WiegrebeFactor=acfTau; |
| 97 |
acfTaus=WiegrebeFactor*lags; |
| 98 |
idx= acfTaus<0.0025; acfTaus(idx)=0.0025; |
| 99 |
acfDecayFactors= exp(-dt./(acfTaus)); |
| 100 |
end |
| 101 |
% make acfDecayFactors into a (channels x lags) matrix for speedy computation |
| 102 |
acfDecayFactors=repmat(acfDecayFactors,nChannels, 1); |
| 103 |
|
| 104 |
% P function lowpass filter decay (only one value needed) |
| 105 |
pDecayFactor=exp(-dt/params.lambda); |
| 106 |
|
| 107 |
% ACF |
| 108 |
% lagPointers is a list of pointers relative to 'time now' |
| 109 |
lagPointers=round(lags/dt); |
| 110 |
if max(lagPointers)+1>inputLength |
| 111 |
error([' filteredSACF: not enough signal to evaluate ACF. Max(lag)= ' num2str(max(lags))]) |
| 112 |
end |
| 113 |
|
| 114 |
|
| 115 |
P=zeros(nLags,inputLength+1); % P must match segment length +1 |
| 116 |
sacf=zeros(nLags,inputLength); |
| 117 |
if ~isfield(method,'segmentNumber') || method.segmentNumber==1 |
| 118 |
acf=zeros(nChannels,nLags); |
| 119 |
% create a runup buffer of signal |
| 120 |
buffer= zeros(nChannels, max(lagPointers)); |
| 121 |
else |
| 122 |
% boundaryValue picks up from a previous calculation |
| 123 |
acf=params.boundaryValue{1};
|
| 124 |
P(: , 1)=params.boundaryValue{2}; % NB first value is last value of previous segment
|
| 125 |
buffer=params.boundaryValue{3};
|
| 126 |
end |
| 127 |
inputSignalMatrix=[buffer inputSignalMatrix]; |
| 128 |
[nChannels inputLength]= size(inputSignalMatrix); |
| 129 |
|
| 130 |
timeCounter=0; biggestSACF=0; |
| 131 |
for timePointer= max(lagPointers)+1:inputLength |
| 132 |
% acf is a continuously changing channels x lags matrix |
| 133 |
% Only the current value is stored |
| 134 |
% sacf is the vertical summary of acf ( a vector) and all values are kept and returned |
| 135 |
% P is the smoothed version of sacf and all values are kept and returned |
| 136 |
% lagWeights emphasise some BF/lag combinations and ignore others |
| 137 |
% NB time now begins at the longest lag. |
| 138 |
% E.g. if max(lags) is .04 then this is when the ACf will begin. |
| 139 |
% AN AN delayed weights filtering |
| 140 |
|
| 141 |
% This is the ACF calculation |
| 142 |
timeCounter=timeCounter+1; |
| 143 |
acf= (repmat(inputSignalMatrix(:, timePointer), 1, nLags) .* inputSignalMatrix(:, timePointer-lagPointers)).*lagWeights *dt + acf.* acfDecayFactors; |
| 144 |
x=(mean(acf,1)./acfTaus)'; |
| 145 |
% disp(num2str(x')) |
| 146 |
sacf(:,timeCounter)=x; |
| 147 |
P(:,timeCounter+1)=sacf(:,timeCounter)*(1-pDecayFactor)+P(:,timeCounter)*pDecayFactor; |
| 148 |
|
| 149 |
% plot at intervals of 200 points |
| 150 |
if plotACF && ~mod(timePointer,params.plotACFsInterval) |
| 151 |
% mark cursor on chart to signal progress |
| 152 |
% this assumes that the user has already plotted |
| 153 |
% the signal in subplot(2,1,1) of figure (13) |
| 154 |
figure(13) |
| 155 |
hold on |
| 156 |
subplot(4,1,1) |
| 157 |
time=timePointer*dt; |
| 158 |
a =ylim; |
| 159 |
plot([time time], [a(1) a(1)+(a(2)-a(1))/4]) % current signal point marker |
| 160 |
|
| 161 |
% plot ACFs one per channel |
| 162 |
subplot(2,1,2), cla |
| 163 |
cascadePlot(acf, lags, BFlist) |
| 164 |
xlim([min(lags) max(lags)]) |
| 165 |
% set(gca,'xscale','log') |
| 166 |
title(num2str(method.dt*timePointer)) |
| 167 |
ylabel('BF'), xlabel('period (lag)')
|
| 168 |
|
| 169 |
% plot SACF |
| 170 |
subplot(4,1,2), hold off |
| 171 |
plot(lags,sacf(:,timeCounter)-min(sacf(:,timeCounter))) |
| 172 |
biggestSACF=max(biggestSACF, max(sacf(:,timeCounter))); |
| 173 |
if biggestSACF>0, ylim([0 biggestSACF]), end |
| 174 |
% set(gca,'xscale','log') |
| 175 |
title('SACF')
|
| 176 |
pause(params.plotMoviePauses) |
| 177 |
end |
| 178 |
end |
| 179 |
P=P(:,1:end-1); % correction for speed up above |
| 180 |
|
| 181 |
% Pressnitzer weights |
| 182 |
if ~isfield(params, 'usePressnitzer'), params.usePressnitzer=0; end |
| 183 |
if params.usePressnitzer |
| 184 |
[a nTimePoints]=size(P); |
| 185 |
% higher pitches get higher weights |
| 186 |
% PressnitzerWeights=repmat(min(lags)./lags,nTimePoints,1); |
| 187 |
% weaker weighting |
| 188 |
PressnitzerWeights=repmat((min(lags)./lags).^0.5, nTimePoints,1); |
| 189 |
P=P.*PressnitzerWeights'; |
| 190 |
sacf=sacf.*PressnitzerWeights'; |
| 191 |
end |
| 192 |
|
| 193 |
% wrap up |
| 194 |
method.acfLags=lags; |
| 195 |
method.filteredSACFdt=dt; |
| 196 |
|
| 197 |
boundaryValue{1}=acf(:,end-nLags+1:end);
|
| 198 |
boundaryValue{2}=P(:,end);
|
| 199 |
% save signal buffer for next segment |
| 200 |
boundaryValue{3} = inputSignalMatrix(:, end-max(lagPointers)+1 : end);
|
| 201 |
|
| 202 |
method.displaydt=method.filteredSACFdt; |
| 203 |
|
| 204 |
% if ~isfield(params, 'plotUnflteredSACF'), params.plotUnflteredSACF=0; end |
| 205 |
% if method.plotGraphs |
| 206 |
% method.plotUnflteredSACF=params.plotUnflteredSACF; |
| 207 |
% if ~method.plotUnflteredSACF |
| 208 |
% method=filteredSACFPlot(P,method); |
| 209 |
% else |
| 210 |
% method=filteredSACFPlot(SACF,method); |
| 211 |
% end |
| 212 |
% end |
| 213 |
|
| 214 |
|
| 215 |
% ------------------------------------------------ plotting ACFs |
| 216 |
function cascadePlot(toPlot, lags, BFs) |
| 217 |
% % useful code |
| 218 |
[nChannels nLags]=size(toPlot); |
| 219 |
|
| 220 |
% cunning code to represent channels as parallel lines |
| 221 |
[nRows nCols]=size(toPlot); |
| 222 |
if nChannels>1 |
| 223 |
% max(toPlot) defines the spacing between lines |
| 224 |
a=max(max(toPlot))*(0:nRows-1)'; |
| 225 |
% a is the height to be added to each channel |
| 226 |
peakGain=10; |
| 227 |
% peakGain emphasises the peak height |
| 228 |
x=peakGain*toPlot+repmat(a,1,nCols); |
| 229 |
x=nRows*x/max(max(x)); |
| 230 |
else |
| 231 |
x=toPlot; % used when only the stimulus is returned |
| 232 |
end |
| 233 |
plot(lags, x','k') |
| 234 |
ylim([0 nRows]) |
| 235 |
|