function [position0,position,messages]= delineateP3D(heasig,w1,w2,w3,timenew,position0,position,intervalo,samp,ultimo_anot,messages) % % [position0,position,A,V,A2,V2]=% delineateP3D(heasig,w1,w2,w3,intreg,scale,timenew,position0,position,intervalo,samp,figuresoff,sig) % % Input Parameters: % heasig: struct vector with header information % w1: matrix with WT scales 1 to 5 for lead 1 % w2: matrix with WT scales 1 to 5 for lead 2 % w3: matrix with WT scales 1 to 5 for lead 1 % intreg: interval to be considered in fitting the optimal direction % scale to use in delineation % timenew: QRS times in inedexes refering the interval included in the current excerpt (borders excluded) % position0: struct vector with the detected points for 3D multilead step1 % position: struct vector with the detected points for 3D multilead step2 % position1: struct vector with the detected points for lead1 - to be replaced for multilead marks % samp: samples included in the current excerpt (borders excluded) % intervalo: numeration of the beats processed in this segment % %Output Parameters: % actualized parameters: position, position0 % A - points of fitted lines in step 1 % A2 - points of fitted lines in step 2 % V- vectors director to the fitted line % V2- vectors director to the fitted line % % Rute Almeida: trabalho de doutoramento % Last update: 07FEB2012 Rute Almeida % % MATLAB Version 6.5.0.180913a (R13) if nargin<11 messages = new_empty_mesg; elseif nargin<10 messages.errors=[messages.errors {'Fatal error in wavedet_3D\delineate3D: not enough inputs.'}]; warning(char(messages.errors(end))) messages.errors_desc=[messages.errors_desc 'Mandatory inputs not defined.']; messages.status=0; return end if ~isfield(messages,'setup'), messages.setup.wavedet=[]; end if ~isfield(messages,'errors'), messages.errors=[]; end if ~isfield(messages,'errors_desc'), messages.errors_desc=[]; end if ~isfield(messages,'warnings'), messages.warnings=[]; end if isfield(messages,'status') if messages.status~=1 messages.warnings=[messages.warnings {['Initial status=' num2str(messages.status) '. status changed to 1']}]; end end messages.status=1; global recursioncount OPT %Threshols for onset and offset detection %%%%%% Constants and Thresholds !!!!!!!!!!!!!!!!!!!!!!!!! if ~isfield(messages.setup.wavedet,'inivent_tol_P') messages.setup.wavedet.inivent_tol_P = 0.34; end if ~isfield(messages.setup.wavedet,'finvent_tol_P') messages.setup.wavedet.finvent_tol_P = 0.1; end if ~isfield(messages.setup.wavedet,'P_CSE_tol') messages.setup.wavedet.P_CSE_tol=10.2*2/1000; % based on CSE tolerance end if ~isfield(messages.setup.wavedet,'Pconvergence_crit') messages.setup.wavedet.Pconvergence_crit=0; % 1 maks are acepted as the same if they difer by Tconvergence_crit end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% A2=[]; if ~isempty(w3) V=NaN*ones(size(timenew,2),3); A=NaN*ones(size(timenew,2),3); else V=NaN*ones(size(timenew,2),2); A=NaN*ones(size(timenew,2),2); end V2=[]; intervalo=intervalo(1):intervalo(end); for i=1:size(timenew,2) if ~isnan(position.QRSon(i+intervalo(1)-1)) qrson = position.QRSon(i+intervalo(1)-1)-samp(1)+1; else qrson = timenew(i) - messages.setup.wavedet.finvent_tol_P*messages.setup.wavedet.freq; end ultimo_anot = ultimo_anot - samp(1)+1; % last anotation of the previous segment can overlap with the present one if (i==1 && ultimo_anot>=1), % Protection in case it is the first beat begwin = max([1 qrson-round(messages.setup.wavedet.inivent_tol_P*messages.setup.wavedet.freq)+1 ultimo_anot+1]); else begwin = max(1, qrson-round(messages.setup.wavedet.inivent_tol_P*messages.setup.wavedet.freq)+1); end endwin = qrson- round(messages.setup.wavedet.finvent_tol_P*messages.setup.wavedet.freq)+1; if begwin>=endwin % empty search window: ultimo_anot should be too close to qrson position.Ptipoon(intervalo(i))=NaN; position.Ppicon(intervalo(i))=NaN; position.PscalePon(intervalo(i))=NaN; position.Pon(intervalo(i))=NaN; recursioncount.Pon(intervalo(i))=NaN; position.contadorPon(intervalo(i))=NaN; position.PscalePoff(intervalo(i))=NaN; position.Ppicoff(intervalo(i))=NaN; position.Poff(intervalo(i))=NaN; position.Ptipooff(intervalo(i))=NaN; recursioncount.Poff(intervalo(i))=NaN; position.contadorPoff(intervalo(i))=NaN; %Rute position.P(intervalo(i))=NaN; else scale=4; if ~isempty(w3) pontos=[w1(begwin:min(endwin,length(w1)),scale) w2(begwin:min(endwin,length(w2)),scale) w3(begwin:min(endwin,length(w3)),scale)]; else pontos=[w1(begwin:min(endwin,length(w1)),scale) w2(begwin:min(endwin,length(w2)),scale)]; end weight=ones(size(pontos,1),1); [a,v] = optimline(pontos, weight,OPT); A(i,:)=a; V(i,:)=v; %WT projected: from the previous QRS complex to the following QRS complex newleadbeat=[]; if ~isempty(w3) if i>1, interval=timenew(i-1):timenew(i); else % if first beat of the segment interval=1:timenew(i); end newleadbeat(interval,3)=(w1(interval,3).*v(1)+w2(interval,3)*v(2)+w3(interval,3)*v(3))./norm(v); %#ok newleadbeat(interval,4)=(w1(interval,4).*v(1)+w2(interval,4)*v(2)+w3(interval,4)*v(3))./norm(v); %#ok newleadbeat(interval,5)=(w1(interval,5).*v(1)+w2(interval,5)*v(2)+w3(interval,5)*v(3))./norm(v); %#ok %signew(interval)=(sig(interval,1).*v(1)+sig(interval,2)*v(2)+sig(interval,3)*v(3))./norm(v); else if i>1, interval=timenew(i-1):timenew(i); else % if first beat of the segment interval=1:timenew(i); end % newleadbeat=NaN*ones(length(interval),5); newleadbeat(:,3)=(w1(interval,3).*v(1)+w2(timenew(i):timenew(i+1),3)*v(2))./norm(v); newleadbeat(:,4)=(w1(interval,4).*v(1)+w2(timenew(i):timenew(i+1),4)*v(2))./norm(v); newleadbeat(:,5)=(w1(interval,5).*v(1)+w2(timenew(i):timenew(i+1),5)*v(2))./norm(v); %signew=(sig(timenew(i):timenew(i+1),1).*v(1)+sig(timenew(i):timenew(i+1),2)*v(2))./norm(v); end if i>1, pos.qrs=position.qrs([i-1 i]); pos.QRSon=position.QRSon([i-1 i]); pos.QRSoff=position.QRSoff([i-1 i]); pos.Toff=position.Toff([i-1 i]); [pos,picon,picoff]= pwavef(heasig,samp,timenew([i i]),position,newleadbeat,[intervalo(i) intervalo(i)],ultimo_anot,messages); else pos.qrs=position.qrs(i); pos.QRSon=position.QRSon(i); pos.QRSoff=position.QRSoff(i); pos.Toff=position.Toff(i); [pos,picon,picoff]= pwavef(heasig,samp,timenew(i),position,newleadbeat,[intervalo(i) intervalo(i)] ,ultimo_anot,messages); end position0.Pscale(intervalo(i))=pos.Pscale(intervalo(i)); position0.Pon(intervalo(i))=pos.Pon(intervalo(i)); position0.Poff(intervalo(i))=pos.Poff(intervalo(i)); position0.Ptipo(intervalo(i))=pos.Ptipo(intervalo(i)); position0.direccionPonopt(:,intervalo(i))=NaN*ones(size(intervalo(i))); %position0.P(intervalo(i))=pos.P(intervalo(i)); %position0.Pprima(intervalo(i))=pos.Pprima(intervalo(i)); %%%%% P wave onset if ~isnan(picon) begaux=max([(position0.Pon(intervalo(i))-samp(1)+1-round(messages.setup.wavedet.P_CSE_tol*messages.setup.wavedet.freq)) 1]); if ~isempty(w3) pontos2on=[w1(begaux:picon,scale) w2(begaux:picon,scale) w3(begaux:picon,scale)]; else pontos2on=[w1(begaux:picon,scale) w2(begaux:picon,scale)]; end if size(pontos2on,1)<=1 % unable to do another step: empty search window position.contadorPon(intervalo(i))=-1; position.PscalePon(intervalo(i))=position0.Pscale(intervalo(i)); position.Pon(intervalo(i))=position0.Pon(intervalo(i)); position.Ppicon=picon+samp(1)-1; %position.P(intervalo(i))= position0.P(intervalo(i)); %position.Pprima(intervalo(i))=position0.Pprima(intervalo(i)); position.direccionPonopt(intervalo(i),:)=V(end,:)'; position.Ptipoon(intervalo(i))=position0.Ptipo(intervalo(i)); else weight2=ones(size(pontos2on,1),1); [a,v] = optimline(pontos2on, weight2,OPT); A2=[A2;a]; %#ok V2=[V2;v]; %#ok newleadbeat2on = []; if ~isempty(w3) newleadbeat2on(interval,3)=(w1(interval,3).*v(1)+w2(interval,3)*v(2)+w3(interval,3)*v(3))./norm(v);%#ok newleadbeat2on(interval,4)=(w1(interval,4).*v(1)+w2(interval,4)*v(2)+w3(interval,4)*v(3))./norm(v);%#ok newleadbeat2on(interval,5)=(w1(interval,5).*v(1)+w2(interval,5)*v(2)+w3(interval,5)*v(3))./norm(v);%#ok % signew2on(interval)=(sig(interval,1).*v(1)+sig(interval,2)*v(2)+sig(interval,3)*v(3))./norm(v); else newleadbeat2on(interval,3)=(w1(interval,3).*v(1)+w2(timenew(i):timenew(i+1),3)*v(2))./norm(v);%#ok newleadbeat2on(interval,4)=(w1(interval,4).*v(1)+w2(timenew(i):timenew(i+1),4)*v(2))./norm(v);%#ok newleadbeat2on(interval,5)=(w1(interval,5).*v(1)+w2(timenew(i):timenew(i+1),5)*v(2))./norm(v);%#ok %signew2on(interval)=(sig(timenew(i):timenew(i+1),1).*v(1)+sig(timenew(i):timenew(i+1),2)*v(2))./norm(v); end if i>1, [pos2,picon2,picoff2]= pwavef(heasig,samp,timenew([i i]),pos,newleadbeat2on,[intervalo(i) intervalo(i)],ultimo_anot,messages); %#ok else [pos2,picon2,picoff2]= pwavef(heasig,samp,timenew(i),pos,newleadbeat2on,[intervalo(i) intervalo(i)] ,ultimo_anot,messages); %#ok end piconall=[picon picon2]; if isnan(picon2) amppiconall=[abs(newleadbeat(picon,scale)) NaN]; else amppiconall=[abs(newleadbeat(picon,scale)) abs(newleadbeat2on(picon2,scale))]; end if (amppiconall(end)messages.setup.wavedet.Pconvergence_crit) && (amppiconall(end)>amppiconall(end-1)) position.contadorPon(intervalo(i))=position.contadorPon(intervalo(i))+1; begaux=max([(position0.Pon(intervalo(i))-samp(1)+1-round(messages.setup.wavedet.P_CSE_tol*messages.setup.wavedet.freq)) 1]); if ~isempty(w3) pontosnewon=[w1( begaux:piconall(end),scale) w2( begaux:piconall(end),scale) w3( begaux:piconall(end),scale)]; else pontosnewon=[w1(begaux:piconall(end),scale) w2( begaux:piconall(end),scale)]; end if size(pontosnewon,1)<=1 % unable to do another step: empty search window posnewon.Pon(intervalo(i))=newPon(end-1); % previous step posnewon.Pscale(intervalo(i))=pos2.Pscale(intervalo(i)); posnewon.Ptipo(intervalo(i))=pos2.Ptipo(intervalo(i)); position.contadorPon(intervalo(i))=position.contadorPon(intervalo(i))-1; piconall=[piconall NaN]; %#ok amppiconall=[amppiconall NaN]; %#ok else weight2=ones(size(pontosnewon,1),1); [a,v] = optimline(pontosnewon, weight2,OPT); A2=[A2;a]; %#ok V2=[V2;v]; %#ok newleadbeatnewon = []; if ~isempty(w3) % newleadbeatnewon=NaN*ones(interval(end),5); newleadbeatnewon(interval,3)=(w1(interval,3).*v(1)+w2(interval,3)*v(2)+w3(interval,3)*v(3))./norm(v);%#ok newleadbeatnewon(interval,4)=(w1(interval,4).*v(1)+w2(interval,4)*v(2)+w3(interval,4)*v(3))./norm(v);%#ok newleadbeatnewon(interval,5)=(w1(interval,5).*v(1)+w2(interval,5)*v(2)+w3(interval,5)*v(3))./norm(v);%#ok %signewon(interval)=(sig(interval,1).*v(1)+sig(interval,2)*v(2)+sig(interval,3)*v(3))./norm(v); else % newleadbeatnewon=NaN*ones(interval(end),5); newleadbeatnewon(interval,3)=(w1(interval,3).*v(1)+w2(timenew(i):timenew(i+1),3)*v(2))./norm(v);%#ok newleadbeatnewon(interval,4)=(w1(interval,4).*v(1)+w2(timenew(i):timenew(i+1),4)*v(2))./norm(v);%#ok newleadbeatnewon(interval,5)=(w1(interval,5).*v(1)+w2(timenew(i):timenew(i+1),5)*v(2))./norm(v);%#ok %signewon(interval)=(sig(timenew(i):timenew(i+1),1).*v(1)+sig(timenew(i):timenew(i+1),2)*v(2))./norm(v); end if i>1, [posnewon,piconnew,picoffnew]= pwavef(heasig,samp,timenew([i i]),pos,newleadbeatnewon,[intervalo(i) intervalo(i)],ultimo_anot,messages); %#ok else [posnewon,piconnew,picoffnew]= pwavef(heasig,samp,timenew(i),pos,newleadbeatnewon,[intervalo(i) intervalo(i)] ,ultimo_anot,messages); %#ok end newPon=[newPon posnewon.Pon(intervalo(i))]; %#ok if isnan(piconnew) amppiconall=[amppiconall NaN]; %#ok else amppiconall=[amppiconall abs(newleadbeatnewon(piconnew,scale))]; %#ok end piconall=[piconall piconnew]; %#ok if isnan(posnewon.Pon(intervalo(i))) || (amppiconall(end)1 end %while position.PscalePon(intervalo(i))=posnewon.Pscale(intervalo(i)); position.Pon(intervalo(i))=posnewon.Pon(intervalo(i)); position.Ptipoon(intervalo(i))=posnewon.Ptipo(intervalo(i)); end % more steps end %size(pontosnewon,1)>1 else % isnan(picon) position.Ptipoon(intervalo(i))=NaN; position.Ppicon(intervalo(i))=NaN; position.PscalePon(intervalo(i))=NaN; position.Pon(intervalo(i))=NaN; recursioncount.Pon(intervalo(i))=NaN; position.contadorPon(intervalo(i))=NaN; %Rute end %%%%%% P wave onset %%%%% P wave end if ~isnan(picoff) endaux=min([(position0.Poff(intervalo(i))-samp(1)+1+round(messages.setup.wavedet.P_CSE_tol*messages.setup.wavedet.freq)) length(w1)]); if ~isempty(w3) pontos2off=[w1(picoff:endaux,scale) w2(picoff:endaux,scale) w3(picoff:endaux,scale)]; else pontos2off=[w1(picoff:endaux,scale) w2(picoff:endaux,scale)]; end if size(pontos2off,1)<=1 % unable to do another step: empty search window position.contadorPoff(intervalo(i))=-1; position.PscalePoff(intervalo(i))=position0.Pscale(intervalo(i)); position.Poff(intervalo(i))=position0.Poff(intervalo(i)); position.Ppicoff=picoff+samp(1)-1; %position.P(intervalo(i))= position0.P(intervalo(i)); %position.Pprima(intervalo(i))=position0.Pprima(intervalo(i)); position.direccionPoffopt(:,intervalo(i))=V(end,:); position.Ptipooff(intervalo(i))=position0.Ptipo(intervalo(i)); else weight2=ones(size(pontos2off,1),1); [a,v] = optimline(pontos2off, weight2,OPT); A2=[A2;a]; %#ok V2=[V2;v]; %#ok newleadbeat2off = []; if ~isempty(w3) % newleadbeat2off=NaN*ones(interval(end),5); newleadbeat2off(interval,3)=(w1(interval,3).*v(1)+w2(interval,3)*v(2)+w3(interval,3)*v(3))./norm(v);%#ok newleadbeat2off(interval,4)=(w1(interval,4).*v(1)+w2(interval,4)*v(2)+w3(interval,4)*v(3))./norm(v);%#ok newleadbeat2off(interval,5)=(w1(interval,5).*v(1)+w2(interval,5)*v(2)+w3(interval,5)*v(3))./norm(v);%#ok %signew2off(interval)=(sig(interval,1).*v(1)+sig(interval,2)*v(2)+sig(interval,3)*v(3))./norm(v); else % newleadbeat2off=NaN*ones(interval(end),5); newleadbeat2off(interval,3)=(w1(interval,3).*v(1)+w2(timenew(i):timenew(i+1),3)*v(2))./norm(v);%#ok newleadbeat2off(interval,4)=(w1(interval,4).*v(1)+w2(timenew(i):timenew(i+1),4)*v(2))./norm(v);%#ok newleadbeat2off(interval,5)=(w1(interval,5).*v(1)+w2(timenew(i):timenew(i+1),5)*v(2))./norm(v);%#ok %signew2off(interval)=(sig(timenew(i):timenew(i+1),1).*v(1)+sig(timenew(i):timenew(i+1),2)*v(2))./norm(v); end if i>1, [pos2off,picon2off,picoff2]= pwavef(heasig,samp,timenew([i i]),pos,newleadbeat2off,[intervalo(i) intervalo(i)],ultimo_anot,messages); %#ok else [pos2off,picon2off,picoff2]= pwavef(heasig,samp,timenew(i),pos,newleadbeat2off,[intervalo(i) intervalo(i)] ,ultimo_anot,messages); %#ok end picoffall=[picoff picoff2]; if isnan(picoff2) amppicoffall=[abs(newleadbeat(picoff,scale)) NaN]; else amppicoffall=[abs(newleadbeat(picoff,scale)) abs(newleadbeat2off(picoff2,scale))]; end if (amppicoffall(end)messages.setup.wavedet.Pconvergence_crit ) && (amppicoffall(end)>amppicoffall(end-1)) position.contadorPoff(intervalo(i))=position.contadorPoff(intervalo(i))+1; endaux=min([(position0.Poff(intervalo(i))-samp(1)+1+round(messages.setup.wavedet.P_CSE_tol*messages.setup.wavedet.freq)) length(w1)]); if ~isempty(w3) pontosnewoff=[w1(picoffall(end):endaux,scale) w2(picoffall(end):endaux,scale) w3(picoffall(end):endaux,scale)]; else pontosnewoff=[w1(picoffall(end):endaux,scale) w2(picoffall(end):endaux,scale)]; end if size(pontosnewoff,1)<=1 % unable to do another step: empty search window posnewoff.Poff(intervalo(i))=newPoff(end-1); % previous step posnewoff.Pscale(intervalo(i))=pos2off.Pscale(intervalo(i)); posnewoff.Ptipo(intervalo(i))=pos2off.Ptipo(intervalo(i)); %posnew.P=pos2off.P; %posnew.Pprima=pos2off.Pprima; position.contadorPoff(intervalo(i))=position.contadorPoff(intervalo(i))-1; picoffall=[picoffall NaN]; %#ok amppicoffall=[amppicoffall NaN]; %#ok else weight2=ones(size(pontosnewoff,1),1); [a,v] = optimline(pontosnewoff, weight2,OPT); A2=[A2;a]; %#ok V2=[V2;v]; %#ok newleadbeatnewoff = []; if ~isempty(w3) %newleadbeatnewoff=NaN*ones(interval(end),5); newleadbeatnewoff(interval,3)=(w1(interval,3).*v(1)+w2(interval,3)*v(2)+w3(interval,3)*v(3))./norm(v);%#ok newleadbeatnewoff(interval,4)=(w1(interval,4).*v(1)+w2(interval,4)*v(2)+w3(interval,4)*v(3))./norm(v);%#ok newleadbeatnewoff(interval,5)=(w1(interval,5).*v(1)+w2(interval,5)*v(2)+w3(interval,5)*v(3))./norm(v);%#ok %signewoff(interval)=(sig(interval,1).*v(1)+sig(interval,2)*v(2)+sig(interval,3)*v(3))./norm(v); else %newleadbeatnewoff=NaN*ones(interval(end),5); newleadbeatnewoff(interval,3)=(w1(interval,3).*v(1)+w2(timenew(i):timenew(i+1),3)*v(2))./norm(v);%#ok newleadbeatnewoff(interval,4)=(w1(interval,4).*v(1)+w2(timenew(i):timenew(i+1),4)*v(2))./norm(v);%#ok newleadbeatnewoff(interval,5)=(w1(interval,5).*v(1)+w2(timenew(i):timenew(i+1),5)*v(2))./norm(v);%#ok %signewoff(interval)=(sig(timenew(i):timenew(i+1),1).*v(1)+sig(timenew(i):timenew(i+1),2)*v(2))./norm(v); end if i>1, [posnewoff,piconnew,picoffnew]= pwavef(heasig,samp,timenew([i i]),pos,newleadbeatnewoff,[intervalo(i) intervalo(i)],ultimo_anot,messages); %#ok else [posnewoff,piconnew,picoffnew]= pwavef(heasig,samp,timenew(i),pos,newleadbeatnewoff,[intervalo(i) intervalo(i)] ,ultimo_anot,messages); %#ok end newPoff=[newPoff posnewoff.Poff(intervalo(i))]; %#ok if isnan(picoffnew) amppicoffall=[amppicoffall NaN]; %#ok else amppicoffall=[amppicoffall abs(newleadbeatnewoff(picoffnew,scale))]; %#ok end picoffall=[picoffall picoffnew]; %#ok if isnan(posnewoff.Poff(intervalo(i))) || (amppicoffall(end)1 end %while position.PscalePoff(intervalo(i))=posnewoff.Pscale(intervalo(i)); position.Poff(intervalo(i))=posnewoff.Poff(intervalo(i)); position.Ptipooff(intervalo(i))=posnewoff.Ptipo(intervalo(i)); % position.P(intervalo(i))= posnewoff.P(intervalo(i)); % position.Pprima(intervalo(i))=posnewoff.Pprima(intervalo(i)); end % more steps end %size(pontosnewoff,1)>1 else % isnan(picoff) position.PscalePoff(intervalo(i))=NaN; position.Ppicoff(intervalo(i))=NaN; position.Poff(intervalo(i))=NaN; position.Ptipooff(intervalo(i))=NaN; %position.P(intervalo(i))=NaN; %position.Pprima(intervalo(i))=NaN; recursioncount.Poff(intervalo(i))=NaN; position.contadorPoff(intervalo(i))=NaN; %Rute end %%%%%% P wave end %P peak if ~isnan(position.Ppicon(intervalo(i))) && ~isnan(position.Ppicoff(intervalo(i))) && position.Ppicon(intervalo(i)) % main P peak position.P(intervalo(i))=m2+position.Ppicon(intervalo(i)); else position.P(intervalo(i))=position0.P(intervalo(i)); end %% %writennot protection: at least one sample between peak and border if (position.P(intervalo(i))-position.Pon(intervalo(i)))<1 position.P(intervalo(i))=NaN; end if (position.Poff(intervalo(i))-position.P(intervalo(i)))<1 position.P(intervalo(i))=NaN; end clear pos pos2 pontos pontos2on pontos2off posnew pos2off posnewoff end end % for