#!/usr/bin/env python3 import os import argparse import numpy as np import matplotlib ################################################################################ args_parser = argparse.ArgumentParser() args_parser.add_argument('--save','-s', action='store_true', help='save to files') args_parser.add_argument('--raster','-r', action='store_true', help='save as raster') args_parser.add_argument('--debug','-d', action='store_true', help='hold for debugging') args_parser.add_argument('--polar','-p', action='store_true', help='do polar plotting (wide bandwidth)') args_parser.add_argument('--headless','-q', action='store_true', help='Remain neadless even if we aren\'t saving files.') args_parser.add_argument('-n', type=int, default=4, help='plot testing number') args_parser.add_argument('-c', type=int, default=16, help='number of phase states [16,32,64]') args = args_parser.parse_args() ################################################################################ if args.raster: args.save = True fig_ext = 'png' else: fig_ext = 'pdf' ################################################################################ HEADLESS = not 'DISPLAY' in os.environ.keys() if args.headless: HEADLESS = True # Override Manually if request if HEADLESS: matplotlib.use('Agg') from matplotlib import rcParams, pyplot as pp import skrf as rf from scipy.io import loadmat from collections import namedtuple import LPRDefaultPlotting from tankComputers import * import re import json ################################################################################ # Override the defaults for this script figScaleSize = 1.0 if args.save else 1.6 rcParams['figure.figsize'] = [3.4*figScaleSize,3*figScaleSize] default_window_position=['+20+80', '+120+80'] ################################################################################ SRC_DATA_NAMES = [\ 'Data_2018-05-15-clean', 'Data_2018-05-16-clean', 'Data_2018-05-21-clean', 'Data_2018-05-25-clean'] SRC_DATA_INDEX = args.n-1 SRC_DATA_NAME = SRC_DATA_NAMES[SRC_DATA_INDEX] #SRC_DATA_DATESTR = '-'.join(SRC_DATA_NAME.split('_')[1].split('-')[:-1]) SRC_DATA_LOC = '/media/ramdisk/' + SRC_DATA_NAME + '/'; SRC_DATA_SUMMARY = '/home/luke/Dropbox/Grad School/1801_PS/' \ '2018-05_Testing/results_plot/dat_clean/' + SRC_DATA_NAME + '_sum.json'; if args.polar: FILE_PAT = '%s-trunk2.s2p'; else: FILE_PAT = '%s-trunk.s2p'; figdir = 'figures-measured' if args.c != 16: figdir=figdir+('-%d' % args.c) class MeasurementConfig(namedtuple('config', ['r','c','inv','bias'])): __slots__ = () @property def fn_str(self): return "C%02d_R%1d_I%1d_B%0.4f" % (self.c, self.r, self.inv, self.bias) Measurement = namedtuple('measurement', ['cfg', 'pwr','gain','phase','f','s21', 'slope']) plottingBandwidthMax = 2.01 plottingBandwidthFreq = 28+np.array([-1,1])*0.5*plottingBandwidthMax slopeBandwidthMax = 1 slopeBandwidthFreq = 28+np.array([-1,1])*0.5*slopeBandwidthMax def dB20(x): return 20*np.log10(np.abs(x)) def ang_deg(x): return 180/np.pi*np.angle(x) def ang(x): return np.angle(x) BDE=namedtuple('BufferDeEmbed',['mstr','PolyGain','PolyPhase','PhiFix','test']) BDE_list=[] # 2018-05-15 BDE_list.append(BDE( '2018-05-15', np.array([ 4.06488853e-03, -5.11527396e-01, 2.53053550e+01]), np.array([-1.62202706e-03, 6.94343608e-01, -1.80381551e+02]), -60, 'S02bB_C+01dB_M0' )) # 2018-05-16 BDE_list.append(BDE( '2018-05-16', np.array([ 4.08875413e-03, -5.13017311e-01, 2.54047949e+01]), np.array([-1.29541398e-03, 6.74431785e-01, -1.80127388e+02]), -60, 'S02bB_C+00dB_M0' )) # 2018-05-21 #PolyGain=np.array( [ 4.08875413e-03, -5.13017311e-01, 2.54047949e+01]) #PolyPhase=np.array([-1.29541398e-03, 6.74431785e-01, -1.80127388e+02]) BDE_list.append(BDE( '2018-05-21', np.array([ 4.08875413e-03, -5.13017311e-01, 2.54047949e+01]), np.array([-1.29541398e-03, 6.74431785e-01, -1.80127388e+02]), -60, 'S02bB_C+00dB_M0' )) # 2018-05-25 #PolyGain=np.array( [ 4.06488853e-03, -5.11527396e-01, 2.53053550e+01]) #PolyPhase=np.array([-1.62202706e-03, 6.94343608e-01, -1.80381551e+02]) BDE_list.append(BDE( '2018-05-25', np.array([ 4.06488853e-03, -5.11527396e-01, 2.53053550e+01]), np.array([-1.62202706e-03, 6.94343608e-01, -1.80381551e+02]), -70, 'S02bB_C+00dB_M0' )) source_directory='fromMat/figures-%d/%s_mat/' % (args.c, SRC_DATA_NAME) for BDEx in BDE_list: if re.search(BDEx.mstr, source_directory) != None: PolyGain=BDEx.PolyGain PolyPhase=BDEx.PolyPhase PhaseFixedRotationFactor=BDEx.PhiFix StopTestString=BDEx.test FamStr=BDEx.mstr break ################################################################################ ################################################################################ ################################################################################ # FIXME ######################################################################## ################################################################################ ################################################################################ ################################################################################ PolyGain_balun=np.array([0, 0, -7]) PolyPhase_balun=np.array([0, 0, 0]) ################################################################################ ################################################################################ ################################################################################ ################################################################################ if args.c == 64: StopTestString='S05bB_C+05dB_M0_-64' elif args.c == 32: StopTestString='S03bB_C+00dB_M0_-32' with open(SRC_DATA_SUMMARY, 'r') as h_sumDat: sumDat = json.load(h_sumDat) def fetchSumDat_pwr(cfg): global sumDat mR = np.array(sumDat['r']) == cfg.r mC = np.array(sumDat['c']) == cfg.c mI = np.array(sumDat['inv']) == cfg.inv mB = np.abs(np.array(sumDat['bias_dp_set'])-cfg.bias) < 0.0005 ind = np.squeeze(np.where(np.all((mR,mC,mI,mB),0))) if ind.size == 0: print("ERROR EVERYTHING IS BROKEN! AND i'M TIRED") return -1 else: return sumDat['ivdd'][ind]*sumDat['vdd'][ind] def sumTuple_avgMinMax(data_list): existing_data = [] for datum in data_list: existing_data.extend([np.mean(datum), np.min(datum), np.max(datum)]) return tuple(existing_data) combined_rms=np.array([]) for filename in os.listdir(source_directory): filename=source_directory+filename group_filename_string = filename.split('/')[-1][:-4] src = loadmat(filename, struct_as_record=False) if not HEADLESS and group_filename_string != StopTestString: # skip until we hit some aribitrary targets continue collectedData=[] for sample in src['data'][0]: tmp = [sample.__getattribute__(key)[0,0] for key in ['r', 'c', 'inv', 'bias_dp_set']] pt = MeasurementConfig(r=tmp[0], c=tmp[1], inv=tmp[2], bias=np.float(tmp[3])) s2p_file = rf.Network(SRC_DATA_LOC + (FILE_PAT % pt.fn_str) ) freq = np.squeeze(s2p_file.f*1e-9) inds_keep = np.where(np.all((freq >= plottingBandwidthFreq[0], freq <= plottingBandwidthFreq[1]),0)) sdat_raw = np.squeeze(s2p_file.s21.s) freq = freq[inds_keep] sdat_raw = sdat_raw[inds_keep] buffer_gain = np.polyval(PolyGain,freq) buffer_phase = np.polyval(PolyPhase,freq) buffer_phase = buffer_phase - np.mean(buffer_phase) + \ PhaseFixedRotationFactor*np.pi/180 buffer_sdat = np.power(10,buffer_gain/20)*np.exp(1j*buffer_phase) balun_gain = np.polyval(PolyGain_balun,freq) balun_phase = np.polyval(PolyPhase_balun,freq) balun_phase = balun_phase - np.mean(balun_phase) balun_sdat = np.power(10,balun_gain/20)*np.exp(1j*balun_phase) sdat = sdat_raw/buffer_sdat/balun_sdat slope_valid_inds = np.where(np.all((freq >= slopeBandwidthFreq[0], freq <= slopeBandwidthFreq[1]),0)) sub_angles = np.unwrap(np.angle(sdat[slope_valid_inds]))*180/np.pi sub_freq = freq[slope_valid_inds]-np.mean(freq[slope_valid_inds]) slope = np.polyfit(sub_freq,sub_angles-np.mean(sub_angles),1)[0] index_f0 = np.squeeze(np.argwhere(freq==28)) collectedData.append(Measurement(cfg=pt, pwr=fetchSumDat_pwr(pt), gain=dB20(sdat[index_f0]), phase=ang_deg(sdat[index_f0]), f=freq, s21=sdat, slope=slope)) # Find the indicies close to 0 and 180 as my reference curves phis = np.array([s.phase for s in collectedData]) best_slopes = np.argsort(np.abs(np.mod(phis+90,180)-90))[0:6] slope_list = np.array([s.slope for s in collectedData]) slope_avg = np.mean(slope_list[best_slopes]) ref_index = np.argmin(np.abs(phis)) unwrapped_ref_phase = 180/np.pi*np.unwrap(ang(collectedData[ref_index].s21)) if args.polar: h=pp.figure() ax=h.add_subplot(1,1,1, projection='polar') else: h=pp.figure(figsize=(3.4*figScaleSize, 4.5*figScaleSize)) h2=pp.figure(figsize=(3.4*figScaleSize, 2.3*figScaleSize)) ax=h.subplots(2,1) ax = np.append(ax, h2.subplots(1,1)) ax = np.append(ax, ax[1].twinx()) ax = np.append(ax, ax[2].twinx()) ax = np.append(ax, ax[0].twinx()) summary_msg = \ "/---------------------\/----------------------------------------\\\n"\ "| _C R I _Bias_ || Gain Phase Power |\n"\ "|---------------------||----------------------------------------|\n" all_sdat = np.column_stack([imeas.s21 for imeas in collectedData]) ang_rms = delta_rms(np.angle(all_sdat), 2*np.pi/args.c)*180/np.pi gain_pm = gain_error(dB20(all_sdat), index_f0) gain_rms = rms(dB20(all_sdat), index_f0) for imeas in collectedData: if args.polar: #ax.plot(ang(imeas.s21)-buffer_phase, dB20(imeas.s21)-buffer_gain) ax.plot(ang(imeas.s21), dB20(imeas.s21)) else: ax[0].plot(imeas.f, dB20(imeas.s21)) unwrapped_phase = 180/np.pi*np.unwrap(ang(imeas.s21)) #ax[1].plot(imeas.f, unwrapped_phase) relative_phase_curve = unwrapped_phase-unwrapped_ref_phase if np.any(relative_phase_curve < 0): relative_phase_curve += 360 #relative_phase_curve -= 180-22.5/2 ax[1].plot(imeas.f, relative_phase_curve) #slope_relative = (imeas.f-28)*slope_avg #ax[2].plot(imeas.f, unwrapped_phase-slope_relative) ax[2].plot(imeas.f, relative_phase_curve) pwr_overage = int(2*(imeas.pwr*1e3 - 10)) pwr_string = (int(pwr_overage/2)*"=") + (np.mod(pwr_overage,2)*">") summary_msg += "| %2d %d %d %.4f || "\ " %+7.1f dB %+9.2f deg %4.1f mW |%s\n" % \ (imeas.cfg.c, imeas.cfg.r, imeas.cfg.inv, imeas.cfg.bias, \ imeas.gain, imeas.phase, imeas.pwr*1e3, pwr_string) summary_msg += \ "\_____________________/\________________________________________/\n" pwr_list=np.array([imeas.pwr*1e3 for imeas in collectedData]) gain_list=np.array([imeas.gain for imeas in collectedData]) summary_msg += \ "/ \\\n" \ "|===> Power: % 7.1f mW (% 7.1f mW - % 7.1f mW) |\n" \ "|===> Gain: %+7.1f dB (%+7.1f dB - %+7.1f dB) | \n" \ "|===> RMS: %6.1f deg (%6.1f deg - %6.1f deg) | \n" \ "\_______________________________________________________________/" % \ (sumTuple_avgMinMax([pwr_list, gain_list, ang_rms])) print(group_filename_string, sumTuple_avgMinMax([ang_rms])) if args.polar: ax.set_ylim(LPRDefaultPlotting.POLAR_YLIM_CONST_MEAS) if args.polar: ax.set_title('Measured Performance') else: # Usually this also has crappy lower ylimits, so we fix that here. # get ALL THE LOWER bounds np.min([np.min(line.get_ydata()) for line in ax[2].get_lines()]) ax[0].set_title('Measured Performance') ax[0].set_ylabel('Gain (dB)') ######### FIXME ######################################################## #ax[0].set_ylim(np.array([-17.5, 2.5])) ax[0].set_ylim(np.array([-20, 0])) ax[1].set_ylabel('Relative Phase (deg)') ax[2].set_ylabel('Relative Phase (deg)') ax[2].set_title('Relative Phase') ax[1].set_ylim(np.array([-100, 360])) ax[2].set_ylim(np.array([-100, 360])) marker_freq = 28.1 LPRDefaultPlotting.annotateArrow(ax[0], -4, \ [marker_freq+0.05+0.02, marker_freq+0.15+0.02], direction='left') for i in [5]: aT=ax[i] aR=ax[0] #aT.plot(imeas.f, gain_pm) aT.plot(imeas.f, gain_rms) for axTLi,axTL in enumerate(aT.get_lines()): axTL.set_linewidth(2.0) axTL.set_color('black') if axTLi == 0: axTL.set_linestyle('-.') else: axTL.set_linestyle(':') aT.set_ylabel('RMS Gain Variation (dB)') marker_freq = 27.7 marker_point = np.argmin(np.abs(imeas.f-marker_freq)) marker_height = gain_pm[marker_point] marker_height = gain_rms[marker_point] LPRDefaultPlotting.annotateArrow(aT, marker_height+0.5, \ [marker_freq+0.05+0.02, marker_freq+0.15+0.02]) aT.set_ylim((aR.get_ylim()/np.array(1)+20)/1) aT.set_yticks([x for x in aT.get_yticks() if x <= 7.5]) aR.set_yticks([x for x in aR.get_yticks() if x >= -17.5]) aT.grid() ######### FIXME ######################################################## for i in range(3,5): aT=ax[i] aR=ax[i-2] # make the ticks, and the y-axis line up in a tidy manner # Recall that the ylimits should be 0-360 basically. aT.set_ylabel('RMS Error (deg)') aT.plot(imeas.f, ang_rms) #marker_freq = 27.5 #marker_freq = 28.3 marker_freq = 27.8 marker_point = np.argmin(np.abs(imeas.f-marker_freq)) marker_height = ang_rms[marker_point]+2 # The goal is to take the usual step size of 50, # and then equate that with a 1-degree step in RMS Error # and to then adjust the y-limit of the twin-axis to align # the grid markers if False: yRscl=np.diff(aR.get_yticks()[-2:]) yTscl=np.diff(aT.get_yticks()[-2:]) # Now find the ratio of the ylimits margin verses their # extreme tick marks. yRmrks = aR.get_yticks()[[0,-1]] yTmrks = aT.get_yticks()[[0,-1]] tickTotal = max(len(aT.get_yticks()), len(aR.get_yticks())) yRover = (aR.get_ylim()-yRmrks)/yRscl yTover = (aT.get_ylim()-yTmrks)/yTscl yRTover = np.stack((yRover,yTover)) yXover = np.array([np.min(yRTover[:,0]), np.max(yRTover[:,1])]) aR.set_ylim(yRscl*yXover + yRmrks) aT.set_ylim(yTscl*yXover + yTmrks) #aT.set_ylim(aR.get_ylim()/np.array(20)+9) aT.set_yticks(np.arange(0,11,5)) aR.set_yticks(np.arange(0,361,60)) aT.set_ylim((0,50)) aR.set_ylim((-90,360)) aT.grid() LPRDefaultPlotting.addHalfTicks(aT) LPRDefaultPlotting.addHalfTicks(aR) aT.get_lines()[0].set_linewidth(2.0) aT.get_lines()[0].set_linestyle('-.') aT.get_lines()[0].set_color('black') LPRDefaultPlotting.annotateArrow(aT, marker_height-0.5, \ [marker_freq+0.05, marker_freq+0.15]) #ax[5].set_ylim(np.array([0, 20])) #ax[3].set_ylim(np.array([0, 42])) #ax[3].set_ylim(np.array([0, 23])) for aT in ax: aT.set_xlabel('Frequency (GHz)') aT.grid() #aT.set_xlim((np.min(imeas.f), np.max(imeas.f))) #aT.set_xlim((28-1.0, 28+1.0)) aT.set_xlim((28-0.5, 28+0.5)) if args.polar: old_pos = ax.title.get_position() ax.title.set_position((old_pos[0], 1.1)) h.tight_layout() if not args.polar: h2.tight_layout() if args.save: with open('%s/Summary-%s-%s.txt' % (figdir, FamStr, group_filename_string), 'w') as summary_file: summary_file.write(summary_msg) summary_file.write("\n") summary_file.close() if args.polar: h.savefig('%s/PolarGain-%s-%s.%s' % (figdir, FamStr, group_filename_string, fig_ext)) else: h.savefig('%s/StdPlots-%s-%s.%s' % (figdir, FamStr, group_filename_string, fig_ext)) h2.savefig('%s/RelStdPlots-%s-%s.%s' % (figdir, FamStr, group_filename_string, fig_ext)) else: print(summary_msg) if HEADLESS: if not args.polar: pp.close() pp.close() else: if not args.polar: h2.show() h.show() break