% [annot sqimatrix template valid] = PPG_SQI_buf(wave,anntime,template_ahead,windowlen,Fs) % % PPG_SQI.m - PPG SQI based on beat template correlation. % (as an advice, the algorithm get 30 beats at each call and run in loop) % by Qiao Li 30 Mar 2011 % % input: % wave: PPG data; % anntime: PPG annotation time (samples), read from ple annot file, % But the ann-time is the OFFSET based on wave(1) % template: Last PPG beat template % windowlen: length of window to calculate template(default: 30s) % Fs : sampling frequency (default Fs=125Hz) % output: % annot: ppg sqi annotation % E - excellent beat; % A - acceptable beat; % Q - unacceptable beat % sqimatrix: ppg sqi matrix % [N,1]: SQI based on Direct compare % [N,2]: SQI based on Linear resampling % [N,3]: SQI based on Dynamic time warping % [N,4]: SQI based on Clipping detection % template: Current PPG beat template % valid: 1 or greater for valid template, % 0 for invalid template % % LICENSE: % This software is offered freely and without warranty under % the GNU (v3 or later) public license. See license file for % more information % % 03-03-2017 % Edits by Adriana Vest % - Changed output variable annot from numeric to cell to preserve % characters % - Style changes to align loops and conditional statements % % 12-01-2017 Modified by Giulia Da Poian: sampling frequency as input % parameter instead of fixed fs = 125 % % 12-19-2017 Modified by Giulia Da Poian: replaced dp_dtw with dpfast function [annot sqimatrix template valid] = PPG_SQI_buf(wave,anntime,template,windowlen,Fs) if nargin < 5 Fs = 125; end if nargin < 4 || isempty(windowlen) windowlen=30*Fs; end if nargin < 3 || isempty(template) template=[]; end if nargin < 2 sprintf('Error: must provide wave, anntime'); annot=[]; sqimatrix=[]; template=[]; valid=0; return; end annot=[]; sqimatrix=[]; % get PPG template [t t2 v]=template_pleth(wave(1:min(windowlen,length(wave))), anntime(find(anntime1 t=t2; end % Calculate the PLA of template for dynamic time warping d1=t; d1=(d1-min(d1))/(max(d1)-min(d1)).*100; [y1 pla1]=PLA(d1,1,1); % Main Loop for j=1:length(anntime)-1 %% SQI1: Direct compare % Calculate correlation coefficients based on the template % length beatbegin=anntime(j); beatend=anntime(j+1); % 07/11/2011 ADD max beat length <= 3s detection if beatend-beatbegin>3*Fs beatend=beatbegin+3*Fs; end templatelength=length(t); if beatbegin+templatelength-1 > length(wave) || beatend > length(wave) || beatbegin < 1 continue; end currentb = j; cc = corrcoef(t,wave(beatbegin:beatbegin+templatelength-1)); c1(j) = cc(1,2); if (c1(j)<0) c1(j)=0; end sqimatrix(currentb,1)=int8(c1(j)*100); %% SQI2: Linear resampling % Calculate correlation coefficients based on the % linear resampling (interp1) y=interp1(1:beatend-beatbegin, wave(beatbegin:beatend-1),1:(beatend-beatbegin-1)/(templatelength-1):(beatend-beatbegin),'spline'); y(isnan(y))=0; cc=corrcoef(t,y); c2(j)=cc(1,2); if (c2(j)<0) c2(j)=0; end sqimatrix(currentb,2)=int8(c2(j)*100); %% SQI3: Dynamic Time Warping % Calculate correlation coefficients based on the dynamic time % warping d2=wave(beatbegin:beatend-1); % if beat too long, set SQI = 0; if (length(d2)>length(d1)*10) c3(j)=0; else d2=(d2-min(d2))/(max(d2)-min(d2)).*100; [y2 pla2]=PLA(d2,1,1); [w ta tb] = simmx_dtw(y1,pla1,y2,pla2); [p,q,Dm] = dpfast(w); [ym1, ym2, yout1] = draw_dtw(y1,pla1,p,y2,pla2,q); cc=corrcoef(y1,ym2); c3(j)=cc(1,2); if (c3(j)<0) c3(j)=0; end end sqimatrix(currentb,3)=int8(c3(j)*100); %% SQI4: Clipping detection d2=wave(beatbegin:beatend-1); y=diff(d2); clipthreshold=0.5; c4(j)=int8(length(find(abs(y)>clipthreshold))/length(y)*100); sqimatrix(currentb,4)=c4(j); %% SQI: Combined sqibuf=[sqimatrix(currentb,1) sqimatrix(currentb,2) sqimatrix(currentb,3) sqimatrix(currentb,4)]; if min(sqibuf)>=90 annot{currentb}='E'; % Excellent else if length(find(sqibuf>=90))>=3 || (median(sqibuf(1:3))>=80 && sqibuf(1)>=50 && sqibuf(4)>=70) || min(sqibuf)>=70 annot{currentb}='A'; % Acceptable else annot{currentb}='Q'; % Unacceptable end end end end template=t; valid=v;