Use relative imports (PEP 328) for calibcant sibling imports.
[calibcant.git] / calibcant / vib_analyze.py
index 74e1ed4e2e00425812eabf8947e1e67ef705269d..67d75193f2ee7ddd9f09ee689cefc7159a48ec68 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # calibcant - tools for thermally calibrating AFM cantilevers
 #
-# Copyright (C) 2007,2008, William Trevor King
+# Copyright (C) 2007-2009 William Trevor King
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
@@ -33,15 +33,18 @@ The relevent physical quantities are :
 """
 
 import os, time, numpy
-import GnuplotBiDir   # used for fitting lorentzian
-import scipy.optimize # alternative for fitting lorentzian
-import common # common module for the calibcant package
-import config # config module for the calibcant package
+import GnuplotBiDir   # can be used for fitting lorentzian
+import scipy.optimize # can be used for fitting lorentzian
+
 import data_logger
 import FFT_tools
 from splittable_kwargs import splittableKwargsFunction, \
     make_splittable_kwargs_function
 
+import .common
+import .config
+
+
 PLOT_GUESSED_LORENTZIAN=False
 
 @splittableKwargsFunction()
@@ -55,8 +58,12 @@ def vib_analyze_naive(deflection_bits, Vphoto_in2V=config.Vphoto_in2V,
     Vphoto_in2V is a function converting Vphoto values from bits to Volts.
     This function is assumed linear, see bump_analyze().
     """
+    if config.TEXT_VERBOSE :
+        print "Calculating the naive (raw) variance"
     Vphoto_std_bits = deflection_bits.std()
     Vphoto_std = Vphoto_in2V(Vphoto_std_bits + zeroVphoto_bits)
+    if config.TEXT_VERBOSE :
+        print "Average deflection (Volts):", Vphoto_in2V(deflection_bits.mean())
     return Vphoto_std**2
 
 #@splittableKwargsFunction((fit_psd, 'freq_axis', 'psd_data'),
