function varargout = setupdata( spikeTimesArray, positionData, parametersFile )
    % Initialise all data structures to do with experimentally observed
    % variables such as spike trains and position data.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % analysisIntervals - a 1 by 2 vector of times, in seconds, between
    % which we wish to constrain the analysis.
    %
    % timeConversionFactor - numeric scalar with which to multiply all raw
    % times to transform them to seconds.
    %
    % maxSpatialDimensionSize is the number of discrete squares that will
    % tile the longest spatial dimension in the desired resolution. Must be
    % a positive integer.
    %
    % smoothingWidth - positive integer. This defines the maximum number of
    % consecutive invalid discrete positions (in a row or column) we will
    % consider as candidates to convert to valid positions in an effort to
    % 'smooth out' unvisited regions. Thus we make more of the environment
    % accessible than was actually visited, approximating the true spatial
    % extend of the environment. See note below for more information. A
    % larger value will fill out more valid regions, but runs a greater
    % risk of making regions valid that should be considered invalid. Some
    % experimentation will be needed to optimise this for the desired
    % resolution.
    %
    % We can use the dataInterval and dataIntervalProportions variables to
    % restrict the supplied raw data to a particular time interval. Then we
    % can further subdivide the remaining data according to 'analysis
    % intervals' using the analysisIntervals and
    % analysisIntervalsProportions variables.
    %
    % These are matrices with two columns. Each row corresponds to an
    % interval for analysis, and hives off the corresponding interval of
    % data into a separate pair of output structures. The parameters of
    % these data are standardised across analysis intervals, so that the
    % number of spike trains remains the same, and so does the number of
    % valid positions, distances, spatial discretisation, etc. Either one
    % or both data types can be used in any interval. These intervals can
    % overlap or not, and can be contiguous or not.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % CHANGELOG
    % 29.09.2014 - created.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    if nargin < 2,
        error('Insufficient arguments!')
    end
    if nargin < 3,
        error('No parameters file supplied!')
    end
    if exist(parametersFile, 'file') ~= 2,
        error('You must supply the filename of a parameters file (.m file) on the search path!')
    end

    % Load script containing parameter values.
    % Chop off any '.m' ending.
    if strcmp(parametersFile((end - 1):end) , '.m'),
        parametersFile = parametersFile(1:(end - 2));
    end
    eval(sprintf('%s;', parametersFile));

    if rem(nargout, 2) ~= 0,
        error('There must be two outputs for each analysis interval (spike trains data and position data)!')
    end
    % Set default values where we can.
    if ~exist('dataInterval', 'var'),
        dataInterval = [];
    end
    if ~exist('dataIntervalProportions', 'var'),
        dataIntervalProportions = [];
    end
    if ~exist('analysisIntervals', 'var'),
        analysisIntervals = [];
    end
    if ~exist('analysisIntervalsProportions', 'var'),
        analysisIntervalsProportions = [];
    end
    if ~exist('timeConversionFactor', 'var'),
        timeConversionFactor = 1e-6;
    end
    if ~exist('maxSpatialDimensionSize', 'var'),
        maxSpatialDimensionSize = 32;
    end
    if ~exist('smoothingWidth', 'var'),
        smoothingWidth = [];
    end
    if ~exist('modelIndicator', 'var'),
        modelIndicator = 2;
    end
    if modelIndicator == 1,
        if ~exist('updateStepInterval', 'var'),
            updateStepInterval = 1;
        elseif isnan(updateStepInterval) || isempty(updateStepInterval) || (updateStepInterval <= 0),
            error('updateStepInterval must be defined and be positive!')
        end
        if ~exist('spikeTrainModelIndicator', 'var'),
            spikeTrainModelIndicator = 1;
        end
    end

    if ~isempty(spikeTimesArray),
        haveSpikeTrainsData = true;
        if length(size(spikeTimesArray)) > 2,
            error('spikeTimesArray should be a ''column'' cell array!')
        end
        if size(spikeTimesArray, 1) == 1,
            spikeTimesArray = spikeTimesArray';
        end
    else
        haveSpikeTrainsData = false;
    end
    if ~isempty(positionData),
        havePositionData = true;
    else
        havePositionData = false;
    end
    if ~haveSpikeTrainsData && ~havePositionData,
        error('At least one of spikeTimesArray and positionData must be non-empty!')
    end
    if haveSpikeTrainsData && any(cellfun('size', spikeTimesArray, 2) > 1),
        error('Spike trains must be column vectors!')
    end
    if haveSpikeTrainsData && all(cellfun(@isempty, spikeTimesArray)),
        error('Spike trains must not all be empty!')
    end
    if havePositionData && size(positionData, 2) ~= 3,
        error('positionData must have 3 columns: time (seconds), Y coord and X coord!')
    end
    if havePositionData && (max(positionData(:, 1)) == min(positionData(:, 1))),
        error('Must have more than one distinct observation in position data!')
    end
    if havePositionData && (max(positionData(:, 2)) == min(positionData(:, 2))) && (max(positionData(:, 3)) == min(positionData(:, 3))),
        error('Must have more than one distinct position in position data!')
    end
    if ~isempty(dataIntervalProportions),
        if ~isequal(size(dataIntervalProportions), [1, 2]),
            error('dataIntervalProportions must be a 1 by 2 vector!')
        end
        if (dataIntervalProportions(1) < 0) || (dataIntervalProportions(2) > 1),
            error('Values in dataIntervalProportions must be between 0 and 1 (inclusive)!')
        end
        if dataIntervalProportions(1) >= dataIntervalProportions(2),
            error('Data interval is invalid!')
        end
    else
        dataIntervalProportions = [0, 1];
    end
    if ~isempty(dataInterval),
        if ~isequal(size(dataInterval), [1, 2]),
            error('dataInterval must be a 1 by 2 vector!')
        end
        if dataInterval(1) >= dataInterval(2),
            error('Data interval is invalid!')
        end
    end
    if ~isempty(analysisIntervalsProportions),
        if size(analysisIntervalsProportions, 2) ~= 2,
            error('analysisIntervalsProportions must have 2 columns!')
        end
        if any(any(analysisIntervalsProportions < 0)) || any(any(analysisIntervalsProportions > 1)),
            error('Values in analysisIntervalsProportions must be between 0 and 1 (inclusive)!')
        end
        if any(analysisIntervalsProportions(:, 1) >= analysisIntervalsProportions(:, 2)),
            error('Start time for analysis must be before end time!')
        end
    else
        analysisIntervalsProportions = [0, 1];
    end
    if ~isempty(analysisIntervals), 
        if size(analysisIntervals, 2) ~= 2,
            error('analysisIntervals must have 2 columns!')
        end
        if any(analysisIntervals(:, 1) >= analysisIntervals(:, 2)),
            error('Start time for analysis must be before end time!')
        end
        nAnalysisIntervals = size(analysisIntervals, 1);
        if size(analysisIntervalsProportions, 1) ~= nAnalysisIntervals,
            if size(analysisIntervalsProportions, 1) ~= 1,
                error('Invalid analysisIntervalsProportions!')
            end
            analysisIntervalsProportions = repmat(analysisIntervalsProportions, [nAnalysisIntervals, 1]);
        end
    else
        nAnalysisIntervals = size(analysisIntervalsProportions, 1);
    end
    if nargout ~= 2 * nAnalysisIntervals,
        error('There must be two outputs for each analysis interval (spike trains data and position data)!')
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % First step: re-zero time and convert to seconds.
    minTimeSpikes = [];
    maxTimeSpikes = [];
    minTimePosition = [];
    maxTimePosition = [];
    if haveSpikeTrainsData,
        minTimeSpikes = min(cellfun(@min, spikeTimesArray(~cellfun(@isempty, spikeTimesArray))));
        maxTimeSpikes = max(cellfun(@max, spikeTimesArray(~cellfun(@isempty, spikeTimesArray))));
    end

    if havePositionData,
        minTimePosition = min(positionData(:, 1));
        maxTimePosition = max(positionData(:, 1));
    end
    minTime = min([minTimeSpikes, minTimePosition]);
    maxTime = max([maxTimeSpikes, maxTimePosition]);
    duration = maxTime - minTime;
    
    % At this point, report some information about the data.
    sprintf('Earliest spike time: %f (%0.4f s)\nLatest spike time: %f (%0.4f s)\nEarliest position observation time: %f (%0.4f s)\nLatest position observation time: %f (%0.4f s)', minTimeSpikes, minTimeSpikes * timeConversionFactor, maxTimeSpikes, maxTimeSpikes * timeConversionFactor, minTimePosition, minTimePosition * timeConversionFactor, maxTimePosition, maxTimePosition * timeConversionFactor)

    if isempty(dataInterval),
        dataInterval = dataIntervalProportions * duration + minTime;
    else
        if dataInterval(1) < minTime,
            error('dataInterval start time is less than earliest observation time!')
