2 % PHYSICALUNITS converts PhysDim inte PhysDimCode and vice versa
3 % according to Annex A of FEF Vital Signs Format [1]
6 % adds HDR.PhysDim or HDR.PhysDimCode,
if needed
9 % converts Code of PhysicalUnits into descriptive physical units
12 % converts descriptive units into Code
for physical units.
15 % scale contains the scaling factor of the decimal prefix
17 % see also: SLOAD, SOPEN, doc/DecimalFactors.txt, doc/units.csv
20 % [1] CEN/TC251/PT40 (2001)
21 % File Exchange Format for Vital Signs - Annex A
22 % [2] The Unified Code for Units of Measure (UCUM)
26 % This program is free software; you can redistribute it and/or
27 % modify it under the terms of the GNU General Public License
28 % as published by the Free Software Foundation; either version 3
29 % of the License, or (at your option) any later version.
32 % Copyright (C) 2005,2008 by Alois Schloegl <a.schloegl@ieee.org>
33 % This is part of the BIOSIG-toolbox http:
38 if ~isfield(BIOSIG_GLOBAL,
'ISLOADED')
39 BIOSIG_GLOBAL.ISLOADED = 0 ;
41 if ~BIOSIG_GLOBAL.ISLOADED;
46 %%%---------- Load Decimal factors ------------%%%
47 BIOSIG_GLOBAL.ISLOADED = 0 ;
48 [fid,msg] = fopen(fullfile(p,'doc','DecimalFactors.txt'),'rt','ieee-le');
52 if ~strncmp(line,'
#',1),
56 DecimalFactor.Code(N1,1) = n(2);
57 DecimalFactor.Cal(N1,1) = n(1);
60 DecimalFactor.Name(N1,1) = s(1);
61 DecimalFactor.Prefix(N1,1) = s(2);
67 BIOSIG_GLOBAL.DecimalFactor = DecimalFactor;
69 %%%---------- Physical units ------------%%%
70 fid = fopen(fullfile(p,
'doc',
'units.csv'));
75 if ~strncmp(line,
'#',1),
76 ix = mod(cumsum(line==
char(34)),2); %%
"
81 fprintf(2,'Warning: line (%3i: %s) not valid\n',N2,line);
84 t2 = line(ix(1)+1:ix(2)-1);
85 t3 = line(ix(2)+1:ix(3)-1);
86 t4 = line(ix(3)+1:end);
87 Code = str2double(t1);
90 UnitsOfMeasurement.Code(N1,1) = Code;
91 ix = min(find([t2, '[' ] == '['))-1;
92 UnitsOfMeasurement.Symbol{N1,1} = char(t2(2:ix-1));
99 BIOSIG_GLOBAL.Units = UnitsOfMeasurement;
101 %%%---------- Load x73-UCUM Table ------------%%%
102 fid=fopen('IEEEandUCUM.1b.txt','rt');
104 r = char(fread(fid,[1,inf],'uint8'));
106 while strncmp(r,'#',1)
107 [line,r] = strtok(r,[10,13]);
110 [line,r] = strtok(r,[10,13]);
112 ix = [0,find(line == 9),length(line)+1]; % tab
113 for K2 = 1:length(ix)-2,
114 if ix(K2)+2>ix(K2+1)-2,
117 tab{K1,K2} = line(ix(K2)+2:ix(K2+1)-2);
121 tab{K1,6} = str2double(line(ix(K2)+1:ix(K2+1)-1));
123 [line,r] = strtok(r,[10,13]);
126 BIOSIG_GLOBAL.x73_UCUM = tab;
129 BIOSIG_GLOBAL.ISLOADED = 1;
136 elseif isfield(HDR,'PhysDim') && isfield(HDR,'PhysDimCode')
137 [PhysDimCode,scale] = physicalunits(HDR.PhysDim);
138 if any(PhysDimCode(:)~=HDR.PhysDimCode(:))
139 warning('PhysDim and PhysDimCode differ');
140 PhysDim',HDR.PhysDim'
142 elseif ~isfield(HDR,'PhysDim') && isfield(HDR,'PhysDimCode')
143 [HDR.PhysDim, scale] = physicalunits(HDR.PhysDimCode);
144 elseif isfield(HDR,'PhysDim') % ~isfield(HDR,'PhysDimCode')
145 [HDR.PhysDimCode,scale] = physicalunits(HDR.PhysDim);
146 elseif ~isfield(HDR,'PhysDim') && ~isfield(HDR,'PhysDimCode')
147 HDR.PhysDimCode = zeros(HDR.NS,1);
148 HDR.PhysDim = repmat({'?'},HDR.NS,1);
149 scale = ones(HDR.NS,1);
150 fprintf(HDR.FILE.stderr,'Neither PhysDim nor PhysDimCode defined in file %s\n',HDR.FileName);
154 elseif isnumeric(arg1)
156 n = bitand(arg1,2^16-32);
157 scale = repmat(NaN,size(arg1));
158 PhysDim = repmat({'?'},size(arg1));
160 if any(BIOSIG_GLOBAL.DecimalFactor.Code==s(k)),
161 t1 = BIOSIG_GLOBAL.DecimalFactor.Prefix{BIOSIG_GLOBAL.DecimalFactor.Code==s(k)};
162 ix = find(BIOSIG_GLOBAL.Units.Code==n(k));
164 t2 = BIOSIG_GLOBAL.Units.Symbol{ix};
165 PhysDim{k} = [t1,t2];
166 scale(k) = BIOSIG_GLOBAL.DecimalFactor.Cal(BIOSIG_GLOBAL.DecimalFactor.Code==s(k));
172 elseif ischar(arg1) || iscell(arg1)
177 arg1 = cellstr(arg1);
182 % This does not work for Octave 2.9.9 and earlier versions.
183 % Uncomment the next line to fix it. It is slower but correct.
184 [arg1,i,j] = unique(arg1);
186 Code = zeros(length(arg1),1); % default value is 0 (unknown)
187 for k=1:length(arg1);
188 unit = deblank(arg1{k});
190 if (unit(1)==181), unit(1)='u'; end;
195 % this lookup table contains first the most widely used
199 elseif strcmpi(unit,'-') % dimensionless
201 elseif strcmpi(unit,'1') % dimensionless
203 elseif strcmpi(unit,'percent')
205 elseif strcmpi(unit,'%')
207 elseif strcmpi(unit,'degree')
209 elseif strcmpi(unit,'rad')
211 elseif strcmp(unit,'Hz')
213 elseif strcmp(unit,'l/(min*m²)')
215 elseif strcmp(unit,'l/min')
217 elseif strcmp(unit,'mmHg')
219 elseif strcmp(unit,'dyne*s/cm^5')
221 elseif strcmp(unit,'V')
223 elseif strcmp(unit,'mV')
225 elseif strcmp(unit,'uV')
227 elseif strcmp(unit,'Ohm')
229 elseif strcmp(unit,'K')
231 elseif strcmp(unit,'°F')
233 elseif strcmp(unit,'°C')
235 elseif strcmp(unit,'m/s²')
237 elseif strcmp(unit,'dyne*s*m²/cm^5')
239 elseif strcmp(unit,'l/m²')
241 elseif strcmp(unit,'ml/m²')
244 % this is the general method to determine the
245 % Physical Dimension's code
247 for k1=1:length(BIOSIG_GLOBAL.DecimalFactor.Code)
248 for k2=1:length(BIOSIG_GLOBAL.Units.Code)
249 if strcmp(unit,[BIOSIG_GLOBAL.DecimalFactor.Prefix{k1},BIOSIG_GLOBAL.Units.Symbol{k2}])
250 ix = [ix,BIOSIG_GLOBAL.Units.Code(k2) + BIOSIG_GLOBAL.DecimalFactor.Code(k1)];
255 %%%%% usis x73-UCUM table, col 3 and 4 %%%%
258 if isfield(BIOSIG_GLOBAL,'x73_UCUM')
259 for k1=1:length(BIOSIG_GLOBAL.DecimalFactor.Code)
260 for k2=1:size(BIOSIG_GLOBAL.x73_UCUM,1)
261 if strcmpi(unit,[BIOSIG_GLOBAL.DecimalFactor.Prefix{k1},BIOSIG_GLOBAL.x73_UCUM{k2,3}])
262 ix2 = [ix2,BIOSIG_GLOBAL.x73_UCUM{k2,6} + BIOSIG_GLOBAL.DecimalFactor.Code(k1)];
264 if strcmpi(unit,[BIOSIG_GLOBAL.DecimalFactor.Prefix{k1},BIOSIG_GLOBAL.x73_UCUM{k2,4}])
265 ix3 = [ix3,BIOSIG_GLOBAL.x73_UCUM{k2,6} + BIOSIG_GLOBAL.DecimalFactor.Code(k1)];
274 ix = ix(~mod(ix,32)); % select those with no PreFix (code offset = 0)
277 elseif sum(ix<64000)==1,
278 Code(k) = ix(ix<64000);
280 warning('ambigous physical unit')
282 elseif length(ix2)==1,
284 elseif length(ix3)==1,
291 scale = repmat(NaN,size(Code));
292 for k = 1:numel(Code);
293 scale(k) = BIOSIG_GLOBAL.DecimalFactor.Cal(BIOSIG_GLOBAL.DecimalFactor.Code==bitand(Code(k),31));