Convert to use nested Configs from h5config.
authorW. Trevor King <wking@drexel.edu>
Fri, 29 Jul 2011 12:39:45 +0000 (08:39 -0400)
committerW. Trevor King <wking@drexel.edu>
Fri, 29 Jul 2011 12:39:45 +0000 (08:39 -0400)
pypiezo/afm.py
pypiezo/base.py
pypiezo/config.py

index 685a779a23a40a5296de672fc48482c5c92dd7cb..af96713d6b3cd399fffb61b5384edf5f7dd1df6a 100644 (file)
@@ -73,21 +73,18 @@ class AFMPiezo (_base.Piezo):
 
     >>> axis_config = config.AxisConfig()
     >>> axis_config.update(
-    ...     {'gain':20, 'sensitivity':8e-9, 'minimum':-9})
-    >>> axis_channel_config = config.ChannelConfig()
-    >>> input_channel_config = config.ChannelConfig()
+    ...     {name: 'z', 'gain':20, 'sensitivity':8e-9, 'minimum':-9})
+    >>> axis_config['channel'] = config.OutputChannelConfig()
+    >>> input_config = config.InputChannelConfig()
+    >>> input_config['name'] = 'deflection'
 
-    >>> a = _base.PiezoAxis(axis_config=axis_config,
-    ...     axis_channel_config=axis_channel_config,
-    ...     axis_channel=axis_channel, name='z')
+    >>> a = _base.PiezoAxis(config=axis_config, axis_channel=axis_channel)
     >>> a.setup_config()
 
-    >>> c = _base.InputChannel(
-    ...     channel_config=input_channel_config, channel=input_channel,
-    ...     name='deflection')
+    >>> c = _base.InputChannel(config=input_config, channel=input_channel)
     >>> c.setup_config()
 
-    >>> p = AFMPiezo(axes=[a], input_channels=[c])
+    >>> p = AFMPiezo(axes=[a], input_channels=[c], name='Molly')
 
     >>> deflection = p.read_deflection()
     >>> deflection  # doctest: +SKIP
@@ -98,7 +95,7 @@ class AFMPiezo (_base.Piezo):
     We need to know where we are before we can move somewhere
     smoothly.
 
-    >>> pos = _base.convert_volts_to_bits(p.axes[0].axis_channel_config, 0)
+    >>> pos = _base.convert_volts_to_bits(p.config['axes'][0]['channel'], 0)
     >>> p.jump('z', pos)
 
     Usually `.move_to_pos_or_def` is used to approach the surface, but
@@ -106,10 +103,9 @@ class AFMPiezo (_base.Piezo):
     into the deflection input channel.
 
     >>> target_pos = _base.convert_volts_to_bits(
-    ...     p.axes[0].axis_channel_config, 2)
+    ...     p.config['axes'][0]['channel'], 2)
     >>> step = int((target_pos - pos)/5)
-    >>> target_def = _base.convert_volts_to_bits(
-    ...     p.input_channels[0].channel_config, 3)
+    >>> target_def = _base.convert_volts_to_bits(p.config['inputs'][0], 3)
     >>> data = p.move_to_pos_or_def('z', target_pos, target_def, step=step,
     ...     return_data=True)
     >>> p.last_output == {'z': int(target_pos)}
@@ -125,7 +121,7 @@ class AFMPiezo (_base.Piezo):
 
     >>> p.jump('z', pos)
     >>> target_def = _base.convert_volts_to_bits(
-    ...     p.input_channels[0].channel_config, 1)
+    ...     p.config['inputs'][0]['channel'], 1)
     >>> data = p.move_to_pos_or_def('z', target_pos, target_def, step=step,
     ...     return_data=True)
     >>> print (p.last_output['z'] < int(target_pos))
