created a HP3562A submodule for specific code

Mon, 17 Dec 2007 18:57:18 +0100

author
David Douard <david.douard@logilab.fr>
date
Mon, 17 Dec 2007 18:57:18 +0100
changeset 11
3ccb0023cf41
parent 10
2999318b49a2
child 12
a04bea92c509

created a HP3562A submodule for specific code

HP3562A/dump_trace.py file | annotate | diff | comparison | revisions
HP3562A/read_trace.py file | annotate | diff | comparison | revisions
dump_trace.py file | annotate | diff | comparison | revisions
read_trace.py file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HP3562A/dump_trace.py	Mon Dec 17 18:57:18 2007 +0100
@@ -0,0 +1,74 @@
+import sys
+import time
+import gpib
+
+class HP3562dumper(gpib.GPIB):
+
+    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(HP3562dumper, self).__init__(device, baudrate, timeout, address, mode=1)
+
+    def dump(self, mode='trace', format="binary"): 
+        format = format.lower()
+        mode = mode.lower()
+        assert mode in self.MODES
+        assert format in self.FORMATS
+        cmd = self.MODES[mode] + self.FORMATS[format]
+
+        res = ""
+        print "command = ", cmd
+        self._cnx.write('%s\r'%cmd)
+        i = 0
+        while i<self._retries:
+            l = self._cnx.readline()
+            if l.strip() == "":
+                i += 1
+                time.sleep(self._timeout)
+                continue
+            res += l 
+            i = 0
+        return res
+
+    
+
+if __name__=='__main__':
+    import optparse
+    opt = optparse.OptionParser("A simple tool for dumping the current trace")
+    opt.add_option('-f', '--filename', default=None,
+                   dest='filename',
+                   help='Output filename. If not set, write to stdout')
+    opt.add_option('-d', '--device', default='/dev/ttyUSB0',
+                   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")',
+                   )
+    options, argv = opt.parse_args(sys.argv)
+
+    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:
+        print res
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HP3562A/read_trace.py	Mon Dec 17 18:57:18 2007 +0100
@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+
+import struct
+import numpy
+
+
+def decode_float(s):
+    assert len(s) in [4,8]
+    # exponential term 
+    e = ord(s[-1])
+    if e & 0x80:
+        e = e - 256
+
+    # mantissa
+    m = [ord(x) for x in s[:-1]]
+    M = 0.
+    for i in range(len(s)-1):
+        #M += m[i]<<(i*8)
+        M += float(m[i])/2**((i+1)*8)
+    # XXX how do we deal negative numbers?
+    #if m[0] & 0x80:
+    #    M = M - 2^(len(s))
+    return M * 2**(e+1)
+
+def decode_string(s):
+    nb = ord(s[0])
+    s = s[1:nb+2]
+    r = ""
+    # XXX why do we need to do this? It's not described in the manual...
+    for c in s:
+        r += chr(ord(c) & 0x7F)
+    return r
+
+EDSP = {0: "No data",
+        1: "Frequency response",
+        2: "Power spectrum 1",
+        3: "Power spectrum 2",
+        4: "Coherence",
+        5: "Cross spectrum",
+        6: "Input time 1",
+        7: "Input time 2",
+        8: "Input linear spectrum 1",
+        9: "Input linear spectrum 2",
+        10: "Impulse response",
+        11: "Cross correlation",
+        12: "Auto correlation 1",
+        13: "Auto correlation 2",
+        14: "Histogram 1",
+        15: "Histogram 2",
+        16: "Cumulative density function 1",
+        17: "Cumulative density function 2",
+        18: "Probability density function 1",
+        19: "Probability density function 2",
+        20: "Average linear spectrum 1",
+        21: "Average linear spectrum 2",
+        22: "Average time record 1",
+        23: "Average time record 2",
+        24: "Synthesis pole-zeros",
+        25: "Synthesis pole-residue",
+        26: "Synthesis polynomial",
+        27: "Synthesis constant",
+        28: "Windowed time record 1",
+        29: "Windowed time record 2",
+        30: "Windowed linear spectrum 1",
+        31: "Windowed linear spectrum 2",
+        32: "Filtered time record 1",
+        33: "Filtered time record 2",
+        34: "Filtered linear spectrum 1",
+        35: "Filtered linear spectrum 2",
+        36: "Time capture buffer",
+        37: "Captured linear spectrum",
+        38: "Captured time record",
+        39: "Throughput time record 1",
+        40: "Throughput time record 2",
+        41: "Curve fit",
+        42: "Weighted function",
+        43: "Not used",
+        44: "Orbits",
+        45: "Demodulation polar",
+        46: "Preview demod record 1",
+        47: "Preview demod record 2",
+        48: "Preview demod linear spectrum 1",
+        49: "Preview demod linear spectrum 2",
+        }
+
+ECH = {0: "Channel 1",
+       1: "Channel 2",
+       2: "Channel 1&2",
+       3: "No channel",
+       }
+
+EOVR = ECH
+
+EDOM = {0: 'Time',
+        1: 'Frequency',
+        2: 'Voltage (amplitude)',
+        }
+
+EVLT = {0: "Peak",
+        1: "RMS",
+        2: "Volt (indicates peak only)",
+        }
+
+EAMP = {0: "Volts",
+        1: "Volts squared",
+        2: "PSD (V²/Hz)",
+        3: "ESD (V²s/Hz)",
+        4: "PSD¹² (V/Hz¹²)",
+        5: "No unit",
+        6: "Unit volts",
+        7: "Unit volts²",
+        }
+        
+EXAXIS= {0: "No units",
+         1: "Hertz",
+         2: "RPM",
+         3: "Orders",
+         4: "Seconds",
+         5: "Revs",
+         6: "Degrees",
+         7: "dB",
+         8: "dBV",
+         9: "Volts",
+         10: "V Hz¹²",
+         11: "Hz/s",
+         12: "V/EU",
+         13: "Vrms",
+         14: "V²/Hz",
+         15: "%",
+         16: "Points",
+         17: "Records",
+         18: "Ohms",
+         19: "Hertz/octave",
+         20: "Pulse/Rev",
+         21: "Decades",
+         22: "Minutes",
+         23: "V²s/Hz",
+         24: "Octave",
+         25: "Seconds/Decade",
+         26: "Seconds/Octave",
+         27: "Hz/Point",
+         28: "Points/Sweep",
+         29: "Points/Decade",
+         30: "Points/Octave",
+         31: "V/Vrms",
+         32: "V²",
+         33: "EU referenced to chan 1",
+         34: "EU referenced to chan 2",
+         35: "EU value",
+         }
+
+EMEAS = {0: "Linear resolution",
+         1: "Log resolution",
+         2: "Swept sine",
+         3: "Time capture",
+         4: "Linear resolution throughput",
+         }
+
+EDEMOD1 = {45: "AM",
+           46: "FM",
+           47: "PM",
+           }
+
+EDEMOD2 = EDEMOD1
+
+EAVG = {0: "No data",
+        1: "Not averaged",
+        2: "Averaged",}
+
+
+
+EWIN = {0: "N/A",
+        1: "Hann",
+        2: "Flat top",
+        3: "Uniforme",
+        4: "Exponential",
+        5: "Force",
+        6: "Force chan 1/expon chan 2",
+        7: "Expon chan 1/force chan 2",
+        8: "User",
+        }
+
+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', EDEMOD1, 'h', 2),
+           ('Demod type channel 2', EDEMOD2, '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):    
+    d = data
+
+    typ = d[:2]
+    assert typ == "#A"
+
+    totlen = struct.unpack('>h', d[2:4])[0]
+    idx = 4
+    tt=0
+    header = {}
+    for i, (nam, dtype, fmt, nbytes) in enumerate(HEADER):
+        if dtype == str:
+            val = decode_string(d[idx:])
+        else:
+            if fmt:
+                v = struct.unpack('>'+fmt, d[idx: idx+nbytes])[0]
+                if isinstance(dtype, dict):
+                    val = dtype.get(int(v), "N/A")
+                else:
+                    val = dtype(v)
+            else:
+                val = dtype(d[idx: idx+nbytes])
+        header[nam] = val
+        idx += nbytes
+    resu = []
+    for i in range(header["Number of elements"]):
+        resu.append(decode_float(d[idx: idx+4]))
+        idx += 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
+    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()
+    
+          
--- a/dump_trace.py	Fri Dec 14 00:24:11 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-import sys
-import time
-import gpib
-
-class HP3562dumper(gpib.GPIB):
-
-    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(HP3562dumper, self).__init__(device, baudrate, timeout, address, mode=1)
-
-    def dump(self, mode='trace', format="binary"): 
-        format = format.lower()
-        mode = mode.lower()
-        assert mode in self.MODES
-        assert format in self.FORMATS
-        cmd = self.MODES[mode] + self.FORMATS[format]
-
-        res = ""
-        print "command = ", cmd
-        self._cnx.write('%s\r'%cmd)
-        i = 0
-        while i<self._retries:
-            l = self._cnx.readline()
-            if l.strip() == "":
-                i += 1
-                time.sleep(self._timeout)
-                continue
-            res += l 
-            i = 0
-        return res
-
-    
-
-if __name__=='__main__':
-    import optparse
-    opt = optparse.OptionParser("A simple tool for dumping the current trace")
-    opt.add_option('-f', '--filename', default=None,
-                   dest='filename',
-                   help='Output filename. If not set, write to stdout')
-    opt.add_option('-d', '--device', default='/dev/ttyUSB0',
-                   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")',
-                   )
-    options, argv = opt.parse_args(sys.argv)
-
-    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:
-        print res
-    
--- a/read_trace.py	Fri Dec 14 00:24:11 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import struct
-import numpy
-
-
-def decode_float(s):
-    assert len(s) in [4,8]
-    # exponential term 
-    e = ord(s[-1])
-    if e & 0x80:
-        e = e - 256
-
-    # mantissa
-    m = [ord(x) for x in s[:-1]]
-    M = 0.
-    for i in range(len(s)-1):
-        #M += m[i]<<(i*8)
-        M += float(m[i])/2**((i+1)*8)
-    # XXX how do we deal negative numbers?
-    #if m[0] & 0x80:
-    #    M = M - 2^(len(s))
-    return M * 2**(e+1)
-
-def decode_string(s):
-    nb = ord(s[0])
-    s = s[1:nb+2]
-    r = ""
-    # XXX why do we need to do this? It's not described in the manual...
-    for c in s:
-        r += chr(ord(c) & 0x7F)
-    return r
-
-EDSP = {0: "No data",
-        1: "Frequency response",
-        2: "Power spectrum 1",
-        3: "Power spectrum 2",
-        4: "Coherence",
-        5: "Cross spectrum",
-        6: "Input time 1",
-        7: "Input time 2",
-        8: "Input linear spectrum 1",
-        9: "Input linear spectrum 2",
-        10: "Impulse response",
-        11: "Cross correlation",
-        12: "Auto correlation 1",
-        13: "Auto correlation 2",
-        14: "Histogram 1",
-        15: "Histogram 2",
-        16: "Cumulative density function 1",
-        17: "Cumulative density function 2",
-        18: "Probability density function 1",
-        19: "Probability density function 2",
-        20: "Average linear spectrum 1",
-        21: "Average linear spectrum 2",
-        22: "Average time record 1",
-        23: "Average time record 2",
-        24: "Synthesis pole-zeros",
-        25: "Synthesis pole-residue",
-        26: "Synthesis polynomial",
-        27: "Synthesis constant",
-        28: "Windowed time record 1",
-        29: "Windowed time record 2",
-        30: "Windowed linear spectrum 1",
-        31: "Windowed linear spectrum 2",
-        32: "Filtered time record 1",
-        33: "Filtered time record 2",
-        34: "Filtered linear spectrum 1",
-        35: "Filtered linear spectrum 2",
-        36: "Time capture buffer",
-        37: "Captured linear spectrum",
-        38: "Captured time record",
-        39: "Throughput time record 1",
-        40: "Throughput time record 2",
-        41: "Curve fit",
-        42: "Weighted function",
-        43: "Not used",
-        44: "Orbits",
-        45: "Demodulation polar",
-        46: "Preview demod record 1",
-        47: "Preview demod record 2",
-        48: "Preview demod linear spectrum 1",
-        49: "Preview demod linear spectrum 2",
-        }
-
-ECH = {0: "Channel 1",
-       1: "Channel 2",
-       2: "Channel 1&2",
-       3: "No channel",
-       }
-
-EOVR = ECH
-
-EDOM = {0: 'Time',
-        1: 'Frequency',
-        2: 'Voltage (amplitude)',
-        }
-
-EVLT = {0: "Peak",
-        1: "RMS",
-        2: "Volt (indicates peak only)",
-        }
-
-EAMP = {0: "Volts",
-        1: "Volts squared",
-        2: "PSD (V²/Hz)",
-        3: "ESD (V²s/Hz)",
-        4: "PSD¹² (V/Hz¹²)",
-        5: "No unit",
-        6: "Unit volts",
-        7: "Unit volts²",
-        }
-        
-EXAXIS= {0: "No units",
-         1: "Hertz",
-         2: "RPM",
-         3: "Orders",
-         4: "Seconds",
-         5: "Revs",
-         6: "Degrees",
-         7: "dB",
-         8: "dBV",
-         9: "Volts",
-         10: "V Hz¹²",
-         11: "Hz/s",
-         12: "V/EU",
-         13: "Vrms",
-         14: "V²/Hz",
-         15: "%",
-         16: "Points",
-         17: "Records",
-         18: "Ohms",
-         19: "Hertz/octave",
-         20: "Pulse/Rev",
-         21: "Decades",
-         22: "Minutes",
-         23: "V²s/Hz",
-         24: "Octave",
-         25: "Seconds/Decade",
-         26: "Seconds/Octave",
-         27: "Hz/Point",
-         28: "Points/Sweep",
-         29: "Points/Decade",
-         30: "Points/Octave",
-         31: "V/Vrms",
-         32: "V²",
-         33: "EU referenced to chan 1",
-         34: "EU referenced to chan 2",
-         35: "EU value",
-         }
-
-EMEAS = {0: "Linear resolution",
-         1: "Log resolution",
-         2: "Swept sine",
-         3: "Time capture",
-         4: "Linear resolution throughput",
-         }
-
-EDEMOD1 = {45: "AM",
-           46: "FM",
-           47: "PM",
-           }
-
-EDEMOD2 = EDEMOD1
-
-EAVG = {0: "No data",
-        1: "Not averaged",
-        2: "Averaged",}
-
-
-
-EWIN = {0: "N/A",
-        1: "Hann",
-        2: "Flat top",
-        3: "Uniforme",
-        4: "Exponential",
-        5: "Force",
-        6: "Force chan 1/expon chan 2",
-        7: "Expon chan 1/force chan 2",
-        8: "User",
-        }
-
-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', EDEMOD1, 'h', 2),
-           ('Demod type channel 2', EDEMOD2, '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):    
-    d = data
-
-    typ = d[:2]
-    assert typ == "#A"
-
-    totlen = struct.unpack('>h', d[2:4])[0]
-    idx = 4
-    tt=0
-    header = {}
-    for i, (nam, dtype, fmt, nbytes) in enumerate(HEADER):
-        if dtype == str:
-            val = decode_string(d[idx:])
-        else:
-            if fmt:
-                v = struct.unpack('>'+fmt, d[idx: idx+nbytes])[0]
-                if isinstance(dtype, dict):
-                    val = dtype.get(int(v), "N/A")
-                else:
-                    val = dtype(v)
-            else:
-                val = dtype(d[idx: idx+nbytes])
-        header[nam] = val
-        idx += nbytes
-    resu = []
-    for i in range(header["Number of elements"]):
-        resu.append(decode_float(d[idx: idx+4]))
-        idx += 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
-    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()
-    
-          

mercurial