# calibcant - tools for thermally calibrating AFM cantilevers
#
-# Copyright (C) 2008-2012 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2008-2013 W. Trevor King <wking@tremily.us>
#
# This file is part of calibcant.
#
from .temperature_analyze import save as _temperature_save
from .vibration_analyze import analyze as _vibration_analyze
from .vibration_analyze import save as _vibration_save
+from .util import SaveSpec as _SaveSpec
+from .util import save as _save
def analyze(bumps, temperatures, vibrations):
v2_m = vibrations.mean() # average voltage variance
v2_s = vibrations.std()
+ if ps_m == 0:
+ raise ValueError('invalid bumps: {}'.format(bumps))
+ if T_m == 0:
+ raise ValueError('invalid temperatures: {}'.format(temperatures))
+ if v2_m == 0:
+ raise ValueError('invalid vibrations: {}'.format(vibrations))
+
# Vphoto / photo_sensitivity = x
# k = kB T / <x**2> = kB T photo_sensitivity**2 / Vphoto_var
#
return figure
_plot = plot # alternative name for use inside analyze_all()
+def save_results(filename=None, group='/', bump=None,
+ temperature=None, vibration=None, spring_constant=None,
+ spring_constant_deviation=None):
+ specs = [
+ _SaveSpec(item=bump, relpath='raw/photodiode-sensitivity',
+ array=True, units='V/m'),
+ _SaveSpec(item=temperature, relpath='raw/temperature',
+ array=True, units='K'),
+ _SaveSpec(item=vibration, relpath='raw/vibration',
+ array=True, units='V^2/Hz'),
+ _SaveSpec(item=spring_constant, relpath='processed/spring-constant',
+ units='N/m', deviation=spring_constant_deviation),
+ ]
+ _save(filename=filename, group=group, specs=specs)
def analyze_all(config, data, raw_data, maximum_relative_error=1e-5,
filename=None, group=None, plot=False, dry_run=False):
if not data.get('vibrations', None):
data['vibration'] = _numpy.zeros(
(config['num-vibrations'],), dtype=float)
+ if 'raw' not in data:
+ data['raw'] = {}
+ if 'bump' not in data['raw']:
+ data['raw']['bump'] = _numpy.zeros((config['num-bumps'],), dtype=float)
+ if 'temperature' not in data['raw']:
+ data['raw']['temperature'] = _numpy.zeros(
+ (config['num-temperatures'],), dtype=float)
+ if 'vibration' not in data['raw']:
+ data['raw']['vibration'] = _numpy.zeros(
+ (config['num-vibrations'],), dtype=float)
axis_config = config['afm']['piezo'].select_config(
setting_name='axes',
attribute_value=config['afm']['main-axis'],
get_attribute=_get_axis_name)
input_config = config['afm']['piezo'].select_config(
setting_name='inputs', attribute_value='deflection')
- bumps_changed = temperatures_changed = vibrations_changed = False
+ calibration_group = None
if not isinstance(group, _h5py.Group) and not dry_run:
- f = _h5py.File(filename, mode)
+ f = _h5py.File(filename, mode='a')
group = _h5_create_group(f, group)
else:
f = None
try:
- for i,bump in enumerate(raw_data['bump']):
+ bumps_changed = len(data['raw']['bump']) != len(data['bump'])
+ for i,bump in enumerate(raw_data.get('bump', [])): # compare values
data['bump'][i],changed = check_bump(
- index=i, bump=bump, z_axis_config=axis_config,
+ index=i, bump=bump, config=config, z_axis_config=axis_config,
deflection_channel_config=input_config, plot=plot,
maximum_relative_error=maximum_relative_error)
if changed and not dry_run:
bumps_changed = True
bump_group = _h5_create_group(group, 'bump/{}'.format(i))
_bump_save(group=bump_group, processed=data['bump'][i])
- for i,temperature in enumerate(raw_data['temperature']):
+ temperatures_changed = len(data['raw']['temperature']) != len(
+ data['temperature'])
+ for i,temperature in enumerate(raw_data.get('temperature', [])):
data['temperature'][i],changed = check_temperature(
- index=i, temperature=temperature,
+ index=i, temperature=temperature, config=config,
maximum_relative_error=maximum_relative_error)
if changed and not dry_run:
temperatures_changed = True
temperature_group = _h5_create_group(
group, 'temperature/{}'.format(i))
_temperature_save(
- group=temerature_group, processed=data['temperature'][i])
- for i,vibration in enumerate(raw_data['vibration']):
+ group=temperature_group, processed=data['temperature'][i])
+ vibrations_changed = len(data['raw']['vibration']) != len(
+ data['vibration'])
+ for i,vibration in enumerate(raw_data.get('vibration', [])):
data['vibration'][i],changed = check_vibration(
- index=i, vibration=vibration,
+ index=i, vibration=vibration, config=config,
deflection_channel_config=input_config, plot=plot,
maximum_relative_error=maximum_relative_error)
if changed and not dry_run:
vibration_group = _h5_create_group(
group, 'vibration/{}'.format(i))
_vibration_save(
- group=vibration_group, processed=data['vibration'])
- k,k_s,changed = check_calibration(
- k=data['processed']['spring_constant'],
- k_s=data['processed']['spring_constant_deviation'],
- bumps=data['bump'],
- temperatures=data['temperature'], vibrations=data['vibration'],
- maximum_relative_error=maximum_relative_error)
- if (changed or bumps_changed or temperatures_changed or
- vibrations_changed) and not dry_run:
+ group=vibration_group, processed=data['vibration'][i])
+ if (bumps_changed or temperatures_changed or vibrations_changed
+ ) and not dry_run:
calibration_group = _h5_create_group(group, 'calibration')
if bumps_changed:
- calib_save(group=calibration_group, bump=data['bump'])
+ save_results(
+ group=calibration_group, bump=data['bump'])
if temperatures_changed:
- calib_save(
+ save_results(
group=calibration_group, temperature=data['temperature'])
if vibrations_changed:
- calib_save(
+ save_results(
group=calibration_group, vibration=data['vibration'])
- if changed:
- calib_save(group=calibration_group, k=k, k_s=k_s)
+ if len(raw_data.get('bump', [])) != len(data['bump']):
+ raise ValueError(
+ 'not enough raw bump data: {} of {}'.format(
+ len(raw_data.get('bump', [])), len(data['bump'])))
+ if len(raw_data.get('temperature', [])) != len(data['temperature']):
+ raise ValueError(
+ 'not enough raw temperature data: {} of {}'.format(
+ len(raw_data.get('temperature', [])),
+ len(data['temperature'])))
+ if len(raw_data['vibration']) != len(data['vibration']):
+ raise ValueError(
+ 'not enough raw vibration data: {} of {}'.format(
+ len(raw_data.get('vibration', [])),
+ len(data['vibration'])))
+ k,k_s,changed = check_calibration(
+ k=data.get('processed', {}).get('spring_constant', None),
+ k_s=data.get('processed', {}).get(
+ 'spring_constant_deviation', None),
+ bumps=data['bump'],
+ temperatures=data['temperature'], vibrations=data['vibration'],
+ maximum_relative_error=maximum_relative_error)
+ if changed and not dry_run:
+ if calibration_group is None:
+ calibration_group = _h5_create_group(group, 'calibration')
+ save_results(
+ group=calibration_group,
+ spring_constant=k, spring_constant_deviation=k_s)
finally:
if f:
f.close()
if plot:
- _plot(bumps=data['raw']['bump'],
- temperatures=data['raw']['temperature'],
- vibrations=data['raw']['vibration'])
+ _plot(bumps=data['bump'],
+ temperatures=data['temperature'],
+ vibrations=data['vibration'])
return (k, k_s)
-def check_bump(index, bump, maximum_relative_error, **kwargs):
+def check_bump(index, bump, config=None, maximum_relative_error=0, **kwargs):
changed = False
+ try:
+ bump_config = bump['config']['bump']
+ except KeyError:
+ bump_config = config['bump']
sensitivity = _bump_analyze(
- config=bump['config']['bump'], data=bump['raw'], **kwargs)
+ config=bump_config, data=bump['raw'], **kwargs)
if bump.get('processed', None) is None:
changed = True
_LOG.warn('new analysis for bump {}: {}'.format(index, sensitivity))
sensitivity-bump['processed'], rel_error))
return (sensitivity, changed)
-def check_temperature(index, temperature, maximum_relative_error, **kwargs):
+def check_temperature(index, temperature, config=None,
+ maximum_relative_error=0, **kwargs):
changed = False
+ try:
+ temp_config = temperature['config']['temperature']
+ except KeyError:
+ temp_config = config['temperature']
temp = _temperature_analyze(
- config=temperature['config']['temperature'],
+ config=temp_config,
temperature=temperature['raw'], **kwargs)
if temperature.get('processed', None) is None:
changed = True
temp-temperature['processed'], rel_error))
return (temp, changed)
-def check_vibration(index, vibration, maximum_relative_error, **kwargs):
+def check_vibration(index, vibration, config=None, maximum_relative_error=0,
+ **kwargs):
changed = False
+ try:
+ vib_config = vibration['config']['vibration']
+ except KeyError:
+ vib_config = config['vibration']
variance = _vibration_analyze(
- config=vibration['config']['vibration'],
- deflection=vibration['raw'], **kwargs)
+ config=vib_config, deflection=vibration['raw'], **kwargs)
if vibration.get('processed', None) is None:
changed = True
- _LOG.warn('new analysis for temperature {}: {}'.format(
+ _LOG.warn('new analysis for vibration {}: {}'.format(
index, variance))
else:
rel_error = abs(variance-vibration['processed'])/vibration['processed']
if rel_error > maximum_relative_error:
+ changed = True
_LOG.warn(("new analysis doesn't match for vibration {}: {} != {} "
"(difference: {}, relative error: {})").format(
index, variance, vibration['processed'],
else:
rel_error = abs(new_k-k)/k
if rel_error > maximum_relative_error:
+ changed = True
_LOG.warn(("new analysis doesn't match for the spring constant: "
"{} != {} (difference: {}, relative error: {})").format(
new_k, k, new_k-k, rel_error))
_LOG.warn('new analysis for the spring constant deviation: {}'.format(
new_k_s))
else:
- rel_error = abs(new_k-k)/k
+ rel_error = abs(new_k_s-k_s)/k_s
if rel_error > maximum_relative_error:
+ changed = True
_LOG.warn(
("new analysis doesn't match for the spring constant deviation"
": {} != {} (difference: {}, relative error: {})").format(