%             dataInterval(1) = minTime;
        end
        if dataInterval(2) > maxTime,
            error('dataInterval end time is greater than latest observation time!')
%             dataInterval(2) = maxTime;
        end
    end
    % Restrict data to range of interest.
    minTime = dataInterval(1);
    maxTime = dataInterval(2);

    duration = maxTime - minTime;
    if haveSpikeTrainsData,
        spikeTimesArray = cellfun(@(iSpikeTrain) iSpikeTrain((iSpikeTrain >= dataInterval(1)) & (iSpikeTrain <= dataInterval(2))), spikeTimesArray, 'UniformOutput', false);
        nSpikeTrains = length(spikeTimesArray);
    end
    if havePositionData,
        positionData = positionData((positionData(:, 1) >= dataInterval(1)) & (positionData(:, 1) <= dataInterval(2)), :);
    end

    if isempty(analysisIntervals),
        analysisIntervals = analysisIntervalsProportions * duration + minTime;
    end
    
    % Re-zeroing, conversion to seconds.
    analysisIntervals = (analysisIntervals - minTime) * timeConversionFactor;
    if haveSpikeTrainsData,
        spikeTimesArray = cellfun(@(iSpikeTrain) (iSpikeTrain - minTime) * timeConversionFactor, spikeTimesArray, 'UniformOutput', false);
    end
    if havePositionData,
        positionData(:, 1) = (positionData(:, 1) - minTime) * timeConversionFactor;
        if ~exist('posObsInterval', 'var') || (isnan(posObsInterval)),
            if modelIndicator == 1,
                posObsInterval = updateStepInterval;
            else
                posObsInterval = mean(positionData(2:end, 1) - positionData(1:(end - 1), 1));
            end
        else
            if modelIndicator == 1,
                posObsInterval = updateStepInterval;
            end
