function PosterBatchAnalyzeTimestamps % PosterBatchAnalyzeTimestamps % % Iterate over all timingtest result files ('Res_flipconfig_xxxx') which % contain valid high precision flip timestamps, either based on % 'p'hotodiode measurements or 'd'atapixx measurements. % % measMethod must be 'p' or 'd' for photo-diode measurement via RTBox, or % Datapixx measurement. % % The recursive search for matching result files starts at /includes the % current working directory. % % The script iterates over each matching file and adds all collected raw % and high precision timestamps to a large array of timestamps. At the end % of iteration, the pooled dataset is analyzed for mean, max and min % deviation between Flip onset timestamps and measured timestamps. The % total range of deviation and the standard deviation from the mean (== % timestamp variability) is computed as well. This is done on the raw % timestamps and high precision timestamps. End results are printed and % scatterplots of all individual samples are shown. % % This script was used to compute the values of the "Stimulus timestamp % precision" result table of Mario Kleiner's ECVP-2010 poster "Visual % stimulus timing precision in Psychtoolbox-3: Tests, pitfalls & % solutions". The same data is used in the corresponding table of his PhD % Dissertation. % clear; global res; global gRawDeltas; global gPrecDeltas; includer = []; keyboard; measMethod = input('Measurement method p or d for photodiode or datapixx?', 's'); if isempty(measMethod) || ~ismember(measMethod, ['p', 'd']) error('Invalid measurement method provided!'); end sdir = pwd; % Recursively get filenames of all result files in 'sdir' directory tree: [fdir, fnames] = subdir(sdir); [gnrTotal, gnrSkipped, gnrCorrupt, gnrDisagree, gnrDelayed, meanDiff, stdDiff, rawmeanDiff, rawstdDiff, rawrangeDiff] = deal(0); sc = 0; count = 0; rangeDiff = zeros(3,0); rawrangeDiff = zeros(3,0); % Check each for valid and matching datafile: for fi = 1:length(fnames) fname = char(fnames{fi}); % Only interested in Priority 1 runs with sync-flip and medium load: if ~isempty(strfind(fname, 'Res_flipconfig_')) %if ~isempty(strfind(fname, 'Res_flipconfig_prio1_syncflip')) && ~isempty(strfind(fname,'_medium_')) %&& ~isempty(strfind(fname,'noload')) % Load result file: Will create struct 'res' with data: load(fname); if (res.measurementType == measMethod) && ismember(res.VBLTimestampingMode, [1,4]) && isfield(res, 'onsetFlipTime') && res.onsetFlipTime(end) > 0 count = count + 1 if isempty(includer) || ismember(count, includer) sc = sc + 1; fprintf('%s\n', fname); [nrTotal, nrSkipped, nrCorrupt, nrDisagree, nrDelayed, meanDiff(sc), stdDiff(sc), rangeDiff(:, sc), rawmeanDiff(sc), rawstdDiff(sc), rawrangeDiff(:, sc)] = AnalyzeThis; gnrTotal = gnrTotal + nrTotal; gnrSkipped = gnrSkipped + nrSkipped; gnrCorrupt = gnrCorrupt + nrCorrupt; gnrDisagree = gnrDisagree + nrDisagree; gnrDelayed = gnrDelayed + nrDelayed; end end end end fprintf('\n\n\n'); fprintf('Total frames: %i\n', gnrTotal); fprintf('Skipped frames: %i\n', gnrSkipped); fprintf('Corrupted frames: %i\n', gnrCorrupt); fprintf('Disagreed frames: %i\n', gnrDisagree); fprintf('Delayed frames: %i\n', gnrDelayed); if ~isempty(gPrecDeltas) meanDiff = mean(gPrecDeltas); stdDiff = std(gPrecDeltas); rangeDiff(1) = psychrange(gPrecDeltas); rangeDiff(2) = min(gPrecDeltas); rangeDiff(3) = max(gPrecDeltas); rawmeanDiff = mean(gRawDeltas); rawstdDiff = std(gRawDeltas); rawrangeDiff(1) = psychrange(gRawDeltas); rawrangeDiff(2) = min(gRawDeltas); rawrangeDiff(3) = max(gRawDeltas); fprintf('Precision timestamps:\n'); fprintf('Mean error: %f\n', meanDiff); fprintf('Stddev. : %f\n', stdDiff); fprintf('Range : %f\n', rangeDiff(1)); fprintf('Min Error : %f\n', rangeDiff(2)); fprintf('Max Error : %f\n', rangeDiff(3)); fprintf('\n\n'); fprintf('Raw timestamps:\n'); fprintf('Mean error: %f\n', rawmeanDiff); fprintf('Stddev. : %f\n', rawstdDiff); fprintf('Range : %f\n', rawrangeDiff(1)); fprintf('Min Error : %f\n', rawrangeDiff(2)); fprintf('Max Error : %f\n', rawrangeDiff(3)); close all; hold on; scatter(0,0,'g'); scatter(ones(1,length(gPrecDeltas)), gPrecDeltas, 'b'); scatter(2*ones(1,length(gRawDeltas)), gRawDeltas, 'r'); hold off; drawnow; else fprintf('No measurement data available for analysis!\n'); end return; end function [nrTotal, nrSkipped, nrCorrupt, nrDisagree, nrDelayed, meanDiff, stdDiff, rangeDiff, rawmeanDiff, rawstdDiff, rawrangeDiff] = AnalyzeThis global valids; global res; global deltas; global vdeltas; global vrawdeltas; global skippedones; global gRawDeltas; global gPrecDeltas; agrthresh = 0.0016; % Discard 1st frame by marking it as invalid: res.failFlag(1) = -1; valids = find(res.failFlag == 0); skippedones = find(abs(res.measuredTime - res.predictedOnset) > 0.75 * res.ifi); skippedones = intersect(skippedones, valids); nrSkipped = length(skippedones); nrCorrupt = length(find(res.failFlag > 0)); deltas = res.measuredTime - res.onsetFlipTime; nrDisagree = length(find(abs(deltas(valids)) > agrthresh)); nrDelayed = length(find(deltas(valids) < -0.66 * res.ifi)); % Compute final indices of valid samples in this set: agreevalids = intersect(valids, find(abs(deltas) <= agrthresh)); % Only take deltas of valid frames into account: vdeltas = 1000 * deltas(agreevalids); %#ok meanDiff = mean(vdeltas); stdDiff = std(vdeltas); rangeDiff(1) = psychrange(vdeltas); rangeDiff(2) = min(vdeltas); rangeDiff(3) = max(vdeltas); % Only take rawdeltas of valid frames into account: rawdeltas = res.measuredTime - res.rawFlipTime; vrawdeltas = 1000 * rawdeltas(agreevalids); % Only add to global sample pools if no corrupt measurements: if nrCorrupt == 0 % Add to global pool of precsion deltas: gPrecDeltas = [gPrecDeltas , vdeltas]; % Add to global pool of raw deltas: gRawDeltas = [gRawDeltas , vrawdeltas]; end rawmeanDiff = mean(vrawdeltas); rawstdDiff = std(vrawdeltas); rawrangeDiff(1) = psychrange(vrawdeltas); rawrangeDiff(2) = min(vrawdeltas); rawrangeDiff(3) = max(vrawdeltas); nrTotal = max(find(res.onsetFlipTime > 0)); %#ok fprintf('Comments: %s\n', res.Comments); if (nrCorrupt > 0) || (nrDisagree > 0) || (nrSkipped > 0) fprintf('Number of skipped frames: %i\n', nrSkipped); fprintf('Number of corrupted frames: %i\n', nrCorrupt); fprintf('Number of > 1.6 msecs disagreement meas vs. flip: %i\n', nrDisagree); fprintf('Number of flip >= 0.66 ifi later than meas. (Excessive wakeup-delay): %i\n', nrDelayed); end fprintf('Valid high-precision frames: Mean difference %f msecs, stddev %f msecs, range %f msecs.\n', meanDiff, stdDiff, rangeDiff(1)); fprintf('Valid raw-precision frames: Mean difference %f msecs, stddev %f msecs, range %f msecs.\n', rawmeanDiff, rawstdDiff, rawrangeDiff(1)); fprintf('\n\n\n'); return; end