Waveform Database Software Package (WFDB) for MATLAB and Octave 0.10.0
(9,801 bytes)
function varargout=rdsamp(varargin)
%
% [signal,Fs,tm]=rdsamp(recordName,signaList,N,N0,rawUnits,highResolution)
%
% Wrapper to WFDB RDSAMP:
% http://www.physionet.org/physiotools/wag/rdsamp-1.htm
%
% Reads a WFDB record and returns:
%
%
% signal
% NxM matrix (doubles) of M signals with each signal being N samples long.
% Signal data type will be either in double int16 format
% depending on the flag passed to the function (according to
% the boolean flags below).
%
% Fs (Optional)
% 1xM Double, sampling frequency in Hz of all the signals in the
% record.
%
%% tm (Optional)
% Nx1 vector of doubles representing the sampling intervals.
% Depending on input flags (see below), this vector can either be a
% vector of integers (sampling number), or a vector of elapsed time
% in seconds ( with up to millisecond precision only).
%
% Required Parameters:
%
% recorName
% String specifying the name of the record in the WFDB path or
% in the current directory.
%
%
% Optional Parameters are:
%
% signalList
% A Mx1 array of integers. Read only the signals (columns)
% named in the signalList (default: read all signals).
% N
% A 1x1 integer specifying the sample number at which to stop reading the
% record file (default read all the samples = N).
% N0
% A 1x1 integer specifying the sample number at which to start reading the
% record file (default 1 = first sample).
%
%
% rawUnits
% A 1x1 integer (default: 0). Returns tm and signal as vectors
% according to the following values:
% rawUnits=0 - Uses Java Native Interface to directly fetch data, returning signal in physical units with double precision.
% rawUnits=1 -returns tm ( millisecond precision only! ) and signal in physical units with 64 bit (double) floating point precision
% rawUnits=2 -returns tm ( millisecond precision only! ) and signal in physical units with 32 bit (single) floating point precision
% rawUnits=3 -returns both tm and signal as 16 bit integers (short). Use Fs to convert tm to seconds.
% rawUnits=4 -returns both tm and signal as 64 bit integers (long). Use Fs to convert tm to seconds.
%
% highResolution
% A 1x1 boolean (default =0). If true, reads the record in high
% resolution mode. Ignored if rawUnits == 0.
%
%
% Written by Ikaro Silva, 2013
% Last Modified: April 3, 2015
% Version 2.0
%
% Since 0.0.1
%
% %Example 1- Read a signal from PhysioNet's Remote server:
%[signal,Fs,tm]=rdsamp('mitdb/100',[],1000);
%plot(tm,signal(:,1))
%
%%Example 2-Read 1000 samples from 3 signals
%[signal,Fs,tm]=rdsamp('mghdb/mgh001', [1 3 5],1000);
%
%%%Example 3- Read 1000 samples from 3 signlas in single precision format
%[signal,Fs,tm]=rdsamp('mghdb/mgh001', [1 3 5],1000,[],2);
%
%
%%%Example 4- Read a multiresolution signal with 32 samples per frame
% [sig,Fs,tm] = rdsamp('drivedb/drive02',[1],[],[],[],1);
%
%
% See also WFDBDESC, PHYSIONETDB, WFDBDOWNLOAD
%endOfHelp
persistent javaWfdbExec config
if(isempty(javaWfdbExec))
[javaWfdbExec,config]=getWfdbClass('rdsamp');
end
%Set default pararamter values
inputs={'recordName','signalList','N','N0','rawUnits','highResolution'};
outputs={'signal','Fs','tm'};
signalList=[];
N=[];
N0=0;
ListCapacity=[]; %Use to pre-allocate space for reading
siginfo=[];
rawUnits=0;
Fs=[];
tm=[];
signal=[];
highResolution=0;
for n=1:nargin
if(~isempty(varargin{n}))
eval([inputs{n} '=varargin{n};']);
end
end
%Cache record
wfdbdownload(recordName);
javaWfdbRdsamp=[];
if(isempty(javaWfdbRdsamp) && (rawUnits ==0))
javaWfdbRdsamp=javaObject('org.physionet.wfdb.jni.Rdsamp');
end
%Remove file extension if present
if(length(recordName)>4 && strcmp(recordName(end-3:end),'.dat'))
recordName=recordName(1:end-4);
end
%Initialize wfdb_argument
if((rawUnits >=3) || (rawUnits ==0) )
%Reads raw data as integer (JNI converts to double later on)
wfdb_argument={'-r',recordName};
else
wfdb_argument={'-r',recordName,'-Ps'};
end
if(N0 ~=0)
%Set start sample
wfdb_argument{end+1}='-f';
wfdb_argument{end+1}=['s' num2str(N0-1)];
end
%If N is empty, it is the entire dataset. We should ensure capacity
%so that the fetching will be more efficient.
if(isempty(N) && (rawUnits ~=0))
[siginfo,~]=wfdbdesc(recordName);
if(~isempty(siginfo))
N=siginfo(1).LengthSamples;
else
warning('Could not get signal information. Attempting to read signal without buffering.');
end
end
if(~isempty(signalList))
wfdb_argument{end+1}='-s ';
%-1 is necessary because WFDB is 0 based indexed.
for sInd=1:length(signalList)
wfdb_argument{end+1}=[num2str(signalList(sInd)-1)];
end
end
if(highResolution && (rawUnits ~=0))
wfdb_argument{end+1}=['-H'];
%In this case overwrite N, multiply by the maximum number of samples
%per frame
maxFrame=1;
for i=1:length(siginfo)
ind=strfind(siginfo(1).Format,'samples per frame');
if(~isempty(ind))
str= siginfo(1).Format(1:ind-1);
ind2=strfind(siginfo(1).Format,'(');
str=str(ind2+1:end);
frm=str2num(str);
if(frm>maxFrame)
maxFrame=frm;
end
end
end
N=N*maxFrame;
end
if(~isempty(N))
%Its is possible where this is not true in rare cases where
%there is no signal length information on the header file
wfdb_argument{end+1}='-t';
wfdb_argument{end+1}=['s' num2str(N)];
ListCapacity=N-N0+min(1, N0);
end
if(nargout>2 && (rawUnits ~=0))
if(isempty(siginfo))
[siginfo,Fs]=wfdbdesc(recordName);
end
end
switch rawUnits
case 0
%Use Java Native Interface wrapper
%try
%Channeles are returned in interleaved fashion, in a single
%array
data=double(conv_matrix(javaWfdbRdsamp.exec(wfdb_argument)));
%catch
% javaWfdbRdsamp.reset();%Free JNI resources
% error(['Could not find record: ' recordName '. Search path is set to: ''' config.WFDB_PATH '''']);
%end
if(isempty(data))
error(['Could not find record: ' recordName '. Search path is set to: ''' config.WFDB_PATH '''']);
end
baseline=double(conv_matrix(javaWfdbRdsamp.getBaseline));
gain=javaWfdbRdsamp.getGain;
Fs=double(javaWfdbRdsamp.getFs);
N=javaWfdbRdsamp.getNSamples;
javaWfdbRdsamp.reset();%Free JNI resources
M=length(baseline);
if(~isnumeric(N))
N=length(data)/M;
end
signal=zeros(N,M);
%Convert to Physical units
for m=1:M
signal(:,m)= (data(m:M:end)-baseline(m))./gain(m);
end
if(nargout>2)
%generate time in seconds
tm=linspace(0,(N-1)/Fs,N)';
end
case 1
if(~isempty(ListCapacity))
%Ensure list capacity if information is available
javaWfdbExec.setDoubleArrayListCapacity(ListCapacity);
end
data=javaWfdbExec.execToDoubleArray(wfdb_argument);
case 2
if(~isempty(ListCapacity))
%Ensure list capacity if information is available
javaWfdbExec.setFloatArrayListCapacity(ListCapacity);
end
data=javaWfdbExec.execToFloatArray(wfdb_argument);
case 3
if(~isempty(ListCapacity))
%Ensure list capacity if information is available
javaWfdbExec.setShortArrayListCapacity(ListCapacity);
end
data=javaWfdbExec.execToShortArray(wfdb_argument);
case 4
if(~isempty(ListCapacity))
%Ensure list capacity if information is available
javaWfdbExec.setLongArrayListCapacity(ListCapacity);
end
data=javaWfdbExec.execToLongArray(wfdb_argument);
otherwise
error(['Unknown rawUnits option: ' num2str(rawUnits)]);
end
if(config.inOctave)
data=conv_matrix(data);
end
if(rawUnits ~=0)
%Remap variables to output variables (if not using JNI interface)
signal=data(:,2:end);
if(nargout>2)
tm=data(:,1);
Fstest=1/(tm(2)-tm(1)); %Not exatly accurate because tm is accurate only the millisecond
else
Fstest=Fs;
end
data=[];
[N,M]=size(signal);
end
%When reading one signal only check if Fs is correct,
%because it may not be for multiresolution signals
if(length(signalList)==1 && rawUnits<3 && (rawUnits ~= 0) )
err=abs(Fs-Fstest);
if(err>1)
warning([ 'Sampling frequency maybe incorrect! ' ...
'Switching from ' num2str(Fs) ' to: ' num2str(Fstest)]);
Fs=Fstest;
end
end
for n=1:nargout
eval(['varargout{n}=' outputs{n} ';']);
%Perform minor data integrity check by validating with the expected
%sizes
if(~isempty(signalList) )
sList=length(signalList);
if(sList ~= (M))
error(['Received: ' num2str(M) ' signals, expected: ' num2str(length(signalList))]);
end
end
if(~isempty(ListCapacity) && ~isnan(ListCapacity) )
if((ListCapacity) ~= N )
warning(['Received: ' num2str(N) ' samples, expected: ' num2str(ListCapacity)]);
end
end
end
end
% Convert a Java array into a matrix.
function matrix = conv_matrix(array)
if(isnumeric(array))
matrix=array;
else
matrix=java2mat(array);
if(~isnumeric(matrix))
if(exist('java_matrix_autoconversion','builtin'))
java_matrix_autoconversion(1,'local');
else
java_convert_matrix(1,'local');
end
matrix=java2mat(javaObject('org.octave.Matrix',array));
end
end
end