Update slow_bend.py to version 0.3.
[blog.git] / posts / slow_bend / slow_bend.py
index bb0cd5d1d9ee5bfb9d97dcd218c9b9c90862d533..0b6963c0fdae7014b2d4553059457b062c553800 100755 (executable)
@@ -4,6 +4,8 @@
 #
 # Version 0.2, WT King, Feb. 20th, 2008
 # (added OptionParser code and stripchart debug parameters)
+# Version 0.3, WT King, Mar. 25th, 2010
+# (added multiple channels option)
 
 """
 Simple single analog channel polling software.
@@ -12,7 +14,7 @@ waking up every dt seconds to record the current voltage.
 Designed for Liming's cellulase activity measurements.
 """
 
-import comedi_single_aio
+import pycomedi.single_aio as single_aio
 import time
 import curses_check_for_keypress
 import stripchart
@@ -20,26 +22,29 @@ import data_logger
 
 DEFAULT_STRIPVERBOSE = False
 TEXT_VERBOSE = False
-LOG_DIR = '~/data/slow_bend' # set LOG_DIR = None to disable logging
+LOG_DIR = '~/rsrch/data/slow_bend' # set LOG_DIR = None to disable logging
 
 class slow_bend :
     """
     Take measurements on a single channel every dt seconds.
     Save '<time>\t<bit_val>\t<physical_val>\n' records.
     """
-    def __init__(self, chan=0, dt=4, log_dir=LOG_DIR) :
+    def __init__(self, chan=[0], dt=4, log_dir=LOG_DIR) :
         if TEXT_VERBOSE :
             print "Initializing slow_bend instance"
-            print " chan %d, dt %g, log_dir %s" % (chan, dt, log_dir)
-        self.ai = comedi_single_aio.ai_obj(chan=[chan])
+            print " chan %s, dt %g, log_dir %s" % (chan, dt, log_dir)
+        self.chan = chan
+        self.ai = single_aio.AI(chan=chan)
         self.dt = dt
         self._data_logger = data_logger.data_log(log_dir, log_name="slow_bend")
         self.savefilename,timestamp = self._data_logger.get_filename()
         self._make_header()
-        self.stripchart = stripchart.stripchart('slow_bend_pipe',
-                                                title='slow bend data')
+        self.stripcharts = [stripchart.stripchart('slow_bend_pipe_%d' % chan,
+                                            title='slow bend data %d' % chan)
+                            for chan in self.chan]
         if DEFAULT_STRIPVERBOSE == True :
-            self.stripchart.open(debug=TEXT_VERBOSE)
+            for chart in self.stripcharts:
+                chart.open(debug=TEXT_VERBOSE)
     def run(self) :
         if TEXT_VERBOSE :
             print "Running slow_bend"
@@ -52,8 +57,9 @@ class slow_bend :
         while self.c.input() == None :
             if TEXT_VERBOSE :
                 self.c.output("Taking measurement\n")
-            tm,bitval,physical = self._take_and_save_reading()
-            self.c.output("%s\t%g\n" % (tm-self.start_time, physical))
+            tm,bitvals,physicals = self._take_and_save_reading()
+            self.c.output("%s\t%s\n" % (tm-self.start_time,
+                          '\t'.join(['%g'%p for p in physicals])))
             next_read_time += self.dt
             self._wait_until(next_read_time)
         del(self.c)
@@ -62,36 +68,45 @@ class slow_bend :
         # but for a slow measurement that's not worth
         # hogging the card.
         self.ai.open()
-        bitval = self.ai.read()[0]
-        physical = self.ai.comedi_to_phys(0,bitval)
+        bitvals = self.ai.read()
+        physicals = [self.ai.comedi_to_phys(0,bitval)
+                     for chan,bitval in zip(self.chan, bitvals)]
         self.ai.close()
         if TEXT_VERBOSE :