@@ -292,11 +288,10 @@ class AFMPiezo (_base.Piezo):
                 else:
                     max_amplitude = int(maxdata-offset)
                 offset_meters = _base.convert_bits_to_meters(
-                    output_axis.axis_channel_config, output_axis.axis_config,
-                    offset)
+                    output_axis.config, offset)
                 bit_wavelength = _base.convert_meters_to_bits(
-                    output_axis.axis_channel_config, output_axis.axis_config,
-                    offset_meters + laser_wavelength) - offset
+                    output_axis.config, offset_meters + laser_wavelength
+                    ) - offset
                 amplitude = 2*bit_wavelength
                 log_string = (
                     'generated amplitude for interference wiggle: %g'
index f15e8f39899ddddcb1a26e2e2491b09059fae9dc..4e58cdb449fe627c77e51d49226b50393eec9ed1 100644 (file)
@@ -119,7 +119,7 @@ def convert_meters_to_volts(config, data):
     """
     return data / (config['gain'] * config['sensitivity'])
 
-def convert_bits_to_meters(channel_config, axis_config, data):
+def convert_bits_to_meters(axis_config, data):
     """Convert bit-valued data to meters.
 
     >>> channel_config = _config.ChannelConfig()
@@ -128,20 +128,20 @@ def convert_bits_to_meters(channel_config, axis_config, data):
     >>> axis_config = _config.AxisConfig()
     >>> axis_config['gain'] = 20.0
     >>> axis_config['sensitivity'] = 8e-9
-    >>> convert_bits_to_meters(channel_config, axis_config, 1)
+    >>> axis_config['channel'] = channel_config
+    >>> convert_bits_to_meters(axis_config, 1)
     ... # doctest: +ELLIPSIS
     2.7...e-06
     >>> convert_bits_to_meters(
-    ...     channel_config, axis_config,
-    ...     _numpy.array([-1, 0, 1, 2], dtype=_numpy.float))
+    ...     axis_config, _numpy.array([-1, 0, 1, 2], dtype=_numpy.float))
     ... # doctest: +ELLIPSIS
     array([  1.6...e-07,   9.6...e-07,   2.7...e-06,
              5.4...e-06])
     """
-    data = convert_bits_to_volts(channel_config, data)
+    data = convert_bits_to_volts(axis_config['channel'], data)
     return convert_volts_to_meters(axis_config, data)
 
-def convert_meters_to_bits(channel_config, axis_config, data):
+def convert_meters_to_bits(axis_config, data):
     """Convert meter-valued data to volts.
 
     >>> channel_config = _config.ChannelConfig()
@@ -150,16 +150,17 @@ def convert_meters_to_bits(channel_config, axis_config, data):
     >>> axis_config = _config.AxisConfig()
     >>> axis_config['gain'] = 20.0
     >>> axis_config['sensitivity'] = 8e-9
-    >>> convert_meters_to_bits(channel_config, axis_config, 1.6e-7)
+    >>> axis_config['channel'] = channel_config
+    >>> convert_meters_to_bits(axis_config, 1.6e-7)
     17.0
     >>> convert_meters_to_bits(
-    ...     channel_config, axis_config,
+    ...     axis_config,
     ...     _numpy.array([1.6e-7, 9.6e-7, 2.72e-6, 5.44e-6],
     ...                  dtype=_numpy.float))
     array([   17.,   162.,  1009.,  3746.])
     """
     data = convert_meters_to_volts(axis_config, data)
-    return convert_volts_to_bits(channel_config, data)
+    return convert_volts_to_bits(axis_config['channel'], data)
 
 def _setup_channel_config(config, channel):
     """Initialize the `ChannelConfig` `config` using the
@@ -208,29 +209,25 @@ class PiezoAxis (object):
     >>> for chan in [axis_channel, monitor_channel]:
     ...     chan.range = chan.find_range(unit=UNIT.volt, min=-10, max=10)
 
-    >>> axis_config = _config.AxisConfig()
-    >>> axis_config.update({'gain':20, 'sensitivity':8e-9})
-    >>> axis_channel_config = _config.ChannelConfig()
-    >>> monitor_channel_config = _config.ChannelConfig()
-    >>> monitor_channel_config['device'] = '/dev/comediX'
-
-    >>> p = PiezoAxis(axis_config=axis_config,
-    ...     axis_channel_config=axis_channel_config,
-    ...     monitor_channel_config=monitor_channel_config)
+    >>> config = _config.AxisConfig()
+    >>> config.update({'gain':20, 'sensitivity':8e-9})
+    >>> config['channel'] = _config.OutputChannelConfig()
+    >>> config['monitor'] = _config.InputChannelConfig()
+    >>> config['monitor']['device'] = '/dev/comediX'
+
+    >>> p = PiezoAxis(config=config)
     ... # doctest: +NORMALIZE_WHITESPACE
     Traceback (most recent call last):
       ...
     NotImplementedError: piezo axis control and monitor on different devices
      (/dev/comedi0 and /dev/comediX)
 
