diff -r 78e3e839658b -r 07e2cbf140df HP3562A/trace_decoder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HP3562A/trace_decoder.py Tue Dec 18 00:23:10 2007 +0100 @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +""" +trace_decoder +============= + +Module for decoding a trace generated by the HP3562A DSA, using the +GPIB command "DDBN" (Dump Data BiNary). + +This file can be exectued as a python script. Use '-h' for more informations. +""" +import struct +import numpy +from HP3562A import format_header, decode_float, decode_string, decode_header +from HP3562A.enum_types import * + + +HEADER = [ ("Display function", EDSP, 'h', 2), + ('Number of elements', int, 'h', 2), + ('Displayed elements', int, 'h', 2), + ('Number of averages', int, 'h', 2), + ('Channel selection', ECH, 'h', 2), + ('Overflow status', EOVR, 'h', 2), + ('Overlap percentage', int, 'h', 2), + ('Domain', EDOM, 'h', 2), + ('Volts peak/rms', EVLT, 'h', 2), + ('Amplitude units', EAMP, 'h', 2), + ('X axis units', EXAXIS, 'h', 2), + ('Auto math label', str, 's', 14), + ('Trace label', str, 's', 22), + ('EU label 1', str, 's', 6), + ('EU label 2', str, 's', 6), + ('Float/Interger', bool, 'h', 2), + ('Complex/Real', bool, 'h', 2), + ('Live/Recalled', bool, 'h', 2), + ('Math result', bool, 'h', 2), + ('Real/Complex input', bool, 'h', 2), + ('Log/Linear data', bool, 'h', 2), + ('Auto math', bool, 'h', 2), + ('Real time status', bool, 'h', 2), + ('Measurement mode', EMEAS, 'h', 2), + ('Window', EWIN, 'h', 2), + ('Demod type channel 1', EDEMOD, 'h', 2), + ('Demod type channel 2', EDEMOD, 'h', 2), + ('Demod active channel 1', bool, 'h', 2), + ('Demod active channel 2', bool, 'h', 2), + ('Average status', EAVG, 'h', 2), + ('Not used', int, 'hh', 4), + ('Samp freq/2 (real)', decode_float, None, 4), + ('Samp freq/2 (imag)', decode_float, None, 4), + ('Not used', decode_float, None, 4), + ('Delta X-axis', decode_float, None, 4), + ('Max range', decode_float, None, 4), + ('Start time value', decode_float, None, 4), + ('Expon wind const 1', decode_float, None, 4), + ('Expon wind const 2', decode_float, None, 4), + ('EU value chan 1', decode_float, None, 4), + ('EU value chan 2', decode_float, None, 4), + ('Trig delay chan 1', decode_float, None, 4), + ('Trig delay chan 2', decode_float, None, 4), + ('Start freq value', decode_float, None, 8), + ('Start data value', decode_float, None, 8), + ] + +def decode_trace(data): + """ + Decode the data (as generated by the HP3562A DSA in response to a + "DDBN" command), and returns a couple (header, values). + + header is the dictionnary of the header of the dumped data block, + value is a numpy array holding the trace (vector of float or + complex values). + """ + header, idx = decode_header(data, HEADER) + resu = [] + for i in range(header["Number of elements"]): + resu.append(decode_float(data[idx: idx+4])) + idx += 4 + return header, numpy.array(resu, dtype=float) + + + +def main(): + import sys + 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() + + +if __name__ == "__main__": + main()