Waveform Database Software Package (WFDB) for MATLAB and Octave 0.10.0
(7,497 bytes)
function varargout=wfdbdesc(varargin)
%
% [siginfo,Fs,sigClass]=wfdbdesc(recordName)
%
% Wrapper to WFDB WFDBDESC:
% http://www.physionet.org/physiotools/wag/wfdbde-1.htm
%
% Reads a WFDB record metadata and returns:
%
%
% siginfo
% Nx1 vector of structures with the following fields:
%
% LengthSamples : Number of samples in record (integer)
% LengthTime : Duration of record (String WFDB Time)
% RecordName : Record name (String)
% RecordIndex : Record Index (Integer)
% Description : Signal Description (String)
% SamplingFrequency : Sampling Frequency w/ Units (String)
% File : File name (String)
% SignalIndex : Zero Based Signal Index (Integer)
% StartTime : Start Time (String WFDB Time)
% Group : Group (Integer)
% AdcResolution : Bit resolution of the signal (String)
% AdcZero : Physical value for 0 ADC (double)
% Baseline : Physical zero level of signal (Integer)
% CheckSum : 16-bit checksum of all samples (Integer)
% Format : WFDB's Format of the samples (String)
% Gain : ADC units per physical unit (String)
% InitialValue : Value of sample 1 in the signal (Integer)
% IO : IO Type (String)
%
% Fs (Optional)
% Nx1 vector of doubles representing the sampling frequency of each
% signal in Hz (if the 'SamplingFrequency' string is parsable).
%
% sigClass (Optional)
% Nx1 cell array of strings for the corresponding signal class based on
% information from PhysioNet: www.physionet.org/physiobank/signals.shtml.
% The signal class will be one of the following:
% BP blood pressure
% CO cardiac output
% CO2 carbon dioxide
% ECG electrocardiogram
% EEG electroencephalogram
% EMG electromyogram
% EOG electrooculogram
% Flow air flow
% HR heart rate
% Noise for stress testing
% O2 oxygen
% PLETH plethysmogram
% Pos body position
% Resp respiration
% Sound sound
% ST ECG ST segment level
% Status status of patient or monitor
% SV stroke volume
% Temp temperature
% [] unkown class
%
%
% Required Parameters:
%
% recorName
% String specifying the name of the record in the WFDB path or
% in the current directory.
%
%
% %Example
% siginfo=wfdbdesc('challenge/2013/set-a/a01')
%
%
% %Example 2 -Get signal Classes
% [siginfo,Fs,sigClass]=wfdbdesc('mitdb/100')
%
%
% Written by Ikaro Silva, 2013
% Last Modified by Ikaro Silva, April 16, 2015
%
% Version 3.0
%
% Since 0.0.1
% See also RDSAMP
%endOfHelp
persistent javaWfdbExec config
if(isempty(javaWfdbExec))
[javaWfdbExec,config]=getWfdbClass('wfdbdesc');
end
%Set default pararamter values
inputs={'recordName'};
outputs={'siginfo','Fs','sigClass'};
for n=1:nargin
if(~isempty(varargin{n}))
eval([inputs{n} '=varargin{n};']);
end
end
wfdb_argument={recordName};
data=char(javaWfdbExec.execToStringList(wfdb_argument));
lines=[1 strfind(data,',')];
siginfo=[];
Fs=[];
sigClass={};
L=length(lines);
%Define record Wide parameters
RecordName=[];
StartTime =[];
LengthSamples=[];
LengthTime=[];
SamplingFrequency =[];
Notes=[];
%index for each signal
ind=0;
for n=1:L-1
str=(data(lines(n):lines(n+1)-1));
str=str(2:end); %Remove comma
if(~isempty(strfind(str,'Record')))
C=textscan(str,'%s%s');
RecordName=C{2}{:};
elseif(~isempty(strfind(str,'Starting time:')))
ind1=strfind(str,':');
StartTime =str(ind1+2:end);
elseif(~isempty(strfind(str,'Length:')))
%Should happen only once
ind1=strfind(str,'(');
ind2=strfind(str,'sample intervals)');
LengthSamples=str2num(str(ind1+1:ind2-1));
C=textscan(str,'%s%s%s%s%s');
LengthTime=C{2};
elseif(~isempty(strfind(str,'Sampling frequency:')))
C=textscan(str,'%s%s%u%s');
SamplingFrequency =C{3};
elseif(~isempty(strfind(str,'Group')))
%In this case we are seeing a new signal, enter record wide
%fields as well
ind=ind+1;
C=textscan(str,'%s%d');
siginfo(ind).Group=C{2};
siginfo(ind).RecordName=RecordName;
siginfo(ind).StartTime =StartTime;
siginfo(ind).LengthSamples=LengthSamples;
siginfo(ind).LengthTime=LengthTime{:};
siginfo(ind).SamplingFrequency =SamplingFrequency;
Fs(end+1)=SamplingFrequency;
elseif(~isempty(strfind(str,'Signal')))
C=textscan(str,'%s%d:');
siginfo(ind).SignalIndex=C{2};
elseif(~isempty(strfind(str,'File:')))
ind1=strfind(str,':');
siginfo(ind).File=str(ind1+2:end);
elseif(~isempty(strfind(str,'Description:')))
ind1=strfind(str,':');
siginfo(ind).Description=str(ind1+2:end);
elseif(~isempty(strfind(str,'Gain:')))
ind1=strfind(str,':');
siginfo(ind).Gain=str(ind1+2:end);
elseif(~isempty(strfind(str,'Initial value:')))
C=textscan(str,'%s%s%f');
siginfo(ind).InitialValue=C{3};
elseif(~isempty(strfind(str,'Storage format:')))
ind1=strfind(str,':');
siginfo(ind).Format=str(ind1+2:end);
elseif(~isempty(strfind(str,'I/O:')))
ind1=strfind(str,':');
siginfo(ind).IO=str(ind1+2:end);
elseif(~isempty(strfind(str,'ADC resolution:')))
ind1=strfind(str,':');
siginfo(ind).AdcResolution=str(ind1+2:end);
elseif(~isempty(strfind(str,'ADC zero:')))
ind1=strfind(str,':');
siginfo(ind).AdcZero=str2num(str(ind1+2:end));
elseif(~isempty(strfind(str,'Baseline:')))
C=textscan(str,'%s%f');
siginfo(ind).Baseline=C{2};
elseif(~isempty(strfind(str,'Checksum:')))
C=textscan(str,'%s%f');
siginfo(ind).CheckSum=C{2};
else
%Skip unused field
end
end
if(nargout>2)
%Get signal class
sigClass=getSignalClass(siginfo,config);
end
for n=1:nargout
eval(['varargout{n}=' outputs{n} ';']);
end
%%%%%% Help function to return signal class information %%%%%
function sigClass=getSignalClass(siginfo,config)
persistent class_def
if(isempty(class_def))
%Get signal class information from PhysioNet's servers
%and store information locally ( persistent )
class_def=urlread([config.CACHE_SOURCE '../signals.shtml']);
st_ind=findstr(class_def,'<td><b>Description</b></td><td></td></tr>');
class_def(1:st_ind+1)=[];
end_ind=findstr(class_def,'</table></center>');
class_def(end_ind:end)=[];
class_def=regexp(class_def,'<tr>','split');
end
M=length(siginfo);
sigClass=cell(M,1);
for m=1:M
ind=strmatch(['<td>' siginfo(m).Description '</td>'],class_def);
if(isempty(ind))
continue
end
str=regexp(class_def{ind},'</td>','split');
str=regexprep(str{2},'<td>','');
sigClass(m)={str};
end