%             if (modelIndicator == 1) && (posObsInterval ~= updateStepInterval),
%                 error('posObsInterval does nto equal updateStepInterval!');
%             end
        end
    end

    sprintf('Analysis intervals are (in seconds):')
    sprintf('%0.4f to %0.4f\n', analysisIntervals')
    
%     % We also "re-zero" position data, so that the lowest observed X
%     % coordinate is 0, and likewise for Y coordinates. This also makes all
%     % observations positive.
%     positionData(:, 2:3) = bsxfun(@minus, positionData(:, 2:3), min(positionData(:, 2:3), [], 1));
    
    % Note that analysis intervals include observations occuring at the
    % lower bound but not at the upper bound, except for the last interval,
    % which DOES include observations at the upper bound.
    for iAnalysisInterval = 1:nAnalysisIntervals,
        iPairIndex = 2 * (iAnalysisInterval - 1) + 1;
        if iAnalysisInterval < nAnalysisIntervals,
            if haveSpikeTrainsData,
                varargout{iPairIndex}.spikeTimesArray = cellfun(@(iSpikeTrain) iSpikeTrain((iSpikeTrain >= analysisIntervals(iAnalysisInterval, 1)) & (iSpikeTrain < analysisIntervals(iAnalysisInterval, 2))), spikeTimesArray, 'UniformOutput', false);
            end
            if havePositionData,
                varargout{iPairIndex + 1}.coordsTrajectory = positionData((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) < analysisIntervals(iAnalysisInterval, 2)), :);
            end
        else
            if haveSpikeTrainsData,
                varargout{iPairIndex}.spikeTimesArray = cellfun(@(iSpikeTrain) iSpikeTrain((iSpikeTrain >= analysisIntervals(iAnalysisInterval, 1)) & (iSpikeTrain <= analysisIntervals(iAnalysisInterval, 2))), spikeTimesArray, 'UniformOutput', false);
            end
            if havePositionData,
                varargout{iPairIndex + 1}.coordsTrajectory = positionData((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) <= analysisIntervals(iAnalysisInterval, 2)), :);
            end
        end
        % If any spikes fall in this analysis interval, we consider
        % ourselves to have spike train data and need to set it up.
        if haveSpikeTrainsData && any(cellfun(@length, varargout{iPairIndex}.spikeTimesArray) > 0),
            varargout{iPairIndex}.haveSpikeTrainsData = true;
            varargout{iPairIndex}.nSpikeTrains = nSpikeTrains;
            varargout{iPairIndex}.analysisInterval = analysisIntervals(iAnalysisInterval, :);
            varargout{iPairIndex}.startTime = analysisIntervals(iAnalysisInterval, 1);
            varargout{iPairIndex}.endTime = analysisIntervals(iAnalysisInterval, 2);
            if modelIndicator == 1,
                varargout{iPairIndex}.updateStepInterval = updateStepInterval;
                varargout{iPairIndex}.nUpdateSteps = ceil((varargout{iPairIndex}.endTime - varargout{iPairIndex}.startTime) / varargout{iPairIndex}.updateStepInterval);
            end
        else
            varargout{iPairIndex}.haveSpikeTrainsData = false;
            varargout{iPairIndex}.analysisInterval = analysisIntervals(iAnalysisInterval, :);
            varargout{iPairIndex}.startTime = analysisIntervals(iAnalysisInterval, 1);
            varargout{iPairIndex}.endTime = analysisIntervals(iAnalysisInterval, 2);
        end
        % These are defauls, that may be replaced later.
        varargout{iPairIndex}.datasetStartTimes = [varargout{iPairIndex}.startTime; varargout{iPairIndex}.endTime];
        % Likewise with position observations in this analysis interval. If
        % the position trajectory is not long enough (in duration), it is
        % extrapolated in the required directions.
        if havePositionData ...
                && (size(varargout{iPairIndex + 1}.coordsTrajectory, 1) > 0),
            varargout{iPairIndex + 1}.havePositionData = true;
            varargout{iPairIndex + 1}.analysisInterval = analysisIntervals(iAnalysisInterval, :);
            varargout{iPairIndex + 1}.startTime = analysisIntervals(iAnalysisInterval, 1);
            varargout{iPairIndex + 1}.endTime = analysisIntervals(iAnalysisInterval, 2);
            varargout{iPairIndex + 1}.maxSpatialDimensionSize = maxSpatialDimensionSize;
