r4631 - in developers/werner/ahrt/host/tmc: . demo lib

werner at docs.openmoko.org werner at docs.openmoko.org
Sat Sep 6 15:18:41 CEST 2008


Author: werner
Date: 2008-09-06 15:18:40 +0200 (Sat, 06 Sep 2008)
New Revision: 4631

Added:
   developers/werner/ahrt/host/tmc/demo/
   developers/werner/ahrt/host/tmc/demo/deglitch.py
   developers/werner/ahrt/host/tmc/demo/fft.py
   developers/werner/ahrt/host/tmc/demo/screen.py
   developers/werner/ahrt/host/tmc/lib/__init__.py
   developers/werner/ahrt/host/tmc/lib/shape.py
Modified:
   developers/werner/ahrt/host/tmc/lib/function.py
   developers/werner/ahrt/host/tmc/lib/instrument.py
   developers/werner/ahrt/host/tmc/lib/meter.py
   developers/werner/ahrt/host/tmc/lib/power.py
   developers/werner/ahrt/host/tmc/lib/scope.py
   developers/werner/ahrt/host/tmc/lib/trigger.py
   developers/werner/ahrt/host/tmc/lib/wave.py
   developers/werner/ahrt/host/tmc/python.c
   developers/werner/ahrt/host/tmc/setup.py
Log:
Lots of cleanup and a restructuring of the modules into a package.
This means that this can now be used like any other Python package.
Also added the possibility to synthesize waveforms, and put this new
feature to good use to debug the deglitcher. Finally, there are a few
example scripts in demo/ The now obsolete examples under examples/
will be removed once they've been converted to more modern counterparts.

