Fri, 14 Dec 2007 00:24:11 +0100
many improvements in the read/dump trace tools.
- read_trace can now read the 3 data blocks (trace, state and coord)
- many command line options added
- plot can now plot in linear, log or db vertical scale (command line options for that)
- plot now display the correct X axis ticks and label
dump_trace.py | file | annotate | diff | comparison | revisions | |
read_trace.py | file | annotate | diff | comparison | revisions |
--- a/dump_trace.py Fri Dec 14 00:21:47 2007 +0100 +++ b/dump_trace.py Fri Dec 14 00:24:11 2007 +0100 @@ -2,22 +2,31 @@ import time import gpib -class GPIBtracedumper(gpib.GPIB): +class HP3562dumper(gpib.GPIB): - MODE = {'binary': 'DDBN', - 'ascii': 'DDAS', - 'ansi': 'DDAN', - } + MODES = {'trace': 'DD', + 'state': 'DS', + 'coord': 'DC', + } + + FORMATS = {'binary': 'BN', + 'ascii': 'AS', + 'ansi': 'AN'} + def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1, address=0): - super(GPIBtracedumper, self).__init__(device, baudrate, timeout, address, mode=1) + super(HP3562dumper, self).__init__(device, baudrate, timeout, address, mode=1) - def read_trace(self, mode="binary"): + def dump(self, mode='trace', format="binary"): + format = format.lower() mode = mode.lower() - assert mode in MODE - mode = MODE[mode] + assert mode in self.MODES + assert format in self.FORMATS + cmd = self.MODES[mode] + self.FORMATS[format] + res = "" - self._cnx.write('%s\r'%mode) + print "command = ", cmd + self._cnx.write('%s\r'%cmd) i = 0 while i<self._retries: l = self._cnx.readline() @@ -29,6 +38,7 @@ i = 0 return res + if __name__=='__main__': import optparse @@ -40,20 +50,23 @@ dest='device', help='Device of the RS232 connection (default: /dev/ttyUSB0)', ) + opt.add_option('-a', '--address', default=0, + dest='address', + help='GPIB address of the device', + ) + opt.add_option('-b', '--block', default='trace', + dest='block', + help='Data block to dump (may be "trace" [default], "state" or "coord")', + ) opt.add_option('-m', '--mode', default='binary', dest='mode', help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', ) - opt.add_option('-a', '--address', default=0, - dest='address', - help='GPIB address of the device', - ) options, argv = opt.parse_args(sys.argv) - cnx = GPIBtracedumper(device=options.device, - address=int(options.address)) - res = cnx.read_trace(mode=options.mode) - + cnx = HP3562dumper(device=options.device, address=int(options.address)) + res = cnx.dump(mode=options.block, format=options.mode) + sys.stderr.write("read %s bytes\n"%(len(res))) if options.filename: open(options.filename, 'w').write(res) else:
--- a/read_trace.py Fri Dec 14 00:21:47 2007 +0100 +++ b/read_trace.py Fri Dec 14 00:24:11 2007 +0100 @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import struct +import numpy def decode_float(s): @@ -226,8 +227,8 @@ ('Start data value', decode_float, None, 8), ] -def decode_file(filename): - d = open(filename).read() +def decode_trace(data): + d = data typ = d[:2] assert typ == "#A" @@ -248,52 +249,98 @@ val = dtype(v) else: val = dtype(d[idx: idx+nbytes]) - - print idx, hex(idx), nam, ":", val header[nam] = val idx += nbytes - resu = [] - for i in range(header["Number of elements"]): resu.append(decode_float(d[idx: idx+4])) idx += 4 - - #print "resu = ", resu - #return - import pylab - import numpy - resu = numpy.array(resu, dtype=float) - print "max = ", max(resu) - #xr = numpy.linspace(0, header['Delta X-axis'], len(resu)) - sf = header['Start freq value'] - xr = numpy.linspace(sf, sf+20000, len(resu)) - mn = min(resu[resu>0]) - resu[resu==0] = mn - pylab.plot(xr, 10*numpy.log10(resu)) - pylab.show() - - # tt=0 - # for i, (nam, dtype, nbytes) in enumerate(HEADER): - # if dtype == str: - # nb = ord(struct.unpack('c', d[idx])[0]) - # val = d[idx+1:idx+1+nb] - # else: - # v = struct.unpack('>d', d[idx: idx+(nbytes*4)])[0] - # if isinstance(dtype, dict): - # val = dtype.get(int(v), "N/A") - # else: - # val = dtype(v) - # print idx, nam, ":", val - # idx += nbytes*4 - - + return header, numpy.array(resu, dtype=float) + +def format_header(header, head_struct, columns=80): + todisp = [] + for row in head_struct: + key = row[0] + val = header.get(key, "N/A") + if isinstance(val, basestring): + val = repr(val) + else: + val = str(val) + todisp.append((key+":", val)) + maxk = max([len(k) for k, v in todisp]) + maxv = max([len(v) for k, v in todisp]) + fmt = "%%-%ds %%-%ds"%(maxk, maxv) + w = maxk+maxv+4 + ncols = columns/w + nrows = len(todisp)/ncols + print "w=", w + print "ncols=", ncols + print "nrows=", nrows + res = "" + for i in range(nrows): + res += "| ".join([fmt%todisp[j*nrows+i] for j in range(ncols)]) + "\n" + return res if __name__ == "__main__": import sys - decode_file(sys.argv[1]) + import optparse + opt = optparse.OptionParser("A simple tool for tracing a dumped trace") + opt.add_option('-f', '--filename', default=None, + dest='filename', + help='Output filename. If not set, read from stdin') + opt.add_option('-m', '--mode', default='binary', + dest='mode', + help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', + ) + opt.add_option('-d', '--display-header', default=False, + action="store_true", + dest="displayheader", + help="Display the trace header") + opt.add_option('-P', '--noplot-trace', default=True, + action="store_false", + dest="plot", + help="Do not display the plot of the trace") + opt.add_option('-x', '--xmode', default='lin', + dest='xmode', + help='X coordinate mode (may be "lin" [default] or "log")') + opt.add_option('-y', '--ymode', default='lin', + dest='ymode', + help='Y coordinate mode (may be "lin" [default], "log" or "db")') + + options, argv = opt.parse_args(sys.argv) + if options.filename is None: + print "Can't deal stdin for now..." + sys.exit(1) + try: + header, data = decode_trace(open(options.filename, 'rb').read()) + except Exception, e: + print "ERROR: can't read %s an interpret it as a HP3562 trace"%options.filename + print e + sys.exit(1) + + if options.displayheader: + print format_header(header, HEADER, 100) + if options.plot: + f0 = header['Start freq value'] + dx = header['Delta X-axis'] + n = header['Number of elements'] + x = numpy.linspace(f0, f0+dx*n, len(data)) + y = data.copy() + + import pylab + if options.ymode != "lin": + minv = min(y[y>0]) + y[y==0] = minv + y = numpy.log10(y) + if options.ymode == "db": + y = y*10 + pylab.ylabel('db') + pylab.grid() + pylab.plot(x, y) + pylab.xlabel('frequency') + pylab.show()