-    >>> monitor_channel_config['device'] = axis_channel_config['device']
-    >>> p = PiezoAxis(axis_config=axis_config,
-    ...     axis_channel_config=axis_channel_config,
-    ...     monitor_channel_config=monitor_channel_config,
+    >>> config['monitor']['device'] = config['channel']['device']
+    >>> p = PiezoAxis(config=config,
     ...     axis_channel=axis_channel, monitor_channel=monitor_channel)
 
     >>> p.setup_config()
-    >>> pprint(axis_channel_config)
+    >>> pprint(config['channel'])
     {'channel': 0,
      'conversion-coefficients': array([ -1.00000000e+01,   3.05180438e-04]),
      'conversion-origin': 0.0,
@@ -240,7 +237,7 @@ class PiezoAxis (object):
      'maxdata': 65535L,
      'range': 0,
      'subdevice': 1}
-    >>> pprint(monitor_channel_config)
+    >>> pprint(config['monitor'])
     {'channel': 0,
      'conversion-coefficients': array([ -1.00000000e+01,   3.05180438e-04]),
      'conversion-origin': 0.0,
@@ -251,50 +248,45 @@ class PiezoAxis (object):
      'range': 0,
      'subdevice': 0}
 
-    >>> convert_bits_to_meters(p.axis_channel_config, p.axis_config, 0)
+    >>> convert_bits_to_meters(p.config, 0)
     ... # doctest: +ELLIPSIS
     -1.6...e-06
 
     >>> d.close()
     """
-    def __init__(self, axis_config, axis_channel_config,
-                 monitor_channel_config=None,
-                 axis_channel=None, monitor_channel=None,
-                 name = None):
-        self.axis_config = axis_config
-        self.axis_channel_config = axis_channel_config
-        self.monitor_channel_config = monitor_channel_config
-        if (monitor_channel_config and
-            axis_channel_config['device'] != monitor_channel_config['device']):
+    def __init__(self, config, axis_channel=None, monitor_channel=None):
+        self.config = config
+        if (config['monitor'] and
+            config['channel']['device'] != config['monitor']['device']):
             raise NotImplementedError(
                 ('piezo axis control and monitor on different devices '
                  '(%s and %s)') % (
-                    axis_channel_config['device'],
-                    monitor_channel_config['device']))
+                    config['channel']['device'],
+                    config['monitor']['device']))
         if not axis_channel:
             raise NotImplementedError(
                 'pypiezo not yet capable of opening its own axis channel')
             #axis_channel = pycomedi...
         self.axis_channel = axis_channel
-        if monitor_channel_config and not monitor_channel:
+        if config['monitor'] and not monitor_channel:
             raise NotImplementedError(
                 'pypiezo not yet capable of opening its own monitor channel')
             #monitor_channel = pycomedi...
         self.monitor_channel = monitor_channel
-        self.name = name
+        self.name = config['channel']['name']
 
     def setup_config(self):
         "Initialize the axis (and monitor) configs."
-        _setup_channel_config(self.axis_channel_config, self.axis_channel)
+        _setup_channel_config(self.config['channel'], self.axis_channel)
         if self.monitor_channel:
             _setup_channel_config(
-                self.monitor_channel_config, self.monitor_channel)
-        if self.axis_config['minimum'] is None:
-            self.axis_config['minimum'] = convert_bits_to_volts(
-                self.axis_channel_config, 0)
+                self.config['monitor'], self.monitor_channel)
+        if self.config['minimum'] is None:
+            self.config['minimum'] = convert_bits_to_volts(
+                self.config['channel'], 0)
         if self.axis_config['maximum'] is None:
             self.axis_config['maximum'] = convert_bits_to_volts(
-                self.axis_channel_config, self.axis_channel.get_maxdata())
+                self.config['channel'], self.axis_channel.get_maxdata())
 
 
 class InputChannel(object):
@@ -315,9 +307,9 @@ class InputChannel(object):
     >>> channel = s.channel(0, factory=AnalogChannel, aref=AREF.diff)
     >>> channel.range = channel.find_range(unit=UNIT.volt, min=-10, max=10)
 
-    >>> channel_config = _config.ChannelConfig()
+    >>> channel_config = _config.InputChannelConfig()
 
-    >>> c = InputChannel(channel_config=channel_config, channel=channel)
+    >>> c = InputChannel(config=channel_config, channel=channel)
     >>> c.setup_config()
     >>> pprint(channel_config)
     {'channel': 0,
@@ -330,22 +322,22 @@ class InputChannel(object):
      'range': 0,
      'subdevice': 0}
 
-    >>> convert_bits_to_volts(c.channel_config, 0)
+    >>> convert_bits_to_volts(c.config, 0)
     -10.0
 
     >>> d.close()
     """
-    def __init__(self, channel_config, channel=None, name=None):
-        self.channel_config = channel_config
+    def __init__(self, config, channel=None):
+        self.config = config
         if not channel:
             raise NotImplementedError(
                 'pypiezo not yet capable of opening its own channel')
             #channel = pycomedi...
         self.channel = channel
-        self.name = name
+        self.name = config['name']
 
     def setup_config(self):
-        _setup_channel_config(self.channel_config, self.channel)
+        _setup_channel_config(self.config, self.channel)
 
 
 class Piezo (object):
@@ -374,29 +366,25 @@ class Piezo (object):
     ...     chan.range = chan.find_range(unit=UNIT.volt, min=-10, max=10)
 
     >>> axis_config = _config.AxisConfig()
-    >>> axis_config.update({'gain':20, 'sensitivity':8e-9})
-    >>> axis_channel_config = _config.ChannelConfig()
-    >>> monitor_channel_config = _config.ChannelConfig()
-    >>> input_channel_config = _config.ChannelConfig()
-
-    >>> a = PiezoAxis(axis_config=axis_config,
-    ...     axis_channel_config=axis_channel_config,
-    ...     monitor_channel_config=monitor_channel_config,
-    ...     axis_channel=axis_channel, monitor_channel=monitor_channel,
-    ...     name='z')
+    >>> axis_config.update({'name': 'z', 'gain':20, 'sensitivity':8e-9})
+    >>> axis_config['channel'] = _config.OutputChannelConfig()
+    >>> axis_config['monitor'] = _config.InputChannelConfig()
+    >>> input_config = _config.InputChannelConfig()
+    >>> input_config['name'] = 'some-input'
+
+    >>> a = PiezoAxis(config=axis_config, axis_channel=axis_channel,
+    ...     monitor_channel=monitor_channel)
     >>> a.setup_config()
 
-    >>> c = InputChannel(
-    ...     channel_config=input_channel_config, channel=input_channel,
-    ...     name='some-input')
+    >>> c = InputChannel(config=input_config, channel=input_channel)
     >>> c.setup_config()
 
-    >>> p = Piezo(axes=[a], input_channels=[c])
+    >>> p = Piezo(axes=[a], inputs=[c], name='Charlie')
     >>> inputs = p.read_inputs()
     >>> pprint(inputs)  # doctest: +SKIP
     {'some-input': 34494L, 'z-monitor': 32669L}
 
-    >>> pos = convert_volts_to_bits(p.axes[0].axis_channel_config, 0)
+    >>> pos = convert_volts_to_bits(p.config['axes'][0]['channel'], 0)
     >>> pos
     32767.5
     >>> p.jump('z', pos)
@@ -443,9 +431,14 @@ class Piezo (object):
 
     >>> d.close()
     """
-    def __init__(self, axes, input_channels):
+    def __init__(self, axes, inputs, name=None):
         self.axes = axes
-        self.input_channels = input_channels
+        self.inputs = inputs
+        self.config = _config.PiezoConfig()
+        self.name = name
+        self.config['name'] = name
+        self.config['axes'] = [x.config for x in axes]
+        self.config['inputs'] = [x.config for x in inputs]
         self.last_output = {}
 
     def axis_by_name(self, name):
@@ -457,7 +450,7 @@ class Piezo (object):
 
     def input_channel_by_name(self, name):
         "Get an input channel by its name."
-        for input_channel in self.input_channels:
+        for input_channel in self.inputs:
             if input_channel.name == name:
                 return input_channel
         raise ValueError(name)
@@ -481,7 +474,7 @@ class Piezo (object):
             if a.monitor_channel and direction != 'output':
                 yield ('%s-monitor' % a.name, a.monitor_channel)
         if direction != 'output':
-            for c in self.input_channels:
+            for c in self.inputs:
                 yield (c.name, c.channel)
 
     def channel_by_name(self, name, direction=None):
@@ -551,11 +544,11 @@ class Piezo (object):
         # TODO: check range?
         output_channels = [self.channel_by_name(name=n, direction='output')
                            for n in output_names]
-        input_channels = [self.channel_by_name(name=n, direction='input')
+        inputs = [self.channel_by_name(name=n, direction='input')
                           for n in input_names]
 
         ao_subdevice = output_channels[0].subdevice
-        ai_subdevice = input_channels[0].subdevice
+        ai_subdevice = inputs[0].subdevice
         device = ao_subdevice.device
 
         output_dtype = ao_subdevice.get_dtype()
@@ -563,12 +556,12 @@ class Piezo (object):
             raise ValueError('output dtype %s does not match expected %s'
                              % (data.dtype, output_dtype))
         input_data = _numpy.ndarray(
-            (n_samps, len(input_channels)), dtype=ai_subdevice.get_dtype())
+            (n_samps, len(inputs)), dtype=ai_subdevice.get_dtype())
 
         _LOG.debug('setup ramp commands')
         scan_period_ns = int(1e9 / frequency)
         ai_cmd = ai_subdevice.get_cmd_generic_timed(
-            len(input_channels), scan_period_ns)
+            len(inputs), scan_period_ns)
         ao_cmd = ao_subdevice.get_cmd_generic_timed(
             len(output_channels), scan_period_ns)
 
@@ -576,7 +569,7 @@ class Piezo (object):
         ai_cmd.start_arg = 0
         ai_cmd.stop_src = TRIG_SRC.count
         ai_cmd.stop_arg = n_samps
-        ai_cmd.chanlist = input_channels
+        ai_cmd.chanlist = inputs
         #ao_cmd.start_src = TRIG_SRC.ext
         #ao_cmd.start_arg = 18  # NI card AI_START1 internal AI start signal
         ao_cmd.start_src = TRIG_SRC.int
index 3f7bba863116a90cb6ec8a5f178e5721d6c7815c..a366b31d968287e75fa808c2251787314d5dae14 100644 (file)
@@ -21,7 +21,6 @@ import sys as _sys
 
 import h5config.config as _config
 import h5config.tools as _h5config_tools
-import h5config.util as _util
 
 
 class PackageConfig (_h5config_tools.PackageConfig):
@@ -34,34 +33,13 @@ class PackageConfig (_h5config_tools.PackageConfig):
         ]
 
 
-PackageConfig._clear_class = PackageConfig
-
-
-class AxisConfig (_config.Config):
-    "Configure a single piezo axis"
-    settings = [
-        _config.FloatSetting(
-            name='gain',
-            help=(
-                'Volts applied at piezo per volt output from the DAQ card '
-                '(e.g. if your DAQ output is amplified before driving the '
-                'piezo),')),
-        _config.FloatSetting(
-            name='sensitivity',
-            help='Meters of piezo deflection per volt applied to the piezo.'),
-        _config.FloatSetting(
-            name='minimum',
-            help='Set a lower limit on allowed output voltage',
-            default=None),
-        _config.FloatSetting(
-            name='maximum',
-            help='Set an upper limit on allowed output voltage',
-            default=None),
-        ]
-
-
 class ChannelConfig (_config.Config):
+    "Convigure a single DAC/ADC channel"
     settings = [
+        _config.Setting(
+            name='name',
+            help="Channel name (so the user will know what it's used for).",
+            default=None),
         _config.Setting(
             name='device',
             help='Comedi device.',
@@ -107,9 +85,54 @@ class InputChannelConfig (ChannelConfig):
     pass
 
 
-_util.build_backend_classes(_sys.modules[__name__])
+class AxisConfig (_config.Config):
+    "Configure a single piezo axis"
+    settings = [
+        _config.FloatSetting(
+            name='gain',
+            help=(
+                'Volts applied at piezo per volt output from the DAQ card '
+                '(e.g. if your DAQ output is amplified before driving the '
+                'piezo),')),
+        _config.FloatSetting(
+            name='sensitivity',
+            help='Meters of piezo deflection per volt applied to the piezo.'),
+        _config.FloatSetting(
+            name='minimum',
+            help='Set a lower limit on allowed output voltage',
+            default=None),
+        _config.FloatSetting(
+            name='maximum',
+            help='Set an upper limit on allowed output voltage',
+            default=None),
+        _config.ConfigSetting(
+            name='channel',
+            help='Configure the underlying DAC channel.',
+            config_class=OutputChannelConfig,
+            default=None),
+        _config.ConfigSetting(
+            name='monitor',
+            help='Configure the underlying (optional) ADC monitoring channel.',
+            config_class=InputChannelConfig,
+            default=None),
+        ]
+
 
-PackageConfig._backed_subclasses = [
-    ('.h5', HDF5_PackageConfig),
-    ('.yaml', YAML_PackageConfig)
-    ]
+class PiezoConfig (_config.Config):
+    "Configure a piezo experiment"
+    settings = [
+        _config.ConfigSetting(
+            name='name',
+            help="Piezo name (so the user will know what it's used for).",
+            default=None),
+        _config.ConfigListSetting(
+            name='axes',
+            help='Configure the underlying axes.',
+            config_class=AxisConfig,
+            default=None),
+        _config.ConfigListSetting(
+            name='inputs',
+            help='Configure the underlying (optional) ADC monitoring channels.',
+            config_class=InputChannelConfig,
+            default=None),
+        ]