%             if modelIndicator == 1,
%                 varargout{iPairIndex + 1}.updateStepInterval = updateStepInterval;
%                 varargout{iPairIndex + 1}.nUpdateSteps = ceil((varargout{iPairIndex + 1}.endTime - varargout{iPairIndex + 1}.startTime) / varargout{iPairIndex}.updateStepInterval);
%             end
        else
            varargout{iPairIndex + 1}.havePositionData = false;
            varargout{iPairIndex + 1}.analysisInterval = analysisIntervals(iAnalysisInterval, :);
            varargout{iPairIndex + 1}.startTime = analysisIntervals(iAnalysisInterval, 1);
            varargout{iPairIndex + 1}.endTime = analysisIntervals(iAnalysisInterval, 2);
        end
        % These are defauls, that may be replaced later.
        varargout{iPairIndex + 1}.datasetStartTimes = [varargout{iPairIndex + 1}.startTime; varargout{iPairIndex + 1}.endTime];
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % Second step: discretise data as required.

    % Position data discretisation over ALL position data available. We do
    % it this way so that the number of valid positions, distance matrices
    % etc are standardised across analysis intervals.
    if havePositionData,
        % Before discretising position we will interpolate the observations
        % we have to a set of time points of fixed interval.
        % Interpolate to new time points.
        positionData = interpolatenewpositiondata( positionData, positionData(1, 1), positionData(end, 1), posObsInterval );
        [discreteCoordsTrajectory, discreteYDim, discreteXDim, spatialBinWidth] = discretisepositiondata( positionData, maxSpatialDimensionSize );
        if ~isempty(smoothingWidth),
            validDiscretePositionsBinMat = formvalidpositionslogicalmatrix( discreteCoordsTrajectory, discreteYDim, discreteXDim, smoothingWidth );
        else
            validDiscretePositionsBinMat = formvalidpositionslogicalmatrix( discreteCoordsTrajectory, discreteYDim, discreteXDim );
        end
        % Now we can compute the centre coordinates of each grid cell.
        [gridCentreCoordsMat, positionIndToGridCentreCoordsMap, gridCentreCoordsTrajectory] = formgridcentrecoords( validDiscretePositionsBinMat, discreteCoordsTrajectory, spatialBinWidth, floor(min(positionData(:, 2))), floor(min(positionData(:, 3))), discreteYDim, discreteXDim );
        % And the 'bottom left' and 'top right' corner coordinates.
