189 lines
6.9 KiB
Matlab
189 lines
6.9 KiB
Matlab
function D = IBWread(FN);
|
|
% IBWread - read Igor wave from IBW file
|
|
% D = IBWread('Foo.ibw') reads Igor file Foo.ibw into struct D.
|
|
|
|
if exist('fullfilename', 'file'), FFN = fullfilename(FN, cd, '.ibw');
|
|
else, FFN = FN;
|
|
end
|
|
|
|
% read headers
|
|
[D.binHeader, D.waveHeader, FFN] = readIBWheaders(FN);
|
|
fid = fopen(FFN,'r');
|
|
fid = fopen(FFN,'r');
|
|
% For numeric waves, the type field is interpreted bitwise. One of the following bits, as represented by symbols defined in IgorBin.h, will be set:
|
|
%
|
|
% % #define NT_CMPLX 1 % Complex numbers.
|
|
% % #define NT_FP32 2 % 32 bit fp numbers.
|
|
% % #define NT_FP64 4 % 64 bit fp numbers.
|
|
% % #define NT_I8 8 % 8 bit signed integer. Requires Igor Pro 2.0 or later.
|
|
% % #define NT_I16 0x10 % 16 bit integer numbers. Requires Igor Pro 2.0 or later.
|
|
% % #define NT_I32 0x20 % 32 bit integer numbers. Requires Igor Pro 2.0 or later.
|
|
% % #define NT_UNSIGNED 0x40 % Makes above signed integers unsigned. Requires Igor Pro 3.0 or later.
|
|
% NT_FP64 64-bit floating point (double)
|
|
% NT_FP32 32-bit floating point (float)
|
|
% NT_I32 32 bit integer (long)
|
|
% NT_16 16 bit integer (short)
|
|
% NT_I8 8 bit integer (char)
|
|
datatype = D.waveHeader.type;
|
|
CMPLX = rem(datatype,2);
|
|
if CMPLX, datatype = datatype-1; end
|
|
switch datatype,
|
|
case 0, prec = '*char';
|
|
case 2, prec = 'single';
|
|
case 4, prec = 'double';
|
|
case 8, prec = 'int8';
|
|
case 16, prec = 'int16';
|
|
case 32, prec = 'int32';
|
|
case 64+8, prec = 'uint8';
|
|
case 64+16, prec = 'uint16';
|
|
case 64+32, prec = 'uint32';
|
|
otherwise, error('Invalid numerical datatype.');
|
|
end
|
|
|
|
D.bname = D.waveHeader.bname;
|
|
% The date/time is store as seconds since midnight, January 1, 1904.
|
|
D.creationDate = local_igorTime2vec(D.waveHeader.creationDate);
|
|
D.modDate = local_igorTime2vec(D.waveHeader.creationDate);
|
|
switch D.binHeader.version,
|
|
case 2,
|
|
% The version 2 file has the following general layout.
|
|
% BinHeader2 structure: 16 bytes
|
|
% WaveHeader2 structure excluding wData field; 110 bytes
|
|
% Wave data: Variable size
|
|
D.Nsam = D.waveHeader.npnts;
|
|
D.Ndim = 1;
|
|
% X value for point p = hsA*p + hsB
|
|
D.dx = D.waveHeader.hsA;
|
|
D.x0 = D.waveHeader.hsB;
|
|
D.x1 = D.x0+D.Nsam*D.dx;
|
|
fseek(fid, 16+110, 'bof');
|
|
NN = D.Nsam*(1+double(CMPLX)); % if complex, read twice as many numbers
|
|
D.y = fread(fid, NN, prec);
|
|
if CMPLX, D.y = D.y(1:2:end) + i*D.y(2:2:end); end; % Re & Im values are interleaved
|
|
case 5,
|
|
% The version 5 file has the following general layout.
|
|
% BinHeader5 structure 64 bytes
|
|
% WaveHeader5 structure excluding wData field 320 bytes
|
|
% Wave data Variable size
|
|
% Optional wave dependency formula Variable size
|
|
% Optional wave note data Variable size
|
|
D.Nsam = D.waveHeader.npnts;
|
|
D.Ndim = sum(D.waveHeader.nDim>0);
|
|
% X offset & spacing (documentation is obscure)
|
|
D.dx = D.waveHeader.sfA(1:D.Ndim);
|
|
D.x0 = D.waveHeader.sfB(1:D.Ndim);
|
|
D.x1 = nan; % D.x0+D.Nsam*D.dx;
|
|
fseek(fid, 64+320, 'bof');
|
|
NN = D.Nsam*(1+double(CMPLX)); % if complex, read twice as many numbers
|
|
if isequal(0,datatype), % text data
|
|
% Number of bytes of wave data = wfmSize - (sizeof(WaveHeader5) - 4)
|
|
NN = D.binHeader.wfmSize-320;
|
|
D.y = fread(fid, NN, prec)';
|
|
else, % numerical data
|
|
D.y = fread(fid, NN, prec);
|
|
end
|
|
if CMPLX, D.y = D.y(1:2:end) + i*D.y(2:2:end); end; % Re & Im values are interleaved
|
|
if ~isempty(D.y) && D.Ndim>1,
|
|
D.y = reshape(D.y, D.waveHeader.nDim(1:D.Ndim));
|
|
end
|
|
end
|
|
D.WaveNotes = local_readNotes(fid, D.binHeader);
|
|
if isequal(0,datatype), % partition text data into lines using string indices stored @ eof
|
|
D = local_partition_text(fid, D);
|
|
end
|
|
fseek(fid,0,'eof');
|
|
D.fileSize = ftell(fid);
|
|
fclose(fid);
|
|
|
|
|
|
%===============================
|
|
function DV=local_igorTime2vec(it);
|
|
% igor time -> date vector a la Matlab
|
|
% The date/time is store as seconds since midnight, January 1, 1904.
|
|
Nsec_4year = 126230400;
|
|
idate_1988 = 21*uint32(Nsec_4year); % # seconds between 1-jan-1904 & 1-jan-1988
|
|
it = double(it-idate_1988); % smaller numbers-> use ordinary numbers ("doubles")
|
|
M4 = floor(it/Nsec_4year);
|
|
YR = double(1988+4*M4);
|
|
it = double(it-M4*Nsec_4year);
|
|
last_it = it;
|
|
while 1, % subtract years as long as they fit
|
|
s = etime([YR+1 1 1 0 0 0], [YR 1 1 0 0 0]);
|
|
if it<s, break; end % we went too far
|
|
YR = YR+1;
|
|
it = it-s;
|
|
end
|
|
MNTH = 1;
|
|
while 1, % subtract months as long as they fit
|
|
s = etime([YR MNTH+1 1 0 0 0], [YR MNTH 1 0 0 0]);
|
|
if it<s, break; end % we went too far
|
|
MNTH = MNTH+1;
|
|
it = it-s;
|
|
end
|
|
DAY = 1;
|
|
while 1, % subtract days as long as they fit
|
|
s = etime([YR MNTH DAY+1 0 0 0], [YR MNTH DAY 0 0 0]);
|
|
if it<s, break; end % we went too far
|
|
DAY = DAY+1;
|
|
it = it-s;
|
|
end
|
|
HR = floor(it/60^2); it = it-HR*60^2;
|
|
MIN = floor(it/60); SEC = it-MIN*60;
|
|
DV = [YR, MNTH, DAY, HR, MIN, SEC];
|
|
if ~isequal(last_it, etime(DV, [1988+4*M4 1 1 0 0 0])),
|
|
error('date error');
|
|
end
|
|
|
|
function Nts = local_readNotes(fid, B);
|
|
switch B.version,
|
|
case 2,
|
|
% BinHeader2 structure 16 bytes
|
|
% WaveHeader2 structure excluding wData field 110 bytes
|
|
% Wave data Variable size
|
|
% 16 bytes of padding 16 bytes
|
|
dum = fread(fid,16,'char');
|
|
% Optional wave note data
|
|
Nts = fread(fid, B.noteSize, '*char').';
|
|
case 5,
|
|
% BinHeader5 structure 64 bytes
|
|
% WaveHeader5 structure excluding wData field 320 bytes
|
|
% Wave data Variable size
|
|
% Optional wave dependency formula Variable size
|
|
dum = fread(fid,B.formulaSize, 'char');
|
|
% Optional wave note data Variable size
|
|
Nts = fread(fid, B.noteSize, '*char').';
|
|
end
|
|
|
|
function D = local_partition_text(fid, D);
|
|
% read sizeindices and chop text accordingly, must be called after reading
|
|
% notes
|
|
bH = D.binHeader;
|
|
% skip other stuff in file
|
|
% The version 5 file has the following general layout.
|
|
% BinHeader5 structure 64 bytes
|
|
% WaveHeader5 structure excluding wData field 320 bytes
|
|
% Wave data Variable size
|
|
% Optional wave dependency formula Variable size
|
|
% Optional wave note data Variable size
|
|
% Optional extended data units data Variable size
|
|
% Optional extended dimension units data Variable size
|
|
% Optional dimension label data Variable size
|
|
% String indices used for text waves only Variable size
|
|
dum=fseek(fid, -bH.sIndicesSize, 'eof'); % string indices are last in file; it's easier to refer from end-of-file
|
|
% bH.sIndicesSize; # bytes of string indices stored for the wave if the wave type is text.
|
|
% String indices are used to determine the offset in the file and the number of bytes for each element of the text wave.
|
|
sIdx = [0 fread(fid, bH.sIndicesSize/4, 'uint32').'];
|
|
for ii=1:numel(sIdx)-1,
|
|
STR{ii,1} = D.y(sIdx(ii)+1:sIdx(ii+1));
|
|
end
|
|
D.y = STR;
|
|
|
|
|
|
% long sIndicesSize; The size of string indicies if this is a text wave.
|
|
|
|
|
|
|
|
|
|
|
|
|