TEAP (Toolbox for Emotion Analysis using Physiological Signals) doc
openxml.m
Go to the documentation of this file.
1 function [HDR]=openxml(arg1,CHAN,arg4,arg5,arg6)
2 % OPENXML reads XML files and tries to extract biosignal data
3 %
4 % This is an auxilary function to SOPEN.
5 % Use SOPEN instead of OPENXML.
6 %
7 
8 %
9 % HDR = openxml(HDR);
10 %
11 % HDR contains the Headerinformation and internal data
12 %
13 % see also: SOPEN, SREAD, SSEEK, STELL, SCLOSE, SWRITE, SEOF
14 
15 
16 % This program is free software; you can redistribute it and/or
17 % modify it under the terms of the GNU General Public License
18 % as published by the Free Software Foundation; either version 3
19 % of the License, or (at your option) any later version.
20 
21 % $Id: openxml.m 2205 2009-10-27 12:18:15Z schloegl $
22 % Copyright 2006,2007,2008 by Alois Schloegl <a.schloegl@ieee.org>
23 % This is part of the BIOSIG-toolbox http://biosig.sf.net/
24 
25 if ischar(arg1);
26  HDR.FileName = arg1;
27  HDR.FILE.PERMISSION = 'r';
28 else
29  HDR = arg1;
30 end;
31 
32 %if strncmp(HDR.TYPE,'XML',3),
33 % if any(HDR.FILE.PERMISSION=='r'),
34  fid = fopen(HDR.FileName,HDR.FILE.PERMISSION,'ieee-le');
35  s = char(fread(fid,[1,1024],'char'));
36  if all(s(1:2)==[255,254]) & all(s(4:2:end)==0)
37  HDR.TYPE='XML-UTF16';
38  elseif ~isempty(findstr(char(s),'?xml version'))
39  HDR.TYPE='XML-UTF8';
40  end;
41  fseek(fid,0,'bof');
42  if strcmp(HDR.TYPE,'XML-UTF16'),
43  magic = char(fread(fid,1,'uint16'));
44  HDR.XML = char(fread(fid,[1,inf],'uint16'));
45  elseif strcmp(HDR.TYPE,'XML-UTF8'),
46  HDR.XML = char(fread(fid,[1,inf],'uint8'));
47  end;
48  fclose(fid);
49  HDR.FILE.FID = fid;
50 
51 
52  if 0, ~exist('xmlstruct')
53  warning('XML toolbox missing')
54  end;
55  if 1,
56  HDR.XMLstruct = xmlstruct(HDR.XML,'sub');
57  HDR.XMLlist = xmlstruct(HDR.XML);
58  end;
59 
60  try
61  XML = xmltree(HDR.XML);
62  XML = convert(XML);
63  HDR.XML = XML;
64  HDR.TYPE = 'XML';
65  catch
66  fprintf(HDR.FILE.stderr,'ERROR SOPEN (XML): XML-toolbox missing or invalid XML file.\n');
67  return;
68  end;
69 
70  tmp = fieldnames(HDR.XML);
71  if any(strmatch('PatientDemographics',tmp)) & any(strmatch('TestDemographics',tmp)) & any(strmatch('RestingECGMeasurements',tmp)) & any(strmatch('Diagnosis',tmp)) & any(strmatch('Waveform',tmp)),
72  % GE-Marquette FDA-XML MAC5000
73 
74  HDR.Patient.ID = HDR.XML.PatientDemographics.PatientID;
75  tmp = HDR.XML.PatientDemographics.Gender;
76  HDR.Patient.Sex = 2*(upper(tmp(1))=='F') + (upper(tmp(1))=='M');
77  HDR.Patient.Name = [HDR.XML.PatientDemographics.PatientLastName,', ',HDR.XML.PatientDemographics.PatientFirstName];
78 
79  tmp = HDR.XML.TestDemographics.AcquisitionDate;
80  tmp(tmp=='-') = ' ';
81  HDR.T0([3,2,1])=str2double(tmp);
82  tmp = HDR.XML.TestDemographics.AcquisitionTime;
83  tmp(tmp==':') = ' ';
84  HDR.T0(4:6) = str2double(tmp);
85 
86  HDR.NS = str2double(HDR.XML.Waveform.NumberofLeads);
87  HDR.SampleRate = str2double(HDR.XML.Waveform.SampleBase);
88  HDR.Filter.LowPass = str2double(HDR.XML.Waveform.LowPassFilter)*ones(1,HDR.NS);
89  HDR.Filter.HighPass = str2double(HDR.XML.Waveform.HighPassFilter)*ones(1,HDR.NS);
90  HDR.Filter.Notch = str2double(HDR.XML.Waveform.ACFilter)*ones(1,HDR.NS);
91 
92  HDR.NRec = 1;
93  HDR.SPR = 1;
94  for k = 1:HDR.NS,
95  CH = HDR.XML.Waveform.LeadData{k};
96  HDR.AS.SPR(k) = str2double(CH.LeadSampleCountTotal);
97  HDR.SPR = lcm(HDR.SPR,HDR.AS.SPR(k));
98  HDR.Cal(k) = str2double(CH.LeadAmplitudeUnitsPerBit);
99  HDR.PhysDim{k} = CH.LeadAmplitudeUnits;
100  HDR.Label{k} = CH.LeadID;
101 
102  t = radix64d(CH.WaveFormData);
103  t = 256*t(2:2:end) + t(1:2:end);
104  t = t - (t>=(2^15))*(2^16);
105  HDR.data(:,k) = t(:);
106  end;
107  HDR.TYPE = 'native';
108 
109 
110  elseif any(strmatch('component',tmp))
111  % FDA-XML Format
112  tmp = HDR.XML.component.series.derivation;
113  if isfield(tmp,'Series');
114  tmp = tmp.Series.component.sequenceSet.component;
115  else % Dovermed.CO.IL version of format
116  tmp = tmp.derivedSeries.component.sequenceSet.component;
117  end;
118  HDR.NS = length(tmp)-1;
119  HDR.NRec = 1;
120  HDR.Cal = 1;
121  HDR.PhysDim = {' '};
122  HDR.SampleRate = 1;
123  HDR.TYPE = 'XML-FDA'; % that's an FDA XML file
124 
125 
126  elseif any(strmatch('dataacquisition',tmp)) & any(strmatch('reportinfo',tmp)) & any(strmatch('patient',tmp)) & any(strmatch('documentinfo',tmp)),
127  % SierraECG 1.03 *.open.xml from PHILIPS
128  HDR.SampleRate = str2double(HDR.XML.dataacquisition.signalcharacteristics.samplingrate);
129  HDR.NS = str2double(HDR.XML.dataacquisition.signalcharacteristics.numberchannelsvalid);
130  HDR.Cal = str2double(HDR.XML.reportinfo.reportgain.amplitudegain.overallgain);
131  HDR.PhysDim = {'uV'};
132  HDR.Filter.HighPass = str2double(HDR.XML.reportinfo.reportbandwidth.highpassfiltersetting);
133  HDR.Filter.LowPass = str2double(HDR.XML.reportinfo.reportbandwidth.lowpassfiltersetting);
134  HDR.Filter.Notch = str2double(HDR.XML.reportinfo.reportbandwidth.notchfiltersetting);
135 
136  t = HDR.XML.reportinfo.reportformat.waveformformat.mainwaveformformat;
137  k = 0;
138  HDR.Label={};
139  while ~isempty(t),
140  [s,t] = strtok(t,' ');
141  k = k+1;
142  HDR.Label{k, 1} = [s,' '];
143  end;
144  HDR.Patient.Id = str2double(HDR.XML.patient.generalpatientdata.patientid);
145  tmp = HDR.XML.patient.generalpatientdata.age;
146  if isfield(tmp,'years'),
147  HDR.Patient.Age = str2double(tmp.years);
148  end
149  if isfield(tmp,'dateofbirth')
150  tmp = tmp.dateofbirth;
151  tmp(tmp=='-')=' ';
152  HDR.Patient.Birthday([6,5,4]) = str2double(tmp);
153  end;
154 
155  tmp = HDR.XML.patient.generalpatientdata.sex;
156  HDR.Patient.Sex = strncmpi(tmp,'Male',1) + strncmpi(tmp,'Female',1)*2;
157  HDR.Patient.Weight = str2double(HDR.XML.patient.generalpatientdata.weight.kg);
158  HDR.Patient.Height = str2double(HDR.XML.patient.generalpatientdata.height.cm);
159 
160  HDR.VERSION = HDR.XML.documentinfo.documentversion;
161  HDR.TYPE = HDR.XML.documentinfo.documenttype;
162 
163 
164  elseif any(strmatch('component',tmp)) & any(strmatch('reportinfo',tmp)) & any(strmatch('patient',tmp)) & any(strmatch('documentinfo',tmp)),
165  % FDA-XML Format
166  tmp = HDR.XML.component.series.derivation;
167  if isfield(tmp,'Series');
168  tmp = tmp.Series.component.sequenceSet.component;
169  else % Dovermed.CO.IL version of format
170  tmp = tmp.derivedSeries.component.sequenceSet.component;
171  end;
172  HDR.NS = length(tmp)-1;
173  HDR.NRec = 1;
174  HDR.Cal = 1;
175  HDR.PhysDim = {' '};
176  HDR.SampleRate = 1;
177  HDR.TYPE = 'XML-FDA'; % that's an FDA XML file
178 
179 
180  elseif any(strmatch('StripData',tmp)) & any(strmatch('ClinicalInfo',tmp)) & any(strmatch('PatientInfo',tmp)) & any(strmatch('ArrhythmiaData',tmp)),
181  % GE Case8000 stress ECG
182 
183  HDR.SampleRate = str2double(HDR.XML.StripData.SampleRate);
184  tmp = HDR.XML.ClinicalInfo.ObservationDateTime;
185  HDR.T0 = [str2double(tmp.Year), str2double(tmp.Month), str2double(tmp.Day), str2double(tmp.Hour), str2double(tmp.Minute), str2double(tmp.Second)];
186 
187  HDR.Patient.Id = HDR.XML.PatientInfo.PID;
188  HDR.Patient.Name = 'X'; % [HDR.XML.PatientInfo.Name, ', ', HDR.XML.PatientInfo.GivenName];
189  HDR.Patient.Age = str2double(HDR.XML.PatientInfo.Age);
190  tmp = HDR.XML.PatientInfo.Gender;
191  HDR.Patient.Sex = any(tmp(1)=='Mm') + any(tmp(1)=='Ff')*2;
192  HDR.Patient.Height = str2double(HDR.XML.PatientInfo.Height);
193  HDR.Patient.Weight = str2double(HDR.XML.PatientInfo.Weight);
194  tmp = HDR.XML.PatientInfo.BirthDateTime;
195  HDR.Patient.Birthday = [str2double(tmp.Year), str2double(tmp.Month), str2double(tmp.Day),0,0,0];
196 
197  tmp = HDR.XML.StripData.Strip;
198  HDR.NS = length(tmp{1}.WaveformData);
199  tmax = str2double(tmp{end}.Time.Minute)*60 + str2double(tmp{end}.Time.Second)+10;
200  data = repmat(NaN,tmax*HDR.SampleRate,HDR.NS);
201  for k = 1:length(tmp);
202  t = HDR.SampleRate*(str2double(tmp{k}.Time.Minute)*60 + str2double(tmp{k}.Time.Second));
203  for k2 = 1:HDR.NS,
204  x = str2double(tmp{k}.WaveformData{k2});
205  data(t+1:t+length(x),k2)=x(:);
206  end;
207  end;
208  tmp = HDR.XML.ArrhythmiaData.Strip;
209  for k = 1:length(tmp);
210  t = HDR.SampleRate*(str2double(tmp{k}.Time.Minute)*60 + str2double(tmp{k}.Time.Second));
211  for k2 = 1:HDR.NS,
212  x = str2double(tmp{k}.WaveformData{k2});
213  data(t+1:t+length(x),k2)=x(:);
214  end;
215  end;
216  HDR.data = data - 2^12*(data>2^11);
217  HDR.TYPE = 'native';
218  HDR.NRec = 1;
219  HDR.SPR = size(HDR.data,1);
220  HDR.Calib = sparse(2:HDR.NS,1:HDR.NS,1);
221  HDR.FLAG.UCAL = 1;
222 
223  else
224  fprintf(HDR.FILE.stderr,'Warning SOPEN (XML): File %s is not supported.\n',HDR.FileName);
225  return;
226  end
227 
228 
229  try
230  tmp=HDR.XML.componentOf.timepointEvent.componentOf.subjectAssignment.subject.trialSubject.subjectDemographicPerson.name;
231  HDR.Patient.Name = sprintf('%s, %s',tmp.family, tmp.given);
232  catch
233  end;
234 
235 
236  HDR.Calib = sparse(2:HDR.NS+1,1:HDR.NS,HDR.Cal);
237  HDR.FILE.OPEN = 1;
238  HDR.FILE.POS = 0;
239 % end;
240 %end;
241 
242 
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %
245 % Auxillary functions
246 %
247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 
249 
250 function y = radix64d(x);
251 % RADIX64D - decoding of radix64 encoded sequence
252 
253 
254 % This program is free software; you can redistribute it and/or
255 % modify it under the terms of the GNU General Public License
256 % as published by the Free Software Foundation; either version 2
257 % of the License, or (at your option) any later version.
258 %
259 % This program is distributed in the hope that it will be useful,
260 % but WITHOUT ANY WARRANTY; without even the implied warranty of
261 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
262 % GNU General Public License for more details.
263 %
264 % You should have received a copy of the GNU General Public License
265 % along with this program; if not, write to the Free Software
266 % Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
267 
268 % $Id: openxml.m 2205 2009-10-27 12:18:15Z schloegl $
269 % (C) 2006 by Alois Schloegl <a.schloegl@ieee.org>
270 % This is part of the BIOSIG-toolbox http://biosig.sf.net/
271 
272 
273 global BIOSIG_GLOBAL
274 
275 if ~isfield(BIOSIG_GLOBAL,'R64E');
276  BIOSIG_GLOBAL.R64E = ['A':'Z','a':'z','0':'9','+','/'];
277  BIOSIG_GLOBAL.R64D = zeros(256,1)-1;
278  for k = 1:length(BIOSIG_GLOBAL.R64E),
279  BIOSIG_GLOBAL.R64D(BIOSIG_GLOBAL.R64E(k)) = k-1;
280  end;
281 end;
282 
283 % http://www.faqs.org/rfcs/rfc2440.html
284 
285 t = BIOSIG_GLOBAL.R64D(x);
286 t = [t(t>=0); zeros(3,1)];
287 N = floor(length(t)/4);
288 t = reshape(bitand(t(1:N*4),2^6-1),4,N);
289 
290 y(1,:) = bitshift(t(1,:),2) + bitshift(t(2,:),-4);
291 y(2,:) = bitshift(mod(t(2,:),16),4) + bitshift(t(3,:),-2);
292 y(3,:) = bitshift(mod(t(3,:),4),6) + t(4,:);
293 
294 y = y(:)';
295 y = y(1:end-sum(x=='=')); % remove possible pad characters
296 
openxml
function openxml(in arg1, in CHAN, in arg4, in arg5, in arg6)
radix64d
function radix64d(in x)
str2double
function str2double(in s, in cdelim, in rdelim, in ddelim)