Massive rewrite (v 0.6) to base everything on Cython and revamped pypiezo.
authorW. Trevor King <wking@drexel.edu>
Thu, 21 Apr 2011 20:45:59 +0000 (16:45 -0400)
committerW. Trevor King <wking@drexel.edu>
Thu, 21 Apr 2011 20:45:59 +0000 (16:45 -0400)
calibcant/config.py

index 7715cd23dd4869e754775202c8ae15f103e0f051..dc549bb5a9d07f2f06a9523215fd67ec3e4c9abd 100644 (file)
 """Define some variables to configure the package for a particular lab
 and workflow."""
 
-import piezo.z_piezo as z_piezo
-
-
-DEFAULT_TEMP = 22  # assume 22 deg C
-LOG_DATA = True  # quietly grab all real-world data and log to LOG_DIR
-LOG_DIR = '${DEFAULT}/calibrate_cantilever'
-GNUFIT_DATA_BASE='./calibrate_cantilever_fitdata'
-TEXT_VERBOSE = True      # for debugging
-GNUPLOT_VERBOSE = True   # turn on fit check plotting
-PYLAB_VERBOSE = True     # turn on plotting
-PYLAB_INTERACTIVE = True # select between draw() and show() for flushing plots
-BASE_FIGNUM = 20 # to avoid writing to already existing figures
-
-
-# HACK
-# make sure you make a system note (add_system_note) if you change
-# these in case you don't have access to a z_piezo for conversion
-# functions
-
-# zpGain      zpiezo applied voltage per output Volt
-zpGain = z_piezo.DEFAULT_GAIN
-# zpSensitivity  nm zpiezo response per applied Volt
-zpSensitivity = z_piezo.DEFAULT_SENSITIVITY
-# Vzp_out2V   function that converts output DAC bits to Volts
-Vzp_out2V = z_piezo.DEFAULT_VZP_OUT_2_VOLTS
-# Vphoto_in2V function that converts input ADC bits to Volts
-Vphoto_in2V = z_piezo.DEFAULT_VPHOTO_IN_2_VOLTS
-# zeroVphoto_bits  ADC bit output for a 0V input
-zeroVphoto_bits = z_piezo.DEFAULT_ZERO_PHOTODIODE_BITS
+import logging as _logging
+import os.path as _os_path
+import sys as _sys
+
+from FFT_tools import window_hann as _window_hann
+from pypiezo.config import (
+    _ChoiceSetting, _BooleanSetting, _IntegerSetting, _FloatSetting,
+    _FloatListSetting, _Config, _BackedConfig, _HDF5Config, _YAMLConfig)
+
+from . import LOG as _LOG
+
+
+class _BaseConfig (_Config):
+    "Configure `calibcant` module operation"
+    settings = [
+        _ChoiceSetting(
+            name='log-level',
+            help='Module logging level.',
+            default=_logging.WARN,
+            choices=[
+                ('critical', _logging.CRITICAL),
+                ('error', _logging.ERROR),
+                ('warn', _logging.WARN),
+                ('info', _logging.INFO),
+                ('debug', _logging.DEBUG),
+                ]),
+        _BooleanSetting(
+            name='syslog',
+            help='Log to syslog (otherwise log to stderr).',
+            default=False),
+        _BooleanSetting(
+            name='matplotlib',
+            help='Plot piezo motion using `matplotlib`.',
+            default=False),
+        _FloatSetting(
+            name='temperature',
+            help=('Default temperature for thermal calibration in degrees '
+                  'Celsius.'),
+            default=22),
+        ]
+
+class _TemperatureUnit (object):
+    pass
+class Celsius (_TemperatureUnit):
+    pass
+class Kelvin (_TemperatureUnit):
+    pass
+
+class _TemperatureConfig (_Config):
+    "Configure `calibcant` temperature operation"
+    settings = [
+        _ChoiceSetting(
+            name='units',
+            help='Units of raw temperature measurements.',
+            default=Celsius,
+            choices=[
+                ('Celsius', Celsius),
+                ('Kelvin', Kelvin),
+                ]),
+        _BooleanSetting(
+            name='default',
+            help=('The temperature values are defaults (vs. real '
+                  'measurements).'),
+            default=True),
+        ]
+
+class _BumpModel (object):
+    pass
+class Linear (_BumpModel):
+    pass
+class Quadratic (_BumpModel):
+    pass
+
+class _BumpConfig (_Config):
+    "Configure `calibcant` bump operation"
+    settings = [
+        _FloatSetting(
+            name='initial-position',
+            help=('Position relative to surface for start of bump in meters.  '
+                  'Should be less than zero to ensure non-contact region '
+                  'before you hit the surface.'),
+            default=-50e-9),
+        _FloatSetting(
+            name='setpoint',
+            help=('Maximum deflection in volts in case of stepper positioning '
+                  'to achieve the initial position.'),
+            default=2.0),
+        _IntegerSetting(
+            name='far-steps',
+            help=('Number of stepper steps to move "far" away from the '
+                  'surface.  For possible stepper adjustments while initially '
+                  'locating the surface.'),
+            default=200),
+        _FloatSetting(
+            name='push-depth',
+            help='Distance to approach in meters.',
+            default=200e-9),
+        _FloatSetting(
+            name='push-speed',
+            help='Approach/retract speed in meters/second.',
+            default=1e-6),
+        _FloatSetting(
+            name='samples',
+            help='Number of samples during approach and during retreat.',
+            default=1024),
+        _ChoiceSetting(
+            name='model',
+            help='Bump deflection model.',
+            default=Quadratic,
+            choices=[
+                ('linear', Linear),
+                ('quadratic', Quadratic),
+                ]),
+        ]
+
+class _VibrationModel (object):
+    pass
+class Variance (_VibrationModel):
+    pass
+class BreitWigner (_VibrationModel):
+    pass
+class OffsetBreitWigner (_VibrationModel):
+    pass
+
+class _VibrationConfig (_Config):
+    "Configure `calibcant` vibration operation"
+    settings = [
+        _FloatSetting(
+            name='frequency',
+            help='Sampling frequency in Hz.',
+            default=50e3),
+        _FloatSetting(
+            name='sample-time',
+            help=('Aquisition time in seconds.  This is rounded up as required '
+                  'so the number of samples will be an integer power of two.'),
+            default=1),
+        _ChoiceSetting(
+            name='model',
+            help='Vibration model.',
+            default=BreitWigner,
+            choices=[
+                ('variance', Variance),
+                ('Breit-Wigner', BreitWigner),
+                ('offset Breit-Wigner', OffsetBreitWigner),
+                ]),
+        _IntegerSetting(
+            name='chunk-size',
+            help='FFT chunk size (for PSD fits).',
+            default=2048),
+        _BooleanSetting(
+            name='overlap',
+            help='Overlap FFT chunks (for PSD fits).'),
+        _ChoiceSetting(
+            name='window',
+            help='FFT chunk window (for PSD fits).',
+            default=_window_hann,
+            choices=[
+                ('Hann', _window_hann),
+                ]),
+        _FloatSetting(
+            name='minimum-fit-frequency',
+            help='Lower bound of Lorentzian fitting region.',
+            default=500.),
+        _FloatSetting(
+            name='maximum-fit-frequency',
+            help='Upper bound of Lorentzian fitting region.',
+            default=25e3),
+        ]
+
+
+class _CalibrationConfig (_Config):
+    "Configure a full `calibcant` calibration run"
+    settings = [
+        _IntegerSetting(
+            name='num-bumps',
+            help='Number of surface bumps.',
+            default=10),
+        _IntegerSetting(
+            name='num-temperatures',
+            help='Number of temperature measurements.',
+            default=10),
+        _IntegerSetting(
+            name='num-vibrations',
+            help='Number of thermal vibration measurements.',
+            default=20),
+        _FloatSetting(
+            name='temperature-sleep',
+            help=('Time between temperature measurements (in seconds) to get '
+                  'independent measurements when reading from slow sensors.'),
+            default=1),
+        _FloatSetting(
+            name='vibration-spacing',
+            help=('Approximate distance from the surface in meters for the '
+                  'vibration measurements.  This should be large enough that '
+                  'surface effects are negligable.'),
+            default=50e-6),
+        ]
+
+
+# Define HDF5- and YAML-backed subclasses of the basic _Config types.
+for name,obj in locals().items():
+    if (obj != _Config and
+        type(obj) == type and
+        issubclass(obj, _Config) and
+        not issubclass(obj, _BackedConfig)):
+        for prefix,base in [('HDF5', _HDF5Config), ('YAML', _YAMLConfig)]:
+            _name = '%s%s' % (prefix, name)
+            _bases = (base, obj)
+            _dict = {}
+            _class = type(_name, _bases, _dict)
+            setattr(_sys.modules[__name__], _name, _class)
+
+del name, obj, prefix, base, _name, _bases, _dict, _class
+
+
+def find_base_config():
+    "Return the best `_BaseConfig` match after scanning the filesystem"
+    _LOG.info('looking for base_config file')
+    user_basepath = _os_path.join(_os_path.expanduser('~'), '.calibcantrc')
+    system_basepath = _os_path.join('/etc', 'calibcant', 'config')
+    distributed_basepath =  _os_path.join(
+        '/usr', 'share', 'calibcant', 'config')
+    for basepath in [user_basepath, system_basepath, distributed_basepath]:
+        for (extension, config) in [('.h5', HDF5_BaseConfig),
+                                    ('.yaml', YAML_BaseConfig)]:
+            filename = basepath + extension
+            if _os_path.exists(filename):
+                _LOG.info('base_config file found at %s' % filename)
+                base_config = config(filename)
+                base_config.load()
+                return base_config
+            else:
+                _LOG.debug('no base_config file at %s' % filename)
+    _LOG.info('new base_config file at %s' % filename)
+    basepath = user_basepath
+    filename = basepath + extension
+    return config(filename)