0001 function [data,stats] = PhasePrecession(positions,spikes,phases,varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 maxGap = 0.1;
0091 boundaries = 'count';
0092 slope = 0;
0093
0094
0095 if nargin < 3 | mod(length(varargin),2) ~= 0,
0096 error('Incorrect number of parameters (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0097 end
0098
0099
0100 if ~isempty(positions) && size(positions,2) < 2,
0101 error('Parameter ''positions'' should have at least 2 columns (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0102 end
0103 if ~isdvector(spikes),
0104 error('Parameter ''spikes'' is not a vector (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0105 end
0106 if size(phases,2) ~= 2,
0107 error('Parameter ''phases'' is not a Nx2 matrix (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0108 end
0109 isradians(phases(:,2));
0110
0111
0112 for i = 1:2:length(varargin),
0113 if ~ischar(varargin{i}),
0114 error(['Parameter ' num2str(i+2) ' is not a property (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).']);
0115 end
0116 switch(lower(varargin{i})),
0117 case 'boundaries',
0118 boundaries = lower(varargin{i+1});
0119 if ~isdvector(boundaries,'#2','>=0','<=1') && ~isastring(boundaries,'count'),
0120 error('Incorrect value for property ''boundaries'' (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0121 end
0122 case 'maxgap',
0123 maxGap = varargin{i+1};
0124 if ~isdscalar(maxGap,'>=0'),
0125 error('Incorrect value for property ''maxGap'' (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).');
0126 end
0127 case 'slope',
0128 slope = varargin{i+1};
0129 if ~isdscalar(slope),
0130 error('Incorrect value for property ''slope'' (type ''help <a href="matlab:help CircularRegression">PhasePrecession</a>'' for details).');
0131 end
0132 otherwise,
0133 error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help <a href="matlab:help PhasePrecession">PhasePrecession</a>'' for details).']);
0134 end
0135 end
0136
0137
0138 data.x = positions;
0139 data.position.t = [];
0140 data.position.x = [];
0141 data.position.phase = [];
0142 data.position.lap = [];
0143 data.rate.t = [];
0144 data.rate.r = [];
0145 data.rate.phase = [];
0146 data.rate.lap = [];
0147 stats.slope = nan;
0148 stats.intercept = nan;
0149 stats.r2 = nan;
0150 stats.p = nan;
0151 stats.x = nan(1,3);
0152 stats.mean = nan(1,3);
0153 stats.var = nan(1,3);
0154 stats.std = nan(1,3);
0155 stats.conf = nan(2,3);
0156 stats.all = {nan nan nan};
0157 stats.rate.mean = nan(1,16);
0158 stats.rate.conf = nan(2,16);
0159 stats.boundaries = [];
0160 stats.lap.slope = [];
0161 stats.lap.intercept = [];
0162 stats.lap.r2 = [];
0163 stats.lap.p = [];
0164
0165
0166 if isempty(spikes), return; end
0167 spikePhases = Interpolate(phases,spikes,'trim','off','type','circular');
0168 if isempty(spikePhases), return; end
0169
0170
0171 if ~isempty(positions),
0172
0173 if max(positions(:,2)) > 1 || min(positions(:,2)) < 0,
0174 positions(:,2) = ZeroToOne(positions(:,2));
0175 warning('Parameter ''positions'' should contain values in [0 1]. The data will now be transformed accordingly.');
0176 end
0177 [x,ignored] = Interpolate(positions,spikes,'trim','off','maxGap',maxGap);
0178 data.position.ok = ~ignored;
0179 data.position.t = spikes(~ignored);
0180 data.position.x = x(:,2);
0181 data.position.phase = spikePhases(~ignored,2);
0182 end
0183
0184
0185 unwrapped = [phases(:,1) unwrap(phases(:,2))];
0186 [spikeUnwrappedPhases,ignored] = Interpolate(unwrapped,spikes,'trim','off');
0187
0188 startUnwrappedPhases = spikeUnwrappedPhases(:,2)-2*pi;
0189 stopUnwrappedPhases = spikeUnwrappedPhases(:,2)+2*pi;
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 data.rate.r = CountInIntervals(spikeUnwrappedPhases(:,2),[startUnwrappedPhases stopUnwrappedPhases]);
0200 data.rate.t = spikes;
0201 data.rate.phase = spikePhases(:,2);
0202
0203
0204
0205
0206 if isdvector(boundaries,'#2') && ~isempty(positions),
0207
0208 stats.boundaries = boundaries;
0209
0210
0211 fieldStart = boundaries(1);
0212 fieldStop = boundaries(2);
0213 fieldSize = abs(fieldStart-fieldStop);
0214
0215
0216 x0 = [positions(1,2);positions(1:end-1,2)];
0217 x1 = positions(:,2);
0218 x2 = [positions(2:end,2);positions(end,2)];
0219
0220
0221
0222
0223
0224
0225
0226 if fieldStart < fieldStop,
0227 x0_inside = x0 >= fieldStart & x0 <= fieldStop;
0228 x1_inside = x1 >= fieldStart & x1 <= fieldStop;
0229 x2_inside = x2 >= fieldStart & x2 <= fieldStop;
0230 x0_near_x1 = abs(x0-x1)<0.1*fieldSize;
0231 x2_near_x1 = abs(x2-x1)<0.1*fieldSize;
0232 else
0233 x0_inside = x0 >= fieldStart | x0 <= fieldStop;
0234 x1_inside = x1 >= fieldStart | x1 <= fieldStop;
0235 x2_inside = x2 >= fieldStart | x2 <= fieldStop;
0236 x0_near_x1 = abs(x0-x1)<0.1*fieldSize | 1-abs(x0-x1)<0.1*fieldSize;
0237 x2_near_x1 = abs(x2-x1)<0.1*fieldSize | 1-abs(x2-x1)<0.1*fieldSize;
0238 end
0239 start = x1_inside & ~(x0_inside & x0_near_x1);
0240 start(1) = x1_inside(1) & abs(x1(1)-fieldStart)<0.1*fieldSize;
0241 stop = x1_inside & ~(x2_inside & x2_near_x1);
0242 stop(end) = x1_inside(end) & abs(x1(end)-fieldStop)<0.1*fieldSize;
0243
0244 if any(start) && any(stop),
0245 startT = positions(start,1);
0246 stopT = positions(stop,1);
0247
0248 s = [startT ones(size(startT));stopT 2*ones(size(stopT))];
0249 s = sortrows(s);
0250 ds = [1;diff(s(:,2))];
0251 s = s(ds~=0,:);
0252 startT = s(s(:,2)==1);
0253 stopT = s(s(:,2)==2);
0254
0255 if startT(1) > stopT(1), stopT(1) = []; end
0256 if ~isempty(stopT),
0257 if startT(end) > stopT(end), startT(end) = []; end
0258 traversals = [startT stopT];
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 [~,lap] = InIntervals(data.position.t,traversals);
0270 data.position.lap = lap;
0271 [~,lap] = InIntervals(data.rate.t,traversals);
0272 data.rate.lap = lap;
0273 end
0274 end
0275
0276 elseif strcmp(boundaries,'count'),
0277
0278
0279 startUnwrappedPhases = spikeUnwrappedPhases(:,2)-8*2*pi;
0280 stopUnwrappedPhases = spikeUnwrappedPhases(:,2);
0281 rateBefore = CountInIntervals(spikeUnwrappedPhases,[startUnwrappedPhases stopUnwrappedPhases]);
0282
0283 startUnwrappedPhases = spikeUnwrappedPhases(:,2);
0284 stopUnwrappedPhases = spikeUnwrappedPhases(:,2)+8*2*pi;
0285 rateAfter = CountInIntervals(spikeUnwrappedPhases,[startUnwrappedPhases stopUnwrappedPhases]);
0286
0287 minimalBefore = rateBefore <= 4;
0288 maximalAfter = rateAfter >= 16;
0289 maximalBefore = rateBefore >= 16;
0290 minimalAfter = rateAfter <= 4;
0291 start = minimalBefore & maximalAfter;
0292 stop = maximalBefore & minimalAfter;
0293
0294 if any(start) && any(stop),
0295 if start(1) >= stop(1), stop(1) = []; end
0296 if start(end) >= stop(end), start(end) = []; end
0297 traversals = [start stop];
0298
0299 [~,lap] = InIntervals(data.position.t,traversals);
0300 data.position.lap = lap;
0301 [~,lap] = InIntervals(data.rate.t,traversals);
0302 data.rate.lap = lap;
0303 end
0304
0305 end
0306
0307
0308 if ~isempty(positions) && nargout >= 2,
0309
0310
0311
0312 x = data.position.x;
0313 dx = 0;
0314 if isdvector(boundaries,'#2'),
0315 if fieldStart > fieldStop,
0316 dx = fieldStop;
0317 left = x < fieldStart;
0318 x(left) = x(left) + 1 - dx;
0319 x(~left) = x(~left) - dx;
0320 end
0321 end
0322
0323 ok = ~isnan(x);
0324 [beta,r2,p] = CircularRegression(x(ok),data.position.phase(ok),'slope',slope);
0325 stats.slope = beta(1);
0326 stats.intercept = beta(2) + stats.slope*dx;
0327 stats.r2 = r2;
0328 stats.p = p;
0329
0330 for lap = 1:max(data.rate.lap),
0331 thisLap = data.position.lap == lap;
0332 [beta,r2,p] = CircularRegression(x(thisLap&ok),data.position.phase(thisLap&ok),'slope',stats.slope);
0333 stats.lap.slope(lap,1) = beta(1);
0334 stats.lap.intercept(lap,1) = beta(2) + stats.lap.slope(lap,1)*dx;
0335 stats.lap.r2(lap,1) = r2;
0336 stats.lap.p(lap,1) = p;
0337 end
0338
0339 x0 = min(data.position.x);
0340 x1 = max(data.position.x);
0341 dx = x1-x0;
0342 for i = 1:3,
0343 ok = data.position.x > x0+dx/3*(i-1) & data.position.x < x0+dx/3*i;
0344 if sum(ok) == 0, continue; end
0345 stats.all{i} = data.position.phase(ok);
0346 stats.x(i) = x0+1.5*dx/3*(i-1);
0347 [stats.var(i),stats.std(i)] = CircularVariance(data.position.phase(ok));
0348 [stats.mean(i),stats.conf(:,i)] = CircularConfidenceIntervals(data.position.phase(ok));
0349 end
0350 end
0351
0352
0353 if nargout >= 2,
0354 for rate = 1:max(data.rate.r),
0355 ok = data.rate.r==rate;
0356 if any(ok),
0357 [stats.rate.mean(rate),stats.rate.conf(:,rate)] = CircularConfidenceIntervals(data.rate.phase(ok));
0358 else
0359 stats.rate.mean(rate) = NaN;
0360 stats.rate.conf(1:2,rate) = NaN;
0361 end
0362 end
0363 end