function a=ats(a) %Reading Alive Technologies .ats files % ats; % a=ats('AT000083.ats') % a.noscaling=1 %use with large files to return uint8 % a.file='AT00083.ats' % a=ats(a) % %Based on Bluetooth Heart Monitor Data Format, August 2006 % Jussi.Virkkala@neuroupdate.com % 2007-10-21 Noscaling option, uint8 % 2007-10-19 Dialog, data block 0, extra header data, plot % 2007-08-15 First version, no GPS information? %File %2007-10-19 Filename as parameter if nargin==0,a='';end if isstr(a) | isempty(a), if isempty(a) [f p]=uigetfile('*.ats','Select Alivetec ats file'); a.file=[p f]; else a.file=a; end end f=fopen(a.file,'r','b'); %Header a.id=char(fread(f,5,'uint8'))'; if ~strcmp(a.id,['ATSF' char(0)]), %ATFS a=[a.file ', unknown ats header:' a.id]; fclose(f); return; end a.header=fread(f,1,'uint16'); a.channels=fread(f,1,'uint8'); a.blocks=fread(f,1,'uint32'); a.blocklength=fread(f,1,'uint16'); %date a.year=fread(f,1,'uint16'); a.month=fread(f,1,'uint8'); a.day=fread(f,1,'uint8'); %time a.hour=fread(f,1,'uint8'); a.minute=fread(f,1,'uint8'); a.second=fread(f,1,'uint8'); %reserved reserved=fread(f,107,'uint8'); %2007-10-19 If zero block, use file size to determine %if ~a.blocks, fseek(f,0,'eof'); s=ftell(f)-128-32*a.channels; a.blocks=fix(s/a.blocklength)-1; fseek(f,128,'bof'); %end %Channels %ECG 0xAA(170), Status 0x11(17), 2 Axis 0x55(85), 3 Axis 0x56(86) for i=1:a.channels, a.type(i)=fread(f,1,'uint8'); a.format(i)=fread(f,1,'uint8'); a.length(i)=fread(f,1,'uint16'); switch a.type(i) case 170 %ECG a.ecg=zeros(1,a.length(i)*a.blocks,'uint8'); switch a.format(i) case 1 a.ecg_sr=150; case 2 a.ecg_sr=300; otherwise a=[a.file ', unknown ecg format' int2str(a.format(i))]; end case 17 %Status a.but=zeros(a.length(i)/2,a.blocks,'uint8'); a.bat=a.but; case 85 %2 axes a.x=zeros(a.length(i)/2,a.blocks,'uint8'); a.y=a.x; case 86 %3 axes a.x=zeros(a.length(i)/3,a.blocks,'uint8'); a.y=a.x; a.z=a.x; otherwise a=[a.file ', unknown ats type:' int2str(a.type(i))]; fclose(f); return end reserved=fread(f,28,'uint8'); %5-32 end a.acc_sr=75; %2007-10-19 extra bytes fseek(f,a.header-128-32*a.channels,'cof'); extra=a.blocklength-sum(a.length); %Blocks for b=1:a.blocks, for i=1:a.channels, switch a.type(i) case 170 %ECG a.ecg((1:a.length(i))+(b-1)*a.length(i))=fread(f,a.length(i),'uint8'); case 17 %status d=fread(f,a.length(i),'uint8'); d=reshape(d,2,a.length(i)/2)'; a.but(:,b)=d(:,1); a.bat(:,b)=d(:,2); case 85 %2 axes d=fread(f,a.length(i),'uint8'); d=reshape(d,2,a.length(i)/2)'; a.x(:,b)=d(:,1); a.y(:,b)=d(:,2); case 86 %3 axes d=fread(f,a.length(i),'uint8'); d=reshape(d,3,a.length(i)/3)'; a.x(:,b)=d(:,1); a.y(:,b)=d(:,2); a.z(:,b)=d(:,3); end end %2007-10-19 Extra zeros ignored fseek(f,extra,'cof'); end fclose(f); %Scaling %2007-10-21 No scaling if ~isfield(a,'noscaling'), for i=1:a.channels, switch a.type(i) case 170 %ECG a.ecg=2*2.66*double(a.ecg(:)')/255-2.66; case 17 a.but=a.but(:); a.bat=a.bat(:)/2; case 85 a.x=2*2*double(a.x(:)')/255-2; a.y=2*2*double(a.y(:)')/255-2; case 86 a.x=2*2.7*double(a.x(:)')/255-2.7; a.y=2*2.7*double(a.y(:)')/255-2.7; a.z=2*2.7*double(a.z(:)')/255-2.7; end end else a.ecg=a.ecg(:); a.bat=a.bat/2; a.x=a.x(:)'; a.y=a.y(:)'; if isfield(a,'z'),a.z=a.z(:)';end end %2007-10-19 if nargout==0, te=(1:length(a.ecg))/a.ecg_sr; ta=(1:length(a.x))/a.acc_sr; if isfield(a,'z'), plot(te,a.ecg+3,'k',ta,a.x,'k',ta,a.y,'b',ta,a.z,'r'); else plot(te,a.ecg+3,'k',ta,a.x,'k',ta,a.y,'b') end xlabel('s'); ylabel('Ecg+3 mV, x (black), y (blue), z (red) g') end %end of ats.m