- setup.py: install the Python modules as well
- lib/*.py: added tmc. prefix where needed and cleaned up imports
- lib/*.py: added copyright notice
- lib/*.py: removed interpreter since none of these scripts are invoked
  directly from the shell anyway
- python.c, setup.py: renamed extension module from "tmc" to "_tmc" to avoid
  conflict with package name
- setup.py: changed version from 1.0 to the more appropriate 0.0
- lib/__init__.py: added to allow for proper package installation
- lib/shape.py: new module to describe and synthesize waveforms
- lib/instrument.py (settable): added mechanism to allow for other classes than
  just "setting"
- demo/fft.py: example for waveform generation and Fourier transform
- demo/screen.py: take a screendump from a Rigol DS1000 and save it in a file
- lib/wave.py (digital_wave.debounce): algorithm was way too complex and 
  actually quite wrong
- demo/deglitch.py: deglitching example



Added: developers/werner/ahrt/host/tmc/demo/deglitch.py
===================================================================
--- developers/werner/ahrt/host/tmc/demo/deglitch.py	                        (rev 0)
+++ developers/werner/ahrt/host/tmc/demo/deglitch.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+#
+# deglitch.py - Deglitch a signal
+#
+
+from tmc.shape import arbitrary
+from tmc.wave import digital_wave
+from math import floor
+
+
+# Define a waveform of pulses going from 0 to 1 with the following property:
+# in each interval [n, n+1), where n is an integer, there is a positive pulse
+# of length n/100.
+ 
+shape = arbitrary(high = 1, freq = 1,
+  fn = lambda t: 100*(t-floor(t)) < floor(t))
+
+# Generate the waveform with 1000 samples per unit (i.e., second)
+
+w = shape.wave(0, 100, 1e-3)
+
+# Crudely convert the analog waveform into a digital one.
+
+dw = digital_wave()
+for p in w:
+    dw.append(p[0], p[1])
+
+# Dump the original waveform to a file
+
+dw.dump("before")
+
+# Remove all transients with a duration of less than 0.1 units.
+#
+# Note that rounding errors make it unpredictable whether transients of exactly
+# 0.1 units are considered glitches or not.
+
+dw.debounce(0.1)
+
+# Dump the deglitched waveform to a file
+
+dw.dump("after")
+
+#
+# Visualize the result with:
+#
+# gnuplot> set yrange [-0.2:3.2]
+# gnuplot> plot "before" with lines, "after" using 1:($2+2) with lines
+#


Property changes on: developers/werner/ahrt/host/tmc/demo/deglitch.py
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/ahrt/host/tmc/demo/fft.py
===================================================================
--- developers/werner/ahrt/host/tmc/demo/fft.py	                        (rev 0)
+++ developers/werner/ahrt/host/tmc/demo/fft.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+#
+# fft.py - Generate a square wave and show its frequency spectrum
+#
+
+# Rather inconveniently, NumPy defines "square" as well so we can't just
+# from tmc.shape import *
+
+import tmc.shape
+from numpy import *
+from numpy.fft import *
+
+
+# Describe a 100Hz square wave with amplitude = 5
+shape = tmc.shape.square(high = 5, freq = 100)
+
+# Generate a waveform over t = [0, 1) with 10kSa/s
+wave = shape.wave(0, 1, 1e-4)
+
+
+#
+# The code that follows can be used also for waveforms obtained from a scope
+#
+
+# convert the waveform into a NumPy array
+a = map(lambda p: p[1], wave)
+
+# get the duration of the waveform
+width = wave.end()-wave.start()
+
+# get the number of samples
+n = len(wave)
+
+# do a discrete Fourier transform using the Hann(ing) window
+fa = abs(fft(array(a)*hanning(n)))/n
+
+# obtain the frequency components and put the positive half of the spectrum
+# into a file with one (frequency, amplitude) tuple per line
+savetxt("fft.out", transpose((fftfreq(n, d = width/n)[0:n/2], fa[0:n/2])))


Property changes on: developers/werner/ahrt/host/tmc/demo/fft.py
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/ahrt/host/tmc/demo/screen.py
===================================================================
--- developers/werner/ahrt/host/tmc/demo/screen.py	                        (rev 0)
+++ developers/werner/ahrt/host/tmc/demo/screen.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+#
+# screen.py - Take a screendump from a Rigol DS1000 and write it to a file in
+#             (almost) any format, using ImageMagick
+#
+
+import tmc.scope
+from popen2 import popen2
+from os import popen
+from sys import argv
+
+
+# Open the Rigol DS1000
+scope = tmc.scope.rigol_ds1000c()
+
+# Open a pipe to a process running "convert" from ImageMagick
+pipe = popen("convert - "+argv[1], "w")
+
+# Retrieve the screendump as PPM file and send it to the converter
+pipe.write(scope.screendump())
+
+# Flush the pipe and terminate
+pipe.close()


Property changes on: developers/werner/ahrt/host/tmc/demo/screen.py
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/ahrt/host/tmc/lib/__init__.py
===================================================================

Modified: developers/werner/ahrt/host/tmc/lib/function.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/function.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/function.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,14 +1,21 @@
-#!/usr/bin/python
 #
-# function.py
+# function.py - Function generator control
 #
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
 
-import instrument
-from instrument import setting
+from tmc.instrument import instrument, setting
 
 
-class function(instrument.instrument):
+class function(instrument):
     pass
 
 

Modified: developers/werner/ahrt/host/tmc/lib/instrument.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/instrument.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/instrument.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,17 +1,34 @@
 #
-# instrument.py
+# instrument.py - General instrument infrastructure
 #
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
 #
 # Special thanks to Guillaume "Charlie" Chereau for his assistance with the
 # get/set functionality.
 #
 
-import tmc
+#
+# Known issue: settings can introduce new attributes. We should have a "lock"
+# method to prevent this. @@@@
+#
 
+import _tmc
 
-class setting(object):
 
+class settings(object):
+    pass
+
+class setting(settings):
+
     def __init__(self, instr, path, in_convert = None, out_convert = None,
       args = "", get_cmd = None, set_cmd = None):
 	self.value = None
@@ -55,26 +72,26 @@
 
     def __getattribute__(self, name):
 	ret = super(settable, self).__getattribute__(name)
-	if isinstance(ret, setting):
+	if isinstance(ret, settings):
 	    return ret.get()
 	return ret
 
     def __setattr__(self, name, value):
 	attr = self.__dict__.get(name)
-	if isinstance(attr, setting):
+	if isinstance(attr, settings):
 	    return attr.set(value)
 	return super(settable, self).__setattr__(name, value)
 
 
 #
-# For some reason, we can't subclass tmc.Instr, so we just redefine the few
+# For some reason, we can't subclass _tmc.Instr, so we just redefine the few
 # methods is has. @@@FIXME
 #
 
 class instrument(settable):
 
     def __init__(self, *args):
-	self.__tmc = tmc.Instr(*args)
+	self.__tmc = _tmc.Instr(*args)
 
     def send(self, s):
 	print "SEND", s

Modified: developers/werner/ahrt/host/tmc/lib/meter.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/meter.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/meter.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,14 +1,21 @@
-#!/usr/bin/python
 #
-# meter.py
+# meter.py - Multimeter control
 #
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
 
-import instrument
-from instrument import setting
+from tmc.instrument import instrument, setting
 
 
-class meter(instrument.instrument):
+class meter(instrument):
     pass
 
 

Modified: developers/werner/ahrt/host/tmc/lib/power.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/power.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/power.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,7 +1,15 @@
-#!/usr/bin/python
 #
-# power.py
+# power.py - Power supply control
 #
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
 
 #
@@ -9,10 +17,9 @@
 #
 #
 
-import instrument
-from instrument import settable, setting
+from tmc.instrument import settable, setting, instrument
 
-class power(instrument.instrument):
+class power(instrument):
 	pass
 
 

Modified: developers/werner/ahrt/host/tmc/lib/scope.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/scope.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/scope.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,8 +1,17 @@
-#!/usr/bin/python
 #
 # scope.py - Oscilloscope control
 # 
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
+
 # Found Rigol screen dump algorithm here:
 # http://www.circuitsonline.net/forum/view/message/652573#652573
 #
@@ -18,9 +27,9 @@
 # - triggers
 #
 
-import time, instrument
-from instrument import setting, settable
-from wave import analog_wave, digital_wave
+import time
+from tmc.instrument import setting, settable, instrument
+from tmc.wave import analog_wave, digital_wave
 
 
 # horizontal system only accepts some frequencies
@@ -206,7 +215,7 @@
 
 # ====
 
-class scope(instrument.instrument):
+class scope(instrument):
     pass
 
 

Added: developers/werner/ahrt/host/tmc/lib/shape.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/shape.py	                        (rev 0)
+++ developers/werner/ahrt/host/tmc/lib/shape.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -0,0 +1,171 @@
+#
+# shape.py - Waveform shape description and waveform synthesis
+#
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+#
+# This is a first try at a class that mainly carries the parameters of a
+# subsystem. The idea is to test drive the concept here, and then apply it to
+# the much more complex trigger system
+#
+# Known limitations:
+#
+# - so far, there's only a callback for setting but not for getting.
+# - we don't have a means to set the phase
+#
+
+from math import pi, sin, floor
+from tmc.instrument import settable, settings
+from tmc.wave import analog_wave
+
+
+def set_low(shape, y):
+    if shape.high < y:
+	shape.high = y
+
+
+def set_high(shape, y):
+    if shape.low > y:
+	shape.low = y
+
+
+def set_offset(shape, y):
+    peak = shape.peak
+    shape.low = y-peak/2.0
+    shape.high = y+peak/2.0
+
+
+def set_peak(shape, y):
+    if y < 0:
+	raise hell
+    offset = shape.offset
+    shape.low = offset-y/2.0
+    shape.high = offset+y/2.0
+
+
+def set_freq(shape, f):
+    if f < 0:
+	raise hell
+
+
+def set_period(shape, t):
+    if t < 0:
+	raise hell
+    shape.freq = 1.0/t
+
+
+def set_duty(shape, n):
+    if n < 0 or n > 1:
+	raise hell
+
+
+def set_width(shape, n):
+    if n <= 0 or 1.0/n > shape.freq:
+	raise hell
+    shape.duty = shape.freq*n
+
+
+class shape_setting(settings):
+
+    def __init__(self, shape, init, set_fn = None, get_fn = None):
+	self.shape = shape
+	self.value = init
+	self.set_fn = set_fn
+	self.get_fn = get_fn
+
+    def get(self):
+	if self.get_fn is None:
+	    return self.value
+	else:
+	    return self.get_fn(self.shape)
+
+    def set(self, value):
+	prev = self.value
+	if self.set_fn is not None:
+	    self.set_fn(self.shape, value)
+	self.value = value
+	if self.shape.notify is not None:
+	    self.shape.notify(shape, self, prev, self.value)
+
+
+class shape(settable):
+
+    def __init__(self, notify = None, **list):
+	self.notify = None
+
+	self.low = shape_setting(self, 0, set_low)
+	self.high = shape_setting(self, 0, set_high)
+	self.offset = shape_setting(self, None, set_offset,
+	  lambda shape: (shape.low+shape.high)/2.0)
+	self.peak = shape_setting(self, None, set_peak,
+	  lambda shape: shape.high-shape.low)
+	self.freq = shape_setting(self, 0, set_freq)
+	self.period = shape_setting(self, None, set_period)
+
+	self.set(**list)
+
+    def wave(self, start, end, step):
+	wave = analog_wave()
+	t = start
+	while t <= end:
+	    wave.append(t, self.get(t))
+	    t += step
+	return wave
+
+
+class sine(shape):
+
+    def get(self, t):
+	return sin(2*pi*t*self.freq)*self.peak/2.0+self.offset
+
+
+class square(shape):
+
+    def __init__(self, **list):
+	self.duty = shape_setting(self, 0.5, set_duty)
+	shape.__init__(self, **list)
+
+    def get(self, t):
+	p = t*self.freq
+	return (self.low, self.high)[p-floor(p) < self.duty]
+
+
+class ramp(shape):
+
+    def __init__(self, **list):
+	self.duty = shape_setting(self, 1, set_duty)
+	shape.__init__(self, **list)
+
+    def get(self, t):
+	p = t*self.freq
+	p -= floor(p)
+	if p-floor(p) < self.duty:
+	    return self.low+self.peak*p/self.duty
+	else:
+	    return self.low+self.peak*(1-p)/(1-self.duty)
+
+
+#
+# Arbitrary waveforms are generated by a function f: R -> [0, 1]
+# The time is multiplied with the frequency before being passed to the
+# function. The results is scaled from [0, 1] to [low, high].
+#
+
+
+class arbitrary(shape):
+
+    def __init__(self, **list):
+	self.fn = shape_setting(self, lambda t: 0, None)
+#	self.arg = shape_setting(self, None, None)
+	shape.__init__(self, **list)
+
+    def get(self, t):
+	return self.low+self.peak*self.fn(t*self.freq)


Property changes on: developers/werner/ahrt/host/tmc/lib/shape.py
___________________________________________________________________
Name: svn:executable
   + *

Modified: developers/werner/ahrt/host/tmc/lib/trigger.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/trigger.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/trigger.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,4 +1,17 @@
 #
+# trigger.py - Trigger description and application
+#
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+#
 # @@@ old-style. needs rewriting.
 #
 

Modified: developers/werner/ahrt/host/tmc/lib/wave.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/wave.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/lib/wave.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,7 +1,15 @@
-#!/usr/bin/python
 #
 # wave.py - Analog and digital waveforms
 #
+# Copyright (C) 2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
 
 # waveform: (t, v)*
 # delta-waveform (digital): (s0, t*)
@@ -232,11 +240,8 @@
 	    if self.data[i]+t <= self.data[i+1]:
 		i += 1
 	    else:
-		if i+2 == len(self.data) or self.data[i]+t >= self.data[i+2]:
-		    del self.data[i]
-		    del self.data[i]
-		else:
-		    i += 1
+		del self.data[i]
+		del self.data[i]
 
     def __len__(self):
 	return len(self.data)*2

Modified: developers/werner/ahrt/host/tmc/python.c
===================================================================
--- developers/werner/ahrt/host/tmc/python.c	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/python.c	2008-09-06 13:18:40 UTC (rev 4631)
@@ -224,7 +224,7 @@
 
 static PyTypeObject tmc_instr_type = {
 	PyObject_HEAD_INIT(NULL)
-	.tp_name	= "tmc.Instr",
+	.tp_name	= "_tmc.Instr",
 	.tp_basicsize	= sizeof(struct py_instr),
 	.tp_flags	= Py_TPFLAGS_DEFAULT,
 	.tp_doc		= "TMC objects",
@@ -241,14 +241,14 @@
 };
 
 
-PyMODINIT_FUNC inittmc(void)
+PyMODINIT_FUNC init_tmc(void)
 {
 	PyObject *m;
 
 	tmc_instr_type.tp_new = PyType_GenericNew;
 	if (PyType_Ready(&tmc_instr_type) < 0)
 		return;
-	m = Py_InitModule3("tmc", tmc_methods, "Test & Mesurement Control");
+	m = Py_InitModule3("_tmc", tmc_methods, "Test & Mesurement Control");
 	Py_INCREF(&tmc_instr_type);
 	PyModule_AddObject(m, "Instr", (PyObject *) &tmc_instr_type);
 }

Modified: developers/werner/ahrt/host/tmc/setup.py
===================================================================
--- developers/werner/ahrt/host/tmc/setup.py	2008-09-05 12:52:35 UTC (rev 4630)
+++ developers/werner/ahrt/host/tmc/setup.py	2008-09-06 13:18:40 UTC (rev 4631)
@@ -1,9 +1,14 @@
 from distutils.core import setup, Extension
 
-setup(name="tmc",
-    version="1.0",
-    ext_modules=[
-	Extension("tmc",
-            ["python.c", "tmc.c", "io.c", "telnet.c", "usbtmc.c", "tty.c"],
-            extra_compile_args=["-Wall"],
-	    libraries=["usb"])])
+setup(name = "tmc",
+    version = "0.0",
+    description = "Test and Measurement Control",
+    py_modules = [ "tmc.instrument",
+	"tmc.wave", "tmc.shape",
+        "tmc.meter", "tmc.scope", "tmc.power", "tmc.function" ],
+    package_dir = { "tmc": "lib" },
+    ext_modules = [
+	Extension("_tmc",
+            [ "python.c", "tmc.c", "io.c", "telnet.c", "usbtmc.c", "tty.c" ],
+            extra_compile_args = [ "-Wall" ],
+	    libraries = [ "usb" ]) ])




More information about the commitlog mailing list