function write_ann(recordName,HRVparams,annotator,ann,annType,subType,chan,num,comments) % % write_ann(recordName,HRVparams,annotator,ann,annType,subType,chan,num,comments) % % OVERVIEW: Writes data into a WFDB annotation file. The files will have % the same name is the recordName but with a 'annotator' % extension. You can use RDANN to verify that the write was % completed sucessfully. % % INPUT: % Required Parameters: % recorName % String specifying the name of the record % HRVparams % Struct with settings for output, generated by initialize_settings.m % annotator % String specifying the name of the annotation file to be generated % ann % Nx1 vector of integers indicating the time of the annotation, in % samples, with respect to the signals in recordName. The values of % ann are sample numbers (indices) with respect to the begining of the % record. % Optional Parameters: % annType % Nx1 vector of the chars or scalar describing annotation type. % Default is 'N'. % For a list of standard annotation codes used by PhyioNet, please see: % http://www.physionet.org/physiobank/annotations.shtml % subType % Nx1 vector of the ints or scalar describing annotation subtype. % Default is 0. % chan % Nx1 vector of the ints or scalar describing annotation CHAN. % Default is 0. % num % Nx1 vector of the ints or scalar describing annotation NUM. % Default is 0. % comments % Nx1 vector of the chars or scalar describing annotation comments. % Default is ''. % OUTPUT: % Binary (WFDB COMPATIBLE) or CSV formatted annotation file % % ORIGINAL SOURCE AND AUTHORS: % This script written by Qiao Li March 2,2017 % Dependent scripts written by various authors % (see scripts for details) % COPYRIGHT (C) 2016 % LICENSE: % This software is offered freely and without warranty under % the GNU (v3 or later) public license. See license file for % more information %% if nargin<4 display('At least four parameters: recordName,HRVparams,annotator,ann, were required.'); return; end if nargin<9 || isempty(comments) comments = repmat('',[length(ann) 1]); end if nargin<8 %num=0; num = zeros(length(ann), 1); end if nargin<7 %chan=0; chan = zeros(length(ann), 1); end if nargin<6 %subType = 0; subType = zeros(length(ann), 1); end if nargin<5 % annType='N'; annType = repmat('N',[length(ann), 1]); end %% Binary ATR Output if strcmp(HRVparams.output.ann_format,'binary') annfile=strcat(recordName, '.', annotator); ann_pre=0; byte_write=[]; for i=1:length(ann) % time from last ann anntime=uint16(ann(i)-ann_pre); % annType if length(annType)>=i annType_c=annType(i); else annType_c=annType(1); end typei=ann2int(annType_c); % short interval if anntime<=1023 % 2^10 - 1 byte1=uint8(bitand(anntime,255)); byte2=uint8(bitshift(anntime,-8))+bitshift(uint8(typei),2); byte_write=[byte_write;byte1;byte2]; % long interval else % 59, SKIP, the next 4 bytes are the interval byte1=uint8(bitand(0,255)); byte2=uint8(bitshift(0,-8))+bitshift(uint8(59),2); byte_write=[byte_write;byte1;byte2]; anntime_L=uint32(ann(i)-ann_pre); byte1=uint8(bitand(bitshift(anntime_L,-16),255)); byte2=uint8(bitand(bitshift(anntime_L,-24),255)); byte3=uint8(bitand(anntime_L,255)); byte4=uint8(bitand(bitshift(anntime_L,-8),255)); byte_write=[byte_write;byte1;byte2;byte3;byte4]; byte1=bitand(0,255); byte2=uint8(bitshift(0,-8))+bitshift(uint8(typei),2); byte_write=[byte_write;byte1;byte2]; end if length(subType)>=i if subType(i)~=0 % 61, SUB, I = annotation subtyp field for current annotation only; otherwise, assume subtyp = 0. if subType(i)>0 byte1=uint8(bitand(uint8(subType(i)),255)); % positive byte2=uint8(bitshift(subType(i),-8))+bitshift(uint8(61),2); else % negative byte1=uint8(bitand(uint8(subType(i)+1+255),255)); byte2=uint8(3+bitshift(uint8(61),2)); end byte_write=[byte_write;byte1;byte2]; end end if i==1 % first annotation if chan(i)~=0 % 62, CHN, I = annotation chan field for current and subsequent annotations; otherwise, assume previous chan (initially 0). if chan(i)>0 byte1=uint8(bitand(uint8(chan(i)),255)); byte2=uint8(bitshift(chan(i),-8))+bitshift(uint8(62),2); else byte1=uint8(bitand(uint8(chan(i)+1+255),255)); byte2=uint8(3+bitshift(uint8(62),2)); end byte_write=[byte_write;byte1;byte2]; end if num(i)~=0 % 60, NUM, I = annotation num field for current and subsequent annotations; otherwise, assume previous annotation num (initially 0). if num(i)>0 byte1=uint8(bitand(uint8(num(i)),255)); % ??? -/+ byte2=uint8(bitshift(num(i),-8))+bitshift(uint8(60),2); else byte1=uint8(bitand(uint8(num(i)+1+255),255)); byte2=uint8(3+bitshift(uint8(60),2)); end byte_write=[byte_write;byte1;byte2]; end else % the remains if length(chan)>=i if chan(i)~=chan(i-1) if chan(i)>=0 byte1=uint8(bitand(uint8(chan(i)),255)); % positive value byte2=uint8(bitshift(chan(i),-8))+bitshift(uint8(62),2); else % negative value, is there negative value for chan ??? byte1=uint8(bitand(uint8(chan(i)+1+255),255)); byte2=uint8(3+bitshift(uint8(62),2)); end byte_write=[byte_write;byte1;byte2]; end end if length(num)>=i if num(i)~=num(i-1) if num(i)>=0 byte1=uint8(bitand(uint8(num(i)),255)); % positive value byte2=uint8(bitshift(num(i),-8))+bitshift(uint8(60),2); else % negative value byte1=uint8(bitand(uint8(num(i)+1+255),255)); byte2=uint8(3+bitshift(uint8(60),2)); end byte_write=[byte_write;byte1;byte2]; end end end if length(comments)>=i % 63, AUX, I = number of bytes of auxiliary information (which is contained in the next I bytes); an extra null, not included in the byte count, is appended if I is odd. com_len=uint8(length(comments{i})); byte1=uint8(bitand(com_len,255)); byte2=uint8(bitshift(com_len,-8))+bitshift(uint8(63),2); byte_write=[byte_write;byte1;byte2]; for j=1:com_len byte_write=[byte_write;uint8(comments{i}(j))]; end if mod(com_len,2) byte_write=[byte_write;uint8(0)]; end end ann_pre=ann(i); end byte_write=[byte_write;uint8(0);uint8(0)]; fid=fopen(annfile,'w'); fwrite(fid,byte_write); fclose(fid); end %% CSV Output if strcmp(HRVparams.output.ann_format,'csv') filename = strcat(recordName, '.', annotator, '.csv'); % ann,annType,subType,chan,num,comments % Write annotations to .txt file in WFDB compatible format for i = 1:length(ann) fileID = fopen(filename,'a'); %fprintf(fileID, '\t%s %7d\t%c\t%5d%5d%5d\r\n',time_formatted,samples(i),ann(i),subType(i),chan(i),num(i)); fprintf(fileID,'%d', ann(i)); if length(annType) >= i fprintf(fileID,',%s',annType(i)); end if length(subType) >= i fprintf(fileID,',%d',subType(i)); end if length(chan) >= i fprintf(fileID,',%d',chan(i)); end if length(num) >= i fprintf(fileID,',%d',num(i)); end if length(comments) >= i fprintf(fileID,',%s',comments(i)); end fprintf(fileID,'\n'); fclose(fileID); end clear i end end % end write_ann function %% function typei=ann2int(ann_Type) % input: ann_Type, annotation type, char % output:typei, annotation code, integer Typestr='NLRaVFJASEj/Q~|sT*D"=pB^t+u?![]en@xf(`)''r'; codeint=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,39,40,40,41]; typei=codeint(strfind(Typestr,ann_Type)); end