-
Notifications
You must be signed in to change notification settings - Fork 0
/
readLeCroyWaveJetWfm.m
394 lines (366 loc) · 14.6 KB
/
readLeCroyWaveJetWfm.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
function [ varargout ] = readLeCroyWaveJetWfm( varargin )
%readLeCroyWaveJetWfm - Read binary waveform (.wfm) files as saved by
% LeCroy WaveJet oscilloscopes.
%
% readLeCroyWaveJetWfm( filename )
%
% Loads the specified file, shows some information about the file,
% and displays the waveform(s).
%
% [ data ] = readLeCroyWaveJetWfm( filename )
% [ data nfo ] = readLeCroyWaveJetWfm( filename )
%
% Load the specified file and returns its data.
% data - Array with loaded waveform(s). If only one channel was recorded
% this is a single column with the waveform. If more than one
% channel was recorded this is a 2D array where each column
% corresponds with a channel. If a lower number channel is not
% recorded it will contain a column with NaN's. If a higher number
% channel is not recorded, it's column is removed from the data
% array. E.g. ch1: x, ch2: 0, ch3: x, ch4: 0 will result in a 2D
% array with 3 column, where the second column contains NaN's.
% nfo - structure with time axis information and text header
% nfo.x0 - time of first sample (trigger will be at t = 0)
% nfo.dx - sampling time, i.e. time between two consecutive samples
% nfo.notes - text field with complete oscilloscope setup.
%
% Copyright (c) 2008-2010, Paul Wagenaars
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
% * Redistributions of source code must retain the above copyright
% notice, this list of conditions and the following disclaimer.
% * Redistributions in binary form must reproduce the above copyright
% notice, this list of conditions and the following disclaimer in
% the documentation and/or other materials provided with the distribution
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.
%
% Changelog:
% v0.1 (2008-06-29)
% - initial release
%
% v0.2 (2008-08-??)
% - in averaging mode the binary WFM waveform seems to have a half a
% sample offset compared to the ASCII CSV file. The binary waveform is
% now shifted half sample downwards.
% - if averaging mode is turned on the data of inactive channels was
% skipped incorrectly. This has been fixed.
%
% v0.3 (2010-03-02)
% - made function compatible with GNU Octave.
% - fixed waveforms with multiple waveform modes, e.g. when averaging and
% equivalent sampling are specified at the same time.
%
% Define some constants
global RLWJW_XWAV_DEF_INF_NOACQ RLWJW_XWAV_DEF_INF_NORM RLWJW_XWAV_DEF_INF_PEAK
global RLWJW_XWAV_DEF_INF_EQU RLWJW_XWAV_DEF_INF_AVG RLWJW_XWAV_DEF_INF_ROLL
global RLWJW_XWAV_DEF_INF_ILV
RLWJW_XWAV_DEF_INF_NOACQ = uint16(0); % 0x0000 /* Not acquired */
RLWJW_XWAV_DEF_INF_NORM = uint16(1); % 0x0001 /* Normal wave */
RLWJW_XWAV_DEF_INF_PEAK = uint16(2); % 0x0002 /* Peak wave */
RLWJW_XWAV_DEF_INF_EQU = uint16(4); % 0x0004 /* Equ wave */
RLWJW_XWAV_DEF_INF_AVG = uint16(8); % 0x0008 /* Average wave */
RLWJW_XWAV_DEF_INF_ROLL = uint16(16); % 0x0010 /* Roll wave */
RLWJW_XWAV_DEF_INF_ILV = uint16(32); % 0x0020 /* Interleave wave */
% Maximum memory enum
global MAX_MEM_ENUM
MAX_MEM_ENUM = 1024 * [0 0.5 ; 1 1 ; 2 10 ; 3 100 ; 4 500];
% V/div enum
global RLWJW_VDIV_ENUM
RLWJW_VDIV_ENUM = [10 5 2 1 500e-3 200e-3 100e-3 50e-3 20e-3 10e-3 5e-3 2e-3];
% time/div enum
global RLWJW_TDIV_ENUM
RLWJW_TDIV_ENUM = [50 20 10 5 2 1 500e-3 200e-3 100e-3 ...
50e-3 20e-3 10e-3 5e-3 2e-3 1e-3 500e-6 200e-6 100e-6 ...
50e-6 20e-6 10e-6 5e-6 2e-6 1e-6 500e-9 200e-9 100e-9 ...
50e-9 20e-9 10e-9 5e-9 2e-9 1e-9 500e-12 200e-12 100e-12 ...
50e-12 20e-12 10e-12 5e-12 2e-12 1e-12 500e-15 200e-15 100e-15];
% Display informatie about waveform(s)
infomode = (nargout == 0);
if nargin < 1
error('No filename specified.');
else
filename = varargin{1};
end
if infomode
fprintf('Loading %s\n', filename);
end
% Open file
[fid, msg] = fopen(filename, 'r', 'b');
if fid == -1
error('Unable to open %s: %s', filename, msg);
end
% Skip text header
fullheader = '';
while true
line = fgetl(fid);
fullheader = sprintf('%s%s\n', fullheader, line);
if ~ischar(line)
fclose(fid);
error('Unable to find end of setup information. Is this a correct LeCroy WaveJet .wfm file?');
elseif strcmp(line, '[END OF SETUP]');
% The 'fgetl' function seems to consume one byte too much.
% So, here we check the byte and rewind in necessary.
fseek(fid, -1, 'cof');
data = fread(fid, 1, 'uint8');
if (data ~= 10) && (data ~= 13)
fseek(fid, -1, 'cof');
end
break;
end
end
% Read the XWAV_TDE_WAVEINF structure
wavinf = load_XWAV_TDE_WAVEINF(fid);
% Read waveform data
data = nan(wavinf.timebase.memoryLength + 1, 4);
dataStart = wavinf.timebase.validWfmStart;
memLen = wavinf.timebase.memoryLength;
bankSize = wavinf.timebase.bankSize;
validChannels = nan(1,4);
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_AVG)
bytesPerSample = 2;
else
bytesPerSample = 1;
end
sampleType = sprintf('int%d', 8 * bytesPerSample);
maxValue = 2^(8 * bytesPerSample);
for j = 1:4
if wavinf.channels(j).isValid
validChannels(j) = 1;
singleChannel = fread(fid, bankSize, sampleType);
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_AVG)
% In average mode there is a half a sample offset compared to
% the csv file. Here we correct that.
singleChannel = singleChannel - 127;
end
singleChannel = singleChannel * 8 * wavinf.channels(j).vdiv / maxValue;
singleChannel = singleChannel - wavinf.channels(j).offset;
data(:, j) = singleChannel((5 + dataStart):(memLen + dataStart + 5));
else
validChannels(j) = 0;
fseek(fid, bankSize * bytesPerSample, 'cof');
end
end
fclose(fid);
clear singleChannel;
% Select only the "good" channels
if sum(validChannels) == 1
data = data(:, validChannels == 1);
elseif sum(validChannels) < 4
maxIndex = find(validChannels == 1, 1, 'last');
data = data(:, 1:maxIndex);
end
% Create nfo structure
totalTime = 10.0 * wavinf.timebase.tdiv;
nfo.dx = totalTime / (wavinf.timebase.memoryLength);
nfo.x0 = -0.5 * totalTime - wavinf.timebase.delay + nfo.dx;
nfo.notes = fullheader;
if infomode
showInfo(wavinf, nfo, data);
end
% Set the output arguments
if nargout >= 1
varargout{1} = data;
end
if nargout >= 2
varargout{2} = nfo;
end
end % End of main function
%%
%% SUBFUNCTIONS
%%
%% load_XWAV_TDE_WAVEINF
% Loads a wave information structure from file.
% The structure (C code):
% typedef struct
% {
% XWAV_TDE_WAVEINF_TBASE TbaseInfo; /* Time Base Info. */
% XWAV_TDE_WAVEINF_CH ChInfo[4]; /* Ch Info. */
% } XWAV_TDE_WAVEINF;
function [waveinfo] = load_XWAV_TDE_WAVEINF(fid)
waveinfo.timebase = load_XWAV_TDE_WAVEINF_TBASE(fid);
waveinfo.channels = load_XWAV_TDE_WAVEINF_CH(fid);
end
%% load_XWAV_TDE_WAVEINF_TBASE
% Loads a time base information structure from file.
% The structure (C code):
% typedef struct
% {
% SVMNG_TDE_TRGDLY delay; /* Trigger delay time?i-500s..750s?j*/
% XWAV_TDE_TSTAMP Tstamp; /* Time stamp */
% IWDP_TDE_BANKS bankNr; /* Current bank size setting in enum */
% Uint mleng; /* Memory length */
% Uint BankSize; /* Actual bank size (512..512*1024) */
% Uint TrgSkew; /* Trigger skew(TDC): WDP internal value */
% Uint WavValidAdr; /* Start address for valid waveform data */
% Ushort wvinf; /* Bitfielf of waveform mode */
% Ushort AvgTimes; /* Number of average (0,1?`256) */
% char tim; /* time/div in enum */
% char spclk; /* sampling clock in enum */
% Uchar RdmInitVal; /* Random seed: WDP internal value */
% Uchar WavSkew; /* Fraction of delay and trigger skew in a
% sampling clock. 0..99 for normalwaveform,
% 0..49 for interleaved waveform,
% (0..100)/(equivalent sampling) for EQU. */
% Uchar maxmem; /* MAX MEMORY LENGTH 0:0.5k, 1:1k, 2:10k,
% 3:100k, 4:500k */
% Ushort MaskBank; /* Mask for bank number */
% } XWAV_TDE_WAVEINF_TBASE;
%
% Sizes of the differnet bank numbers (bankNr):
% IWDP_ENM_BANKS = [8 16 32 64 128 256 512 1024 2*1024 4*1024 8*1024 ...
% 16*1024 32*1024 64*1024 128*1024 256*1024 512*1024 1048576 ...
% 2*1048576 4*1048576 Inf];
function [tbase] = load_XWAV_TDE_WAVEINF_TBASE(fid)
global MAX_MEM_ENUM RLWJW_TDIV_ENUM
tbase.delay = load_SVMNG_TDE_TRGDLY(fid);
tbase.timeStamp = load_XWAV_TDE_TSTAMP(fid);
tbase.bankNr = fread(fid, 1, 'uint32');
tbase.memoryLength = fread(fid, 1, 'uint32');
tbase.bankSize = fread(fid, 1, 'uint32');
tbase.triggerSkew = fread(fid, 1, 'uint32');
tbase.validWfmStart = fread(fid, 1, 'uint32');
tbase.wfmMode = fread(fid, 1, 'uint16');
tbase.nrAvgs = fread(fid, 1, 'uint16');
tbase.tdivEnum = fread(fid, 1, 'uint8');
tbase.tdiv = RLWJW_TDIV_ENUM(1 + tbase.tdivEnum);
tbase.samplingClockEnum = fread(fid, 1, 'uint8');
tbase.rndInit = fread(fid, 1, 'uint8');
tbase.wavSkew = fread(fid, 1, 'uint8');
tbase.maxMemory = MAX_MEM_ENUM(1 + fread(fid, 1, 'uint8'), :);
tbase.bankMask = fread(fid, 1, 'uint16');
fread(fid, 1, 'uint8');
end
%% load_SVMNG_TDE_TRGDLY
% // Trigger delay structure
% typedef struct {
% Uint sgn; // -1:-/0:+
% Uint sec; // 0?`750s (1s?`750s)
% Uint us; // 0?`999999us (1us?`999ms)
% Uint ps; // 0?`999999ps (1ps?`999ns)
% } SVMNG_TDE_TRGDLY;
function [delay] = load_SVMNG_TDE_TRGDLY(fid)
sgn = fread(fid, 1, 'uint32');
sec = fread(fid, 1, 'uint32');
us = fread(fid, 1, 'uint32');
ps = fread(fid, 1, 'uint32');
if sgn == 0
delay = 1.0;
else
delay = -1.0;
end
delay = delay * (sec + 1e-6 * us + 1e-12 * ps);
end
%% load_XWAV_TDE_TSTAMP
% Load time stamp information.
%
% // Date structure
% typedef struct {
% Ushort year;
% Uchar month;
% Uchar day;
% } SVMNG_TDE_DATE;
%
% // Time structure
% typedef struct {
% Uchar hour;
% Uchar min;
% Uchar sec;
% } SVMNG_TDE_TIME;
%
% typedef struct {
% SVMNG_TDE_DATE date; // DATE year:2000..2099, month:1..12, day:1..31
% SVMNG_TDE_TIME time; // TIME hour:0..23, min:0..59, sec:0..59
% Uchar msec; // 100ms
% } XWAV_TDE_TSTAMP;
function [tstamp] = load_XWAV_TDE_TSTAMP(fid)
year = fread(fid, 1, 'uint16');
month = fread(fid, 1, 'uint8');
day = fread(fid, 1, 'uint8');
hour = fread(fid, 1, 'uint8');
min = fread(fid, 1, 'uint8');
sec = fread(fid, 1, 'uint8');
msec = 100 * fread(fid, 1, 'uint8');
tstamp = [year month day hour min sec msec];
end
%% load_XWAV_TDE_WAVEINF_CH
% Load channel information for a single channel.
function [chs] = load_XWAV_TDE_WAVEINF_CH(fid)
global RLWJW_VDIV_ENUM
chs = struct('offset', {NaN NaN NaN NaN}, ...
'vdivEnum', {NaN NaN NaN NaN}, ...
'isValid', {false false false false});
for i = 1:4
chs(i).offset = fread(fid, 1, 'int32');
chs(i).vdivEnum = fread(fid, 1, 'uint8');
chs(i).vdiv = RLWJW_VDIV_ENUM(1 + chs(i).vdivEnum);
chs(i).offset = chs(i).offset / 3200 * chs(i).vdiv;
chs(i).isValid = (fread(fid, 1, 'uint8') > 0);
chs(i).unknown = fread(fid, 1, 'uint16');
end
end
%% Show information about the waveform(s)
function showInfo(wavinf, nfo, data)
global RLWJW_XWAV_DEF_INF_NOACQ RLWJW_XWAV_DEF_INF_NORM
global RLWJW_XWAV_DEF_INF_PEAK RLWJW_XWAV_DEF_INF_EQU
global RLWJW_XWAV_DEF_INF_AVG RLWJW_XWAV_DEF_INF_ROLL
global RLWJW_XWAV_DEF_INF_ILV
fprintf('Time stamp: %04d-%02d-%02d %02d:%02d:%02d.%03d\n', ...
wavinf.timebase.timeStamp);
fprintf('Memory length: %d (max.mem %dk)\n', wavinf.timebase.memoryLength, ...
wavinf.timebase.maxMemory(2)/1024);
fprintf('Bank size: %d\n', wavinf.timebase.bankSize);
fprintf('Waveform mode:');
if wavinf.timebase.wfmMode == RLWJW_XWAV_DEF_INF_NOACQ
fprintf(' not_acquired');
else
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_NORM)
fprintf(' normal');
end
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_PEAK)
fprintf(' peak');
end
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_EQU)
fprintf(' equivalent_sampling');
end
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_AVG)
fprintf(' averaged(%dx)', wavinf.timebase.nrAvgs);
end
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_ROLL)
fprintf(' roll');
end
if bitand(wavinf.timebase.wfmMode, RLWJW_XWAV_DEF_INF_ILV)
fprintf(' interleaved');
end
end
fprintf('\n');
fprintf('Hor. resolution: %g s/div (%d)\n', wavinf.timebase.tdiv, ...
wavinf.timebase.tdivEnum);
fprintf('Trigger delay: %g s\n', wavinf.timebase.delay);
fprintf('Valid wfm start: %d\n', wavinf.timebase.validWfmStart);
fprintf(' Channel 1 Channel 2 Channel 3 Channel 4 \n');
fprintf('offset (V) %9g %9g %9g %9g\n', wavinf.channels.offset);
fprintf('resolution (V/div) %9g %9g %9g %9g\n', wavinf.channels.vdiv);
fprintf('channel on or off? %9g %9g %9g %9g\n', wavinf.channels.isValid);
fprintf('unknown %9d %9d %9d %9d\n', wavinf.channels.unknown);
xf = (wavinf.timebase.memoryLength) * nfo.dx + nfo.x0;
t = linspace(nfo.x0, xf, wavinf.timebase.memoryLength + 1);
figure;
plot(t, data);
grid on;
xlabel('Time (s)');
end % end of showInfo function