From db85577a88003c32e363f1e1713b890fc7826488 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 29 Jul 2011 08:39:45 -0400 Subject: [PATCH] Convert to use nested Configs from h5config. --- pypiezo/afm.py | 33 +++++------ pypiezo/base.py | 143 ++++++++++++++++++++++------------------------ pypiezo/config.py | 87 +++++++++++++++++----------- 3 files changed, 137 insertions(+), 126 deletions(-) diff --git a/pypiezo/afm.py b/pypiezo/afm.py index 685a779..af96713 100644 --- a/pypiezo/afm.py +++ b/pypiezo/afm.py @@ -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' diff --git a/pypiezo/base.py b/pypiezo/base.py index f15e8f3..4e58cdb 100644 --- a/pypiezo/base.py +++ b/pypiezo/base.py @@ -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 diff --git a/pypiezo/config.py b/pypiezo/config.py index 3f7bba8..a366b31 100644 --- a/pypiezo/config.py +++ b/pypiezo/config.py @@ -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), + ] -- 2.26.2