1 # calibcant - tools for thermally calibrating AFM cantilevers
3 # Copyright (C) 2008-2011 W. Trevor King <wking@drexel.edu>
5 # This file is part of calibcant.
7 # calibcant is free software: you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation, either
10 # version 3 of the License, or (at your option) any later version.
12 # calibcant is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with calibcant. If not, see
19 # <http://www.gnu.org/licenses/>.
21 """Define some variables to configure the package for a particular lab
24 import logging as _logging
25 import os.path as _os_path
28 from FFT_tools import window_hann as _window_hann
29 from pypiezo.config import (
30 _ChoiceSetting, _BooleanSetting, _IntegerSetting, _FloatSetting,
31 _FloatListSetting, _Config, _BackedConfig, _HDF5Config, _YAMLConfig)
33 from . import LOG as _LOG
36 class _BaseConfig (_Config):
37 "Configure `calibcant` module operation"
41 help='Module logging level.',
42 default=_logging.WARN,
44 ('critical', _logging.CRITICAL),
45 ('error', _logging.ERROR),
46 ('warn', _logging.WARN),
47 ('info', _logging.INFO),
48 ('debug', _logging.DEBUG),
52 help='Log to syslog (otherwise log to stderr).',
56 help='Plot piezo motion using `matplotlib`.',
60 help=('Default temperature for thermal calibration in degrees '
65 class _TemperatureUnit (object):
67 class Celsius (_TemperatureUnit):
69 class Kelvin (_TemperatureUnit):
72 class _TemperatureConfig (_Config):
73 "Configure `calibcant` temperature operation"
77 help='Units of raw temperature measurements.',
85 help=('The temperature values are defaults (vs. real '
90 class _BumpModel (object):
92 class Linear (_BumpModel):
94 class Quadratic (_BumpModel):
97 class _BumpConfig (_Config):
98 "Configure `calibcant` bump operation"
101 name='initial-position',
102 help=('Position relative to surface for start of bump in meters. '
103 'Should be less than zero to ensure non-contact region '
104 'before you hit the surface.'),
108 help=('Maximum deflection in volts in case of stepper positioning '
109 'to achieve the initial position.'),
113 help=('Number of stepper steps to move "far" away from the '
114 'surface. For possible stepper adjustments while initially '
115 'locating the surface.'),
119 help='Distance to approach in meters.',
123 help='Approach/retract speed in meters/second.',
127 help='Number of samples during approach and during retreat.',
131 help='Bump deflection model.',
135 ('quadratic', Quadratic),
139 class _VibrationModel (object):
141 class Variance (_VibrationModel):
143 class BreitWigner (_VibrationModel):
145 class OffsetBreitWigner (_VibrationModel):
148 class _VibrationConfig (_Config):
149 "Configure `calibcant` vibration operation"
153 help='Sampling frequency in Hz.',
157 help=('Aquisition time in seconds. This is rounded up as required '
158 'so the number of samples will be an integer power of two.'),
162 help='Vibration model.',
165 ('variance', Variance),
166 ('Breit-Wigner', BreitWigner),
167 ('offset Breit-Wigner', OffsetBreitWigner),
171 help='FFT chunk size (for PSD fits).',
175 help='Overlap FFT chunks (for PSD fits).'),
178 help='FFT chunk window (for PSD fits).',
179 default=_window_hann,
181 ('Hann', _window_hann),
184 name='minimum-fit-frequency',
185 help='Lower bound of Lorentzian fitting region.',
188 name='maximum-fit-frequency',
189 help='Upper bound of Lorentzian fitting region.',
194 class _CalibrationConfig (_Config):
195 "Configure a full `calibcant` calibration run"
199 help='Number of surface bumps.',
202 name='num-temperatures',
203 help='Number of temperature measurements.',
206 name='num-vibrations',
207 help='Number of thermal vibration measurements.',
210 name='temperature-sleep',
211 help=('Time between temperature measurements (in seconds) to get '
212 'independent measurements when reading from slow sensors.'),
215 name='vibration-spacing',
216 help=('Approximate distance from the surface in meters for the '
217 'vibration measurements. This should be large enough that '
218 'surface effects are negligable.'),
223 # Define HDF5- and YAML-backed subclasses of the basic _Config types.
224 for name,obj in locals().items():
225 if (obj != _Config and
226 type(obj) == type and
227 issubclass(obj, _Config) and
228 not issubclass(obj, _BackedConfig)):
229 for prefix,base in [('HDF5', _HDF5Config), ('YAML', _YAMLConfig)]:
230 _name = '%s%s' % (prefix, name)
233 _class = type(_name, _bases, _dict)
234 setattr(_sys.modules[__name__], _name, _class)
236 del name, obj, prefix, base, _name, _bases, _dict, _class
239 def find_base_config():
240 "Return the best `_BaseConfig` match after scanning the filesystem"
241 _LOG.info('looking for base_config file')
242 user_basepath = _os_path.join(_os_path.expanduser('~'), '.calibcantrc')
243 system_basepath = _os_path.join('/etc', 'calibcant', 'config')
244 distributed_basepath = _os_path.join(
245 '/usr', 'share', 'calibcant', 'config')
246 for basepath in [user_basepath, system_basepath, distributed_basepath]:
247 for (extension, config) in [('.h5', HDF5_BaseConfig),
248 ('.yaml', YAML_BaseConfig)]:
249 filename = basepath + extension
250 if _os_path.exists(filename):
251 _LOG.info('base_config file found at %s' % filename)
252 base_config = config(filename)
256 _LOG.debug('no base_config file at %s' % filename)
257 _LOG.info('new base_config file at %s' % filename)
258 basepath = user_basepath
259 filename = basepath + extension
260 return config(filename)