gyang_curve.py: reader for LabVIEW unfolding experiments.
authorW. Trevor King <wking@tremily.us>
Thu, 11 Oct 2012 22:19:34 +0000 (18:19 -0400)
committerW. Trevor King <wking@tremily.us>
Thu, 11 Oct 2012 22:19:34 +0000 (18:19 -0400)
posts/Comparing_velocity_clamp_experiments/gyang_curve.py [new file with mode: 0755]

diff --git a/posts/Comparing_velocity_clamp_experiments/gyang_curve.py b/posts/Comparing_velocity_clamp_experiments/gyang_curve.py
new file mode 100755 (executable)
index 0000000..310e514
--- /dev/null
@@ -0,0 +1,210 @@
+#!/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()