--- /dev/null
+#!/usr/bin/env python2
+#
+# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""Load pulling data from Prof. Yang's LabVIEW puller.
+"""
+
+import datetime as _datetime
+import os as _os
+import re as _re
+import time as _time
+
+from matplotlib import pyplot as _pyplot
+import numpy as _numpy
+from igor.binarywave import load as _load_ibw
+
+
+class Curve (object):
+ _filename_regexp = _re.compile('^([A-Z][a-z]{2}[0-9]{2})_([0-9]+).ibw$')
+ _auxiliary_files = [
+ 'par',
+ 'piz',
+ 'Vz', 'can', 'temp', 'time']
+ _attribute_units = {
+ 'series': None,
+ 'trace': None,
+ 'z piezo sensitivity': 'V/m',
+ 'z input gain': None,
+ 'approach speed': 'm/s',
+ 'setpoint voltage': 'V',
+ 'sleep': 's',
+ 'pull range': 'm',
+ 'pull speed': 'm/s',
+ 'step size': 'm',
+ 'num steps': None,
+ 'points per step': None,
+ 'piezo': 'bits',
+ 'piezo expanded': 'bits',
+ 'deflection': 'bits',
+ 'back': 'm',
+ }
+
+ _attributes = [
+ 'series',
+ 'trace',
+ 'z piezo sensitivity',
+ 'z input gain',
+ 'approach speed',
+ 'setpoint voltage',
+ 'sleep',
+ 'pull range',
+ 'pull speed',
+ 'step size',
+ 'num steps',
+ 'points per step',
+ 'back',
+ ]
+
+ def __init__(self, path, trace=0):
+ self.path = path
+ self.trace = trace
+ self._process_path()
+ self._load()
+
+ def _process_path(self):
+ dirname,filename = _os.path.split(self.path)
+ match = self._filename_regexp.match(filename)
+ month_day,series = match.groups()
+ time = _time.strptime(month_day, '%b%d')
+ self.month = time.tm_mon
+ self.day = time.tm_mday
+ self.series = int(series)
+ self._auxiliary_paths = dict(
+ (aux,
+ _os.path.join(
+ dirname, 'params', '{}{}_{}'.format(
+ month_day, aux, series)))
+ for aux in self._auxiliary_files)
+
+ def _load(self):
+ for aux in self._auxiliary_files:
+ loader = getattr(self, '_load_{}'.format(aux.lower()))
+ data = _load_ibw(self._auxiliary_paths[aux])
+ loader(data=data)
+ data = _load_ibw(self.path)
+ self._load_deflection(data=data)
+
+ def _load_par(self, data):
+ (series,pull_range,pull_speed,self.num_steps,self.points_per_step,
+ self.setpoint_voltage,self.sleep,step_size,back,approach_speed,
+ z_piezo_sensitivity,self.z_input_gain
+ ) = data['wave']['wData']
+ assert series == self.series, (series, self.series)
+ self.pull_range = pull_range * 1e-9 # convert nm -> m
+ self.pull_speed = pull_speed * 1e-9 # convert nm/s -> m/s
+ self.step_size = step_size * 1e-9 # convert nm -> m
+ self.back = back * 1e-9 # convert nm -> m
+ self.approach_speed = approach_speed * 1e-9 # convert nm/s -> m/s
+ # convert nm/V -> V/m
+ self.z_piezo_sensitivity = 1e9 / z_piezo_sensitivity
+
+ def _load_piz(self, data):
+ start = self.trace * self.num_steps
+ stop = (self.trace+1) * self.num_steps
+ self.piezo = data['wave']['wData'][start:stop]
+ self.piezo_expanded = _numpy.concatenate(
+ [[p]*self.points_per_step for p in self.piezo])
+ self.traces = int(len(data['wave']['wData']) / self.num_steps)
+
+ def _load_vz(self, data):
+ pass
+
+ def _load_can(self, data):
+ pass
+
+ def _load_temp(self, data):
+ #print(data['wave']['wData'])
+ pass
+
+ def _load_time(self, data):
+ offset = 3070632000 # saved time = time since 1904 - offset
+ index = self.traces - self.trace
+ time_since_1904 = data['wave']['wData'][-index] + offset
+ # LabVIEW's `Get Date/Time In Seconds` returns seconds since
+ # 1904-01-01T00:00:00Z.
+ dt_1904 = _datetime.datetime(1904, 01, 01, 0, 0, 0)
+ dt_1970 = _datetime.datetime(1970, 01, 01, 0, 0, 0)
+ delta = (dt_1970 - dt_1904).total_seconds()
+ time_since_1970 = time_since_1904 - delta
+ # Unix time is measured from 1970-01-01T00:00:00Z
+ self.time_seconds = time_since_1970
+ self.time = _time.gmtime(time_since_1970)
+ # ISO 8601
+ self.time_iso = _time.strftime('%Y-%m-%dT%H:%M:%S%Z', self.time)
+
+ def _load_deflection(self, data):
+ points = self.num_steps * self.points_per_step
+ start = self.trace * points
+ stop = (self.trace+1) * points
+ self.deflection = data['wave']['wData'][start:stop]
+
+ def get_attribute(self, name):
+ return name.replace(' ', '_')
+
+ def get_attribute_name(self, attribute):
+ return attribute.replace('_', ' ')
+
+ def get_attribute_units(self, attribute):
+ name = self.get_attribute_name(attribute)
+ return self._attribute_units.get(name, None)
+
+ def dumps(self):
+ lines = ['time = {} ({})'.format(self.time_iso, self.time_seconds)]
+ for name in self._attributes:
+ attr = self.get_attribute(name)
+ value = getattr(self, attr)
+ units = self.get_attribute_units(attr)
+ if units:
+ lines.append('{} = {} {}'.format(name, value, units))
+ else:
+ lines.append('{} = {}'.format(name, value))
+ return '\n'.join(lines)
+
+ def plot(self):
+ figure = _pyplot.figure()
+ axes = figure.add_subplot(1, 1, 1)
+ axes.plot(self.piezo_expanded, self.deflection, 'b.')
+
+
+def load_all_traces(path):
+ curve = Curve(path=path)
+ yield curve
+ for trace in range(1, curve.traces):
+ yield Curve(path=path, trace=trace)
+
+
+if __name__ == '__main__':
+ import argparse
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ 'path', nargs='+',
+ help='path to load')
+
+ args = parser.parse_args()
+
+ for path in args.path:
+ if ':' in path:
+ path,trace = path.split(':')
+ curve = Curve(path=path, trace=int(trace))
+ print(curve.dumps())
+ curve.plot()
+ else:
+ for curve in load_all_traces(path):
+ print(curve.dumps())
+ curve.plot()
+ _pyplot.show()