ECG-Kit 1.0

File: <base>/examples/examples.m (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