%         gridBottomLeftCornerCoordsMat = gridCentreCoordsMat - spatialBinWidth / 2;
%         gridTopRightCornerCoordsMat = gridCentreCoordsMat + spatialBinWidth / 2;
    end

    for iAnalysisInterval = 1:nAnalysisIntervals,
        iPairIndex = 2 * (iAnalysisInterval - 1) + 1;
        % Incremental spike counts.
        if varargout{iPairIndex}.haveSpikeTrainsData,
            if modelIndicator == 1,
                [varargout{iPairIndex}.discreteSpikeTrainsMat, ~, ~] = discretisespiketrains( varargout{iPairIndex}.spikeTimesArray, spikeTrainModelIndicator, varargout{iPairIndex}.nUpdateSteps, varargout{iPairIndex}.updateStepInterval, varargout{iPairIndex}.startTime, varargout{iPairIndex}.endTime );
                if spikeTrainModelIndicator == 2,
                    varargout{iPairIndex}.logPoissonLikelihoodFactor = computepoissonloglikleihoodnormalisingconstant( varargout{iPairIndex}.discreteSpikeTrainsMat, varargout{iPairIndex}.updateStepInterval );
                end
            end
            varargout{iPairIndex}.spikeIncrementsArray = cellfun(@(timesVec) (1:length(timesVec))', varargout{iPairIndex}.spikeTimesArray, 'UniformOutput', false);
        end
        if varargout{iPairIndex + 1}.havePositionData,
            varargout{iPairIndex + 1}.discreteYDim = discreteYDim;
            varargout{iPairIndex + 1}.discreteXDim = discreteXDim;
            if iAnalysisInterval < nAnalysisIntervals,
                varargout{iPairIndex + 1}.discreteCoordsTrajectory = discreteCoordsTrajectory((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) < analysisIntervals(iAnalysisInterval, 2)), :);
                varargout{iPairIndex + 1}.gridCentreCoordsTrajectory = gridCentreCoordsTrajectory((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) < analysisIntervals(iAnalysisInterval, 2)), :);
            else
                varargout{iPairIndex + 1}.discreteCoordsTrajectory = discreteCoordsTrajectory((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) <= analysisIntervals(iAnalysisInterval, 2)), :);
                varargout{iPairIndex + 1}.gridCentreCoordsTrajectory = gridCentreCoordsTrajectory((positionData(:, 1) >= analysisIntervals(iAnalysisInterval, 1)) & (positionData(:, 1) <= analysisIntervals(iAnalysisInterval, 2)), :);
            end
            varargout{iPairIndex + 1}.linearisedPositionTrajectory = formlinearisedtrajectory( varargout{iPairIndex + 1}.discreteCoordsTrajectory, validDiscretePositionsBinMat, discreteYDim, discreteXDim );
        end
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % Third step: prepare incidental structures.
    if havePositionData,
        nValidDiscretePositions = length(find(validDiscretePositionsBinMat));
        validDiscretePositionsVector = (1:nValidDiscretePositions)';
        [discretePositionIndToCoordsMap, discreteCoordsToPositionIndMap] = formpositioncoordinatemaps( validDiscretePositionsBinMat, nValidDiscretePositions );
        % Distance matrix, in continuous units.
        constrainedDistanceMat = computeeuclideanaccessibledistance( validDiscretePositionsBinMat, spatialBinWidth );
        spaceTransformationFactor = computespacetransformationfactor( constrainedDistanceMat, discretePositionIndToCoordsMap, spatialBinWidth );
        % Line of sight matrix:
