PhysioNet Cardiovascular Signal Toolbox 1.0.0
(9,281 bytes)
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