process_friis_plots.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 # Basically a giant script.
00004 
00005 import roslib
00006 roslib.load_manifest( 'geometry_msgs' )  # the pickle files containe Point and Pose Stamped.
00007 import rospy
00008 
00009 from geometry_msgs.msg import PointStamped, PoseStamped
00010 
00011 
00012 import sys
00013 import glob
00014 import yaml
00015 import time
00016 import optparse
00017 import cPickle as pkl
00018 import numpy as np, math
00019 import pylab as pl
00020 
00021 import friis
00022 
00023 PLOT = False
00024 
00025 # glob_files: '/home/travis/svn/robot1/src/projects/rfid_datacapture/src/rfid_datacapture/cap_360/datacap/*.pkl'
00026 # filters:
00027 #   antennas:
00028 #     PR2_Head: '/head_rfid'
00029 #   tags:
00030 #     'datacap     ':
00031 
00032 if __name__ == '__main__':
00033     p = optparse.OptionParser()
00034     p.add_option('--yaml', action='store', type='string', dest='yaml', default='',
00035                  help='yaml file that describes this run.')
00036     p.add_option('--plot', action='store_true', dest='plot',
00037                  help='Pop-up the resulting plot')
00038     opt, args = p.parse_args()
00039 
00040     yaml_fname = opt.yaml
00041     PLOT = opt.plot
00042 else:
00043     yaml_fname = '/home/travis/svn/robot1/src/projects/rfid_datacapture/src/rfid_datacapture/cap_360/friis_plot_datacap.yaml'
00044 
00045 
00046 # SCRIPT:
00047 
00048 
00049 if not yaml_fname:
00050     print 'YAML file required!'
00051     exit()
00052 else:
00053     f = open( yaml_fname )
00054     yaml_config = yaml.load( f )
00055     f.close()
00056 
00057 
00058 # Load all pkl files into one huge dictionary.
00059 # d = { 'tagid1': [ PROC_READ1, PROC_READ2, ... ],
00060 #       ...
00061 #     }
00062 def add_files( d, arg ):
00063     fname, fcount = arg
00064     print 'Loading (%d of %d): %s' % (fcount, len(fnames), fname)
00065     f = open( fname, 'r' )
00066     d_new = pkl.load( f )
00067     f.close()
00068 
00069     for k in d_new.keys():
00070         if not d.has_key( k ):
00071             d[k] = []
00072         d[k] += d_new[k]
00073 
00074     return d
00075 
00076 # Calculate Useful Values
00077 
00078 def friis_pwr_tag( reading ):
00079     # Model estimate of P^inc_tag.
00080     # r_rdr, theta_rdr, phi_rdr, r_tag, theta_tag, phi_tag, rssi, antname, tagid = reading
00081     d_rdr = reading[0]
00082     d_tag = reading[1]
00083     read = reading[2]
00084     d_rot = reading[3]
00085     ps = reading[4]
00086 
00087     r_rdr, theta_rdr, phi_rdr = d_rdr
00088     r_tag, theta_tag, phi_tag = d_tag
00089 
00090     watts = friis.pwr_inc_tag( r_rdr,
00091                                friis.patch.G, theta_rdr, phi_rdr,
00092                                friis.dipole.G, theta_tag, phi_tag )
00093     return friis.WattsToDBm( watts )
00094 
00095 def friis_pwr_rdr( reading ):
00096     # Model estimate of P^inc_rdr.
00097     # r_rdr, theta_rdr, phi_rdr, r_tag, theta_tag, phi_tag, rssi, antname, tagid = reading
00098     d_rdr = reading[0]
00099     d_tag = reading[1]
00100     read = reading[2]
00101     d_rot = reading[3]
00102     ps = reading[4]
00103 
00104     r_rdr, theta_rdr, phi_rdr = d_rdr
00105     r_tag, theta_tag, phi_tag = d_tag
00106     
00107     watts = friis.pwr_inc_rdr( r_rdr,
00108                                friis.patch.G, theta_rdr, phi_rdr,
00109                                friis.dipole.G, theta_tag, phi_tag )
00110     return friis.WattsToDBm( watts )
00111 
00112 
00113 
00114 fnames = reduce( lambda x,y: x+y, [ glob.glob(i) for i in yaml_config['glob_files'] ], [] )
00115 
00116 
00117 if len(glob.glob(yaml_config['use_combined'])) > 0:
00118     print 'Loading pickle: %s' % (yaml_config['use_combined'])
00119     f = open( yaml_config['use_combined'], 'r' )
00120     data = pkl.load( f )
00121     f.close()
00122     print 'Done.'
00123 else:
00124     f = open( yaml_config['use_combined'], 'w' )
00125     d = reduce( add_files, zip(fnames,range(len(fnames))), {} )
00126 
00127     # Apply Filters:
00128 
00129     # Start with just the desired tagids
00130     all_reads = reduce( lambda x,y: x+y,
00131                         [ d[k] for k in yaml_config['filters']['tags'] if d.has_key(k) ],
00132                         [] )
00133 
00134     print '*** File \'%s\' had a total of %d reads ***' % ( yaml_fname, len( all_reads ))
00135 
00136     # Filter based on antennas
00137     # return [ [r_rdr, theta_rdr, phi_rdr],  # all floats
00138     #          [r_tag, theta_tag, phi_tag],  # all floats
00139     #          [rr.rssi, rr.antenna_name, rr.tagID ], # int, string, string
00140     #          [theta_rot_map, theta_tag_map], # floats (radians)
00141     #          [ tag_map, rdr_map, rot_map ] ] # geometry_msgs/PoseStamped
00142 
00143     ant_dict = dict.fromkeys( yaml_config['filters']['antennas'] )
00144     filt_reads = [ r for r in all_reads if ant_dict.has_key( r[2][1] ) ]
00145 
00146     reads = filt_reads
00147 
00148     p_inc_tag = np.array([ friis_pwr_tag( r ) for r in reads ]) # in dBm!
00149     p_inc_rdr = np.array([ friis_pwr_rdr( r ) for r in reads ]) # in dBm!
00150     rssi      = np.array([ r[2][0] for r in reads ])
00151     data = np.row_stack([ p_inc_tag,
00152                           p_inc_rdr,
00153                           rssi ])
00154     print 'Dumping data into combined pickle file: %s ' % (yaml_config['use_combined'])
00155     pkl.dump( data, f, -1 )
00156     f.close()
00157     print 'Done.  Re-run.'
00158     exit()
00159 
00160 p_inc_tag = data[0]
00161 p_inc_rdr = data[1]
00162 rssi = data[2]
00163 
00164 pos_mask = rssi != -1
00165 neg_mask = rssi == -1
00166 
00167 if len(pos_mask) == 0:
00168     print '### File \'%s\' had no positive reads -- exiting ###' % ( yaml_fname )
00169     exit()
00170 if len(neg_mask) == 0:
00171     print '### File \'%s\' had no positive reads -- exiting ###' % ( yaml_fname )
00172     exit()
00173 
00174 # P^inc_rdr vs. RSSI.
00175 def plot_pincrdr( f = None ):
00176     if not f:
00177         f = pl.figure( figsize=(10,6) )
00178         
00179     pl.axes([0.1,0.1,0.65,0.8])
00180     pl.plot( p_inc_rdr[pos_mask], rssi[pos_mask], 'bx', alpha = 0.5 )
00181     pl.xlabel( '$P^{inc}_{rdr}$ (dBm)')
00182     pl.ylabel( 'RSSI')
00183     pl.title( 'Measured RSSI vs Predicted Power at Reader' )
00184 
00185     xval = None
00186     yval = None
00187     if yaml_config.has_key( 'rdr_calcfriis' ):
00188         # Old way: take max Pincrdr
00189         # ind = p_inc_rdr >= np.max( p_inc_rdr ) - yaml_config['rdr_calcfriis']['within_max']
00190 
00191         # New way: take region we know to be linear in Friis.  Note, this also elimates negative reads!
00192         ind = np.all( np.row_stack([
00193             rssi >= yaml_config['rdr_calcfriis']['rssi_min'],
00194             rssi <= yaml_config['rdr_calcfriis']['rssi_max'] ]), axis = 0)
00195 
00196         xval = np.mean( p_inc_rdr[ ind ] )  # Friis line runs throught this point
00197         yval = np.mean( rssi[ ind ] )
00198 
00199         # CURIOUS: Both methods are the same.  I could probably show that, but I'm tired!
00200 
00201         # We know the slope is 0.75.  y = 0.75 * x + c ==>  c = mean( y - 0.75 x )
00202         # c = np.mean( rssi[ind] - 0.75 * p_inc_rdr[ind] )  
00203         # xval = -19.19 # arbitrary, but convenient
00204         # yval = 0.75 * xval + c
00205         
00206         print 'Calculated Friis Line:\n\txval: %3.2f\n\tyval: %3.2f' % (xval,yval)
00207 
00208     if yaml_config.has_key( 'rdr_drawfriis' ):
00209         xval = yaml_config[ 'rdr_drawfriis' ][ 'xval' ]
00210         yval = yaml_config[ 'rdr_drawfriis' ][ 'yval' ]
00211 
00212     if xval and yval:
00213         pl.hold( True )
00214 
00215         # Slope of line (from Matt's measurements) should be 0.75
00216         xs = np.linspace( yaml_config['rdr_axis'][0], yaml_config['rdr_axis'][1], 100 )
00217         ys = 0.75 * ( xs - xval ) + yval # pt-slope form
00218         pl.plot( xs, ys, 'g-', linewidth = 2.0 )
00219         pl.legend(['Positive Reads','Friis Model Fit'], loc=(1.03,0.2))
00220     else:
00221         pl.legend(['Positive Reads'], loc=(1.03,0.2))
00222 
00223 
00224     pl.axis( yaml_config['rdr_axis'] )
00225     return f
00226 
00227 plot_pincrdr()
00228 pl.savefig( yaml_config['outimage'] + '_pincrdr.png' )
00229 
00230 
00231 # P^inc_rdr vs. P(read)
00232 def plot_pincrdr_probs( f = None ):
00233     hist, bins = np.histogram( p_inc_rdr,
00234                                bins = yaml_config['rdr_histbins']['bins'],
00235                                range = (yaml_config['rdr_histbins']['min'],
00236                                         yaml_config['rdr_histbins']['max']) )
00237     bin_width = bins[1] - bins[0]
00238     # Find out which bin each read belongs to.
00239     # Sanity check: print [ sum( bins_ind == i ) for i in xrange(len(hist)) ] => equals hist
00240     bins_ind = np.sum( p_inc_rdr[:,np.newaxis] > bins[:-1], axis = 1 ) - 1
00241     prob_read = [ sum(rssi[bins_ind == i] != -1)*1.0 / hist[i] # positive reads / total reads for bin i
00242                   for i in xrange(len(hist)) # same as len(bins)-1
00243                   if hist[i] != 0 ] # only where we have data!  (also prevents div by 0)
00244 
00245     if not f:
00246         f = pl.figure( figsize=(10,6) )
00247     pl.axes([0.1,0.1,0.65,0.8])
00248     pos_bars = pl.bar([ bins[i] for i in xrange(len(hist)) if hist[i] != 0 ], # Only plot the bars for places we have data!
00249                       prob_read,  # This is only defined for ones that have data!
00250                       width = bin_width,
00251                       color = 'b',
00252                       alpha = 0.7 )
00253     pl.hold( True )
00254     neg_bars = pl.bar([ bins[i] for i in xrange(len(hist)) if hist[i] != 0 ], # Only plot the bars for places we have data!
00255                       [ 1.0 - p for p in prob_read ],  # This is only defined for ones that have data!
00256                       width = bin_width,
00257                       bottom = prob_read,
00258                       color = 'r',
00259                       alpha = 0.7 )
00260     pl.axis([ yaml_config['rdr_axis'][0], yaml_config['rdr_axis'][1], 0.0, 1.0 ])
00261     pl.xlabel( '$P^{inc}_{rdr}$ (dBm)')
00262     pl.ylabel( 'Probability of Tag Read / No-Read')
00263     pl.title( 'Probability of Tag Read / No-Read vs Predicted Power at Reader ' )
00264     pl.legend((pos_bars[0], neg_bars[0]), ('P( read )', 'P( no read )'), loc=(1.03,0.2))
00265 
00266     return f
00267 
00268 plot_pincrdr_probs()
00269 pl.savefig( yaml_config['outimage'] + '_pincrdr_probs.png' )
00270 
00271 
00272 
00273 
00274 # P^inc_tag vs. P(read)
00275 def plot_pinctag_probs( f = None ):
00276     pl.figure( figsize=(10,6) )
00277     pl.axes([0.1,0.1,0.65,0.8])
00278     pl.plot( p_inc_tag[pos_mask], rssi[pos_mask], 'bx', alpha = 0.5 )
00279     pl.xlabel( '$P^{inc}_{tag}$ (dBm)')
00280     pl.ylabel( 'RSSI')
00281     pl.title( 'Measured RSSI vs Predicted Power at Tag' )
00282     pl.legend(['Positive Reads'], loc=(1.03,0.2))
00283     pl.axis( yaml_config['tag_axis'] )
00284     pl.savefig( yaml_config['outimage'] + '_pinctag.png' )
00285     
00286     hist, bins = np.histogram( p_inc_tag,
00287                                bins = yaml_config['tag_histbins']['bins'],
00288                                range = (yaml_config['tag_histbins']['min'],
00289                                         yaml_config['tag_histbins']['max']) )
00290     bin_width = bins[1] - bins[0]
00291     # Find out which bin each read belongs to.
00292     # Sanity check: print [ sum( bins_ind == i ) for i in xrange(len(hist)) ] => equals hist
00293     bins_ind = np.sum( p_inc_tag[:,np.newaxis] > bins[:-1], axis = 1 ) - 1
00294     prob_read = [ sum(rssi[bins_ind == i] != -1)*1.0 / hist[i] # positive reads / total reads for bin i
00295                   for i in xrange(len(hist)) # same as len(bins)-1
00296                   if hist[i] != 0 ] # only where we have data!  (also prevents div by 0)
00297 
00298     if not f:
00299         f = pl.figure( figsize=(10,6) )
00300     pl.axes([0.1,0.1,0.65,0.8])
00301     pos_bars = pl.bar([ bins[i] for i in xrange(len(hist)) if hist[i] != 0 ], # Only plot the bars for places we have data!
00302                       prob_read,  # This is only defined for ones that have data!
00303                       width = bin_width,
00304                       color = 'b',
00305                       alpha = 0.7 )
00306     pl.hold( True )
00307     neg_bars = pl.bar([ bins[i] for i in xrange(len(hist)) if hist[i] != 0 ], # Only plot the bars for places we have data!
00308                       [ 1.0 - p for p in prob_read ],  # This is only defined for ones that have data!
00309                       width = bin_width,
00310                       bottom = prob_read,
00311                       color = 'r',
00312                       alpha = 0.7)
00313     pl.axis([ yaml_config['tag_axis'][0], yaml_config['tag_axis'][1], 0.0, 1.0 ])
00314     pl.xlabel( '$P^{inc}_{tag}$ (dBm)')
00315     pl.ylabel( 'Probability of Tag Read / No-Read')
00316     pl.title( 'Probability of Tag Read / No-Read vs Predicted Power at Tag' )
00317     pl.legend((pos_bars[0], neg_bars[0]), ('P( read )', 'P( no read )'), loc=(1.03,0.2))
00318     # pl.legend(['P( read )'], loc=(1.03,0.2))
00319     pl.savefig( yaml_config['outimage'] + '_pinctag_probs.png' )
00320     # return f
00321 
00322 plot_pinctag_probs()
00323 
00324 
00325 
00326 
00327 if PLOT:
00328     pl.show()


rfid_datacapture
Author(s): Travis Deyle
autogenerated on Wed Nov 27 2013 12:11:16