├── Hilbert_Envelope.m ├── Homomorphic_Envelope_with_Hilbert.m ├── README.md ├── butterworth_high_pass_filter.m ├── butterworth_low_pass_filter.m ├── default_Springer_HSMM_options.m ├── example_data.mat ├── expand_qt.m ├── getDWT.m ├── getHeartRateSchmidt.m ├── getSpringerPCGFeatures.m ├── get_PSD_feature_Springer_HMM.m ├── get_duration_distributions.m ├── labelPCGStates.m ├── normalise_signal.m ├── runSpringerSegmentationAlgorithm.m ├── run_Example_Springer_Script.m ├── schmidt_spike_removal.m ├── trainBandPiMatricesSpringer.m ├── trainSpringerSegmentationAlgorithm.m ├── viterbiDecodePCG_Springer.m └── viterbi_Springer.c /Hilbert_Envelope.m: -------------------------------------------------------------------------------- 1 | % function [hilbert_envelope] = Hilbert_Envelope(input_signal, sampling_frequency,figures) 2 | % 3 | % This function finds the Hilbert envelope of a signal. This is taken from: 4 | % 5 | % Choi et al, Comparison of envelope extraction algorithms for cardiac sound 6 | % signal segmentation, Expert Systems with Applications, 2008 7 | % 8 | %% Inputs: 9 | % input_signal: the original signal 10 | % samplingFrequency: the signal's sampling frequency 11 | % figures: (optional) boolean variable to display a figure of both the 12 | % original and normalised signal 13 | % 14 | %% Outputs: 15 | % hilbert_envelope is the hilbert envelope of the original signal 16 | % 17 | % This code was developed by David Springer for comparison purposes in the 18 | % paper: 19 | % D. Springer et al., "Logistic Regression-HSMM-based Heart Sound 20 | % Segmentation," IEEE Trans. Biomed. Eng., In Press, 2015. 21 | % 22 | %% Copyright (C) 2016 David Springer 23 | % dave.springer@gmail.com 24 | % 25 | % This program is free software: you can redistribute it and/or modify 26 | % it under the terms of the GNU General Public License as published by 27 | % the Free Software Foundation, either version 3 of the License, or 28 | % any later version. 29 | % 30 | % This program is distributed in the hope that it will be useful, 31 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | % GNU General Public License for more details. 34 | % 35 | % You should have received a copy of the GNU General Public License 36 | % along with this program. If not, see . 37 | 38 | function hilbert_envelope = Hilbert_Envelope(input_signal, sampling_frequency,figures) 39 | 40 | if nargin <3, 41 | figures = 0; 42 | end 43 | 44 | 45 | hilbert_envelope = abs(hilbert(input_signal)); %find the envelope of the signal using the Hilbert transform 46 | 47 | if(figures) 48 | figure('Name', 'Hilbert Envelope'); 49 | plot(input_signal'); 50 | hold on; 51 | plot(hilbert_envelope,'r'); 52 | legend('Original Signal','Hilbert Envelope'); 53 | pause(); 54 | end -------------------------------------------------------------------------------- /Homomorphic_Envelope_with_Hilbert.m: -------------------------------------------------------------------------------- 1 | % function homomorphic_envelope = Homomorphic_Envelope_with_Hilbert(input_signal, sampling_frequency,lpf_frequency,figures) 2 | % 3 | % This function finds the homomorphic envelope of a signal, using the method 4 | % described in the following publications: 5 | % 6 | % S. E. Schmidt et al., ?Segmentation of heart sound recordings by a 7 | % duration-dependent hidden Markov model.,? Physiol. Meas., vol. 31, no. 4, 8 | % pp. 513?29, Apr. 2010. 9 | % 10 | % C. Gupta et al., ?Neural network classification of homomorphic segmented 11 | % heart sounds,? Appl. Soft Comput., vol. 7, no. 1, pp. 286?297, Jan. 2007. 12 | % 13 | % D. Gill et al., ?Detection and identification of heart sounds using 14 | % homomorphic envelogram and self-organizing probabilistic model,? in 15 | % Computers in Cardiology, 2005, pp. 957?960. 16 | % (However, these researchers found the homomorphic envelope of shannon 17 | % energy.) 18 | % 19 | % In I. Rezek and S. Roberts, ?Envelope Extraction via Complex Homomorphic 20 | % Filtering. Technical Report TR-98-9,? London, 1998, the researchers state 21 | % that the singularity at 0 when using the natural logarithm (resulting in 22 | % values of -inf) can be fixed by using a complex valued signal. They 23 | % motivate the use of the Hilbert transform to find the analytic signal, 24 | % which is a converstion of a real-valued signal to a complex-valued 25 | % signal, which is unaffected by the singularity. 26 | % 27 | % A zero-phase low-pass Butterworth filter is used to extract the envelope. 28 | %% Inputs: 29 | % input_signal: the original signal (1D) signal 30 | % samplingFrequency: the signal's sampling frequency (Hz) 31 | % lpf_frequency: the frequency cut-off of the low-pass filter to be used in 32 | % the envelope extraciton (Default = 8 Hz as in Schmidt's publication). 33 | % figures: (optional) boolean variable dictating the display of a figure of 34 | % both the original signal and the extracted envelope: 35 | % 36 | %% Outputs: 37 | % homomorphic_envelope: The homomorphic envelope of the original 38 | % signal (not normalised). 39 | % 40 | % This code was developed by David Springer for comparison purposes in the 41 | % paper: 42 | % D. Springer et al., ?Logistic Regression-HSMM-based Heart Sound 43 | % Segmentation,? IEEE Trans. Biomed. Eng., In Press, 2015. 44 | % 45 | %% Copyright (C) 2016 David Springer 46 | % dave.springer@gmail.com 47 | % 48 | % This program is free software: you can redistribute it and/or modify 49 | % it under the terms of the GNU General Public License as published by 50 | % the Free Software Foundation, either version 3 of the License, or 51 | % any later version. 52 | % 53 | % This program is distributed in the hope that it will be useful, 54 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 55 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 56 | % GNU General Public License for more details. 57 | % 58 | % You should have received a copy of the GNU General Public License 59 | % along with this program. If not, see . 60 | 61 | function homomorphic_envelope = Homomorphic_Envelope_with_Hilbert(input_signal, sampling_frequency,lpf_frequency,figures) 62 | 63 | if nargin <4, 64 | figures = 0; 65 | end 66 | if nargin <3, 67 | figures = 0; 68 | lpf_frequency = 8; 69 | end 70 | 71 | %8Hz, 1st order, Butterworth LPF 72 | [B_low,A_low] = butter(1,2*lpf_frequency/sampling_frequency,'low'); 73 | homomorphic_envelope = exp(filtfilt(B_low,A_low,log(abs(hilbert(input_signal))))); 74 | 75 | % Remove spurious spikes in first sample: 76 | homomorphic_envelope(1) = [homomorphic_envelope(2)]; 77 | 78 | if(figures) 79 | figure('Name', 'Homomorphic Envelope'); 80 | plot(input_signal); 81 | hold on; 82 | plot(homomorphic_envelope,'r'); 83 | legend('Original Signal','Homomorphic Envelope') 84 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Springer-Segmentation-Code 2 | Heart sound segmentation code based on duration-dependant HMM 3 | 4 | This is Matlab code to run the heart sound segmentation algorithm as outlined in the publication: 5 | 6 | D. Springer et al., "Logistic Regression-HSMM-based Heart Sound 7 | Segmentation," IEEE Trans. Biomed. Eng., In Press, 2015. 8 | 9 | The code includes the feature extraction, training of the duration-dependant HMM, 10 | and the decoding of the most likely sequence of states using an extended Viterbi algorithm. 11 | 12 | An example of the code at work can be seen in "run_Example_Springer_Script.m". 13 | 14 | Copyright (C) 2016 David Springer 15 | dave.springer@gmail.com 16 | 17 | This program is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU General Public License as published by 19 | the Free Software Foundation, either version 3 of the License, or 20 | any later version. 21 | 22 | This program is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with this program. If not, see . 29 | 30 | -------------------------------------------------------------------------------- /butterworth_high_pass_filter.m: -------------------------------------------------------------------------------- 1 | % function high_pass_filtered_signal = butterworth_high_pass_filter(original_signal,order,cutoff,sampling_frequency) 2 | % 3 | % High-pass filter a given signal using a forward-backward, zero-phase 4 | % butterworth filter. 5 | % 6 | %% INPUTS: 7 | % original_signal: The 1D signal to be filtered 8 | % order: The order of the filter (1,2,3,4 etc). NOTE: This order is 9 | % effectively doubled as this function uses a forward-backward filter that 10 | % ensures zero phase distortion 11 | % cutoff: The frequency cutoff for the high-pass filter (in Hz) 12 | % sampling_frequency: The sampling frequency of the signal being filtered 13 | % (in Hz). 14 | % figures (optional): boolean variable dictating the display of figures 15 | % 16 | %% OUTPUTS: 17 | % high_pass_filtered_signal: the high-pass filtered signal. 18 | % 19 | % This code is derived from the paper: 20 | % S. E. Schmidt et al., "Segmentation of heart sound recordings by a 21 | % duration-dependent hidden Markov model," Physiol. Meas., vol. 31, 22 | % no. 4, pp. 513-29, Apr. 2010. 23 | % 24 | % Developed by David Springer for comparison purposes in the paper: 25 | % D. Springer et al., ?Logistic Regression-HSMM-based Heart Sound 26 | % Segmentation,? IEEE Trans. Biomed. Eng., In Press, 2015. 27 | % 28 | %% Copyright (C) 2016 David Springer 29 | % dave.springer@gmail.com 30 | % 31 | % This program is free software: you can redistribute it and/or modify 32 | % it under the terms of the GNU General Public License as published by 33 | % the Free Software Foundation, either version 3 of the License, or 34 | % any later version. 35 | % 36 | % This program is distributed in the hope that it will be useful, 37 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 38 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 39 | % GNU General Public License for more details. 40 | % 41 | % You should have received a copy of the GNU General Public License 42 | % along with this program. If not, see . 43 | 44 | function high_pass_filtered_signal = butterworth_high_pass_filter(original_signal,order,cutoff,sampling_frequency, figures) 45 | 46 | if nargin < 5, 47 | figures = 0; 48 | end 49 | 50 | %Get the butterworth filter coefficients 51 | [B_high,A_high] = butter(order,2*cutoff/sampling_frequency,'high'); 52 | 53 | %Forward-backward filter the original signal using the butterworth 54 | %coefficients, ensuring zero phase distortion 55 | high_pass_filtered_signal = filtfilt(B_high,A_high,original_signal); 56 | 57 | if(figures) 58 | 59 | figure('Name','High-pass filter frequency response'); 60 | [sos,g] = zp2sos(B_high,A_high,1); % Convert to SOS form 61 | Hd = dfilt.df2tsos(sos,g); % Create a dfilt object 62 | h = fvtool(Hd); % Plot magnitude response 63 | set(h,'Analysis','freq') % Display frequency response 64 | 65 | figure('Name','Original vs. high-pass filtered signal'); 66 | plot(original_signal); 67 | hold on; 68 | plot(high_pass_filtered_signal,'r'); 69 | legend('Original Signal', 'High-pass filtered signal'); 70 | pause(); 71 | end 72 | 73 | -------------------------------------------------------------------------------- /butterworth_low_pass_filter.m: -------------------------------------------------------------------------------- 1 | % function low_pass_filtered_signal = butterworth_low_pass_filter(original_signal,order,cutoff,sampling_frequency, figures) 2 | % 3 | % Low-pass filter a given signal using a forward-backward, zero-phase 4 | % butterworth low-pass filter. 5 | % 6 | %% INPUTS: 7 | % original_signal: The 1D signal to be filtered 8 | % order: The order of the filter (1,2,3,4 etc). NOTE: This order is 9 | % effectively doubled as this function uses a forward-backward filter that 10 | % ensures zero phase distortion 11 | % cutoff: The frequency cutoff for the low-pass filter (in Hz) 12 | % sampling_frequency: The sampling frequency of the signal being filtered 13 | % (in Hz). 14 | % figures (optional): boolean variable dictating the display of figures 15 | % 16 | %% OUTPUTS: 17 | % low_pass_filtered_signal: the low-pass filtered signal. 18 | % 19 | % This code is derived from the paper: 20 | % S. E. Schmidt et al., "Segmentation of heart sound recordings by a 21 | % duration-dependent hidden Markov model," Physiol. Meas., vol. 31, 22 | % no. 4, pp. 513-29, Apr. 2010. 23 | % 24 | % Developed by David Springer for comparison purposes in the paper: 25 | % D. Springer et al., ?Logistic Regression-HSMM-based Heart Sound 26 | % Segmentation,? IEEE Trans. Biomed. Eng., In Press, 2015. 27 | % 28 | %% Copyright (C) 2016 David Springer 29 | % dave.springer@gmail.com 30 | % 31 | % This program is free software: you can redistribute it and/or modify 32 | % it under the terms of the GNU General Public License as published by 33 | % the Free Software Foundation, either version 3 of the License, or 34 | % any later version. 35 | % 36 | % This program is distributed in the hope that it will be useful, 37 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 38 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 39 | % GNU General Public License for more details. 40 | % 41 | % You should have received a copy of the GNU General Public License 42 | % along with this program. If not, see . 43 | 44 | function low_pass_filtered_signal = butterworth_low_pass_filter(original_signal,order,cutoff,sampling_frequency, figures) 45 | 46 | if nargin < 5, 47 | figures = 0; 48 | end 49 | 50 | %Get the butterworth filter coefficients 51 | [B_low,A_low] = butter(order,2*cutoff/sampling_frequency,'low'); 52 | 53 | if(figures) 54 | figure('Name','Low-pass filter frequency response'); 55 | [sos,g] = zp2sos(B_low,A_low,1); % Convert to SOS form 56 | Hd = dfilt.df2tsos(sos,g); % Create a dfilt object 57 | h = fvtool(Hd); % Plot magnitude response 58 | set(h,'Analysis','freq') % Display frequency response 59 | end 60 | 61 | 62 | %Forward-backward filter the original signal using the butterworth 63 | %coefficients, ensuring zero phase distortion 64 | low_pass_filtered_signal = filtfilt(B_low,A_low,original_signal); 65 | 66 | if(figures) 67 | figure('Name','Original vs. low-pass filtered signal'); 68 | plot(original_signal); 69 | hold on; 70 | plot(low_pass_filtered_signal,'r'); 71 | legend('Original Signal', 'Low-pass filtered signal'); 72 | pause(); 73 | end -------------------------------------------------------------------------------- /default_Springer_HSMM_options.m: -------------------------------------------------------------------------------- 1 | % function springer_options = default_Springer_HSMM_options() 2 | % 3 | % The default options to be used with the Springer segmentation algorithm. 4 | % USAGE: springer_options = default_Springer_HSMM_options 5 | % 6 | % Developed for use in the paper: 7 | % D. Springer et al., "Logistic Regression-HSMM-based Heart Sound 8 | % Segmentation," IEEE Trans. Biomed. Eng., In Press, 2015. 9 | % 10 | %% Copyright (C) 2016 David Springer 11 | % dave.springer@gmail.com 12 | % 13 | % This program is free software: you can redistribute it and/or modify 14 | % it under the terms of the GNU General Public License as published by 15 | % the Free Software Foundation, either version 3 of the License, or 16 | % any later version. 17 | % 18 | % This program is distributed in the hope that it will be useful, 19 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | % GNU General Public License for more details. 22 | % 23 | % You should have received a copy of the GNU General Public License 24 | % along with this program. If not, see . 25 | 26 | function springer_options = default_Springer_HSMM_options() 27 | 28 | %% The sampling frequency at which to extract signal features: 29 | springer_options.audio_Fs = 1000; 30 | 31 | %% The downsampled frequency 32 | %Set to 50 in Springer paper 33 | springer_options.audio_segmentation_Fs = 50; 34 | 35 | 36 | %% Tolerance for S1 and S2 localization 37 | springer_options.segmentation_tolerance = 0.1;%seconds 38 | 39 | %% Whether to use the mex code or not: 40 | % The mex code currently has a bug. This will be fixed asap. 41 | springer_options.use_mex = false; 42 | 43 | %% Whether to use the wavelet function or not: 44 | springer_options.include_wavelet_feature = false; 45 | 46 | -------------------------------------------------------------------------------- /example_data.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidspringer/Springer-Segmentation-Code/853cb535247dbea013798683ac343d9526aed973/example_data.mat -------------------------------------------------------------------------------- /expand_qt.m: -------------------------------------------------------------------------------- 1 | % function expanded_qt = expand_qt(original_qt, old_fs, new_fs, new_length) 2 | % 3 | % Function to expand the derived HMM states to a higher sampling frequency. 4 | % 5 | % Developed by David Springer for comparison purposes in the paper: 6 | % D. Springer et al., "Logistic Regression-HSMM-based Heart Sound 7 | % Segmentation," IEEE Trans. Biomed. Eng., In Press, 2015. 8 | % 9 | %% INPUTS: 10 | % original_qt: the original derived states from the HMM 11 | % old_fs: the old sampling frequency of the original_qt 12 | % new_fs: the desired sampling frequency 13 | % new_length: the desired length of the qt signal 14 | 15 | %% Outputs: 16 | % expanded_qt: the expanded qt, to the new FS and length 17 | % 18 | %% Copyright (C) 2016 David Springer 19 | % dave.springer@gmail.com 20 | % 21 | % This program is free software: you can redistribute it and/or modify 22 | % it under the terms of the GNU General Public License as published by 23 | % the Free Software Foundation, either version 3 of the License, or 24 | % any later version. 25 | % 26 | % This program is distributed in the hope that it will be useful, 27 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | % GNU General Public License for more details. 30 | % 31 | % You should have received a copy of the GNU General Public License 32 | % along with this program. If not, see . 33 | 34 | function expanded_qt = expand_qt(original_qt, old_fs, new_fs, new_length) 35 | 36 | original_qt = original_qt(:)'; 37 | expanded_qt = zeros(new_length,1); 38 | 39 | indeces_of_changes = find(diff(original_qt)); 40 | 41 | indeces_of_changes = [indeces_of_changes, length(original_qt)]; 42 | 43 | start_index = 0; 44 | for i = 1:length(indeces_of_changes) 45 | 46 | start_index; 47 | end_index = indeces_of_changes(i); 48 | 49 | mid_point = round((end_index - start_index)/2) + start_index; 50 | 51 | value_at_mid_point = original_qt(mid_point); 52 | 53 | expanded_start_index = round((start_index./old_fs).*new_fs) + 1; 54 | expanded_end_index = round((end_index./(old_fs)).*new_fs); 55 | 56 | if(expanded_end_index > new_length) 57 | expanded_end_index = new_length; 58 | end 59 | 60 | expanded_qt(expanded_start_index:expanded_end_index) = value_at_mid_point; 61 | 62 | start_index = end_index; 63 | end -------------------------------------------------------------------------------- /getDWT.m: -------------------------------------------------------------------------------- 1 | % function [cD cA] = getDWT(X,N,Name) 2 | % 3 | % finds the discrete wavelet transform at level N for signal X using the 4 | % wavelet specified by Name. 5 | % 6 | %% Inputs: 7 | % X: the original signal 8 | % N: the decomposition level 9 | % Name: the wavelet name to use 10 | % 11 | %% Outputs: 12 | % cD is a N-row matrix containing the detail coefficients up to N levels 13 | % cA is the same for the approximations 14 | 15 | % This code was developed by David Springer for comparison purposes in the 16 | % paper: 17 | % D. Springer et al., "Logistic Regression-HSMM-based Heart Sound 18 | % Segmentation," IEEE Trans. Biomed. Eng., In Press, 2015. 19 | % 20 | %% Copyright (C) 2016 David Springer 21 | % dave.springer@gmail.com 22 | % 23 | % This program is free software: you can redistribute it and/or modify 24 | % it under the terms of the GNU General Public License as published by 25 | % the Free Software Foundation, either version 3 of the License, or 26 | % any later version. 27 | % 28 | % This program is distributed in the hope that it will be useful, 29 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | % GNU General Public License for more details. 32 | % 33 | % You should have received a copy of the GNU General Public License 34 | % along with this program. If not, see . 35 | 36 | function [cD cA] = getDWT(X,N,Name) 37 | 38 | 39 | %No DWT available for Morlet - therefore perform CWT: 40 | if(strcmp(Name,'morl')) 41 | 42 | c = cwt(X,1:N,'morl'); 43 | 44 | cD = c; 45 | cA = c; 46 | else 47 | %Preform wavelet decomposition 48 | 49 | [c,l] = wavedec(X,N,Name); 50 | 51 | %Reorder the details based on the structure of the wavelet 52 | %decomposition (see help in wavedec.m) 53 | len = length(X); 54 | cD = zeros(N,len); 55 | for k = 1:N 56 | d = detcoef(c,l,k); 57 | d = d(:)'; 58 | d = d(ones(1,2^k),:); 59 | cD(k,:) = wkeep1(d(:)',len); 60 | end 61 | cD = cD(:); 62 | 63 | %Space cD according to spacing of floating point numbers: 64 | I = find(abs(cD)