-import numpy
-import time
-import z_piezo_utils
-from splittable_kwargs import splittableKwargsFunction, \
- make_splittable_kwargs_function
-import FFT_tools
-
-import common
-import config
-import bump_analyze
-import T_analyze
-import vib_analyze
-import analyze
-
-# bump family
-
-@splittableKwargsFunction()
-def bump_aquire(zpiezo, push_depth=200, npoints=1024, freq=100e3) :
- """
- Ramps closer push_depth and returns to the original position.
- Inputs:
- zpiezo an opened zpiezo.zpiezo instance
- push_depth distance to approach, in nm
- npoints number points during the approach and during the retreat
- freq rate at which data is aquired
- Returns the aquired ramp data dictionary, with data in DAC/ADC bits.
- """
- # generate the bump output
- start_pos = zpiezo.curPos()
- pos_dist = zpiezo.pos_nm2out(push_depth) - zpiezo.pos_nm2out(0)
- close_pos = start_pos + pos_dist
- appr = numpy.linspace(start_pos, close_pos, npoints)
- retr = numpy.linspace(close_pos, start_pos, npoints)
- out = numpy.concatenate((appr, retr))
- # run the bump, and measure deflection
- if config.TEXT_VERBOSE :
- print "Bump %g nm" % push_depth
- data = zpiezo.ramp(out, freq)
- return data
-
-@splittableKwargsFunction(bump_aquire,
- (bump_analyze.bump_save, 'data'),
- (bump_analyze.bump_analyze, 'data'))
-def bump(**kwargs):
- """
- Wrapper around bump_aquire(), bump_save(), bump_analyze()
- """
- bump_aquire_kwargs,bump_save_kwargs,bump_analyze_kwargs = \
- bump._splitargs(bump, kwargs)
- data = bump_aquire(**bump_aquire_kwargs)
- bump_analyze.bump_save(data, **bump_save_kwargs)
- photoSensitivity = bump_analyze.bump_analyze(data, **bump_analyze_kwargs)
- return photoSensitivity
-
-# T family.
-# Fairly stubby, since a one shot Temp measurement is a common thing.
-# We just wrap that to provide a consistent interface.
-
-@splittableKwargsFunction()
-def T_aquire(get_T=None) :
- """
- Measure the current temperature of the sample,
- or, if get_T == None, fake it by returning config.DEFAULT_TEMP
- """
- if get_T == None :
- if config.TEXT_VERBOSE :
- print "Fake temperature %g" % config.DEFAULT_TEMP
- return config.DEFAULT_TEMP
- else :
- if config.TEXT_VERBOSE :
- print "Measure temperature"
- return get_T()
-
-@splittableKwargsFunction(T_aquire,
- (T_analyze.T_save, 'T'),
- (T_analyze.T_analyze, 'T'))
-def T(**kwargs):
- """
- Wrapper around T_aquire(), T_save(), T_analyze(), T_plot()
- """
- T_aquire_kwargs,T_save_kwargs,T_analyze_kwargs = \
- T._splitargs(T, kwargs)
- T_raw = T_aquire(**T_aquire_kwargs)
- T_analyze.T_save(T_raw, **T_save_kwargs)
- T_ret = T_analyze.T_analyze(T_raw, **T_analyze_kwargs) # returns array
- return T_ret[0]
-
-# vib family
-
-@splittableKwargsFunction()
-def vib_aquire(zpiezo, time=1, freq=50e3) :
- """
- Record data for TIME seconds at FREQ Hz from ZPIEZO at it's current position.
- """
- # round up to the nearest power of two, for efficient FFT-ing
- nsamps = FFT_tools.ceil_pow_of_two(time*freq)
- time = nsamps / freq
- # take some data, keeping the position voltage at it's current value
- out = numpy.ones((nsamps,), dtype=numpy.uint16) * zpiezo.curPos()
- if config.TEXT_VERBOSE :
- print "get %g seconds of data" % time
- data = zpiezo.ramp(out, freq)
- data['sample frequency Hz'] = numpy.array([freq])
- return data
-
-@splittableKwargsFunction(vib_aquire,
- (vib_analyze.vib_save, 'data'),
- (vib_analyze.vib_analyze, 'deflection_bits', 'freq'))
-def vib(**kwargs) :
- """
- Wrapper around vib_aquire(), vib_save(), vib_analyze()
- """
- vib_aquire_kwargs,vib_save_kwargs,vib_analyze_kwargs = \
- vib._splitargs(vib, kwargs)
- data = vib_aquire(**vib_aquire_kwargs)
- vib_analyze.vib_save(data, **vib_save_kwargs)
- freq = data['sample frequency Hz']
- deflection_bits = data['Deflection input']
- Vphoto_var = vib_analyze.vib_analyze(deflection_bits=deflection_bits,
- freq=freq, **vib_analyze_kwargs)
- return Vphoto_var
-
-# A few positioning functions, so we can run bump_aquire() and vib_aquire()
-# with proper spacing relative to the surface.
-
-@splittableKwargsFunction()
-def move_just_onto_surface(stepper, zpiezo, Depth_nm=100, setpoint=2) :
+from time import sleep as _sleep
+
+from numpy import zeros as _zeros
+from numpy import float as _float
+
+import h5py as _h5py
+from pyafm.afm import AFM as _AFM
+from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage
+
+from . import LOG as _LOG
+from .config import CalibrateConfig as _CalibrateConfig
+from .bump import run as _bump
+from .bump_analyze import load as _bump_load
+from .temperature import run as _temperature
+from .temperature_analyze import load as _temperature_load
+from .vibration import run as _vibration
+from .vibration_analyze import load as _vibration_load
+from .analyze import analyze as _analyze
+from .util import SaveSpec as _SaveSpec
+from .util import save as _save
+from .util import load as _load
+
+
+def load(filename=None, group='/'):
+ config = _CalibrateConfig(storage=_HDF5_Storage(
+ filename=filename, group=group))
+ config.load()
+ return Calibrator(config=config)
+
+def load_all(filename=None, group='/', raw=True):
+ "Load all data from a `Calibration.calibrate()` run."
+ assert group.endswith('/'), group
+ calibrator = load(
+ filename=filename, group='{}config/'.format(group))
+ data = calibrator.load_results(
+ filename=filename, group='{}calibration/'.format(group))
+ if raw:
+ raw_data = calibrator.load_raw(filename=filename, group=group)
+ else:
+ raw_data = None
+ return (calibrator, data, raw_data)
+
+
+class Calibrator (object):
+ """Calibrate a cantilever spring constant using the thermal tune method.
+
+ >>> import os
+ >>> from pprint import pprint
+ >>> import tempfile
+ >>> from h5config.storage.hdf5 import pprint_HDF5
+ >>> from pyafm.storage import load_afm
+ >>> from .config import (CalibrateConfig, BumpConfig,
+ ... TemperatureConfig, VibrationConfig)
+
+ >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-')
+ >>> os.close(fd)
+
+ >>> devices = []
+
+ >>> afm = load_afm()
+ >>> afm.load_from_config(devices=devices)
+ >>> if afm.piezo is None:
+ ... raise NotImplementedError('save a better default AFM!')
+ >>> config = CalibrateConfig()
+ >>> config['bump'] = BumpConfig()
+ >>> config['temperature'] = TemperatureConfig()
+ >>> config['vibration'] = VibrationConfig()
+ >>> c = Calibrator(config=config, afm=afm)
+ >>> c.setup_config()
+ >>> k,k_s,data = c.calibrate(filename=filename)
+ >>> k # doctest: +SKIP
+ 0.058402262154840491
+ >>> k_s # doctest: +SKIP
+ 0.0010609833397949553
+ >>> pprint(data) # doctest: +ELLIPSIS, +REPORT_UDIFF
+ {'bump': array([...]),
+ 'temperature': array([...]),
+ 'vibration': array([...])}
+ >>> pprint_HDF5(filename) # doctest: +ELLIPSIS, +REPORT_UDIFF
+ /
+ /bump
+ /bump/0
+ /bump/0/config
+ /bump/0/config/bump
+ <HDF5 dataset "far-steps": shape (), type "<i4">
+ 200
+ <HDF5 dataset "initial-position": shape (), type "<f8">
+ -5e-08
+ ...
+ /bump/0/processed
+ <HDF5 dataset "data": shape (), type "<f8">
+ ...
+ <HDF5 dataset "units": shape (), type "|S3">
+ V/m
+ /bump/0/raw
+ /bump/0/raw/deflection
+ <HDF5 dataset "data": shape (2048,), type "<u2">
+ [...]
+ <HDF5 dataset "units": shape (), type "|S4">
+ bits
+ /bump/0/raw/z
+ <HDF5 dataset "data": shape (2048,), type "<u2">
+ [...]
+ <HDF5 dataset "units": shape (), type "|S4">
+ bits
+ /bump/1
+ ...
+ /config
+ /config/afm
+ <HDF5 dataset "fallback-temperature": shape (), type "<f8">
+ 295.15
+ <HDF5 dataset "far": shape (), type "<f8">
+ 3e-05
+ <HDF5 dataset "main-axis": shape (), type "|S1">
+ z
+ <HDF5 dataset "name": shape (), type "|S5">
+ 1B3D9
+ /config/afm/piezo
+ /config/afm/piezo/axes
+ /config/afm/piezo/axes/0
+ /config/afm/piezo/axes/0/channel
+ <HDF5 dataset "analog-reference": shape (), type "|S6">
+ ground
+ <HDF5 dataset "channel": shape (), type "<i4">
+ 0
+ <HDF5 dataset "conversion-coefficients": shape (2,), type "<f8">
+ [ -1.00000000e+01 3.05180438e-04]
+ <HDF5 dataset "conversion-origin": shape (), type "<f8">
+ 0.0
+ <HDF5 dataset "device": shape (), type "|S12">
+ /dev/comedi0
+ <HDF5 dataset "inverse-conversion-coefficients": shape (2,), type "<f8">
+ [ 0. 3276.75]
+ <HDF5 dataset "inverse-conversion-origin": shape (), type "<f8">
+ -10.0
+ <HDF5 dataset "maxdata": shape (), type "<i8">
+ 65535
+ <HDF5 dataset "name": shape (), type "|S1">
+ z
+ <HDF5 dataset "range": shape (), type "<i4">
+ 0
+ <HDF5 dataset "subdevice": shape (), type "<i4">
+ 1
+ <HDF5 dataset "gain": shape (), type "<f8">
+ 20.0
+ <HDF5 dataset "maximum": shape (), type "<f8">
+ 9.0
+ <HDF5 dataset "minimum": shape (), type "<f8">
+ -9.0
+ <HDF5 dataset "monitor": shape (), type "|S1">
+ <BLANKLINE>
+ <HDF5 dataset "sensitivity": shape (), type "<f8">
+ 8.8e-09
+ /config/afm/piezo/axes/1
+ /config/afm/piezo/axes/1/channel
+ <HDF5 dataset "analog-reference": shape (), type "|S6">
+ ground
+ <HDF5 dataset "channel": shape (), type "<i4">
+ 1
+ <HDF5 dataset "conversion-coefficients": shape (2,), type "<f8">
+ [ -1.00000000e+01 3.05180438e-04]
+ <HDF5 dataset "conversion-origin": shape (), type "<f8">
+ 0.0
+ <HDF5 dataset "device": shape (), type "|S12">
+ /dev/comedi0
+ <HDF5 dataset "inverse-conversion-coefficients": shape (2,), type "<f8">
+ [ 0. 3276.75]
+ <HDF5 dataset "inverse-conversion-origin": shape (), type "<f8">
+ -10.0
+ <HDF5 dataset "maxdata": shape (), type "<i8">
+ 65535
+ <HDF5 dataset "name": shape (), type "|S1">
+ x
+ <HDF5 dataset "range": shape (), type "<i4">
+ 0
+ <HDF5 dataset "subdevice": shape (), type "<i4">
+ 1
+ <HDF5 dataset "gain": shape (), type "<f8">
+ 20.0
+ <HDF5 dataset "maximum": shape (), type "<f8">
+ 8.0
+ <HDF5 dataset "minimum": shape (), type "<f8">
+ -8.0
+ <HDF5 dataset "monitor": shape (), type "|S1">
+ <BLANKLINE>
+ <HDF5 dataset "sensitivity": shape (), type "<f8">
+ 4.16e-09
+ /config/afm/piezo/inputs
+ /config/afm/piezo/inputs/0
+ <HDF5 dataset "analog-reference": shape (), type "|S4">
+ diff
+ <HDF5 dataset "channel": shape (), type "<i4">
+ 0
+ <HDF5 dataset "conversion-coefficients": shape (2,), type "<f8">
+ [ -1.00000000e+01 3.05180438e-04]
+ <HDF5 dataset "conversion-origin": shape (), type "<f8">
+ 0.0
+ <HDF5 dataset "device": shape (), type "|S12">
+ /dev/comedi0
+ <HDF5 dataset "inverse-conversion-coefficients": shape (2,), type "<f8">
+ [ 0. 3276.75]
+ <HDF5 dataset "inverse-conversion-origin": shape (), type "<f8">
+ -10.0
+ <HDF5 dataset "maxdata": shape (), type "<i8">
+ 65535
+ <HDF5 dataset "name": shape (), type "|S10">
+ deflection
+ <HDF5 dataset "range": shape (), type "<i4">
+ 0
+ <HDF5 dataset "subdevice": shape (), type "<i4">
+ 0
+ <HDF5 dataset "name": shape (), type "|S5">
+ 2253E
+ /config/afm/stepper
+ <HDF5 dataset "backlash": shape (), type "<i4">
+ 100
+ <HDF5 dataset "delay": shape (), type "<f8">
+ 0.01
+ <HDF5 dataset "full-step": shape (), type "|b1">
+ True
+ <HDF5 dataset "logic": shape (), type "|b1">
+ True
+ <HDF5 dataset "name": shape (), type "|S9">
+ z-stepper
+ /config/afm/stepper/port
+ <HDF5 dataset "channels": shape (4,), type "<i4">
+ [0 1 2 3]
+ <HDF5 dataset "device": shape (), type "|S12">
+ /dev/comedi0
+ <HDF5 dataset "direction": shape (), type "|S6">
+ output
+ <HDF5 dataset "name": shape (), type "|S12">
+ stepper DB-9
+ <HDF5 dataset "subdevice": shape (), type "<i4">
+ 2
+ <HDF5 dataset "subdevice-type": shape (), type "|S3">
+ dio
+ <HDF5 dataset "step-size": shape (), type "<f8">
+ 1.7e-07
+ /config/afm/temperature
+ <HDF5 dataset "baudrate": shape (), type "<i4">
+ 9600
+ <HDF5 dataset "controller": shape (), type "<i4">
+ 1
+ <HDF5 dataset "device": shape (), type "|S10">
+ /dev/ttyS0
+ <HDF5 dataset "max-current": shape (), type "<f8">
+ 0.0
+ <HDF5 dataset "name": shape (), type "|S14">
+ room (ambient)
+ <HDF5 dataset "units": shape (), type "|S7">
+ Celsius
+ /config/bump
+ <HDF5 dataset "far-steps": shape (), type "<i4">
+ 200
+ <HDF5 dataset "initial-position": shape (), type "<f8">
+ -5e-08
+ <HDF5 dataset "min-slope-ratio": shape (), type "<f8">
+ 10.0
+ <HDF5 dataset "model": shape (), type "|S9">
+ quadratic
+ <HDF5 dataset "push-depth": shape (), type "<f8">
+ 2e-07
+ <HDF5 dataset "push-speed": shape (), type "<f8">
+ 1e-06
+ <HDF5 dataset "samples": shape (), type "<i4">
+ 1024
+ <HDF5 dataset "setpoint": shape (), type "<f8">
+ 2.0
+ <HDF5 dataset "num-bumps": shape (), type "<i4">
+ 10
+ <HDF5 dataset "num-temperatures": shape (), type "<i4">
+ 10
+ <HDF5 dataset "num-vibrations": shape (), type "<i4">
+ 20
+ /config/temperature
+ <HDF5 dataset "sleep": shape (), type "<i4">
+ 1
+ /config/vibration
+ <HDF5 dataset "chunk-size": shape (), type "<i4">
+ 2048
+ <HDF5 dataset "frequency": shape (), type "<f8">
+ 50000.0
+ <HDF5 dataset "maximum-fit-frequency": shape (), type "<f8">
+ 25000.0
+ <HDF5 dataset "minimum-fit-frequency": shape (), type "<f8">
+ 500.0
+ <HDF5 dataset "model": shape (), type "|S12">
+ Breit-Wigner
+ <HDF5 dataset "overlap": shape (), type "|b1">
+ False
+ <HDF5 dataset "sample-time": shape (), type "<i4">
+ 1
+ <HDF5 dataset "window": shape (), type "|S4">
+ Hann
+ <HDF5 dataset "vibration-spacing": shape (), type "<f8">
+ 5e-05
+ /temperature
+ /temperature/0
+ /temperature/0/config
+ /temperature/0/config/temperature
+ <HDF5 dataset "sleep": shape (), type "<i4">
+ 1
+ /temperature/0/processed
+ <HDF5 dataset "data": shape (), type "<f8">
+ ...
+ <HDF5 dataset "units": shape (), type "|S1">
+ K
+ /temperature/0/raw
+ <HDF5 dataset "data": shape (), type "<f8">
+ ...
+ <HDF5 dataset "units": shape (), type "|S1">
+ K
+ /temperature/1
+ ...
+ /vibration
+ /vibration/0
+ /vibration/0/config
+ /vibration/0/config/deflection
+ ...
+ /vibration/0/config/vibration
+ <HDF5 dataset "chunk-size": shape (), type "<i4">
+ 2048
+ <HDF5 dataset "frequency": shape (), type "<f8">
+ 50000.0
+ ...
+ /vibration/0/processed
+ <HDF5 dataset "data": shape (), type "<f8">
+ ...
+ <HDF5 dataset "units": shape (), type "|S6">
+ V^2/Hz
+ /vibration/0/raw
+ <HDF5 dataset "data": shape (65536,), type "<u2">
+ [...]
+ <HDF5 dataset "units": shape (), type "|S4">
+ bits
+ ...
+
+ >>> calibrator,data,raw_data = load_all(filename=filename)
+ >>> calibrator.load_from_config(devices=devices)
+ >>> print(calibrator.config.dump()) # doctest: +ELLIPSIS, +REPORT_UDIFF
+ afm:
+ name: 1B3D9
+ main-axis: z
+ piezo:
+ name: 2253E
+ ...
+ >>> pprint(data) # doctest: +ELLIPSIS, +REPORT_UDIFF
+ {'processed': {'spring_constant': ...
+ 'spring_constant_deviation': ...},
+ 'raw': {'bump': array([...]),
+ 'temperature': array([...]),
+ 'vibration': array([...])}}
+
+ >>> pprint(raw_data) # doctest: +ELLIPSIS, +REPORT_UDIFF
+ {'bump': [{'config': {'bump': <BumpConfig ...>},
+ 'processed': ...,
+ 'raw': {'deflection': array([...], dtype=uint16),
+ 'z': array([...], dtype=uint16)}},
+ {...},
+ ...],
+ 'temperature': [{'config': {'temperature': <TemperatureConfig ...>},
+ 'processed': ...,
+ 'raw': ...},
+ {...},
+ ...],
+ 'vibration': [{'config': {'vibration': <InputChannelConfig ...>},
+ 'processed': ...
+ 'raw': array([...], dtype=uint16)},
+ {...},
+ ...]}
+
+ Close the Comedi devices.
+
+ >>> for device in devices:
+ ... device.close()
+
+ Cleanup our temporary config file.
+
+ >>> os.remove(filename)