From 27790ad67e4706f65de1ec22cfcc51e8d3da03bf Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 15 Sep 2011 08:17:14 -0400 Subject: [PATCH] Convert calibcant to the new, nestable h5config. --- calibcant/T.py | 16 ++-- calibcant/T_analyze.py | 21 ++--- calibcant/analyze.py | 32 ++++--- calibcant/bump.py | 21 ++--- calibcant/bump_analyze.py | 183 +++++++++++++++++++++----------------- calibcant/calibrate.py | 44 ++++----- calibcant/config.py | 22 +++-- calibcant/vib.py | 12 ++- calibcant/vib_analyze.py | 82 ++++++++--------- 9 files changed, 229 insertions(+), 204 deletions(-) diff --git a/calibcant/T.py b/calibcant/T.py index 5898a8c..bf3c29d 100644 --- a/calibcant/T.py +++ b/calibcant/T.py @@ -29,14 +29,14 @@ def T(get_T, temperature_config, filename, group='/'): >>> import os >>> import tempfile - >>> from h5config.hdf5 import pprint_HDF5 - >>> from .config import HDF5_TemperatureConfig + >>> from h5config.storage.hdf5 import HDF5_Storage, pprint_HDF5 + >>> from .config import TemperatureConfig >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) - >>> temperature_config = HDF5_TemperatureConfig( - ... filename=filename, group='/T/config/') + >>> temperature_config = TemperatureConfig(storage=HDF5_Storage( + ... filename=filename, group='/T/config/')) >>> def get_T(): ... return 19.2 >>> t = T(get_T=get_T, temperature_config=temperature_config, @@ -45,8 +45,8 @@ def T(get_T, temperature_config, filename, group='/'): / /T /T/config - - no + + False Celsius @@ -59,8 +59,8 @@ def T(get_T, temperature_config, filename, group='/'): / /T /T/config - - yes + + True Celsius diff --git a/calibcant/T_analyze.py b/calibcant/T_analyze.py index 4831eac..d03bf4d 100644 --- a/calibcant/T_analyze.py +++ b/calibcant/T_analyze.py @@ -30,14 +30,14 @@ The relevant physical quantities are: >>> import os >>> import tempfile >>> import numpy ->>> from .config import HDF5_TemperatureConfig ->>> from h5config.hdf5 import pprint_HDF5 +>>> from .config import TemperatureConfig +>>> from h5config.storage.hdf5 import pprint_HDF5, HDF5_Storage >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) ->>> temperature_config = HDF5_TemperatureConfig( -... filename=filename, group='/T/config/') +>>> temperature_config = TemperatureConfig(storage=HDF5_Storage( +... filename=filename, group='/T/config/')) >>> raw_T = numpy.array([22, 23.5, 24]) >>> processed_T = T_analyze(raw_T, temperature_config) @@ -49,8 +49,8 @@ The relevant physical quantities are: / /T /T/config - - yes + + True Celsius @@ -84,13 +84,14 @@ except (ImportError, RuntimeError), e: _matplotlib = None _matplotlib_import_error = e -from h5config.hdf5 import h5_create_group as _h5_create_group +from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage +from h5config.storage.hdf5 import h5_create_group as _h5_create_group from . import LOG as _LOG from . import package_config as _package_config from .config import Celsius as _Celsius from .config import Kelvin as _Kelvin -from .config import HDF5_TemperatureConfig as _HDF5_TemperatureConfig +from .config import TemperatureConfig as _TemperatureConfig def T_analyze(T, temperature_config): @@ -132,8 +133,8 @@ def T_load(filename, group='/'): raw_T = f[group+'raw'][...] except KeyError: pass - temperature_config = _HDF5_TemperatureConfig( - filename=filename, group=group+'config/') + temperature_config = _TemperatureConfig(storage=_HDF5_Storage( + filename=filename, group=group+'config/')) try: processed_T = f[group+'processed'][...] except KeyError: diff --git a/calibcant/analyze.py b/calibcant/analyze.py index d32e7fa..e29d6c7 100644 --- a/calibcant/analyze.py +++ b/calibcant/analyze.py @@ -44,13 +44,14 @@ Which are related by the parameters: >>> import os >>> import tempfile >>> import numpy ->>> from h5config.hdf5 import pprint_HDF5 ->>> from .config import HDF5_CalibrationConfig +>>> from h5config.storage.hdf5 import HDF5_Storage, pprint_HDF5 +>>> from .config import CalibrationConfig >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) ->>> calibration_config = HDF5_CalibrationConfig(filename, '/calib/config/') +>>> calibration_config = CalibrationConfig(storage=HDF5_Storage( +... filename=filename, group='/calib/config/')) >>> bumps = numpy.array((15.9e6, 16.9e6, 16.3e6)) >>> temperatures = numpy.array((295, 295.2, 294.8)) >>> vibrations = numpy.array((2.20e-5, 2.22e-5, 2.21e-5)) @@ -79,15 +80,21 @@ photodiode sensitivity (bumps). / /calib /calib/config - + + + 10 - + 10 - + 20 - + + + 1 - + + + 5e-05 /calib/processed /calib/processed/spring-constant @@ -140,14 +147,15 @@ except (ImportError, RuntimeError), e: _matplotlib = None _matplotlib_import_error = e -from h5config.hdf5 import h5_create_group as _h5_create_group +from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage +from h5config.storage.hdf5 import h5_create_group as _h5_create_group from . import LOG as _LOG from . import package_config as _package_config from .bump_analyze import bump_analyze as _bump_analyze from .bump_analyze import bump_load as _bump_load from .bump_analyze import bump_save as _bump_save -from .config import HDF5_CalibrationConfig as _HDF5_CalibrationConfig +from .config import CalibrationConfig as _CalibrationConfig from .T_analyze import T_analyze as _temperature_analyze from .T_analyze import T_load as _temperature_load from .T_analyze import T_save as _temperature_save @@ -303,8 +311,8 @@ def calib_load(filename, group='/'): k_s = f[group+'processed/spring-constant/standard-deviation'][...] except KeyError: pass - calibration_config = _HDF5_CalibrationConfig( - filename=filename, group=group+'config/') + calibration_config = _CalibrationConfig(storage=_HDF5_Storage( + filename=filename, group=group+'config/')) calibration_config.load() return (bumps, temperatures, vibrations, calibration_config, k, k_s) diff --git a/calibcant/bump.py b/calibcant/bump.py index 8cf78ad..1e2a5b0 100644 --- a/calibcant/bump.py +++ b/calibcant/bump.py @@ -123,17 +123,17 @@ def bump(afm, bump_config, filename, group='/'): >>> import os >>> import tempfile + >>> from h5config.storage.hdf5 import HDF5_Storage, pprint_HDF5 >>> from pycomedi.device import Device >>> from pycomedi.subdevice import StreamingSubdevice >>> from pycomedi.channel import AnalogChannel, DigitalChannel >>> from pycomedi.constant import AREF, IO_DIRECTION, SUBDEVICE_TYPE, UNIT >>> from pypiezo.afm import AFMPiezo >>> from pypiezo.base import PiezoAxis, InputChannel - >>> from pypiezo.config import (HDF5_ChannelConfig, HDF5_AxisConfig, - ... pprint_HDF5) + >>> from pypiezo.config import ChannelConfig, AxisConfig >>> from stepper import Stepper >>> from pyafm import AFM - >>> from .config import HDF5_BumpConfig + >>> from .config import BumpConfig >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) @@ -161,13 +161,14 @@ def bump(afm, bump_config, filename, group='/'): first few surface approaching steps, which could lead to an `EdgeKink` error instead of a `FlatFit` error. - >>> axis_config = HDF5_AxisConfig(filename, '/bump/config/z/axis') + >>> axis_config = AxisConfig(storage=HDF5_Storage( + ... filename=filename, group='/bump/config/z/axis')) >>> axis_config.update( ... {'gain':20, 'sensitivity':8e-9, 'minimum':-9}) - >>> axis_channel_config = HDF5_ChannelConfig( - ... filename, '/bump/config/z/channel') - >>> input_channel_config = HDF5_ChannelConfig( - ... filename, '/bump/config/deflection/channel') + >>> axis_channel_config = ChannelConfig(storage=HDF5_Storage( + ... filename=filename, group='/bump/config/z/channel')) + >>> input_channel_config = ChannelConfig(storage=HDF5_Storage( + ... filename=filename, group='/bump/config/deflection/channel')) >>> a = PiezoAxis(axis_config=axis_config, ... axis_channel_config=axis_channel_config, @@ -200,8 +201,8 @@ def bump(afm, bump_config, filename, group='/'): Test a bump: - >>> bump_config = HDF5_BumpConfig( - ... filename=filename, group='/bump/config/bump') + >>> bump_config = BumpConfig(storage=HDF5_Storage( + ... filename=filename, group='/bump/config/bump')) >>> bump(afm, bump_config, filename, group='/bump') TODO: replace skipped example data with real-world values >>> pprint_HDF5(filename) # doctest: +ELLIPSIS, +REPORT_UDIFF diff --git a/calibcant/bump_analyze.py b/calibcant/bump_analyze.py index 05ef0b0..ab745b8 100644 --- a/calibcant/bump_analyze.py +++ b/calibcant/bump_analyze.py @@ -46,20 +46,23 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with >>> from pprint import pprint >>> import tempfile >>> import numpy ->>> from .config import HDF5_BumpConfig ->>> from h5config.hdf5 import pprint_HDF5, HDF5_ChannelConfig, HDF5_AxisConfig +>>> from h5config.storage.hdf5 import pprint_HDF5 +>>> from pypiezo.config import ChannelConfig, AxisConfig +>>> from .config import BumpConfig >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) ->>> bump_config = HDF5_BumpConfig(filename=filename, group='/bump/config/') ->>> bump_config.save() ->>> z_channel_config = HDF5_ChannelConfig(filename=None) +>>> bump_config = BumpConfig() +>>> z_channel_config = ChannelConfig() +>>> z_channel_config['name'] = 'z' >>> z_channel_config['maxdata'] = 200 >>> z_channel_config['conversion-coefficients'] = (0,1) >>> z_channel_config['conversion-origin'] = 0 ->>> z_axis_config = HDF5_AxisConfig(filename=None) ->>> deflection_channel_config = HDF5_ChannelConfig(filename=None) +>>> z_axis_config = AxisConfig() +>>> z_axis_config['channel'] = z_channel_config +>>> deflection_channel_config = ChannelConfig() +>>> deflection_channel_config['name'] = 'deflection' >>> deflection_channel_config['maxdata'] = 200 >>> deflection_channel_config['conversion-coefficients'] = (0,1) >>> deflection_channel_config['conversion-origin'] = 0 @@ -70,11 +73,10 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with ... } >>> raw_bump['deflection'][:50] = 50 >>> processed_bump = bump_analyze( -... raw_bump, bump_config, z_channel_config, z_axis_config, -... deflection_channel_config) +... raw_bump, bump_config, z_axis_config, deflection_channel_config) >>> bump_plot(data=raw_bump) # TODO: convert to V and m >>> bump_save(filename=filename, group='/bump/', raw_bump=raw_bump, -... z_channel_config=z_channel_config, z_axis_config=z_axis_config, +... bump_config=bump_config, z_axis_config=z_axis_config, ... deflection_channel_config=deflection_channel_config, ... processed_bump=processed_bump) @@ -82,80 +84,84 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with / /bump /bump/config + /bump/config/bump + + 200 + + quadratic + + 2e-07 + + 1e-06 + + 1024 + + 2.0 /bump/config/deflection /bump/config/deflection/channel - + 0 - - 0, 1 - + + [0 1] + 0 /dev/comedi0 - + 1.0 - + 200 - + + deflection + 1 - + -1 - - 200 - - -5e-08 - - quadratic - - 2e-07 - - 1e-06 - - 1024 - - 2.0 /bump/config/z /bump/config/z/axis - + /bump/config/z/axis/channel + + 0 + + [0 1] + + 0 + + /dev/comedi0 + + + + 1.0 + + 200 + + z + + 1 + + -1 + 1.0 None None - - 1.0 - /bump/config/z/channel - - 0 - - 0, 1 - - 0 - - /dev/comedi0 - + - + 1.0 - - 200 - - 1 - - -1 - 1.00000002115 + 1.00... /bump/raw [50 50 ... 50 51 52 ... 97 98 99] [ 0 1 2 3 ... 97 98 99] ->>> (raw_bump,bump_config,z_channel_config,z_axis_config, -... deflection_channel_config,processed_bump) = bump_load( -... filename=filename, group='/bump/') +>>> (raw_bump,bump_config,z_axis_config,deflection_channel_config, +... processed_bump) = bump_load(filename=filename, group='/bump/') >>> pprint(raw_bump) # doctest: +ELLIPSIS {'deflection': array([50, 50, ... 51, 52, 53, ..., 97, 98, 99], dtype=uint16), @@ -178,27 +184,27 @@ except (ImportError, RuntimeError), e: _matplotlib = None _matplotlib_import_error = e -from h5config.hdf5 import h5_create_group as _h5_create_group +from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage +from h5config.storage.hdf5 import h5_create_group as _h5_create_group from pypiezo.base import convert_bits_to_volts as _convert_bits_to_volts from pypiezo.base import convert_bits_to_meters as _convert_bits_to_meters -from pypiezo.config import HDF5_ChannelConfig as _HDF5_ChannelConfig -from pypiezo.config import HDF5_AxisConfig as _HDF5_AxisConfig +from pypiezo.config import ChannelConfig as _ChannelConfig +from pypiezo.config import AxisConfig as _AxisConfig from . import LOG as _LOG from . import package_config as _package_config from .config import Linear as _Linear from .config import Quadratic as _Quadratic -from .config import HDF5_BumpConfig as _HDF5_BumpConfig +from .config import BumpConfig as _BumpConfig -def bump_analyze(data, bump_config, z_channel_config, z_axis_config, +def bump_analyze(data, bump_config, z_axis_config, deflection_channel_config, plot=False): """Return the slope of the bump. Inputs: data dictionary of data in DAC/ADC bits bump_config `.config._BumpConfig` instance - z_channel_config z `pypiezo.config.ChannelConfig` instance z_axis_config z `pypiezo.config.AxisConfig` instance deflection_channel_config deflection `pypiezo.config.ChannelConfig` instance @@ -209,9 +215,11 @@ def bump_analyze(data, bump_config, z_channel_config, z_axis_config, Checks for strong correlation (r-value) and low randomness chance (p-value). """ - z = _convert_bits_to_meters(z_channel_config, z_axis_config, data['z']) + z = _convert_bits_to_meters(z_axis_config, data['z']) deflection = _convert_bits_to_volts( deflection_channel_config, data['deflection']) + high_voltage_rail = _convert_bits_to_volts( + deflection_channel_config, deflection_channel_config['maxdata']) if bump_config['model'] == _Linear: kwargs = { 'param_guesser': limited_linear_param_guess, @@ -224,10 +232,12 @@ def bump_analyze(data, bump_config, z_channel_config, z_axis_config, 'model': limited_quadratic, 'sensitivity_from_fit_params': limited_quadratic_sensitivity, } - photo_sensitivity = bump_fit(z, deflection, plot=plot, **kwargs) + photo_sensitivity = bump_fit( + z, deflection, high_voltage_rail=high_voltage_rail, plot=plot, + **kwargs) return photo_sensitivity -def limited_linear(x, params): +def limited_linear(x, params, high_voltage_rail): """ Model the bump as: flat region (off-surface) @@ -238,9 +248,11 @@ def limited_linear(x, params): y_contact (y value for the surface-contact kink) slope (dy/dx at the surface-contact kink) """ - high_voltage_rail = 2**16 - 1 # bits x_contact,y_contact,slope = params - y = slope*(x-x_contact) + y_contact + off_surface_mask = x <= x_contact + on_surface_mask = x > x_contact + y = (off_surface_mask * y_contact + + on_surface_mask * (y_contact + slope*(x-x_contact))) y = _numpy.clip(y, y_contact, high_voltage_rail) return y @@ -277,7 +289,7 @@ def limited_linear_sensitivity(params): slope = params[2] return slope -def limited_quadratic(x, params): +def limited_quadratic(x, params, high_voltage_rail): """ Model the bump as: flat region (off-surface) @@ -289,9 +301,12 @@ def limited_quadratic(x, params): slope (dy/dx at the surface-contact kink) quad (d**2 y / dx**2, allow decreasing sensitivity with increased x) """ - high_voltage_rail = 2**16 - 1 # bits x_contact,y_contact,slope,quad = params - y = slope*(x-x_contact) + quad*(x-x_contact)**2+ y_contact + off_surface_mask = x <= x_contact + on_surface_mask = x > x_contact + y = (off_surface_mask * y_contact + + on_surface_mask * ( + y_contact + slope*(x-x_contact) + quad*(x-x_contact)**2)) y = _numpy.clip(y, y_contact, high_voltage_rail) return y @@ -321,7 +336,7 @@ def limited_quadratic_sensitivity(params): slope = params[2] return slope -def bump_fit(z, deflection, +def bump_fit(z, deflection, high_voltage_rail, param_guesser=limited_quadratic_param_guess, model=limited_quadratic, sensitivity_from_fit_params=limited_quadratic_sensitivity, @@ -340,7 +355,7 @@ def bump_fit(z, deflection, """ _LOG.debug('fit bump data with model %s' % model) def residual(p, deflection, z): - return model(z, p) - deflection + return model(z, p, high_voltage_rail=high_voltage_rail) - deflection param_guess = param_guesser(z, deflection) p,cov,info,mesg,ier = _leastsq( residual, param_guess, args=(deflection, z), full_output=True, @@ -353,15 +368,15 @@ def bump_fit(z, deflection, _LOG.debug('solution converged') else: _LOG.debug('solution did not converge') - if plot or _package_config['matplotlib']: - yguess = model(z, param_guess) - yfit = model(z, p) + if plot or _package_config['matplotlib'] or True: + yguess = model(z, param_guess, high_voltage_rail=high_voltage_rail) + yfit = model(z, p, high_voltage_rail=high_voltage_rail) bump_plot({'z': z, 'deflection': deflection}, yguess=yguess, yfit=yfit) return sensitivity_from_fit_params(p) def bump_save(filename, group='/', raw_bump=None, bump_config=None, - z_channel_config=None, z_axis_config=None, - deflection_channel_config=None, processed_bump=None): + z_axis_config=None, deflection_channel_config=None, + processed_bump=None): with _h5py.File(filename, 'a') as f: cwg = _h5_create_group(f, group) if raw_bump is not None: @@ -372,15 +387,15 @@ def bump_save(filename, group='/', raw_bump=None, bump_config=None, pass cwg['raw/z'] = raw_bump['z'] cwg['raw/deflection'] = raw_bump['deflection'] + storage = _HDF5_Storage() for config,key in [(bump_config, 'config/bump'), - (z_channel_config, 'config/z/channel'), (z_axis_config, 'config/z/axis'), (deflection_channel_config, 'config/deflection/channel')]: if config is None: continue config_cwg = _h5_create_group(cwg, key) - config.save(group=config_cwg) + storage.save(config=config, group=config_cwg) if processed_bump is not None: try: del cwg['processed'] @@ -400,11 +415,11 @@ def bump_load(filename, group='/'): } except KeyError: pass - for Config,key in [(_HDF5_BumpConfig, 'config/bump'), - (_HDF5_ChannelConfig, 'config/z/channel'), - (_HDF5_AxisConfig, 'config/z/axis'), - (_HDF5_ChannelConfig, 'config/deflection/channel')]: - config = Config(filename=filename, group=group+key) + for Config,key in [(_BumpConfig, 'config/bump'), + (_AxisConfig, 'config/z/axis'), + (_ChannelConfig, 'config/deflection/channel')]: + config = Config(storage=_HDF5_Storage( + filename=filename, group=group+key)) configs.append(config) try: processed_bump = f[group+'processed'][...] diff --git a/calibcant/calibrate.py b/calibcant/calibrate.py index a3f7058..426abbf 100644 --- a/calibcant/calibrate.py +++ b/calibcant/calibrate.py @@ -116,16 +116,12 @@ def move_far_from_surface(stepper, distance): _LOG.info('step back %d steps (~%g m)' % (steps, distance)) stepper.step_relative(-steps) -def calib_acquire(afm, calibration_config, bump_config, temperature_config, - vibration_config, filename=None, group='/'): +def calib_acquire(afm, calibration_config, filename=None, group='/'): """Acquire data for calibrating a cantilever in one function. Inputs: afm a pyafm.AFM instance calibration_config a .config._CalibrationConfig instance - bump_config a .config._BumpConfig instance - temperature_config a .config._TConfig instance - vibration_config a .config._VibrationConfig instance Outputs (all are arrays of recorded data): bumps measured (V_photodiode / nm_tip) proportionality constant @@ -141,7 +137,7 @@ def calib_acquire(afm, calibration_config, bump_config, temperature_config, bumps = _zeros((calibration_config['num-bumps'],), dtype=_float) for i in range(calibration_config['num-bumps']): _LOG.info('acquire bump %d of %d' % (i, calibration_config['num-bumps'])) - bumps[i] = _bump(afm=afm, bump_config=bump_config, + bumps[i] = _bump(afm=afm, bump_config=calibration_config['bump'], filename=filename, group='%sbump/%d/' % (group, i)) _LOG.debug('bumps: %s' % bumps) @@ -153,7 +149,8 @@ def calib_acquire(afm, calibration_config, bump_config, temperature_config, _LOG.info('acquire T %d of %d' % (i, calibration_config['num-temperatures'])) Ts[i] = _T( - get_T=afm.get_temperature, temperature_config=temperature_config, + get_T=afm.get_temperature, + temperature_config=calibration_config['temperature'], filename=filename, group='%stemperature/%d/' % (group, i)) _sleep(calibration_config['temperature-sleep']) _LOG.debug('temperatures: %s' % Ts) @@ -162,14 +159,13 @@ def calib_acquire(afm, calibration_config, bump_config, temperature_config, vibs = _zeros((calibration_config['num-vibrations'],), dtype=_float) for i in range(calibration_config['num-vibrations']): vibs[i] = _vib( - piezo=afm.piezo, vibration_config=vibration_config, + piezo=afm.piezo, vibration_config=calibration_config['vibration'], filename=filename, group='%svibration/%d/' % (group, i)) _LOG.debug('vibrations: %s' % vibs) return (bumps, Ts, vibs) -def calib(afm, calibration_config, bump_config, temperature_config, - vibration_config, filename=None, group='/'): +def calib(afm, calibration_config, filename=None, group='/'): """Calibrate a cantilever in one function. Inputs: @@ -182,18 +178,18 @@ def calib(afm, calibration_config, bump_config, temperature_config, >>> import os >>> from pprint import pprint >>> import tempfile + >>> from h5config.storage.hdf5 import pprint_HDF5 >>> from pycomedi.device import Device >>> from pycomedi.subdevice import StreamingSubdevice >>> from pycomedi.channel import AnalogChannel, DigitalChannel >>> from pycomedi.constant import AREF, IO_DIRECTION, SUBDEVICE_TYPE, UNIT >>> from pypiezo.afm import AFMPiezo >>> from pypiezo.base import PiezoAxis, InputChannel - >>> from pypiezo.config import (HDF5_ChannelConfig, HDF5_AxisConfig, - ... pprint_HDF5) + >>> from pypiezo.config import ChannelConfig, AxisConfig >>> from stepper import Stepper >>> from pyafm import AFM - >>> from .config import (HDF5_CalibrationConfig, HDF5_BumpConfig, - ... HDF5_TemperatureConfig, HDF5_VibrationConfig) + >>> from .config import (CalibrationConfig, BumpConfig, + ... TemperatureConfig, VibrationConfig) >>> from .analyze import calib_load_all >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') @@ -222,13 +218,11 @@ def calib(afm, calibration_config, bump_config, temperature_config, first few surface approaching steps, which could lead to an `EdgeKink` error instead of a `FlatFit` error. - >>> axis_config = HDF5_AxisConfig(filename, '/bump/config/z/axis') + >>> axis_config = AxisConfig() >>> axis_config.update( ... {'gain':20, 'sensitivity':8e-9, 'minimum':-9}) - >>> axis_channel_config = HDF5_ChannelConfig( - ... filename, '/bump/config/z/channel') - >>> input_channel_config = HDF5_ChannelConfig( - ... filename, '/bump/config/deflection/channel') + >>> axis_channel_config = ChannelConfig() + >>> input_channel_config = ChannelConfig() >>> a = PiezoAxis(axis_config=axis_config, ... axis_channel_config=axis_channel_config, @@ -261,14 +255,10 @@ def calib(afm, calibration_config, bump_config, temperature_config, Test calibration: - >>> calibration_config = HDF5_CalibrationConfig( - ... filename=filename, group='/bump/config/calibration/') - >>> bump_config = HDF5_BumpConfig( - ... filename=filename, group='/bump/config/bump/') - >>> temperature_config = HDF5_TemperatureConfig( - ... filename=filename, group='/bump/config/temperature/') - >>> vibration_config = HDF5_VibrationConfig( - ... filename=filename, group='/bump/config/vibration') + >>> calibration_config = CalibrationConfig() + >>> bump_config = BumpConfig() + >>> temperature_config = TemperatureConfig() + >>> vibration_config = VibrationConfig() >>> calib(afm, calibration_config, bump_config, temperature_config, ... vibration_config, filename=filename, group='/') TODO: replace skipped example data with real-world values diff --git a/calibcant/config.py b/calibcant/config.py index 0a20c8f..cffb58f 100644 --- a/calibcant/config.py +++ b/calibcant/config.py @@ -77,12 +77,6 @@ class Quadratic (_BumpModel): class BumpConfig (_config.Config): "Configure `calibcant` bump operation" settings = [ - _config.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), _config.FloatSetting( name='setpoint', help=('Maximum deflection in volts in case of stepper positioning ' @@ -116,6 +110,10 @@ class BumpConfig (_config.Config): ]), ] +class BumpResult (_config.Config): + "The result of a `calibcant` bump operation" + + class _VibrationModel (object): pass class Variance (_VibrationModel): @@ -174,14 +172,26 @@ class VibrationConfig (_config.Config): class CalibrationConfig (_config.Config): "Configure a full `calibcant` calibration run" settings = [ + _config.ConfigSetting( + name='bump', + help='Configure the surface bumps', + config_class=BumpConfig), _config.IntegerSetting( name='num-bumps', help='Number of surface bumps.', default=10), + _config.ConfigSetting( + name='temperature', + help='Configure the temperature measurements', + config_class=TemperatureConfig), _config.IntegerSetting( name='num-temperatures', help='Number of temperature measurements.', default=10), + _config.ConfigSetting( + name='vibration', + help='Configure the temperature measurements', + config_class=VibrationConfig), _config.IntegerSetting( name='num-vibrations', help='Number of thermal vibration measurements.', diff --git a/calibcant/vib.py b/calibcant/vib.py index e57e1bf..608b9b0 100644 --- a/calibcant/vib.py +++ b/calibcant/vib.py @@ -89,15 +89,15 @@ def vib(piezo, vibration_config, filename, group='/'): >>> import os >>> import tempfile - >>> from h5config.hdf5 import pprint_HDF5 + >>> from h5config.storage.hdf5 import pprint_HDF5 >>> from pycomedi.device import Device >>> from pycomedi.subdevice import StreamingSubdevice >>> from pycomedi.channel import AnalogChannel >>> from pycomedi.constant import AREF, SUBDEVICE_TYPE, UNIT >>> from pypiezo.afm import AFMPiezo >>> from pypiezo.base import InputChannel - >>> from pypiezo.config import HDF5_ChannelConfig - >>> from .config import HDF5_VibrationConfig + >>> from pypiezo.config import ChannelConfig + >>> from .config import VibrationConfig Setup an `AFMPiezo` instance. @@ -113,8 +113,7 @@ def vib(piezo, vibration_config, filename, group='/'): >>> channel = s_in.channel(0, factory=AnalogChannel, aref=AREF.diff) >>> channel.range = channel.find_range( ... unit=UNIT.volt, min=-10, max=10) - >>> channel_config = HDF5_ChannelConfig( - ... filename, group='/vibration/config/deflection/channel') + >>> channel_config = ChannelConfig() >>> c = InputChannel( ... channel_config=channel_config, channel=channel, @@ -125,8 +124,7 @@ def vib(piezo, vibration_config, filename, group='/'): Test a vibration: - >>> vibration_config = HDF5_VibrationConfig( - ... filename=filename, group='/vibration/config/vibration') + >>> vibration_config = VibrationConfig() >>> vib(piezo, vibration_config, filename, group='/vibration') TODO: replace skipped example data with real-world values >>> pprint_HDF5(filename) # doctest: +ELLIPSIS, +REPORT_UDIFF diff --git a/calibcant/vib_analyze.py b/calibcant/vib_analyze.py index 38997a6..6b5d682 100644 --- a/calibcant/vib_analyze.py +++ b/calibcant/vib_analyze.py @@ -31,23 +31,17 @@ The relevent physical quantities are : >>> import random >>> import tempfile >>> import numpy ->>> from .config import HDF5_VibrationConfig ->>> from h5config.hdf5 import pprint_HDF5, HDF5_ChannelConfig +>>> from .config import VibrationConfig +>>> from h5config.storage.hdf5 import pprint_HDF5 +>>> from pypiezo.test import get_piezo_config >>> from pypiezo.base import convert_volts_to_bits >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) ->>> vibration_config = HDF5_VibrationConfig( -... filename=filename, group='/vibration/config/vibration') +>>> piezo_config = get_piezo_config() +>>> vibration_config = VibrationConfig() >>> vibration_config['frequency'] = 50e3 ->>> vibration_config.save() ->>> deflection_channel_config = HDF5_ChannelConfig(filename=None) ->>> deflection_channel_config['maxdata'] = 200 ->>> deflection_channel_config['conversion-coefficients'] = (0,1) ->>> deflection_channel_config['conversion-origin'] = 0 ->>> deflection_channel_config['inverse-conversion-coefficients'] = (0,1) ->>> deflection_channel_config['inverse-conversion-origin'] = 0 We'll be generating a test vibration time series with the following parameters. Make sure these are all floats to avoid accidental @@ -58,7 +52,7 @@ integer division in later steps. >>> k = 0.05 # N/m >>> T = 1/vibration_config['frequency'] >>> T # doctest: +ELLIPSIS -2.00...e-05 +2...e-05 >>> N = int(2**15) # count >>> F_sigma = 1e3 # N @@ -134,7 +128,8 @@ Rearranging and shifting to `j=i-1` Convert the simulated data to bits. >>> deflection = x ->>> deflection_bits = convert_volts_to_bits(deflection_channel_config, x) +>>> deflection_bits = convert_volts_to_bits( +... piezo_config.select_config('inputs', 'deflection'), x) Analyze the simulated data. @@ -145,14 +140,16 @@ Analyze the simulated data. True >>> processed_vibration = vib_analyze( -... deflection_bits, vibration_config, deflection_channel_config) +... deflection_bits, vibration_config, +... piezo_config.select_config('inputs', 'deflection')) >>> processed_vibration # doctest: +SKIP 136457906.25574699 >>> vib_plot(deflection=deflection_bits, vibration_config=vibration_config) >>> vib_save(filename=filename, group='/vibration/', ... raw_vibration=deflection_bits, vibration_config=vibration_config, -... deflection_channel_config=deflection_channel_config, +... deflection_channel_config=piezo_config.select_config( +... 'inputs', 'deflection'), ... processed_vibration=processed_vibration) >>> pprint_HDF5(filename) # doctest: +ELLIPSIS, +REPORT_UDIFF @@ -160,38 +157,40 @@ True /vibration /vibration/config /vibration/config/deflection - + 0 - - 0, 1 - + + [0 1] + 0 /dev/comedi0 - - 0, 1 - + + [0 1] + 0 - - 200 - + + 100 + + deflection + 1 - + -1 /vibration/config/vibration - + 2048 - + 50000.0 - + 25000.0 - + 500.0 Breit-Wigner - - no - + + False + 1 Hann @@ -228,17 +227,18 @@ except (ImportError, RuntimeError), e: _matplotlib = None _matplotlib_import_error = e -from h5config.hdf5 import h5_create_group as _h5_create_group +from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage +from h5config.storage.hdf5 import h5_create_group as _h5_create_group import FFT_tools as _FFT_tools from pypiezo.base import convert_bits_to_volts as _convert_bits_to_volts -from pypiezo.config import HDF5_ChannelConfig as _HDF5_ChannelConfig +from pypiezo.config import ChannelConfig as _ChannelConfig from . import LOG as _LOG from . import package_config as _package_config from .config import Variance as _Variance from .config import BreitWigner as _BreitWigner from .config import OffsetBreitWigner as _OffsetBreitWigner -from .config import HDF5_VibrationConfig as _HDF5_VibrationConfig +from .config import VibrationConfig as _VibrationConfig def vib_analyze_naive(deflection): @@ -459,13 +459,14 @@ def vib_save(filename, group='/', raw_vibration=None, vibration_config=None, except KeyError: pass cwg['raw/deflection'] = raw_vibration + storage = _HDF5_Storage() for config,key in [(vibration_config, 'config/vibration'), (deflection_channel_config, 'config/deflection')]: if config is None: continue config_cwg = _h5_create_group(cwg, key) - config.save(group=config_cwg) + storage.save(config=config, group=config_cwg) if processed_vibration is not None: try: del cwg['processed'] @@ -482,9 +483,10 @@ def vib_load(filename, group='/'): raw_vibration = f[group+'raw/deflection'][...] except KeyError: pass - for Config,key in [(_HDF5_VibrationConfig, 'config/vibration'), - (_HDF5_ChannelConfig, 'config/deflection')]: - config = Config(filename=filename, group=group+key) + for Config,key in [(_VibrationConfig, 'config/vibration'), + (_ChannelConfig, 'config/deflection')]: + config = Config(storage=_HDF5_Storage( + filename=filename, group=group+key)) configs.append(config) try: processed_vibration = f[group+'processed'][...] -- 2.26.2