Home > FMAToolbox > IO > LoadBinary.m

LoadBinary

PURPOSE ^

LoadBinary - Load data from a multiplexed binary file.

SYNOPSIS ^

function data = LoadBinary(filename,varargin)

DESCRIPTION ^

LoadBinary - Load data from a multiplexed binary file.

  Reading a subset of the data can be done in two different manners: either
  by specifying start time and duration (more intuitive), or by indicating
  the position and size of the subset in terms of number of records (more
  accurate) - a 'record' is a chunk of data containing one sample for each
  channel.

  LoadBinary can also deal with lists of start times and durations (or
  offsets and number of records).

  USAGE

    data = LoadBinary(filename,<options>)

    filename       file to read
    <options>      optional list of property-value pairs (see table below)

    =========================================================================
     Properties    Values
    -------------------------------------------------------------------------
     'frequency'   sampling rate (in Hz, default = 20kHz)
     'start'       position to start reading (in s, default = 0)
     'duration'    duration to read (in s, default = Inf)
     'offset'      position to start reading (in records, default = 0)
     'nRecords'    number of records to read (default = Inf)
     'samples'     same as above (for backward compatibility reasons)
     'nChannels'   number of data channels in the file (default = 1)
     'channels'    channels to read (default = all)
     'precision'   sample precision (default = 'int16')
     'skip'        number of records to skip after each record is read
                   (default = 0)
    =========================================================================

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function data = LoadBinary(filename,varargin)
0002 
0003 %LoadBinary - Load data from a multiplexed binary file.
0004 %
0005 %  Reading a subset of the data can be done in two different manners: either
0006 %  by specifying start time and duration (more intuitive), or by indicating
0007 %  the position and size of the subset in terms of number of records (more
0008 %  accurate) - a 'record' is a chunk of data containing one sample for each
0009 %  channel.
0010 %
0011 %  LoadBinary can also deal with lists of start times and durations (or
0012 %  offsets and number of records).
0013 %
0014 %  USAGE
0015 %
0016 %    data = LoadBinary(filename,<options>)
0017 %
0018 %    filename       file to read
0019 %    <options>      optional list of property-value pairs (see table below)
0020 %
0021 %    =========================================================================
0022 %     Properties    Values
0023 %    -------------------------------------------------------------------------
0024 %     'frequency'   sampling rate (in Hz, default = 20kHz)
0025 %     'start'       position to start reading (in s, default = 0)
0026 %     'duration'    duration to read (in s, default = Inf)
0027 %     'offset'      position to start reading (in records, default = 0)
0028 %     'nRecords'    number of records to read (default = Inf)
0029 %     'samples'     same as above (for backward compatibility reasons)
0030 %     'nChannels'   number of data channels in the file (default = 1)
0031 %     'channels'    channels to read (default = all)
0032 %     'precision'   sample precision (default = 'int16')
0033 %     'skip'        number of records to skip after each record is read
0034 %                   (default = 0)
0035 %    =========================================================================
0036 
0037 % Copyright (C) 2004-2013 by Michaƫl Zugaro
0038 %
0039 % This program is free software; you can redistribute it and/or modify
0040 % it under the terms of the GNU General Public License as published by
0041 % the Free Software Foundation; either version 3 of the License, or
0042 % (at your option) any later version.
0043 
0044 % Default values
0045 nChannels = 1;
0046 precision = 'int16';
0047 skip = 0;
0048 frequency = 20000;
0049 channels = [];
0050 start = 0;
0051 duration = Inf;
0052 offset = 0;
0053 nRecords = Inf;
0054 time = false;
0055 records = false;
0056 
0057 if nargin < 1 | mod(length(varargin),2) ~= 0,
0058   error('Incorrect number of parameters (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0059 end
0060 
0061 % Parse options
0062 for i = 1:2:length(varargin),
0063     if ~ischar(varargin{i}),
0064         error(['Parameter ' num2str(i+3) ' is not a property (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).']);
0065     end
0066     switch(lower(varargin{i})),
0067         case 'frequency',
0068             frequency = varargin{i+1};
0069             if ~isdscalar(frequency,'>0'),
0070                 error('Incorrect value for property ''frequency'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0071             end
0072         case 'start',
0073             start = varargin{i+1};
0074             if ~isdvector(start),
0075                 error('Incorrect value for property ''start'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0076             end
0077             if start < 0, start = 0; end
0078             time = true;
0079         case 'duration',
0080             duration = varargin{i+1};
0081             if ~isdvector(duration,'>=0'),
0082                 error('Incorrect value for property ''duration'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0083             end
0084             time = true;
0085         case 'offset',
0086             offset = varargin{i+1};
0087             if ~isivector(offset),
0088                 error('Incorrect value for property ''offset'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0089             end
0090             if offset < 0, offset = 0; end
0091             records = true;
0092         case {'nrecords','samples'},
0093             nRecords = varargin{i+1};
0094             if ~isivector(nRecords,'>=0'),
0095                 error('Incorrect value for property ''nRecords'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0096             end
0097             if length(nRecords) > 1 && any(isinf(nRecords(1:end-1))),
0098                 error('Incorrect value for property ''nRecords'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0099             end
0100             records = true;
0101         case 'nchannels',
0102             nChannels = varargin{i+1};
0103             if ~isiscalar(nChannels,'>0'),
0104                 error('Incorrect value for property ''nChannels'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0105             end
0106         case 'channels',
0107             channels = varargin{i+1};
0108             if ~isivector(channels,'>=0'),
0109                 error('Incorrect value for property ''channels'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0110             end
0111         case 'precision',
0112             precision = varargin{i+1};
0113             if ~isastring(precision),
0114                 error('Incorrect value for property ''precision'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0115             end
0116         case 'skip',
0117             skip = varargin{i+1};
0118             if ~isiscalar(skip,'>=0'),
0119                 error('Incorrect value for property ''skip'' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0120             end
0121         otherwise,
0122             error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).']);
0123     end
0124 end
0125 
0126 % Either start+duration, or offset+size
0127 if time && records,
0128     error(['Data subset can be specified either in time or in records, but not both (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).']);
0129 end
0130 
0131 % By default, load all channels
0132 if isempty(channels),
0133     channels = 1:nChannels;
0134 end
0135 
0136 % Check consistency between channel IDs and number of channels
0137 if any(channels>nChannels),
0138     error('Cannot load specified channels (listed channel IDs inconsistent with total number of channels).');
0139 end
0140 
0141 % Open file
0142 if ~exist(filename),
0143     error(['File ''' filename ''' not found.']);
0144 end
0145 f = fopen(filename,'r');
0146 if f == -1,
0147     error(['Cannot read ' filename ' (insufficient access rights?).']);
0148 end
0149 
0150 % Size of one data point (in bytes)
0151 sampleSize = 0;
0152 switch precision,
0153     case {'uchar','unsigned char','schar','signed char','int8','integer*1','uint8','integer*1'},
0154         sampleSize = 1;
0155     case {'int16','integer*2','uint16','integer*2'},
0156         sampleSize = 2;
0157     case {'int32','integer*4','uint32','integer*4','single','real*4','float32','real*4'},
0158         sampleSize = 4;
0159     case {'int64','integer*8','uint64','integer*8','double','real*8','float64','real*8'},
0160         sampleSize = 8;
0161 end
0162 
0163 % Position and number of records of the data subset
0164 if time,
0165     if length(duration) == 1,
0166         duration = repmat(duration,length(start),1);
0167     elseif length(duration) ~= length(start),
0168         error('Start and duration lists have different lengths (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0169     end
0170     dataOffset = floor(start*frequency)*nChannels*sampleSize;
0171     nRecords = floor(duration*frequency);
0172 else
0173     if length(nRecords) == 1,
0174         nRecords = repmat(nRecords,size(offset,1),1);
0175     elseif length(nRecords) ~= length(offset),
0176         error('Offset and number of records lists have different lengths (type ''help <a href="matlab:help LoadBinary">LoadBinary</a>'' for details).');
0177     end
0178     dataOffset = offset*nChannels*sampleSize;
0179 end
0180 
0181 % Determine total number of records in file
0182 fileStart = ftell(f);
0183 status = fseek(f,0,'eof');
0184 if status ~= 0,
0185     fclose(f);
0186     error('Error reading the data file (possible reasons include trying to read past the end of the file).');
0187 end
0188 fileStop = ftell(f);
0189 
0190 % Last number of records may be infinite, compute explicit value
0191 if isinf(nRecords(end)),
0192     status = fseek(f,dataOffset(end),'bof');
0193     if status ~= 0,
0194         fclose(f);
0195         error('Error reading the data file (possible reasons include trying to read past the end of the file).');
0196     end
0197     lastOffset = ftell(f);
0198     lastNRecords = floor((fileStop-lastOffset)/nChannels/sampleSize);
0199     nRecords(end) = lastNRecords;
0200 end
0201 
0202 % Preallocate memory
0203 data = zeros(sum(nRecords)/(skip+1),length(channels));
0204 
0205 % Loop through list of start+duration or offset+nRecords
0206 i = 1;
0207 for k = 1:length(dataOffset),
0208 
0209     % Position file index for reading
0210     status = fseek(f,dataOffset(k),'bof');
0211     fileOffset = ftell(f);
0212     if status ~= 0,
0213         fclose(f);
0214         error('Could not start reading (possible reasons include trying to read past the end of the file).');
0215     end
0216 
0217     % (floor in case all channels do not have the same number of samples)
0218     maxNRecords = floor((fileStop-fileOffset)/nChannels/sampleSize);
0219     if nRecords(k) > maxNRecords, nRecords(k) = maxNRecords; end
0220 
0221     % For large amounts of data, read chunk by chunk
0222     maxSamplesPerChunk = 10000;
0223     nSamples = nRecords(k)*nChannels;
0224     if nSamples <= maxSamplesPerChunk,
0225         d = LoadChunk(f,nChannels,channels,nRecords(k),precision,skip*sampleSize);
0226         [m,n] = size(d);
0227         if m == 0, break; end
0228         data(i:i+m-1,:) = d;
0229         i = i+m;
0230     else
0231         % Determine chunk duration and number of chunks
0232         nSamplesPerChunk = floor(maxSamplesPerChunk/nChannels)*nChannels;
0233         nChunks = floor(nSamples/nSamplesPerChunk)/(skip+1);
0234         % Read all chunks
0235         for j = 1:nChunks,
0236             d = LoadChunk(f,nChannels,channels,nSamplesPerChunk/nChannels,precision,skip*sampleSize);
0237             [m,n] = size(d);
0238             if m == 0, break; end
0239             data(i:i+m-1,:) = d;
0240             i = i+m;
0241         end
0242         % If the data size is not a multiple of the chunk size, read the remainder
0243         remainder = nSamples - nChunks*nSamplesPerChunk;
0244         if remainder ~= 0,
0245             d = LoadChunk(f,nChannels,channels,remainder/nChannels,precision,skip*sampleSize);
0246             [m,n] = size(d);
0247             if m == 0, break; end
0248             data(i:i+m-1,:) = d;
0249             i = i+m;
0250         end
0251     end
0252 end
0253 
0254 fclose(f);
0255 
0256 % ---------------------------------------------------------------------------------------------------------
0257 
0258 function data = LoadChunk(fid,nChannels,channels,nSamples,precision,skip)
0259 
0260 if skip ~= 0,
0261     data = fread(fid,[nChannels nSamples],[int2str(nChannels) '*' precision],skip*nChannels);
0262 else
0263     data = fread(fid,[nChannels nSamples],precision);
0264 end
0265 data = data';
0266 
0267 if isempty(data),
0268     warning('No data read (trying to read past file end?)');
0269 elseif ~isempty(channels),
0270     data = data(:,channels);
0271 end

Generated on Fri 16-Mar-2018 13:00:20 by m2html © 2005