HP3562A/trace_decoder.py

changeset 14
07e2cbf140df
parent 11
3ccb0023cf41
child 16
de9122b5680a
--- /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()

mercurial