I've gone back to my waveform reader for these clock analyses, and I've been able to develop some heuristics to identify the raw data bytes instead of manually looking at a dump of hex bytes. It works for all the files I have, which in the grand scheme of things, isn't many.
Thought I'd post it if it can be of any use to others. Save it as "rig_read.m".
It's written in Octave, which is somewhat of a cross between Basic and APL, and should run in matlab also. For anyone who's interested in installing Octave:
http://wiki.octave.org/Main_PageThis is NOT a generalized utility, so no complaints please. It was written to deal with our clock investigation. Suggestions or improvements, however, in the form of code snippets are welcome.
Alessandro: Does your utility only go at the SCPI port or can it read files too?
function [t, v] = rig_read(name, over_read = -1)
#
# v0.3 - MarkL @ eevblog, Dec 18, 2014
#
# Quick and extremely dirty read of rigol waveform (.wfm) dump
# files. Throw-away code written for sample clock analysis.
#
# Returns time and raw ADC values in two N-row arrays.
#
# Example usage:
#
# [t,v] = rig_read("NewFile5.wfm");
#
# Assumes:
# One byte per data point (acquisition mode "Normal")
# One channel enabled
# 1GS/s or 2GS/s, depending on model
#
# Debugging and verifying data:
#
# If over_read is not 0, over_read bytes will be read before and
# after (if possible) the calculated start and end of data. When
# the returned waveform is plotted, the extra bytes can be examined
# to verify the correct start and end has been calculated since the
# extra bytes before and after (if any) should appear as garbage.
# Example:
#
# [t,v] = rig_read("NewFile5.wfm", 20);
# plot(v(1:100)) # valid data should start at point 21
#
# If there's data past the calculated end, the following *may*
# show garbage bytes after the data:
#
# plot(v(end-100:end))
#
# Setting over_read to anything, even 0, also disables interleave.
# This prevents interleave from creating garbage if the data
# start/end are wrong, and also allows you to check for the
# discontnuity which should appear in the exact middle of
# pre-interleaved data:
#
# [t,v] = rig_read("NewFile5.wfm", 0);
# plot(v(end/2 -9: end/2 +10)) # discontinuity at point 10 to 11
#
#
# Runs in Octave, but should run in matlab too.
#
# Disclaimer: This program is NOT the proper way to read these files
# and has only been tested on a limited number of waveform files.
#
f = fopen(name, "r");
if (f < 0)
fprintf(stderr, "%s: file open failed\n", name);
return
endif
# Figure out the file size.
#
fseek(f, 0, SEEK_END);
fsize = ftell(f);
frewind(f);
fprintf(stderr, "file size %d bytes\n", fsize);
# The model name is somewhere in the first 24 bytes. So far, two
# possible file formats have been encountered.
pre = fread(f, 24, "uchar");
if (strcmp(char(pre(5:7)'), "DS2"))
# First file format.
#
model = "DS2";
else
# Second file format.
#
# Convert to string and get rid of trailing zeros with sprintf()
#
model = sprintf("%s", char(pre(9:24)));
endif
fprintf(stderr, "model: %s\n", model);
skip = -1; # bytes until data start, -1 means not computed yet
interleave = 0; # perform interleave when done
switch (model)
case { "DS1054Z", "DS1104Z" }
# Raw data runs to the end of the file. Work backwards by
# comparing the file size against the number of points possible
# that the scope can store.
#
# An extra 512 points always seems to get stored at the tail.
# Sometimes it's ok, and sometimes it appears to contain
# out-of-sync waveform data in the middle of it starting at
# various offsets. Just drop the last 512 bytes since we don't
# know. Maybe it's a leftover buffer.
#
bytes = guess_points_ds1k(fsize);
skip = fsize - bytes - 512;
sample_hz = 1e9;
case "DS2"
# Look for a possible number of data points and try to match it
# to the file size assuming we started reading from that point.
#
# A pointer to the data start seems to live at 0x00f0.
#
fseek(f, 0x00f0);
possible_skip = fread(f, 1, "uint32", "ieee-le");
# After that, there's other stuff but the number of data points
# seems to always land on a 16 byte boundary. We just don't
# know which one so check a range to see if there's a
# combination that works out to the right file size.
#
for offset = 0x100:0x10:0x170
fseek(f, offset);
bytes = fread(f, 1, "uint32", "ieee-le");
if (possible_skip + bytes == fsize)
# heuristic matched
skip = possible_skip;
# assume DS2k
interleave = 1;
sample_hz = 2e9;
break;
endif
endfor
otherwise
fprintf(stderr, "model %s: unknown\n", model);
return
endswitch
if (skip < 0)
fprintf(stderr, "sorry, no heuristics matched\n");
return
endif
# Hopefully it's all figured out at this point. Extract the data
# bytes.
if (over_read == -1)
# over_read was not set by the user
over_read = 0;
else
# over_read was set
if (interleave)
fprintf(stderr, "warning: over_read set; interleave disabled\n", over_read);
endif
interleave = 0;
endif
skip = skip - over_read;
bytes = bytes + 2*over_read;
fprintf(stderr, "raw data %d (0x%04x) to %d (0x%04x)\n", skip, skip, skip+bytes, skip+bytes);
# Skip to start of data bytes.
#
fseek(f, skip);
# Read bytes until end of the file.
#
[v,c] = fread(f, bytes, "uchar");
# [v,c] = fread(f, Inf, "uint16", "ieee-be"); # not used
# [v,c] = fread(f, Inf, "uint32", "ieee-be"); # not used
fclose(f);
if (c != bytes)
fprintf(stderr, "warning: end of file reached: couldn't read last %d bytes\n", bytes - c);
endif
fprintf(stderr, "read %d data points\n", length(v));
if (interleave)
# Two channels alternately sample the signal, but appear in the
# data as a full channel record, then the other. Re-interleave
# them as alternating bytes, like so:
#
# AAAABBBB --> ABABABAB
#
if (interleave)
fprintf(stderr, "performing data interleave\n");
endif
v = vec( [v(1:end/2), v(end/2+1:end)]' );
endif
# Hard code time array.
#
t = (([0:length(v)-1])/sample_hz)';
endfunction
function n = guess_points_ds1k(size)
# Given the file size, return a guess on how many data points are in
# the file, based on the possibilities in the DS1k series. The
# guess is whatever's closest to the file size.
pts = [12000 120000 1200000 12000000 24000000];
[s, i] = sort(abs(pts - size));
n = pts(i(1));
endfunction
# emacs
# Local Variables:
# mode: text
# End: