Skip to content

Commit

Permalink
v1.0.2
Browse files Browse the repository at this point in the history
See Changelog for v1.0.2
Fix for incorrect mapping between up/downsampled signal when annotating median beats for ECGs not sampled at 500 Hz.
  • Loading branch information
BIVectors committed Sep 29, 2023
1 parent bf72e4e commit 9751bce
Show file tree
Hide file tree
Showing 16 changed files with 200 additions and 79 deletions.
2 changes: 1 addition & 1 deletion AnnoResult.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
obj.missing_lead = num2cell(missing_lead);

% VERSION MANUALLY UPDATED HERE
obj.version = {'1.0.1'};
obj.version = {'1.0.2'};

end
end
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ identifiers:
Programs in Biomedicine
repository-code: 'https://github.com/BIVectors/BRAVEHEART'
license: GPL-3.0
version: 1.0.1
version: 1.0.2
date-released: '2023-09-12'
preferred-citation:
type: article
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![badge](https://badgen.net/badge/MATLAB/R2022a/?color=green)](https://www.mathworks.com/products/matlab.html) ![badge](https://badgen.net/badge/License/GPL-3.0/?color=red)
![badge](https://github.com/BIVectors/BRAVEHEART/actions/workflows/testing.yml/badge.svg)
[![badge](https://img.shields.io/github/v/release/BIVectors/BRAVEHEART?label=Latest%20Release)](https://github.com/BIVectors/BRAVEHEART/releases) ![badge](https://img.shields.io/github/repo-size/BIVectors/BRAVEHEART?label=Repo%20Size) ![badge](https://img.shields.io/github/directory-file-count/BIVectors/BRAVEHEART?label=File%20Count) ![badge](https://img.shields.io/github/languages/code-size/BIVectors/BRAVEHEART?label=Code%20Size) [![badge](https://badgen.net/badge/icon/Windows%20.exe?icon=windows&label)](https://github.com/BIVectors/BRAVEHEART/releases) [![badge](https://badgen.net/badge/icon/Mac%20.app?icon=apple&label)](https://github.com/BIVectors/BRAVEHEART/releases)
[![badge](https://img.shields.io/badge/braveheart__userguide.pdf-yellow?logo=adobeacrobatreader&logoColor=white&label=User%20Guide&color=F7DF1E)](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_userguide.pdf) [![badge](https://img.shields.io/badge/https%3A%2F%2Fdoi.org%2F10.1016%2Fj.cmpb.2023.107798-yellow?logo=elsevier&logoColor=white&label=Methods%20Manuscript&color=F7DF1E)](https://doi.org/10.1016/j.cmpb.2023.107798)
[![badge](https://img.shields.io/badge/User%20Guide-F7DF1E?logo=adobeacrobatreader&style=flat&labelColor=555)](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_userguide.pdf) [![badge](https://img.shields.io/badge/Methods%20Manuscript-F7DF1E?logo=elsevier&style=flat&logoColor=white&labelColor=555)](https://doi.org/10.1016/j.cmpb.2023.107798)

**Hans Fredrich Stabenau, MD, PhD & Jonathan W. Waks, MD
Harvard-Thorndike Electrophysiology Institute, Department of Cardiovascular Medicine,
Expand Down Expand Up @@ -32,11 +32,11 @@ All rights reserved.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/ or the [LICENSE](https://github.com/BIVectors/BRAVEHEART/blob/main/LICENSE) file included in this repository.

## Installation & User Guide/Software Methods
[![badge](https://img.shields.io/badge/braveheart__userguide.pdf-yellow?logo=adobeacrobatreader&logoColor=white&label=User%20Guide&color=F7DF1E)](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_userguide.pdf)
[![badge](https://img.shields.io/badge/User%20Guide-F7DF1E?logo=adobeacrobatreader&style=flat&labelColor=555)](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_userguide.pdf)
A detailed user guide that covers installation and use of the software, including a quick start guide and examples of ECG/VCG processing, is available in the file [braveheart_userguide.pdf](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_userguide.pdf).

[![badge](https://img.shields.io/badge/https%3A%2F%2Fdoi.org%2F10.1016%2Fj.cmpb.2023.107798-yellow?logo=elsevier&logoColor=white&label=Methods%20Manuscript&color=F7DF1E)](https://doi.org/10.1016/j.cmpb.2023.107798)
A manuscript describing the software methods in detail is available in the file [braveheart_methods.pdf](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_methods.pdf) and as a [manuscript in Computer Methods and Programs in Biomedicine](https://doi.org/10.1016/j.cmpb.2023.107798).
[![badge](https://img.shields.io/badge/Methods%20Manuscript-F7DF1E?logo=elsevier&style=flat&logoColor=white&labelColor=555)](https://doi.org/10.1016/j.cmpb.2023.107798)
A manuscript describing the software methods in detail is available in the file [braveheart_methods.pdf](https://github.com/BIVectors/BRAVEHEART/blob/main/braveheart_methods.pdf) and as a [manuscript in Computer Methods and Programs in Biomedicine (DOI: https://doi.org/10.1016/j.cmpb.2023.107798)](https://doi.org/10.1016/j.cmpb.2023.107798).

## How to Cite Use of BRAVEHEART
Please include the link to this GitHub repository and cite our [manuscript in Computer Methods and Programs in Biomedicine](https://doi.org/10.1016/j.cmpb.2023.107798). The upper right section of this repository has a [CITATION file](https://github.com/BIVectors/BRAVEHEART/blob/main/CITATION.cff) that will provide the appropriate references:
Expand Down
10 changes: 5 additions & 5 deletions braveheart_batch_windows.prj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<deployment-project plugin="plugin.ezdeploy" plugin-version="1.0">
<configuration build-checksum="2297591659" file="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_batch_windows.prj" location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV" name="braveheart_batch_windows" preferred-package-location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_batch_windows\for_redistribution" preferred-package-type="package.type.exe" target="target.ezdeploy.standalone" target-name="Application Compiler">
<configuration build-checksum="350153431" file="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_batch_windows.prj" location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV" name="braveheart_batch_windows" preferred-package-location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_batch_windows\for_redistribution" preferred-package-type="package.type.exe" target="target.ezdeploy.standalone" target-name="Application Compiler">
<param.appname>braveheart_batch</param.appname>
<param.icon>${PROJECT_ROOT}\braveheart_batch_windows_resources\icon.ico</param.icon>
<param.icons>
Expand All @@ -8,13 +8,13 @@
<file>${PROJECT_ROOT}\braveheart_batch_windows_resources\icon_24.png</file>
<file>${PROJECT_ROOT}\braveheart_batch_windows_resources\icon_16.png</file>
</param.icons>
<param.version>1.0.1</param.version>
<param.version>1.0.2</param.version>
<param.authnamewatermark>Hans F. Stabenau and Jonathan W. Waks</param.authnamewatermark>
<param.email>braveheart.ecg@gmail.com</param.email>
<param.company />
<param.summary />
<param.description>BRAVHEART ECG/VCG Analysis Software -- Command Line Version
Version 1.0.1</param.description>
Version 1.0.2</param.description>
<param.screenshot>${PROJECT_ROOT}\braveheart_splash.png</param.screenshot>
<param.guid />
<param.installpath.string>\braveheart_batch\</param.installpath.string>
Expand Down Expand Up @@ -50,7 +50,7 @@ Version 1.0.1</param.description>
varargin input arguments
Description
BRAVHEART ECG/VCG Analysis Software -- Command Line Version
Version 1.0.1</param.help.text>
Version 1.0.2</param.help.text>
<unset>
<param.company />
<param.summary />
Expand Down Expand Up @@ -89,7 +89,7 @@ Version 1.0.1</param.help.text>
<file>${PROJECT_ROOT}\braveheart_variables.pdf</file>
<file>${PROJECT_ROOT}\findHighpassLvl.m</file>
<file>${PROJECT_ROOT}\load_cardiosoftxml.m</file>
<file>${PROJECT_ROOT}\test_braveheart.m</file>
<file>${PROJECT_ROOT}\resamp_loc.m</file>
</fileset.resources>
<fileset.package>
<file>${PROJECT_ROOT}\Annoparams.csv</file>
Expand Down
Binary file modified braveheart_gui.fig
Binary file not shown.
4 changes: 2 additions & 2 deletions braveheart_gui.m
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ function about_help_button_Callback(hObject, eventdata, handles)
{'\fontsize{14}\it\bf \color[rgb]{0.09,0.078,0.377}';...
'BRAVE\color[rgb]{0.89,0.016,0.016}H\fontsize{11}EART';...
'\fontsize{8}\rm\color{black}(Beth Israel Analysis of Vectors of the Heart)';...
'Version 1.0.1' ;
'Version 1.0.2' ;
' ' ;...
'Copyright 2016-2023 Hans F. Stabeneau and Jonathan W. Waks' ;...
' ' ;...
Expand Down Expand Up @@ -426,7 +426,7 @@ function about_help_button_Callback(hObject, eventdata, handles)
{'\fontsize{18}\it\bf \color[rgb]{0.09,0.078,0.377}';...
'BRAVE\color[rgb]{0.89,0.016,0.016}H\fontsize{14}EART\fontsize{11}';...
'\rm\color{black}(Beth Israel Analysis of Vectors of the Heart)';...
'Version 1.0.1' ;
'Version 1.0.2' ;
' ' ;...
'Copyright 2016-2023 Hans F. Stabeneau and Jonathan W. Waks' ;...
' ' ;...
Expand Down
11 changes: 6 additions & 5 deletions braveheart_gui_windows.prj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<deployment-project plugin="plugin.ezdeploy" plugin-version="1.0">
<configuration build-checksum="4041263907" file="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_gui_windows.prj" location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV" name="braveheart_gui_windows" preferred-package-location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_gui_windows\for_redistribution" preferred-package-type="package.type.exe" target="target.ezdeploy.standalone" target-name="Application Compiler">
<configuration build-checksum="277122574" file="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_gui_windows.prj" location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV" name="braveheart_gui_windows" preferred-package-location="C:\Users\jwaks\Documents\GitHub\BRAVEHEART_DEV\braveheart_gui_windows\for_redistribution" preferred-package-type="package.type.exe" target="target.ezdeploy.standalone" target-name="Application Compiler">
<param.appname>braveheart_gui</param.appname>
<param.icon>${PROJECT_ROOT}\braveheart_gui_windows_resources\icon.ico</param.icon>
<param.icons>
Expand All @@ -8,13 +8,13 @@
<file>${PROJECT_ROOT}\braveheart_gui_windows_resources\icon_24.png</file>
<file>${PROJECT_ROOT}\braveheart_gui_windows_resources\icon_16.png</file>
</param.icons>
<param.version>1.0.1</param.version>
<param.version>1.0.2</param.version>
<param.authnamewatermark>Hans F. Stabenau and Jonathan W. Waks</param.authnamewatermark>
<param.email>bravheart.ecg@gmail.com</param.email>
<param.company />
<param.summary />
<param.description>BRAVEHEART ECG/VCG Analysis Software -- GUI Version
Version 1.0.1</param.description>
Version 1.0.2</param.description>
<param.screenshot>${PROJECT_ROOT}\braveheart_splash.png</param.screenshot>
<param.guid />
<param.installpath.string>\braveheart_gui\</param.installpath.string>
Expand Down Expand Up @@ -50,7 +50,7 @@ Version 1.0.1</param.description>
varargin input arguments
Description
BRAVEHEART ECG/VCG Analysis Software -- GUI Version
Version 1.0.1</param.help.text>
Version 1.0.2</param.help.text>
<unset>
<param.company />
<param.summary />
Expand Down Expand Up @@ -89,12 +89,13 @@ Version 1.0.1</param.help.text>
<file>${PROJECT_ROOT}\braveheart_variables.pdf</file>
<file>${PROJECT_ROOT}\findHighpassLvl.m</file>
<file>${PROJECT_ROOT}\load_cardiosoftxml.m</file>
<file>${PROJECT_ROOT}\test_braveheart.m</file>
<file>${PROJECT_ROOT}\resamp_loc.m</file>
</fileset.resources>
<fileset.package>
<file>${PROJECT_ROOT}\Annoparams.csv</file>
<file>${PROJECT_ROOT}\batch_settings.csv</file>
<file>${PROJECT_ROOT}\braveheart_userguide.pdf</file>
<file>${PROJECT_ROOT}\Download MATLAB Runtime - Windows 64 bit.url</file>
<file>${PROJECT_ROOT}\ecg_formats.csv</file>
<file>${PROJECT_ROOT}\Example ECGs</file>
<file>${PROJECT_ROOT}\quality_presets.csv</file>
Expand Down
51 changes: 26 additions & 25 deletions load_cardiosoftxml.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,33 @@
W = string((wlist.item(k).getFirstChild.getNodeValue));
W = regexprep(W, '\t', '');
label = char(wlist.item(k).getAttributes.item(0));
D = sscanf(W, '%g,', [1, inf]) * gain / unit_div;

switch label
case 'lead="I"'
I = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="II"'
II = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="III"'
III = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="aVR"'
avR = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="aVL"'
avL = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="aVF"'
avF = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V1"'
V1 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V2"'
V2 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V3"'
V3 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V4"'
V4 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V5"'
V5 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
case 'lead="V6"'
V6 = sscanf(W, '%g,', [1, inf]) * gain / unit_div;
switch lower(label) % User lowercase because some different versions use different capital letters
case 'lead="i"'
I = D;
case 'lead="ii"'
II = D;
case 'lead="iii"'
III = D;
case 'lead="avr"'
avR = D;
case 'lead="avl"'
avL = D;
case 'lead="avf"'
avF = D;
case 'lead="v1"'
V1 = D;
case 'lead="v2"'
V2 = D;
case 'lead="v3"'
V3 = D;
case 'lead="v4"'
V4 = D;
case 'lead="v5"'
V5 = D;
case 'lead="v6"'
V6 = D;
end

end % End for loop
Expand Down
85 changes: 66 additions & 19 deletions load_dicom.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,29 @@

% Pull out waveform part of DICOM and the field names in that part of DICOM
ws_fn = fieldnames(D.WaveformSequence);
ws = D.WaveformSequence.(ws_fn{1});

% Check if there is more than 1 'Item' if there are rhythm strips and medians
% Format requires that there are between 1 and 4 'Items'
% see https://www.dicomstandard.org/News-dir/ftsup/docs/sups/sup30.pdf
len_ws_fn = length(ws_fn);
itemN = 0;

% Only take the RHYTHM data, although could modify to get other types of waveforms if needed
for i = 1:length(len_ws_fn)

if strcmp(string(D.WaveformSequence.(ws_fn{i}).MultiplexGroupLabel),"RHYTHM")
itemN = i;
break;
end
end

% Check that found a RHYTHM waveform
if itemN == 0
error('load_dicom.m: Didnt find a RHYTHM WaveformSequence')
end

% Choose the RHYTHM Waveforms
ws = D.WaveformSequence.(ws_fn{itemN});
waveform = ws.WaveformData;

% Sample frequency
Expand All @@ -52,8 +74,21 @@
lead_str{i} = ch_def.(ch_def_fn{i}).ChannelSourceSequence.Item_1.CodeMeaning;
end

% Convert uint16 to int16
fullsignal = double(typecast(uint16(waveform), 'int16'));
% Convert into int16 based on whatever encoding DICOM using
% Get encoding
E = string(class(ws.WaveformData));

if strcmp(E, 'uint16')
% Convert uint16 to int16
fullsignal = double(typecast(uint16(waveform), 'int16'));
elseif strcmp(E, 'uint8')
% Convert uint8 to int16
fullsignal = double(typecast(uint8(waveform), 'int16'));
elseif strcmp(E, 'int16')
fullsignal = waveform;
else
error('Check WaveformSequence.Item_N.WaveformData encoding - may need to add current encoding to load_dicom.m')
end

% get each lead out of the singla waveform
L = zeros(num_leads, num_samples);
Expand All @@ -62,22 +97,34 @@
for i = 1:num_samples
L(s,i) = (((fullsignal(s + (12*(i-1)))) + baseline(s)) * (mcv_perunit(s)/1000 * correction(s)));
end
% Read lead_str to determine which lead it is
switch string(lead_str(s))
case 'Lead I'
I = L(s,:);
case 'Lead II'
II = L(s,:);
case 'Lead III'
III = L(s,:);
case 'Lead aVR'
avR = L(s,:);
case 'Lead aVL'
avL = L(s,:);
case 'Lead aVF'
avF = L(s,:);

case 'Lead V1'
V1 = L(s,:);
case 'Lead V2'
V2 = L(s,:);
case 'Lead V3'
V3 = L(s,:);
case 'Lead V4'
V4 = L(s,:);
case 'Lead V5'
V5 = L(s,:);
case 'Lead V6'
V6 = L(s,:);
end
end

% Signal is now in MILLIVOLTS

% Parse out each lead
I = L(1,:);
II = L(2,:);
III = L(3,:);
avR = L(4,:);
avL = L(5,:);
avF = L(6,:);

V1 = L(7,:);
V2 = L(8,:);
V3 = L(9,:);
V4 = L(10,:);
V5 = L(11,:);
V6 = L(12,:);

3 changes: 3 additions & 0 deletions load_hl7xml.m
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
lead_name = D.component.series.component.sequenceSet.component(i).sequence.code.codeAttribute;
signal = D.component.series.component.sequenceSet.component(i).sequence.value.digits;

% Remove end of line characters that can be an issue on some systems
signal = regexprep(signal, '\r\n|\n|\r', '');

switch lead_name
case "MDC_ECG_LEAD_I"
I = str2num(signal).*scale;
Expand Down
7 changes: 6 additions & 1 deletion median_offset_measure_GUI.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ function median_offset_measure_GUI(hObject, eventdata, handles, aps)
hold on
plot(ecg.(shift_prop{i}),'r');
line([0 length(ecg_noshift.(shift_prop{i}))],[0 0],'Color','b');
ylim( [ min( [min(ecg_noshift.(shift_prop{i})) min(ecg.(shift_prop{i}))]) max( [max(ecg_noshift.(shift_prop{i})) max(ecg.(shift_prop{i}))])]);
% Prevent figure not genearating if a lead is missing due to ylim error
if min( [min(ecg_noshift.(shift_prop{i})) min(ecg.(shift_prop{i}))]) ~= max( [max(ecg_noshift.(shift_prop{i})) max(ecg.(shift_prop{i}))])
ylim( [ min( [min(ecg_noshift.(shift_prop{i})) min(ecg.(shift_prop{i}))]) max( [max(ecg_noshift.(shift_prop{i})) max(ecg.(shift_prop{i}))])]);
else
ylim( [ min( [min(ecg_noshift.(shift_prop{i})) min(ecg.(shift_prop{i}))])-0.01 max( [max(ecg_noshift.(shift_prop{i})) max(ecg.(shift_prop{i}))])+0.01 ]);
end
ylabel(label(i))
hold off

Expand Down
27 changes: 18 additions & 9 deletions nnet_median_annotate.m
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,24 @@
T_down = T;
Tend_down = Tend;

% Need to assign points differently if the 500 Hz median beat was due to
% downsampling or upsampling, because if UPsampled to get to 500 Hz median
% and an interpolated point is chosen as a fiducial point, this point does
% not directly map onto the orignal signal. If the sampling frequency of
% the original signal is > 500 Hz and the signal was DOWNsampled to create
% a 500 Hz median beat to pass into the NN, then the point chosen on the
% median should exist on the original signal (with slight exception for
% sampling frequencies that are not multiples of 500 Hz like 997 Hz, but in
% these cases the error should be small since you actually downsampled the
% original signal to get the median). This issue was fixed in v1.0.2

if freq ~= 500

c = freq/500;

Q = round(c*Q)-1;
S = round(c*S)-1;
T = round(c*T)-1;
Tend = round(c*Tend)-1;


Q = resamp_loc(500, freq, Q);
S = resamp_loc(500, freq, S);
T = resamp_loc(500, freq, T);
Tend = resamp_loc(500, freq, Tend);

end


Expand All @@ -112,7 +121,7 @@ function plot_scores(signal, signal_orig, freq, scores, Q, S, T, Tend, Q_down, S

figure('name','Median Reannotation Fiducial Point Debug','numbertitle','off')
subplot(1,2,1)
title('Downsampled Signal - 500 Hz')
title('Resampled Signal - 500 Hz')
yyaxis left

ylabel('VM Signal (mV)')
Expand Down
Loading

0 comments on commit 9751bce

Please sign in to comment.