X-Git-Url: http://git.tremily.us/?p=calibcant.git;a=blobdiff_plain;f=calibcant%2Fbump_analyze.py;h=d5256fc84bd1ea660c05c81b6bfc73d188d35de9;hp=67312a80d3683f2751f9ff9d877cce57b2c9a51b;hb=560f9f9;hpb=ee9d140813ea4a3419f7c12ae63e808ceb1ab8a1 diff --git a/calibcant/bump_analyze.py b/calibcant/bump_analyze.py index 67312a8..d5256fc 100644 --- a/calibcant/bump_analyze.py +++ b/calibcant/bump_analyze.py @@ -18,7 +18,7 @@ """Surface bump analysis (measures photodiode sensitivity). -Separate the more general `bump_analyze()` from the other `bump_*()` +Separate the more general `analyze()` from the other `bump_*()` functions in calibcant. The relevant physical quantities are: @@ -38,7 +38,7 @@ Which are related by the parameters: `photo_sensitivity` is measured by bumping the cantilever against the surface, where `Zp = Zcant` (see `calibrate.bump_acquire()`). The measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with -`bump_analyze()`. +`analyze()`. >>> import os >>> from pprint import pprint @@ -51,7 +51,7 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') >>> os.close(fd) ->>> bump_config = BumpConfig() +>>> config = BumpConfig() >>> z_channel_config = ChannelConfig() >>> z_channel_config['name'] = 'z' >>> z_channel_config['maxdata'] = 200 @@ -65,18 +65,17 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with >>> deflection_channel_config['conversion-coefficients'] = (0,1) >>> deflection_channel_config['conversion-origin'] = 0 ->>> raw_bump = { +>>> raw = { ... 'z': numpy.arange(100, dtype=numpy.uint16), ... 'deflection': numpy.arange(100, dtype=numpy.uint16), ... } ->>> raw_bump['deflection'][:50] = 50 ->>> processed_bump = bump_analyze( -... 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, -... bump_config=bump_config, z_axis_config=z_axis_config, -... deflection_channel_config=deflection_channel_config, -... processed_bump=processed_bump) +>>> raw['deflection'][:50] = 50 +>>> processed = analyze( +... config=config, data=raw, z_axis_config=z_axis_config, +... deflection_channel_config=deflection_channel_config) +>>> plot(data=raw) # TODO: convert to V and m +>>> save(filename=filename, group='/bump/', +... config=config, raw=raw, processed=processed) >>> pprint_HDF5(filename) # doctest: +ELLIPSIS, +REPORT_UDIFF / @@ -87,6 +86,8 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with 200 -5e-08 + + 10.0 quadratic @@ -97,82 +98,34 @@ measured slope `Vphoto/Vout` is converted to `photo_sensitivity` with 1024 2.0 - /bump/config/deflection - /bump/config/deflection/channel - - 0 - - [0 1] - - 0 - - /dev/comedi0 - - - - 1.0 - - 200 - - deflection - - 1 - - -1 - /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 - - 1.00... + /bump/processed + + 1.00... + + V/m /bump/raw - - [50 50 ... 50 51 52 ... 97 98 99] - - [ 0 1 2 3 ... 97 98 99] - ->>> (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), - 'z': array([ 0, 1, 2, ..., 97, 98, 99], dtype=uint16)} ->>> processed_bump # doctest: +ELLIPSIS -1.00... + /bump/raw/deflection + + [50 50 ... 50 51 52 ... 97 98 99] + + bits + /bump/raw/z + + [ 0 1 2 3 ... 97 98 99] + + bits + +>>> data = load(filename=filename, group='/bump/') + +>>> pprint(data) # doctest: +ELLIPSIS, +REPORT_UDIFF +{'config': {'bump': }, + 'processed': 1.00..., + 'raw': {'deflection': array([50, 50, ..., 52, 53, ..., 98, 99], dtype=uint16), + 'z': array([ 0, 1, 2, ..., 97, 98, 99], dtype=uint16)}} >>> os.remove(filename) """ -import h5py as _h5py import numpy as _numpy from scipy.optimize import leastsq as _leastsq @@ -184,30 +137,31 @@ except (ImportError, RuntimeError), e: _matplotlib = None _matplotlib_import_error = e -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 ChannelConfig as _ChannelConfig from pypiezo.config import AxisConfig as _AxisConfig +from pypiezo.config import InputChannelConfig as _InputChannelConfig 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 BumpConfig as _BumpConfig +from .util import SaveSpec as _SaveSpec +from .util import save as _save +from .util import load as _load -def bump_analyze(data, bump_config, z_axis_config, - deflection_channel_config, plot=False): +def analyze(config, data, 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 + config `.config._BumpConfig` instance z_axis_config z `pypiezo.config.AxisConfig` instance deflection_channel_config - deflection `pypiezo.config.ChannelConfig` instance + deflection `pypiezo.config.InputChannelConfig` instance plot boolean overriding matplotlib config setting. Returns: photo_sensitivity (Vphoto/Zcant) in Volts/m @@ -220,7 +174,7 @@ def bump_analyze(data, bump_config, z_axis_config, deflection_channel_config, data['deflection']) high_voltage_rail = _convert_bits_to_volts( deflection_channel_config, deflection_channel_config['maxdata']) - if bump_config['model'] == _Linear: + if config['model'] == _Linear: kwargs = { 'param_guesser': limited_linear_param_guess, 'model': limited_linear, @@ -232,7 +186,7 @@ def bump_analyze(data, bump_config, z_axis_config, 'model': limited_quadratic, 'sensitivity_from_fit_params': limited_quadratic_sensitivity, } - photo_sensitivity = bump_fit( + photo_sensitivity = fit( z, deflection, high_voltage_rail=high_voltage_rail, plot=plot, **kwargs) return photo_sensitivity @@ -338,11 +292,11 @@ def limited_quadratic_sensitivity(params): slope = params[2] return slope -def bump_fit(z, deflection, high_voltage_rail, - param_guesser=limited_quadratic_param_guess, - model=limited_quadratic, - sensitivity_from_fit_params=limited_quadratic_sensitivity, - plot=False): +def fit(z, deflection, high_voltage_rail, + param_guesser=limited_quadratic_param_guess, + model=limited_quadratic, + sensitivity_from_fit_params=limited_quadratic_sensitivity, + plot=False): """Fit a aurface bump and return the photodiode sensitivitiy. Parameters: @@ -359,9 +313,16 @@ def bump_fit(z, deflection, high_voltage_rail, def residual(p, deflection, z): 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, - maxfev=int(10e3)) + try: + p,cov,info,mesg,ier = _leastsq( + residual, param_guess, args=(deflection, z), full_output=True, + maxfev=int(10e3)) + except ValueError: + zd = _numpy.ndarray(list(z.shape) + [2], dtype=z.dtype) + zd[:,0] = z + zd[:,1] = d + _numpy.savetxt('/tmp/z-deflection.dat', zd, delimiter='\t') + raise _LOG.debug('fitted params: %s' % p) _LOG.debug('covariance matrix: %s' % cov) #_LOG.debug('info: %s' % info) @@ -373,68 +334,41 @@ def bump_fit(z, deflection, high_voltage_rail, if plot or _package_config['matplotlib']: 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) + _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_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: - for k in ['z', 'deflection']: - try: - del cwg['raw/{}'.format(k)] - except KeyError: - 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_axis_config, 'config/z/axis'), - (deflection_channel_config, - 'config/deflection/channel')]: - if config is None: - continue - config_cwg = _h5_create_group(cwg, key) - storage.save(config=config, group=config_cwg) - if processed_bump is not None: - try: - del cwg['processed'] - except KeyError: - pass - cwg['processed'] = processed_bump - -def bump_load(filename, group='/'): - assert group.endswith('/') - raw_bump = processed_bump = None - configs = [] - with _h5py.File(filename, 'a') as f: - try: - raw_bump = { - 'z': f[group+'raw/z'][...], - 'deflection': f[group+'raw/deflection'][...], - } - except KeyError: - pass - 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 = float(f[group+'processed'][...]) - except KeyError: - pass - ret = [raw_bump] - ret.extend(configs) - ret.append(processed_bump) - for config in configs: - config.load() - return tuple(ret) - -def bump_plot(data, yguess=None, yfit=None): +def save(filename=None, group='/', config=None, z_axis_config=None, + deflection_channel_config=None, raw=None, processed=None): + specs = [ + _SaveSpec(item=config, relpath='config/bump', config=_BumpConfig), + _SaveSpec(item=z_axis_config, relpath='config/z', config=_AxisConfig), + _SaveSpec(item=deflection_channel_config, relpath='config/deflection', + config=_InputChannelConfig), + _SaveSpec(item=processed, relpath='processed', units='V/m'), + ] + if raw is not None: + for key in raw.keys(): + specs.append(_SaveSpec( + item=raw[key], relpath='raw/{}'.format(key), array=True, + units='bits')) + _save(filename=filename, group=group, specs=specs) + +def load(filename=None, group='/'): + specs = [ + _SaveSpec(key=('config', 'bump'), relpath='config/bump', + config=_BumpConfig), + _SaveSpec(key=('config', 'z_axis_config'), relpath='config/z', + config=_AxisConfig), + _SaveSpec(key=('config', 'deflection_channel_config'), + relpath='config/deflection', config=_InputChannelConfig), + _SaveSpec(key=('raw', 'z'), relpath='raw/z', array=True, units='bits'), + _SaveSpec(key=('raw', 'deflection'), relpath='raw/deflection', + array=True, units='bits'), + _SaveSpec(key=('processed',), relpath='processed', units='V/m'), + ] + return _load(filename=filename, group=group, specs=specs) + +def plot(data, yguess=None, yfit=None): "Plot the bump (Vphoto vs Vzp)" if not _matplotlib: raise _matplotlib_import_error @@ -466,3 +400,4 @@ def bump_plot(data, yguess=None, yfit=None): residual_axes.set_ylabel('Photodiode (Volts)') if hasattr(figure, 'show'): figure.show() +_plot = plot # alternative name for use inside fit()