-            self.c.output("%d\t%g\n" % (bitval, physical))
-        if self.stripchart.status == "open" :
-            if bitval == 0 :
-                self.stripchart.add_point(-10)
-            elif bitval == 2**16-1 :
-                self.stripchart.add_point(10)
-            else :
-                self.stripchart.add_point(physical)
-        return (bitval, physical)
+            self.c.output('%s\n'
+                          % ('\t'.join(['%d\t%g' % (bitval, physical)
+                                        for bitval,physical
+                                        in zip(bitvals, physicals)])))
+        if self.stripcharts[0].status == "open" :
+            for bitval,physical,stripchart \
+                    in zip(bitvals, physicals, self.stripcharts):
+                if bitval == 0 :
+                    stripchart.add_point(-10)
+                elif bitval == 2**16-1 :
+                    stripchart.add_point(10)
+                else :
+                    stripchart.add_point(physical)
+        return (bitvals, physicals)
     def _make_header(self) :
         "create the save file header"
         fid = file(self.savefilename, 'w')
-        fid.write('#%s\t%s\t%s\n' % ('time (s)',
-                                     'deflection (bits)',
-                                     'deflection (V)'))
+        fid.write('#%s\t%s\n' % ('time (s)',
+                                 '\t'.join(['chan %d (bits)\tchan %g (V)'
+                                            % (chan, chan)
+                                            for chan in self.chan])))
         fid.close()
-    def _save_reading(self, time, bitval, physical) :
+    def _save_reading(self, time, bitvals, physicals) :
         fid = file(self.savefilename, 'a+')
-        fid.write("%g\t%d\t%g\n" % (time - self.start_time,
-                                    bitval, physical))
+        fid.write('%g\t%s\n' % (time - self.start_time,
+                                 '\t'.join(['%d\t%g' % (bitval, physical)
+                                            for bitval,physical
+                                            in zip(bitvals, physicals)])))
         fid.close()
     def _take_and_save_reading(self) :
         tm = time.time()
-        bitval,physical = self._measure_voltage()
-        self._save_reading(tm, bitval, physical)
-        return tm, bitval, physical
+        bitvals,physicals = self._measure_voltage()
+        self._save_reading(tm, bitvals, physicals)
+        return tm, bitvals, physicals
     def _wait_until(self, targ_time) :
         dt = targ_time - time.time()
         if dt > 0 :
@@ -104,14 +119,14 @@ if __name__ == "__main__" :
 
 2008, W. Trevor King.
 """
-    parser = OptionParser(usage=usage_string, version="%prog 0.2")
+    parser = OptionParser(usage=usage_string, version="%prog 0.3")
 
     parser.add_option('-t', '--timestep', dest="dt",
                       help="Measure voltage evert DT seconds (default '%default')",
                       type='float', metavar="DATABASE", default=4.0)
     parser.add_option('-c', '--input-channel', dest="chan",
-                      help="Input voltage CHANNEL (default '%default')",
-                      type='int', metavar="CHANNEL", default=0)
+                      help="Input voltage CHANNEL (default '%default').  Add multiple channels in a comma-seperated list (e.g. 0,1,2,...).",
+                      type='string', metavar="CHANNEL", default='0,1')
     parser.add_option('-d', '--log-directory', dest="log_dir",
                       help="Write output to subdir of LOG_DIR (default %default)",
                       type='string', metavar="LOG_DIR", default=LOG_DIR)
@@ -128,12 +143,13 @@ if __name__ == "__main__" :
 
     (options, args) = parser.parse_args()
     parser.destroy()
+    options.chan = [int(x) for x in options.chan.split(',')]
 
     if options.verbose :
         TEXT_VERBOSE = True
 
     sb = slow_bend(chan=options.chan, dt=options.dt, log_dir=options.log_dir)
     if options.stripchart :
-        sb.stripchart.open(debug=TEXT_VERBOSE)
-
+        for stripchart in sb.stripcharts:
+            stripchart.open(debug=TEXT_VERBOSE)
     sb.run()