%         lineOfSightBinMat = computelineofsightmatrix( constrainedDistanceMat, discretePositionIndToCoordsMap, spatialBinWidth );
        mazeEdgeCoords = getmazeedgecoords( validDiscretePositionsBinMat, discreteYDim, discreteXDim );
    else
        nValidDiscretePositions = 0;
        validDiscretePositionsVector = [];
    end

    for iAnalysisInterval = 1:nAnalysisIntervals,
        iPairIndex = 2 * (iAnalysisInterval - 1) + 1;
        varargout{iPairIndex + 1}.nValidDiscretePositions = nValidDiscretePositions;
        varargout{iPairIndex + 1}.validDiscretePositionsVector = validDiscretePositionsVector;
        if havePositionData,
            varargout{iPairIndex + 1}.constrainedDistanceMat = constrainedDistanceMat;
            varargout{iPairIndex + 1}.spaceTransformationFactor = spaceTransformationFactor;
            varargout{iPairIndex + 1}.validDiscretePositionsBinMat = validDiscretePositionsBinMat;
            varargout{iPairIndex + 1}.discreteYDim = discreteYDim;
            varargout{iPairIndex + 1}.discreteXDim = discreteXDim;
            varargout{iPairIndex + 1}.mazeEdgeCoords = mazeEdgeCoords;
            varargout{iPairIndex + 1}.gridCentreCoordsMat = gridCentreCoordsMat;
            varargout{iPairIndex + 1}.positionIndToGridCentreCoordsMap = positionIndToGridCentreCoordsMap;
%             varargout{iPairIndex + 1}.gridBottomLeftCornerCoordsMat = gridBottomLeftCornerCoordsMat;
%             varargout{iPairIndex + 1}.gridTopRightCornerCoordsMat = gridTopRightCornerCoordsMat;
%             varargout{iPairIndex + 1}.lineOfSightBinMat = lineOfSightBinMat;
            varargout{iPairIndex + 1}.spatialBinWidth = spatialBinWidth;
            varargout{iPairIndex + 1}.posObsInterval = posObsInterval;
            varargout{iPairIndex + 1}.discretePositionIndToCoordsMap = discretePositionIndToCoordsMap;
            varargout{iPairIndex + 1}.discreteCoordsToPositionIndMap = discreteCoordsToPositionIndMap;
            varargout{iPairIndex + 1}.resShifterMats = formresolutionshifters( validDiscretePositionsBinMat );
            varargout{iPairIndex + 1}.sandMats = formsandmatrices( varargout{iPairIndex + 1}.resShifterMats, constrainedDistanceMat );
            if varargout{iPairIndex + 1}.havePositionData,
                % Involved in computing likelihood.
                consecutivePosFactorMatInds = varargout{iPairIndex + 1}.linearisedPositionTrajectory(2:end) + (varargout{iPairIndex + 1}.linearisedPositionTrajectory(1:(end - 1)) - 1) .* varargout{iPairIndex + 1}.nValidDiscretePositions;
                consecutivePosTransformationFactors = varargout{iPairIndex + 1}.spaceTransformationFactor(consecutivePosFactorMatInds(:));
                varargout{iPairIndex + 1}.consecutiveDistances = bsxfun(@times, varargout{iPairIndex + 1}.gridCentreCoordsTrajectory(2:end, :) - varargout{iPairIndex + 1}.gridCentreCoordsTrajectory(1:(end - 1), :), consecutivePosTransformationFactors);
                varargout{iPairIndex + 1}.posTimeVec = (varargout{iPairIndex + 1}.startTime:varargout{iPairIndex + 1}.posObsInterval:(varargout{iPairIndex + 1}.startTime + varargout{iPairIndex + 1}.posObsInterval * (size(varargout{iPairIndex + 1}.linearisedPositionTrajectory, 1) - 1)))';
            end
        end
    end
end