Skip to content

Commit 833ceb8

Browse files
authored
Merge pull request #9 from xdf-modules/fix_robust_fit
Fix robust_fit issue with large timestamps
2 parents c0e0ae7 + 3102d9d commit 833ceb8

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

load_xdf.m

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@
7373
% ClockOffset difference that is at least this
7474
% many seconds away from the median. (default: 1)
7575
%
76+
% 'WinsorThreshold' : Error threshold beyond which clock offset deviations are considered
77+
% outliers, and therefore penalized less severely (linear instead of quadratic).
78+
% (default: 0.0001)
79+
%
7680
% 'ClockResetMaxJitter' : Maximum tolerable jitter (in seconds of error) for clock
7781
% reset handling. (default: 5)
7882
%
@@ -365,7 +369,7 @@
365369
temp(id).time_series = {};
366370
temp(id).time_stamps = {};
367371
temp(id).clock_times = [];
368-
temp(id).clock_values = [];
372+
temp(id).offset_values = [];
369373
if temp(id).srate > 0
370374
temp(id).sampling_interval = 1/temp(id).srate;
371375
else
@@ -391,7 +395,7 @@
391395
% read [CollectionTime]
392396
temp(id).clock_times(end+1) = fread(f,1,'double');
393397
% read [OffsetValue]
394-
temp(id).clock_values(end+1) = fread(f,1,'double');
398+
temp(id).offset_values(end+1) = fread(f,1,'double');
395399
catch e
396400
% an error occurred (perhaps a chopped-off file): emit a
397401
% warning and scan forward to the next recognized chunk
@@ -431,7 +435,7 @@
431435
if ~isempty(temp(k).time_stamps)
432436
try
433437
clock_times = temp(k).clock_times;
434-
clock_values = temp(k).clock_values;
438+
offset_values = temp(k).offset_values;
435439
if isempty(clock_times)
436440
error('No clock offset values present.'); end
437441
catch
@@ -447,7 +451,7 @@
447451
% importer should be able to deal with recordings where the computer that served a stream
448452
% was restarted or hot-swapped during an ongoing recording, or the clock was reset otherwise
449453
time_diff = diff(clock_times);
450-
value_diff = abs(diff(clock_values));
454+
value_diff = abs(diff(offset_values));
451455
% points where a glitch in the timing of successive clock measurements happened
452456
time_glitch = (time_diff < 0 | (((time_diff - median(time_diff)) ./ median(abs(time_diff-median(time_diff)))) > opts.ClockResetThresholdStds & ...
453457
((time_diff - median(time_diff)) > opts.ClockResetThresholdSeconds)));
@@ -472,15 +476,18 @@
472476
ranges = {[1,length(clock_times)]};
473477
end
474478

475-
% calculate clock offset mappings for each data range
479+
% Calculate clock offset mappings for each data range
476480
mappings = {};
477481
for r=1:length(ranges)
478482
idx = ranges{r};
479483
if idx(1) ~= idx(2)
480-
% to accomodate the Winsorizing threshold (in seconds) we rescale the data (robust_fit sets it to 1 unit)
481-
mappings{r} = robust_fit([ones(idx(2)-idx(1)+1,1) clock_times(idx(1):idx(2))']/opts.WinsorThreshold, clock_values(idx(1):idx(2))'/opts.WinsorThreshold);
484+
Ax = clock_times(idx(1):idx(2))' / opts.WinsorThreshold;
485+
y = offset_values(idx(1):idx(2))' / opts.WinsorThreshold;
486+
fit_params = robust_fit([ones(size(Ax)) Ax], y);
487+
fit_params(1) = fit_params(1)*opts.WinsorThreshold;
488+
mappings{r} = fit_params;
482489
else
483-
mappings{r} = [clock_values(idx(1)) 0]; % just one measurement
490+
mappings{r} = [offset_values(idx(1)) 0]; % just one measurement
484491
end
485492
end
486493

@@ -781,7 +788,7 @@ function close_file(f,filename)
781788
% minimize 1/2*sum(huber(A*x - y))
782789
%
783790
% Based on the ADMM Matlab codes also found at:
784-
% http://www.stanford.edu/~boyd/papers/distr_opt_stat_learning_admm.html
791+
% https://web.stanford.edu/~boyd/papers/admm_distr_stats.html
785792
%
786793
% Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
787794
% 2013-03-04
@@ -790,15 +797,21 @@ function close_file(f,filename)
790797
rho = 1; end
791798
if ~exist('iters','var')
792799
iters = 1000; end
800+
801+
x_offset = min(A(:, 2));
802+
A(:, 2) = A(:, 2) - x_offset;
793803
Aty = A'*y;
794-
L = sparse(chol(A'*A,'lower')); U = L';
804+
L = chol( A'*A, 'lower' );
805+
L = sparse(L);
806+
U = sparse(L');
795807
z = zeros(size(y)); u = z;
796808
for k = 1:iters
797809
x = U \ (L \ (Aty + A'*(z - u)));
798810
d = A*x - y + u;
799811
z = rho/(1+rho)*d + 1/(1+rho)*max(0,(1-(1+1/rho)./abs(d))).*d;
800812
u = d - z;
801813
end
814+
x(1) = x(1) - x(2)*x_offset;
802815
end
803816

804817

0 commit comments

Comments
 (0)