#!/usr/bin/python # # tpcplot - plot pcal for one station over time (multiple scans) # # first created 2018.1.26 rjc import datetime import optparse import re import string import sys import os import fnmatch import math import cmath import numpy as np import matplotlib.pyplot as plt from subprocess import Popen, PIPE import mk4b def main(): usage_text = '\n tpcplot ' parser = optparse.OptionParser(usage=usage_text) parser.add_option( '-v', '--verbose', action='store_true', dest='verbose', help='verbose mode (default false)', default=False) parser.add_option( '-t', '--type', dest='plot_type', help='1: all tone phases (default) \ 2: all tones, phase-connected \ 3: phases relative to first tone \ 4: phases rel to mean of all tones', default=1) parser.add_option( '-o', '--outfile', action='store_true', dest='ofile', help='create output file (default false)', default=False) parser.add_option( '-f', '--filename', dest='fout', help='set output file name (default ./out.pdf)', default='./out.pdf') (opts, args) = parser.parse_args() if len (args) < 2 or len (args) > 3: print "use -h option for help" sys.exit(0) if opts.verbose: print 'opts: ', opts print 'args: ', args opts.plot_type = int (opts.plot_type) stn = args[0] ch_name = args[1] if len (args) > 2: directory = args[2] if directory[-1:] != '/': directory += ('/') else: directory = './' print 'stn', stn, 'directory', directory philes = [] # find all of this station's files for root, dirs, files in os.walk (directory): if len (files) > 0: for phile in files: if fnmatch.fnmatch (phile, stn + '..??????'): if root[len(root)-1] == '/': philes.append (root + phile) else: philes.append (root + '/' + phile) print len (philes), 'files for station', stn """ for ff in philes: print ff """ # get data samples from midpoint of each file rots = [] amps = [] phases = [] for phile in philes: # loop over scans stn_data = mk4b.mk4sdata (phile) tmid = stn_data.n309 / 2 #print phile, 'has', stn_data.n309, 'type 309 records w/ midpoint', tmid t309 = stn_data.t309[tmid] found = False for ch in range (64): if t309.contents.chan[ch].chan_name == ch_name: #print 'ch', ch, t309.contents.chan[ch].chan_name, 'fr', t309.contents.chan[ch].freq found = True break if not found: print "couldn't find channel", ch_name, "in type 309 record of", phile quit () rots.append (t309.contents.rot / (32e6 * 8.64e4)) am = [] ph = [] for tone in range (64): if t309.contents.chan[ch].acc[tone][0] != 0: #print 'rot %18.2f' % t309.contents.rot, 'ch', ch, 'tone', tone, \ # t309.contents.chan[ch].acc[tone][0], t309.contents.chan[ch].acc[tone][1] phasor = convert_integer_phasor_to_float (t309.contents.chan[ch].acc[tone][0], t309.contents.chan[ch].acc[tone][1], t309.contents.acc_period) am.append (abs (phasor)) ph.append (cmath.phase (phasor) * 180.0 / cmath.pi) amps.append (am) # append tone vector for this scan/time phases.append (ph) #print '\namps', amps #print '\nphases', phases ctamps = map (list, zip (*amps)) ctphases = map (list, zip (*phases)) # corner-turn to get times within tone #print '\nctamps', ctamps #print '\nctphases', ctphases #print data # print len(rots), 'rots:', rots ''' for j in range (len (rots)): #print 'j', j, '# of tones',len(amps[j]) print '%8.5f %6.2f %6.2f' % (rots[j], amps[j][0], phases[j][0]),philes[j] ''' # modify data for plotting massage_data (opts, rots, ctamps, ctphases) # now generate plots plot_data (opts, rots, ctamps, ctphases, ch_name) # modify data according to the chosen plot type def massage_data (opts, rots, amps, phases): # plot_type 1 requires no changes # for types 2..4 we need to unwrap phases if opts.plot_type != 1: for i in range (len (phases)): # loop over tones for j in range (1, len (phases[i])): while phases[i][j] - phases[i][j-1] > 180.0: phases[i][j] -= 360.0 while phases[i][j] - phases[i][j-1] < -180.0: phases[i][j] += 360.0 if opts.plot_type == 3: # form differences from 1st tone for i in range (1, len (phases)): for j in range (len (phases[i])): phases[i][j] -= phases[0][j] elif opts.plot_type == 4: # form differences from mean phase (over tones) for j in range (len (phases[0])): avg = 0.0 for i in range (len (phases)): avg += phases[i][j] avg = (avg / len (phases)) for i in range (len (phases)): phases[i][j] -= avg def plot_data (opts, rots, amps, phases, ch_name): cols = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b'] if opts.plot_type == 1: label = 'phases by tone for channel ' + ch_name if opts.plot_type == 2: label = 'phase-connected by tone for channel ' + ch_name elif opts.plot_type == 3: label = 'phase diffs wrt tone 0 for channel ' + ch_name elif opts.plot_type == 4: label = 'phase diffs wrt mean of tones for ch ' + ch_name plt.figure (label, figsize=(8,10.5)) plt.suptitle (label) for j in range (len (phases)): plt.subplot (4, 2, j+1) plt.plot (rots, phases[j], '.', color=cols[j]) # phase-connect need big range, diff mean needs small if opts.plot_type == 1: plt.ylim (-180.0, 180.0) plt.xlabel ('time (doy)') plt.ylabel ('phase (deg)') if opts.ofile: # save output to file if requested plt.savefig (opts.fout) plt.show () def convert_integer_phasor_to_float (u, v, acc_period): #convert to double (taken from pcal_interp.c) #correct for 2's complement arithmetic if u < TWO31: u = u else: u = u - TWO32 if v < TWO31: v = v else: v = v - TWO32 #scale such that 1000 = 100% correlation #and match SU phase by shifting 180 degrees #what is the origin of the hard-coded value 128? pc_real = (float (u) * 1e-6 ) / (-128.0 * acc_period) pc_imag = (float (v) * 1e-6 ) / (-128.0 * acc_period) cp = complex (pc_real, pc_imag) return cp if __name__ == '__main__': # official entry point TWO31 = 2147483648.0 TWO32 = 4294967296.0 main() sys.exit(0)