1 %This file is part of TEAP.
3 %TEAP is free software: you can redistribute it and/or modify
4 %it under the terms of the GNU General Public License as published by
5 %the Free Software Foundation, either version 3 of the License, or
6 %(at your option) any later version.
8 %TEAP is distributed in the hope that it will be useful,
9 %but WITHOUT ANY WARRANTY; without even the implied warranty of
10 %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 %GNU General Public License
for more details.
13 %You should have received a copy of the GNU General Public License
14 %along with TEAP. If not, see <http://www.gnu.org/licenses/>.
17 %> @brief Computes ECG features
18 %TODO: clarifiy the help
19 %TODO call on other simple
function instead of having all the computation
20 %TODO: changes all any statement to all or ismember because I think it can
21 %lead to problems (variable computation
while it should not compute it)
25 %> @param ECGSignal: the ECG signal (already subtracted from one lead)
26 %> @param varargin: you can choose which features to extract
27 %>
default or no input will result in extracting all the features
28 %> (see feature Extractor)
29 %> featues names include:
30 %> - meanIBI: mean interbeat interval
31 %> - HRV: heart rate variability (deviation of IBI)
32 %> - MSE: Multi-Scale Entropy at 5 levels 1-5 (5 features)
33 %> - sp0001: Spectral power 0-0.1Hz,
34 %> - sp0102: Spectral power 0.1-0.2Hz,
35 %> - sp0203: Spectral power 0.2-0.3Hz,
36 %> - sp0304: Spectral power 0.3-0.4Hz,
37 %> - energyRatio: Spectral energy ratio between f<0.08Hz/f>0.15Hz and f<5.0Hz
38 %> - tachogram_LF: Low frequency spectral power in tachogram (HRV) [0.01-0.08Hz]
39 %> - tachogram_MF: Medium frequency spectral power in tachogram (HRV) [0.08-0.15Hz]
40 %> - tachogram_HF: High frequency spectral power in tachogram (HRV) [0.15-0.5Hz]
41 %> - tachogram_energy_ratio: Energy ratio
for tachogram spectral content (MF/(LF+HF))
43 %> @retval ECG_features: vector of features among the following features
44 %> @retval ECG_feats_names: the names of the features is the same order than in
46 %> @retval Bulk:
if the input to the
function is a Bulk than the Bulk is returned
47 %> with the updated ECG signal, including IBI. Otherwise NaN is
51 %> @author Copyright Guillaume Chanel 2013, 2015
52 %> @author Copyright Frank Villaro-Dixon, 2014
53 function [ECG_features, ECG_feats_names, Bulk] =
ECG_feat_extr(ECGSignal,varargin)
55 %Make sure we have an ECG signal and get the bulk
for saving IBI (
if needed)
57 if(nargout < 3) %No bulk requested ->
do not need to keep it
61 % Define full feature list and get features selected by user
62 %TODO: confirm with Mohammad that the changes are ok (suppression of
'sp0103'
63 featuresNames = {
'meanIBI',
'HRV',
'MSE',
'sp0001',
'sp0102',
'sp0203',
'sp0304',
'energyRatio',
'tachogram_LF',
'tachogram_MF',
'tachogram_HF',...
64 'tachogram_energy_ratio'};
65 featuresNamesIBI = {
'meanIBI',
'HRV',
'MSE',
'energyRatio',
'tachogram_LF',
'tachogram_MF',
'tachogram_HF',
'tachogram_energy_ratio'};
69 if(~isempty(ECG_feats_names))
71 %Compute IBI
if a features needing it is requested
72 if(any(ismember(featuresNamesIBI,ECG_feats_names)))
78 %Update the Bulk with the
new ECG signal
84 %Get information of ECG signal
87 %set the welch window size
88 welch_window_size_ECG = ECG_sp* 20;
89 welch_window_size_IBI= IBI_sp* 20;
92 if any(strcmp(
'meanIBI',ECG_feats_names)) || any(strcmp(
'HRV',ECG_feats_names))
96 if any(strcmp(
'MSE',ECG_feats_names))
97 %multi-scale entropy
for 5 scales on hrv
100 if length(ECG)< welch_window_size_ECG +ECG_sp
101 warning(
'singal to short for the welch size');
103 if length(ECG)< welch_window_size_ECG +1
104 warning(
'singal to short for the welch size - PSD features cannot be calcualted');
105 sp0001 = NaN;sp0102 = NaN;sp0203 = NaN; sp0304 = NaN;energyRatio = NaN;
107 if any(strcmp(
'sp0001',ECG_feats_names)) || any(strcmp(
'sp0102',ECG_feats_names)) ...
108 || any(strcmp(
'sp0203',ECG_feats_names)) || any(strcmp(
'sp0304',ECG_feats_names)) ...
109 || any(strcmp(
'energyRatio',ECG_feats_names))
111 [P, f] = pwelch(ECG, welch_window_size_ECG, [], [], ECG_sp);
113 %power spectral featyres
114 %WARN: check that
this resolution is obrainable with the ECG sampling rate
115 sp0001 = log(sum(P(f>0.0 & f<=0.1))+eps);
116 sp0102 = log(sum(P(f>0.1 & f<=0.2))+eps);
117 sp0203 = log(sum(P(f>0.2 & f<=0.3))+eps);
118 sp0304 = log(sum(P(f>0.3 & f<=0.4))+eps);
119 energyRatio = log(sum(P(f<0.08))/sum(P(f>0.15 & f<0.5))+eps);
121 if length(IBI)< welch_window_size_IBI +IBI_sp
122 warning(
'singal to short for the welch size');
124 if length(IBI)< welch_window_size_IBI +1
125 warning(
'singal to short for the welch size - PSD features cannot be calcualted');
126 tachogram_LF = NaN;tachogram_MF = NaN;tachogram_HF = NaN;
127 tachogram_energy_ratio = NaN;
129 %tachogram features; psd features on inter beat intervals
130 %R. McCraty, M. Atkinson, W. Tiller, G. Rein, and A. Watkins, �The
131 %effects of emotions on
short-term power spectrum analysis of
132 %heart rate variability,� The American Journal of Cardiology, vol. 76,
133 %no. 14, pp. 1089 � 1093, 1995
134 if any(strcmp(
'tachogram_LF',ECG_feats_names)) ...
135 || any(strcmp(
'tachogram_MF',ECG_feats_names)) || any(strcmp(
'tachogram_HF',ECG_feats_names)) ...
136 || any(strcmp(
'tachogram_energy_ratio',ECG_feats_names))
138 %Handle the
case were IBI could not be computed
140 [Pt, ft] = pwelch(IBI, welch_window_size_IBI, [], [], IBI_sp);
141 %WARN: check that
this is possible with the IBI sampling rate
142 %WARN: these values are sometimes negative because of the log, doesn
't it appear as strange for a user ?
143 tachogram_LF = log(sum(Pt(ft>0.01 & ft<=0.08))+eps);
144 tachogram_MF = log(sum(Pt(ft>0.08 & ft<=0.15))+eps);
145 tachogram_HF = log(sum(Pt(ft>0.15 & ft<=0.5))+eps);
146 tachogram_energy_ratio = tachogram_MF/(tachogram_LF+tachogram_HF);
151 tachogram_energy_ratio = NaN;
156 %Setup feature vector
158 for i = 1:length(ECG_feats_names)
159 eval(['ECG_features = cat(2, ECG_features,
' ECG_feats_names{i} ');
']);
162 %MSE actually contains five features so rename features MSE as MSE1, MSE2... if it exists
163 %TODO: just a temporary hack ?
164 idx = find(ismember(ECG_feats_names, 'MSE
'));
166 ECG_feats_names = {ECG_feats_names{1:idx-1} 'MSE1
' 'MSE2
' 'MSE3
' 'MSE4
' 'MSE5
' ECG_feats_names{idx+1:end}};