From e3637a7fc60c5b057f2b8c7ffc4f6303ca3a9f0e Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 21 Jul 2018 16:28:18 -0700 Subject: [PATCH] Continued refactoring, split up plotting statements. --- LPRDefaultPlotting.py | 21 ++++- TankGlobals.py | 68 ++++++++++++++-- tankComputers.py | 15 +++- tankPlot.py | 183 ++++++++++++++++++++++++++++-------------- 4 files changed, 218 insertions(+), 69 deletions(-) diff --git a/LPRDefaultPlotting.py b/LPRDefaultPlotting.py index 5ca7b66..10ac314 100644 --- a/LPRDefaultPlotting.py +++ b/LPRDefaultPlotting.py @@ -7,14 +7,33 @@ ################################################################################ from matplotlib import rcParams, pyplot as pp +from cycler import cycler rcParams['grid.alpha'] = 0.7 rcParams['grid.linestyle'] = ':' rcParams['font.family'] = ['serif'] -rcParams['font.size'] = 9.0 +rcParams['font.size'] = 8.0 rcParams['mathtext.fontset'] = 'dejavuserif' rcParams['mathtext.it'] = 'serif:italic' rcParams['mathtext.bf'] = 'serif:bold' rcParams['mathtext.sf'] = 'serif' rcParams['mathtext.tt'] = 'monospace' +# axes.prop_cycle +COLOR_CYCLE_LIST = [ + [0, 0.4470, 0.7410], + [0.8500, 0.3250, 0.0980], + [0.4940, 0.1840, 0.5560], + [0.4660, 0.6740, 0.1880], + [0.3010, 0.7450, 0.9330], + [0.6350, 0.0780, 0.1840], + [0.9290, 0.6940, 0.1250], + [1, 0, 1]]#, +# [0, 1, 1], +# [1, 0, 0], +# [0, 1, 0]] + +rcParams['axes.prop_cycle'] = (cycler('linestyle',['-','--'])*cycler(color=COLOR_CYCLE_LIST)) + +for tri in COLOR_CYCLE_LIST: + color = '0x' + ''.join([ "%02x" % int(255*x) for x in tri]) diff --git a/TankGlobals.py b/TankGlobals.py index a73a4d2..f9f5173 100644 --- a/TankGlobals.py +++ b/TankGlobals.py @@ -15,11 +15,14 @@ def g1_map_default(system): # Operating Enviornment ##### class ampSystem: + f0 = 28 + bw0 = 8 + bw_plt = 0.5 """define global (hardware descriptive) variables for use in our system.""" def __init__(self, quiet=False): - self.f0 = 28 # design frequency (GHz) - self.bw0 = 8 # assumed extreme tuning range (GHz) - self.bw_plt = 4 # Plotting range (GHz) + self.f0 = self.__class__.f0 # design frequency (GHz) + self.bw0 = self.__class__.bw0 # assumed extreme tuning range (GHz) + self.bw_plt = self.__class__.bw_plt # Plotting range (GHz) # Configuration Of Hardware ##### @@ -46,9 +49,6 @@ class ampSystem: @property def fbw(self): # fractional bandwidth return self.bw0/self.f0 - @property - def phase_max(self): - return np.pi/2 * (1 - 1/self.gamma_len) # Compute system ##### @@ -65,6 +65,9 @@ class ampSystem: return np.sqrt(self.c1/self.l1)/self.g1 @property + def phase_max(self): + return np.pi/2 * (1 - 1/self.gamma_len) + @property def gamma_len(self): return self._gamma_steps @@ -160,5 +163,58 @@ class ampSystem: * 1j*(1+delta) \ / (1j*(1+delta) + Q*(1-np.power(1+delta,2)*(1+gamma))) +# Operating Enviornment +##### +class bufferSystem: + """define global (hardware descriptive) variables for use in our system.""" + def __init__(self, quiet=False): + self.f0 = ampSystem.f0 # design frequency (GHz) + self.bw0 = ampSystem.bw0 # assumed extreme tuning range (GHz) + self.bw_plt = ampSystem.bw_plt # Plotting range (GHz) + # Configuration Of Hardware + ##### + self.q2_L = 25 + self.q2_C = 50 + self.l2 = 140e-3 # nH + self.gm2 = 5e-3 # S + + if not quiet: + ## Report System Descrption + print(' L2 = %.3fpH, C2 = %.3ffF' % (1e3*self.l2, 1e6*self.c2)) + print(' Rp = %.3f Ohm' % (1/self.g2)) + print(' Q = %.1f' % (self.Q2)) + + @property + def w0(self): + return self.f0*2*np.pi + @property + def fbw(self): # fractional bandwidth + return self.bw0/self.f0 + + # Compute system + ##### + @property + def c2(self): + return 1/(self.w0*self.w0*self.l2) + @property + def g2(self): + g2_L = 1 / (self.q2_L*self.w0*self.l2) + g2_C = self.w0 * self.c2 / self.q2_C + return g2_L + g2_C + @property + def Q2(self): + return np.sqrt(self.c2/self.l2)/self.g2 + + def compute_ref(self, f_dat): + y_tank = self.g2 + f_dat.jw*self.c2 + 1/(f_dat.jw * self.l2) + tf = self.__class__.tf_compute(f_dat.delta, self.g2, self.gm2, self.l2, self.c2) + return (y_tank, tf) + + @classmethod + def tf_compute(cls, delta, gx, gm, l, c): + Q = np.sqrt(c/l)/gx + return gm / gx \ + * 1j*(1+delta) \ + / (1j*(1+delta) + Q*(1-np.power(1+delta,2))) diff --git a/tankComputers.py b/tankComputers.py index d178362..631191b 100644 --- a/tankComputers.py +++ b/tankComputers.py @@ -23,7 +23,20 @@ def wrap_rads(angles): return np.mod(angles+np.pi,2*np.pi)-np.pi def atand(x): return 180/np.pi*np.arctan(x) - + +def setLimitsTicks(ax, data, steps): + targs = np.array([1, 2, 4, 5, 10, 20, 30, 50, 60, 100, 250, 1000]) + lo = np.min(data) + hi = np.max(data) + rg = hi-lo + step_size = rg / steps + step_size = np.select(targs >= step_size, targs) + lo = np.floor(lo / step_size)*step_size + hi = np.ceil(hi / step_size)*step_size + marks = np.arange(0,steps+1)*step_size + lo + ax.set_ylim((lo,hi)) + ax.set_yticks(marks) + def rms_v_bw(err_sig, bandwidth_scale=1): """compute the rms vs bandwidth assuming a fixed center frequency""" # First compute the error power diff --git a/tankPlot.py b/tankPlot.py index 964936f..15fa04f 100644 --- a/tankPlot.py +++ b/tankPlot.py @@ -10,9 +10,11 @@ sys.path.append("./pySmithPlot") import smithplot from smithplot import SmithAxes +plot_list = [4] + ################################################################################ # Override the defaults for this script -rcParams['figure.figsize'] = [10,7] +rcParams['figure.figsize'] = [3.4,2.2] default_window_position=['+20+80', '+120+80'] ################################################################################ @@ -22,29 +24,31 @@ from FreqClass import FreqClass from tankComputers import * S=TankGlobals.ampSystem() +B=TankGlobals.bufferSystem() f=FreqClass(501, S.f0, S.bw_plt) ################################################################################ # We want a smooth transition out to alpha. So For now assume a squares # weighting out to the maximum alpha at the edges. -gain_variation = -8*0 # dB +# This gain variation function is the default function baked into the method. +gain_variation = 0 # dB S.alpha_min = dB2Vlt(gain_variation) -# compute correction factor for g1 that will produce common gain at f0 -# this is defined as the class default -g1_swp = S.g1_swp # and compute how much of a negative gm this requres, and it's relative # proportion to the gm of the assumed main amplifier gm. -g1_boost = (g1_swp - S.g1) +g1_boost = (S.g1_swp - S.g1) g1_ratio = -g1_boost / S.gm1 print(' Max G1 boost %.2fmS (%.1f%% of gm1)' % \ (1e3*np.max(np.abs(g1_boost)), 100*np.max(g1_ratio))) ################################################################################ -# Generate a reference implementation +# Extract the computed tank conductanec, and the transfer functions. (y_tank, tf) = S.compute_block(f) (_, tf_ref) = S.compute_ref(f) + +# To produce full 360 dgree plots, double the two transfer functions by +# considering inversion. # double to describe with perfect inversion stage tf = np.column_stack((tf,-tf)) @@ -63,66 +67,123 @@ y_tank = y_tank.T (bw_ang, rms_ang_swp)=rms_v_bw(tf_r_ang-tf_r_ang_ideal, S.bw_plt) (bw_mag, rms_gain_swp)=rms_v_bw(tf_r, S.bw_plt) -################################################################################ +(y_buf, tf_buf) = B.compute_ref(f) -h1 = pp.figure() -h2 = pp.figure(figsize=(5,7)) -h3 = pp.figure(figsize=(5,7)) +################################################################################ +################################################################################ +################################################################################ mgr = pp.get_current_fig_manager() -################################################################################ -ax1 = h1.add_subplot(2,2,1, projection='smith') -ax2 = h1.add_subplot(2,2,3, projection='polar') -ax3 = h1.add_subplot(2,2,2) -ax4 = h1.add_subplot(2,2,4) - -ax1.plot(y_tank, datatype=SmithAxes.Y_PARAMETER, marker="None") -ax2.plot(np.angle(tf), dB20(tf)) -ax3.plot(f.hz,dB20(tf)) -ax4.plot(f.hz,ang_unwrap(tf)) ################################################################################ -ax6 = h2.add_subplot(2,1,1) -ax7 = h2.add_subplot(2,1,2) -ax6.plot(f.hz,dB20(tf_r)) -ax7.plot(f.hz,ang_unwrap(tf_r.T).T) +if 6 in plot_list: + h6 = pp.figure() + mgr = pp.get_current_fig_manager() + ax6 = [h6.subplots(1,1)] + ax6.append(ax6[0].twinx()) -ax8 = h3.add_subplot(2,1,1) -ax9 = h3.add_subplot(2,1,2) -ax8.plot(bw_mag,dB20(rms_gain_swp)) -ax9.plot(bw_ang,rms_ang_swp*180/np.pi) + axT=ax6[0] + axT.plot(f.hz,dB20(tf_buf)) + axT.set_ylabel('Gain (dB)') + axT.set_title('Buffer Response') + setLimitsTicks(axT, dB20(tf_buf), 6) + axT=ax6[1] + axT.plot(f.hz,ang_unwrap(tf_buf)) + axT.set_ylabel('Phase (deg)') + setLimitsTicks(axT, ang_unwrap(tf_buf), 6) -ax1.set_title('Tank Impedance') -ax2.set_title('Transfer Function') - -ax3.set_title('TF Gain') -ax3.set_ylabel('Gain (dB)') -ax4.set_title('TF Phase') -ax4.set_ylabel('Phase (deg)') -ax6.set_title('TF Relative Gain') -ax6.set_ylabel('Relative Gain (dB)') -ax7.set_title('TF Relative Phase') -ax7.set_ylabel('Relative Phase (deg)') -for ax_T in [ax3, ax4, ax6, ax7]: - ax_T.grid() - ax_T.set_xlabel('Freq (GHz)') - ax_T.set_xlim(f.hz_range) - -ax8.set_title('RMS Gain Error') -ax8.set_ylabel('RMS Gain Error (dB)') -ax9.set_title('RMS Phase Error') -ax9.set_ylabel('RMS Phase Error (deg)') -for ax_T in [ax8, ax9]: - ax_T.grid() - ax_T.set_xlim((0,S.bw_plt)) - ax_T.set_xlabel('Bandwidth (GHz)') + for i,axT in enumerate(ax6): + if i==0: axT.grid() + axT.set_xlim(f.hz_range) + axT.set_xlabel('Frequency (GHz)') + c_color = LPRDefaultPlotting.COLOR_CYCLE_LIST[i] + axT.lines[0].set_color(c_color) + axT.yaxis.label.set_color(c_color) + axT.tick_params('y', colors=c_color) + h6.tight_layout() + mgr.window.geometry(default_window_position[0]) + h6.show() ################################################################################ -h1.tight_layout() -h2.tight_layout() -h3.tight_layout() -mgr.window.geometry(default_window_position[0]) -h1.show() -mgr.window.geometry(default_window_position[1]) -h2.show() -h3.show() +if 1 in plot_list: + h1 = [pp.figure() for x in range(2)] + ax1 = [hT.add_subplot(1,1,1) for hT in h1] + ax1[0].plot(f.hz,dB20(tf)) + ax1[1].plot(f.hz,ang_unwrap(tf)) + + ax1[0].set_title('TF Gain') + ax1[0].set_ylabel('Gain (dB)') + ax1[1].set_title('TF Phase') + ax1[1].set_ylabel('Phase (deg)') + + for axT in ax1: + axT.grid() + axT.set_xlabel('Freq (GHz)') + axT.set_xlim(f.hz_range) + + [hT.tight_layout() for hT in h1] + mgr.window.geometry(default_window_position[0]) + [hT.show() for hT in h1] + +if 4 in plot_list: + h4 = [pp.figure(figsize=(3.4,3.4)) for x in range(2)] + ax4 = [] + ax4.append(h4[0].add_subplot(1,1,1, projection='smith')) + ax4.append(h4[1].add_subplot(1,1,1, projection='polar')) + + ax4[0].plot(y_tank, datatype=SmithAxes.Y_PARAMETER, marker="None") + ax4[1].plot(np.angle(tf), dB20(tf)) + + ax4[0].set_title('Tank Impedance') + ax4[1].set_title('Transfer Function') + + old_pos = ax4[1].title.get_position() + ax4[1].title.set_position((old_pos[0], 1.1)) + h4[1].tight_layout() + #[hT.tight_layout() for hT in h4] + mgr.window.geometry(default_window_position[0]) + [hT.show() for hT in h4] + +################################################################################ +if 2 in plot_list: + h2 = [pp.figure() for x in range(2)] + + ax2 = [hT.add_subplot(1,1,1) for hT in h2] + ax2[0].plot(f.hz,dB20(tf_r)) + setLimitsTicks(ax2[0], dB20(tf_r), 6) + ax2[1].plot(f.hz,ang_unwrap(tf_r.T).T) + setLimitsTicks(ax2[1], ang_unwrap(tf_r.T), 6) + + ax2[0].set_title('Relative Gain') + ax2[0].set_ylabel('Gain (dB)') + ax2[1].set_title('Relative Phase') + ax2[1].set_ylabel('Phase (deg)') + + for axT in ax2: + axT.grid() + axT.set_xlabel('Freq (GHz)') + axT.set_xlim(f.hz_range) + [hT.tight_layout() for hT in h2] + mgr.window.geometry(default_window_position[1]) + [hT.show() for hT in h2] + +################################################################################ +if 3 in plot_list: + h3 = [pp.figure() for x in range(2)] + + ax3 = [hT.add_subplot(1,1,1) for hT in h3] + ax3[0].plot(bw_mag,dB20(rms_gain_swp)) + ax3[1].plot(bw_ang,rms_ang_swp*180/np.pi) + + ax3[0].set_title('RMS Gain Error') + ax3[0].set_ylabel('RMS Gain Error (dB)') + ax3[1].set_title('RMS Phase Error') + ax3[1].set_ylabel('RMS Phase Error (deg)') + for axT in ax3: + axT.grid() + axT.set_xlim((0,S.bw_plt)) + axT.set_xlabel('Bandwidth (GHz)') + + [hT.tight_layout() for hT in h3] + [hT.show() for hT in h3] +