@@ -95,9 +102,11 @@ def vib_analyze(deflection_bits, freq,
         print "Converting %d bit values to voltages" % len(Vphoto_t)
     for i in range(len(deflection_bits)) :
         Vphoto_t[i] = Vphoto_in2V(deflection_bits[i])
-
+    if config.TEXT_VERBOSE :
+        print "Average deflection (Volts):", Vphoto_t.mean()
+    
     # Compute the average power spectral density per unit time (in uV**2/Hz)
-    if config.TEXT_VERBOSE : 
+    if config.TEXT_VERBOSE :
         print "Compute the averaged power spectral density in uV**2/Hz"
     (freq_axis, power) = \
         FFT_tools.unitary_avg_power_spectrum((Vphoto_t - Vphoto_t.mean())*1e6,
@@ -105,7 +114,7 @@ def vib_analyze(deflection_bits, freq,
 
     A,B,C,D = fit_psd(freq_axis, power, **kwargs)
 
-    if config.TEXT_VERBOSE : 
+    if config.TEXT_VERBOSE :
         print "Fitted f(x) = C / ((A**2-x**2)**2 + (x*B)**2) with"
         print "A = %g, \t B = %g, \t C = %g, \t D = %g" % (A, B, C, D)
 
@@ -389,12 +398,12 @@ make_splittable_kwargs_function(vib_analyze,
      'minFreq', 'maxFreq'))
 
 @splittableKwargsFunction((vib_analyze, 'deflection_bits', 'freq'))
-def vib_load_analyze_tweaked(tweak_file, **kwargs) :
+def vib_load_analyze_tweaked(tweak_file, analyze=vib_analyze, **kwargs) :
     """
     Read the vib files listed in tweak_file.
     Return an array of Vphoto variances (due to the cantilever) in Volts**2
     """
-    vib_analyze_kwargs, = \
+    analyze_kwargs, = \
         vib_load_analyze_tweaked._splitargs(vib_load_analyze_tweaked, kwargs)
     dl = data_logger.data_load()
     Vphoto_var = []
@@ -409,8 +418,11 @@ def vib_load_analyze_tweaked(tweak_file, **kwargs) :
         if config.TEXT_VERBOSE :
             print "Analyzing '%s' at %g Hz" % (path, freq)
         # analyze
-        Vphoto_var.append(vib_analyze(deflection_bits, freq,
-                                      **vib_analyze_kwargs))
+        if 'freq' in analyze._kwargs(analyze):
+            var = analyze(deflection_bits, freq, **analyze_kwargs)
+        else:
+            var = analyze(deflection_bits, **analyze_kwargs)
+        Vphoto_var.append(var)
     return numpy.array(Vphoto_var, dtype=numpy.float)
 
 # commandline interface functions
@@ -432,13 +444,25 @@ if __name__ == '__main__' :
     from optparse import OptionParser
     
     usage_string = ('%prog <input-file>\n'
-                    '2008, W. Trevor King.\n'
+                    '2007-2009 W. Trevor King.\n'
+                    '\n'
+                    'There are several operation modes, each handling a different <input-file>\n'
+                    'type.  In each case, the output is the fitted variance (in square Volts).\n'
                     '\n'
-                    'Deflection power spectral density (PSD) data (X^2/Hz)\n'
-                    'and returns the variance in X units (X^2)\n'
-                    '<input-file> should be 1 column ASCII without a header line.\n'
+                    'Single file mode without datalogger mode (the default) :\n'
+                    '<input-file> should be a 1 column ASCII without a header line of cantilever\n'
+                    'deflection (in bits)\n'
                     'e.g: "<deflection bits>\\n..."\n'
-                    #TODO, better overview of input modes, e.g. a la T_analyze
+                    '\n'
+                    'Single file mode with datalogger mode :\n'
+                    'Same as without datalogger mode, except the input should be a datalogger file\n'
+                    'with data stored in bits (e.g. as saved by the unfold module).\n'
+                    '\n'
+                    'Tweak file mode:\n'
+                    'Runs the same analysis as in single file mode for each vib file in a tweak\n'
+                    'file.  Each line in the tweak file specifies a single vib file.  Blank lines\n'
+                    'and those beginning with a pound sign (#) are ignored.  Vib files are valid\n'
+                    'datalogger files as per single-file-with-datalogger-mode.\n'
                     )
     parser = OptionParser(usage=usage_string, version='%prog 0.1')
     parser.add_option('-f', '--sample-freq', dest='freq', default=100e3,
@@ -471,6 +495,10 @@ if __name__ == '__main__' :
     parser.add_option('-d', '--datalogger-mode', dest='datalogger_mode', action='store_true',
                       help='Read input files with datalogger.read_dict_of_arrays().  This is useful, for example, to test a single line from a tweakfile.',
                       default=False)
+    parser.add_option('-s', '--disable-spectrum-fitting', dest='spectrum_fitting',
+                      action='store_false',
+                      help='Disable PSD fitting, just use the raw variance',
+                      default=True)
     parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
                       help='Print lots of debugging information',
                       default=False)
@@ -490,21 +518,30 @@ if __name__ == '__main__' :
     config.PYLAB_VERBOSE = options.pylab
     config.GNUPLOT_VERBOSE = options.gnuplot
     PLOT_GUESSED_LORENTZIAN = options.plot_guess
+    if options.spectrum_fitting == True:
+        analyze = vib_analyze
+        analyze_args = {'freq':options.freq,
+                        'minFreq':options.min_freq,
+                        'maxFreq':options.max_freq}
+    else:
+        analyze = vib_analyze_naive
+        analyze_args = dict()
+        make_splittable_kwargs_function(vib_load_analyze_tweaked,
+                                        (vib_analyze, 'deflection_bits'))
 
-    if options.tweakmode == False :
+    if options.tweakmode == False : # single file mode
         if options.datalogger_mode:
             data = vib_load(ifilename)
             deflection_bits = data['Deflection input']
         else:
             deflection_bits = read_data(ifilename)
-        Vphoto_var = vib_analyze(deflection_bits, freq=options.freq,
-                                 minFreq=options.min_freq,
-                                 maxFreq=options.max_freq)
+        Vphoto_var = analyze(deflection_bits, **analyze_args)
         print >> ofile, Vphoto_var
     else : # tweak mode
-        Vphoto_vars = vib_load_analyze_tweaked(ifilename,
-                                               minFreq=options.min_freq,
-                                               maxFreq=options.max_freq)
+        if 'freq' in analyze_args:
+            analyze_args.pop('freq') # freq extracted from vib file names
+        Vphoto_vars = vib_load_analyze_tweaked(ifilename, analyze=analyze,
+                                               **analyze_args)
         if options.comma_out :
             sep = ','
         else :
@@ -516,4 +553,5 @@ if __name__ == '__main__' :
     
     if options.ofilename != None :
         ofile.close()
-    
+
+#  LocalWords:  calibcant AFM