ECG-Kit 1.0
(7,972 bytes)
classdef ECGtask_heartbeat_classifier < ECGtask
% ECGtask for ECGwrapper (for Matlab)
% ---------------------------------
%
% Description:
%
% Abstract class for defining ECGtask interface
%
%
% Author: Mariano Llamedo Soria (llamedom at {electron.frba.utn.edu.ar; unizar.es}
% Version: 0.1 beta
% Birthdate : 18/2/2013
% Last update: 18/2/2013
properties(GetAccess = public, Constant)
name = 'ECG_heartbeat_classifier';
target_units = 'ADCu';
doPayload = true;
end
properties( GetAccess = public, SetAccess = private)
% if user = memory;
% memory_constant is the fraction respect to user.MaxPossibleArrayBytes
% which determines the maximum input data size.
memory_constant = 0.3;
started = false;
end
properties( Access = private, Constant)
fig_hdl = 1;
cKnownModesOfOperation = {'auto' 'slightly-assisted', 'assisted'};
end
properties( Access = private )
end
properties
progress_handle
payload
mode
tmp_path
% minimum amount of heartbeats required
min_heartbeats_required = 500;
% maximum amount of heartbeats to process each iteration
max_heartbeats_per_iter = 4000;
% qrs locations provided to the task, result of previous QRS
% detections / correction
annotations = [];
end
methods
function obj = ECGtask_heartbeat_classifier(obj)
if( isempty(obj.mode) )
obj.mode = obj.cKnownModesOfOperation{1};
end
end
function Start(obj, ECG_header, ECG_annotations)
if( ECG_header.nsig == 1 )
return
end
lead_idx = get_ECG_idx_from_header(ECG_header);
if( length(lead_idx) <= 1 )
return
end
obj.annotations = ParsePayloadAnnotations(obj);
if( (~isempty(obj.annotations) && length(obj.annotations) > obj.min_heartbeats_required ) || ( isfield(ECG_annotations, 'time') && ~isempty(ECG_annotations.time)) )
obj.started = true;
end
end
function payload_out = Process(obj, ECG, ECG_start_offset, ECG_sample_start_end_idx, ECG_header, ECG_annotations, ECG_annotations_start_end_idx )
payload_out = [];
if( ~obj.started )
obj.Start(ECG_header);
if( ~obj.started )
cprintf('*[1,0.5,0]', 'Task %s unable to be started for %s.\n', obj.name, ECG_header.recname);
return
end
end
% aux_val = ECG_sample_start_end_idx + ECG_start_offset - 1;
% disp_string_title(1, sprintf( 'Classifying from %d to %d', aux_val(1), aux_val(2) ) );
[lead_idx, ECG_header ] = get_ECG_idx_from_header(ECG_header);
[aux_val, ~, lablist ] = a2hbc('ECG', ECG(:,lead_idx), ...
'ECG_header', ECG_header, ...
'ECG_annotations', ECG_annotations, ...
'op_mode', obj.mode );
bAux = ECG_annotations.time > ECG_sample_start_end_idx(1) & ECG_annotations.time < ECG_sample_start_end_idx(2);
ECG_annotations.anntyp = lablist(colvec(aux_val(bAux)),1);
ECG_annotations.time = ECG_annotations.time(bAux) + ECG_start_offset - 1;
payload_out = ECG_annotations;
end
function payload = Finish(obj, payload, ECG_header)
end
function payload = Concatenate(obj, plA, plB)
if( isempty(plA) )
payload = plB;
else
for fn = rowvec(fieldnames(plA))
if( isfield(plA, fn{1}) && isfield(plB, fn{1}) )
payload.(fn{1}) = [ plA.(fn{1}); plB.(fn{1}) ];
elseif( ~isfield(plA, fn{1}) && isfield(plB, fn{1}) )
payload.(fn{1}) = plB.(fn{1});
end
end
end
end
%% property restriction functions
function set.mode(obj,x)
if( ischar(x) && ~isempty(strcmpi(x, obj.cKnownModesOfOperation)) )
obj.mode = x;
else
warning('ECGtask_QRS_detection:BadArg', 'Invalid detectors.');
end
end
end
methods ( Access = private )
function aux_val = ParsePayloadAnnotations(obj)
aux_val = [];
if( isstruct(obj.payload) )
aux_fn = fieldnames(obj.payload);
jj = 1;
while( isempty( aux_val ) )
% prefer manually reviewed annotations corrected
aux_idx = find(cell2mat( cellfun(@(a)(~isempty(strfind(a, 'corrected_'))), aux_fn, 'UniformOutput', false)));
if( isempty(aux_idx) )
if( isfield(obj.payload, 'series_quality') )
% choose the best ranked automatic detection
[~, aux_idx] = sort(obj.payload.series_quality.ratios, 'descend' );
if( jj <= length(aux_idx))
aux_val = obj.payload.(obj.payload.series_quality.AnnNames{aux_idx(jj),1} ).(obj.payload.series_quality.AnnNames{aux_idx(jj),2});
delineation_chosen = obj.payload.series_quality.AnnNames{aux_idx(jj),1};
else
break
end
else
% choose the first of wavedet
aux_idx = find(cell2mat( cellfun(@(a)(~isempty(strfind(a, 'wavedet_'))), aux_fn, 'UniformOutput', false)));
if( isempty(aux_idx) )
disp_string_framed(2, 'Could not identify QRS detections in the input payload.');
return
else
if( jj <= length(aux_idx))
aux_val = obj.payload.(aux_fn{aux_idx(jj)}).time;
delineation_chosen = aux_fn{aux_idx(jj)};
else
break
end
end
end
else
% choose the first manually audited
if( jj <= length(aux_idx))
aux_val = obj.payload.(aux_fn{aux_idx(jj)}).time;
delineation_chosen = aux_fn{aux_idx(jj)};
else
break
end
end
cprintf('blue', [' + Using ' delineation_chosen ' detections.\n' ] );
aux_val = sort(unique(aux_val));
jj = jj + 1;
end
elseif( isnumeric(obj.payload) )
aux_val = sort(unique(obj.payload));
end
end
end
end