ECG-Kit 1.0
(18,159 bytes)
function examples(pid_str, examples_path, user_str)
% Example of how to use the ECGkit
% ---------------------------------
%
% Description:
%
% This script exemplifies the use of the most important features of the
% kit, which are:
%
% + QRS detection algorithms: (Wavedet - Pan&Tompkins - gqrs)
% + QRS manual corrector graphical user interface (GUI)
% + ECG waves delineator algorithm (Wavedet)
% + Time-series manual corrector graphical user interface (GUI)
% + Heartbeat classifier (a2hbc)
% + ABP/PPG pulse detection/delineation ( WavePPG - wabp )
% + Signal report generator
%
% This script is prepared to run locally without arguments, as well as in
% a cluster environment by using "pid_str" argument. The pid_str
% argument is a char with format 'N/M', being N <= M with default value
% '1/1'. You can partition a big job into M pieces in cluster
% architecture, by starting M processes with N ranging from 1 to M.
%
% You can watch a typical run of this script for small, local ECG
% recording here:
%
% https://www.youtube.com/watch?v=8lJtkGhrqFw&list=PLlD2eDv5CIe9sA2atmnb-DX48FIRG46z7&index=1
%
% Example:
%
% examples()
%
% Author: Mariano Llamedo Soria (llamedom at {electron.frba.utn.edu.ar; unizar.es}
% Version: 0.1 beta
% Birthdate : 11/2/2014
% Last update: 18/7/2014
% Copyright 2008-2015
%% Argument parsing
if( nargin < 1 || ~ischar(pid_str) )
% single PID run
pid_str = '1/1';
end
if( nargin < 2 || ~exist(examples_path, 'dir') )
% inspect ECG files in rootpath\example recordings\ folder
root_path = fileparts(mfilename('fullpath'));
root_path = fileparts(root_path);
% default folder to look at
examples_path = [root_path filesep 'recordings' filesep ];
if(~exist(examples_path, 'dir'))
disp_string_framed(2, 'Please provide a valid path with ECG recordings');
return
end
else
if( examples_path(end) ~= filesep )
examples_path = [examples_path filesep];
end
end
if( nargin < 3 )
user_str = '';
end
%% Start
% This script exemplifies the use of the toolbox in several typical
% tasks
filenames = dir(examples_path);
recnames = {filenames(:).name};
[~,recnames] = cellfun(@(a)(fileparts(a)), recnames, 'UniformOutput', false);
recnames = unique(recnames);
recnames = setdiff(recnames, {'' '.' '..' 'results' 'condor' });
% recnames = {'ex_ABP_PPG_Registro_01M'};
% recnames = recnames(1)
lrecnames = length(recnames);
% In case of running in a user-assisted fashion.
bUseDesktop = usejava('desktop');
if( bUseDesktop )
tmp_path = tempdir;
output_path = [ examples_path 'results' filesep ];
else
% For cluster or distributed environment processing.
InstallECGkit();
% this is a local path, usually faster to reach than output_path
tmp_path = '/scratch/';
% distributed or cluster-wide accesible path
output_path = [ examples_path 'results' filesep ];
end
% just for debugging, keep it commented.
% bUseDesktop = false
%% QRS automatic detection
% go through all files
ECG_all_wrappers = [];
jj = 1;
for ii = 1:lrecnames
rec_filename = [examples_path recnames{ii}];
% task name,
% ECGt_QRSd = 'QRS_detection';
% or create an specific handle to have more control
ECGt_QRSd = ECGtask_QRS_detection();
% % select an specific algorithm. Default: Run all detectors
% ECGt_QRSd.detectors = 'wavedet'; % Wavedet algorithm based on
% ECGt_QRSd.detectors = 'pantom'; % Pan-Tompkins alg.
ECGt_QRSd.detectors = 'gqrs'; % WFDB gqrs algorithm.
% ECGt_QRSd.detectors = 'user:example_worst_ever_QRS_detector'; % Example of how you can add your own QRS detector.
% ECGt_QRSd.detectors = 'user:your_QRS_detector_func_name'; %
% "your_QRS_detector_func_name" can be your own detector.
% ECGt_QRSd.detectors = {'wavedet' 'gqrs' 'user:example_worst_ever_QRS_detector'};
% ECGt_QRSd.only_ECG_leads = false; % consider all signals ECG
ECGt_QRSd.only_ECG_leads = true; % Identify ECG signals based on their header description.
ECG_w = ECGwrapper( 'recording_name', rec_filename, ...
'this_pid', pid_str, ...
'tmp_path', tmp_path, ...
'output_path', output_path, ...
'ECGtaskHandle', ECGt_QRSd);
% you can individualize each experiment with an external string
ECG_w.user_string = user_str;
try
% process the task
ECG_w.Run;
% collect object if were recognized as ECG recordings.
if( jj == 1)
ECG_all_wrappers = ECG_w;
else
ECG_all_wrappers(jj) = ECG_w;
end
jj = jj + 1;
catch MException
if( strfind(MException.identifier, 'ECGwrapper:ArgCheck:InvalidFormat') )
disp_string_framed('*Red', sprintf( 'Could not guess the format of %s', ECG_w.recording_name) );
else
% report just in case
report = getReport(MException);
fprintf(2, '\n%s\n', report);
end
end
end
% recognized recordings
lrecnames = length(ECG_all_wrappers);
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
%% QRS visual inspection and correction
if( bUseDesktop )
% other task can be performed on the same objects
for ii = 1:lrecnames
% last worker is the responsible of the visual correction.
if( ECG_all_wrappers(ii).this_pid == ECG_all_wrappers(ii).cant_pids)
% if there are not any previous error.
if( ECG_all_wrappers(ii).Processed && ~ECG_all_wrappers(ii).Error )
% this is to use previous saved results as starting point,
% if any available
cached_filenames = ECG_all_wrappers(ii).GetCahchedFileName({'QRS_corrector' 'QRS_detection'});
% if no previous correction work, try the automatic
% detection task
% if any, do the correction
if( ~isempty(cached_filenames) )
% this is to use previous saved results as starting point,
% if any available
ECG_all_wrappers(ii).ECGtaskHandle = 'QRS_corrector';
% This task is supposed to be supervised, so only one pid is enough.
ECG_all_wrappers(ii).this_pid = '1/1';
% to avoid loading cached results and exit, this flag
% allows the re-editing of the current state of the
% detections.
ECG_all_wrappers(ii).cacheResults = false;
% maybe in your application you should run this for
% all files.
ECG_all_wrappers(ii).ECGtaskHandle.payload = load(cached_filenames{1});
% process the task
ECG_all_wrappers(ii).Run;
% restore the original pids configuration
ECG_all_wrappers(ii).this_pid = pid_str;
% As we changed for "QRS correction" task, we have to enable this
% value again in order to avoid performing the following tasks every time.
% If you want to recalculate any task, change it to false
ECG_all_wrappers(ii).cacheResults = true;
end
end
end
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
end
%% PPG/ABP pulse detection
% other task can be performed on the same objects
for ii = 1:lrecnames
% set the delineator task name and run again.
ECG_all_wrappers(ii).ECGtaskHandle = 'PPG_ABP_detector';
% process the task
ECG_all_wrappers(ii).Run;
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
%% PPG/ABP waves visual inspection and correction
if( bUseDesktop )
% other task can be performed on the same objects
for ii = 1:lrecnames
% last worker is the responsible of the visual correction.
if( ECG_all_wrappers(ii).this_pid == ECG_all_wrappers(ii).cant_pids)
% if there are not any previous error.
if( ECG_all_wrappers(ii).Processed && ~ECG_all_wrappers(ii).Error )
% this is to use previous saved results as starting point,
% if any available
cached_filenames = ECG_all_wrappers(ii).GetCahchedFileName({'PPG_ABP_corrector' 'PPG_ABP_detector'});
% if no previous correction work, try the automatic
% detection task
% if any, do the correction
if( ~isempty(cached_filenames) )
% this is to use previous saved results as starting point,
% if any available
ECG_all_wrappers(ii).ECGtaskHandle = 'PPG_ABP_corrector';
% This task is supposed to be supervised, so only one pid is enough.
ECG_all_wrappers(ii).this_pid = '1/1';
% to avoid loading cached results and exit, this flag
% allows the re-editing of the current state of the
% detections.
ECG_all_wrappers(ii).cacheResults = false;
% maybe in your application you should run this for
% all files.
ECG_all_wrappers(ii).ECGtaskHandle.payload = load(cached_filenames{1});
% process the task
ECG_all_wrappers(ii).Run;
% restore the original pids configuration
ECG_all_wrappers(ii).this_pid = pid_str;
% As we changed for "QRS correction" task, we have to enable this
% value again in order to avoid performing the following tasks every time.
% If you want to recalculate any task, change it to false
ECG_all_wrappers(ii).cacheResults = true;
end
end
end
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
end
%% ECG automatic delineation
% other task can be performed on the same objects
for ii = 1:lrecnames
% this is to use previous cached results as starting point
cached_filenames = ECG_all_wrappers(ii).GetCahchedFileName('QRS_corrector');
% set the delineator task name and run again.
ECG_all_wrappers(ii).ECGtaskHandle = 'ECG_delineation';
% if corrected QRS detections are not available, wavedet
% performs automatic QRS detection.
if( ~isempty(cached_filenames) )
% this is to use previous result from the automatic QRS
% detection
ECG_all_wrappers(ii).ECGtaskHandle.payload = load(cached_filenames{1});
end
% ECGt_QRSd.detectors = 'wavedet'; % Wavedet algorithm based on
% ECGt_QRSd.detectors = 'user:example_worst_ever_ECG_delineator';
% % Example of how you can add your own ECG delineator.
% ECGt_QRSd.detectors = 'user:your_ECG_delineator_func_name';
% "your_ECG_delineator_func_name" can be your own delineator.
ECG_all_wrappers(ii).ECGtaskHandle.delineators = {'wavedet' 'user:example_worst_ever_ECG_delineator'};
% process the task
ECG_all_wrappers(ii).Run;
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
%% Visual inspection of the detection/delineation
if( bUseDesktop )
% other task can be performed on the same objects
for ii = 1:lrecnames
% last worker is the responsible of the visual correction.
if( ECG_all_wrappers(ii).this_pid == ECG_all_wrappers(ii).cant_pids)
% if there are not any previous error.
if( ECG_all_wrappers(ii).Processed && ~ECG_all_wrappers(ii).Error )
% this is to use previous saved results as starting point,
% if any available
cached_filenames = ECG_all_wrappers(ii).GetCahchedFileName( {'ECG_delineation_corrector' 'ECG_delineation'} );
% if no previous correction work, try the automatic
% detection task
% if any, do the correction
if( ~isempty(cached_filenames) )
% this is to use previous saved results as starting point,
% if any available
ECG_all_wrappers(ii).ECGtaskHandle = 'ECG_delineation_corrector';
% This task is supposed to be supervised, so only one pid is enough.
ECG_all_wrappers(ii).this_pid = '1/1';
% to avoid loading cached results and exit, this flag
% allows the re-editing of the current state of the
% detections.
ECG_all_wrappers(ii).cacheResults = false;
% maybe in your application you should run this for
% all files.
ECG_all_wrappers(ii).ECGtaskHandle.payload = load(cached_filenames{1});
% process the task
ECG_all_wrappers(ii).Run;
% restore the original pids configuration
ECG_all_wrappers(ii).this_pid = pid_str;
% As we changed for "QRS correction" task, we have to enable this
% value again in order to avoid performing the following tasks every time.
% If you want to recalculate any task, change it to false
ECG_all_wrappers(ii).cacheResults = true;
end
end
end
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
end
%% Automatic Heartbeat classification
% other task can be performed on the same objects
for ii = 1:lrecnames
% this is to use previous cached results as starting point
cached_filenames = ECG_all_wrappers(ii).GetCahchedFileName({'QRS_corrector' 'QRS_detection'});
% if corrected QRS detections are not available, wavedet
% performs automatic QRS detection.
if( ~isempty(cached_filenames) )
ECG_all_wrappers(ii).ECGtaskHandle = 'ECG_heartbeat_classifier';
ECG_all_wrappers(ii).ECGtaskHandle.payload = load(cached_filenames{1});
% process the task
ECG_all_wrappers(ii).Run;
end
end
% at the end, report problems if happened.
for ii = 1:lrecnames
ECG_all_wrappers(ii).ReportErrors;
end
%% Visual inspection of the signal
filename = []; % default setting. Let the report function decide.
% filename = 'container_filename'; % to put everything in one big file.
% other winlengths can be added to the array in order to further
% explore the recordings, and the algorithm results.
% winlengths = []; % default setting
winlengths = [ 7 ]; %seconds
% go through all files
for ii = 1:lrecnames
% last worker is the responsible of the reporting.
if( ECG_all_wrappers(ii).this_pid == ECG_all_wrappers(ii).cant_pids)
try
reportECG(ECG_all_wrappers(ii), 'LowDetail', 'full', winlengths, 'pdf', [] );
% reportECG(ECG_all_wrappers(ii), 'LowDetail', 'full', winlengths, 'png', filename);
catch MException
report = getReport(MException);
disp_string_framed(2, ECG_all_wrappers(ii).recording_name)
fprintf(2, '\n%s\n', report);
end
end
end
%% other user-defined tasks ...
if( ~bUseDesktop )
UnInstallECGkit();
end