1017 KiB
1017 KiB
In [2]:
import numpy as np import skrf import skrf.media as media from skrf.media import DistributedCircuit import skrf.frequency as freq import skrf.network as net import skrf.util import matplotlib.pyplot as plt %matplotlib inline plt.rcParams['figure.figsize'] = [10, 10] f = freq.Frequency(0.1, 0.95, 1001) tem = DistributedCircuit(f, z0=50) bjt = net.Network('bfu520_7ma_attenuated10db_calibratedout_082519.s2p').interpolate(f) bjt bjt.plot_s_smith()
In [3]:
# well, on the bright side it stays mostly inside the unit circle # let's calculate the matching values for 144 MHz and 915 MHz # calculate the stability circles for the source and load impedances idx_915mhz = skrf.util.find_nearest_index(bjt.f, 915.e+6) idx_144mhz = skrf.util.find_nearest_index(bjt.f, 144.e+6) sqabs = lambda x: np.square(np.absolute(x)) delta = bjt.s11.s*bjt.s22.s - bjt.s12.s*bjt.s21.s rl = np.absolute((bjt.s12.s * bjt.s21.s)/(sqabs(bjt.s22.s) - sqabs(delta))) cl = np.conj(bjt.s22.s - delta*np.conj(bjt.s11.s))/(sqabs(bjt.s22.s) - sqabs(delta)) rl_915mhz = rl[idx_915mhz][0, 0] cl_915mhz = cl[idx_915mhz][0, 0] rl_144mhz = rl[idx_144mhz][0, 0] cl_144mhz = cl[idx_144mhz][0, 0] rl_144mhz, cl_144mhz, rl_915mhz, cl_915mhz
Out[3]:
(0.24538732275188085, (0.90996369931107579+0.54180299545778843j), 1.2327504787552828, (1.3139029137857448+1.8217439279569125j))
In [4]:
def calc_circle(c, r): theta = np.linspace(0, 2*np.pi, 1000) return c + r*np.exp(1.0j*theta) def plot_smith(pts): n = net.Network(s=pts) n.plot_s_smith() rs = np.absolute((bjt.s12.s * bjt.s21.s)/(sqabs(bjt.s11.s) - sqabs(delta))) cs = np.conj(bjt.s11.s - delta*np.conj(bjt.s22.s))/(sqabs(bjt.s11.s) - sqabs(delta)) rs_144mhz = rs[idx_144mhz][0, 0] cs_144mhz = cs[idx_144mhz][0, 0] rs_915mhz = rs[idx_915mhz][0, 0] cs_915mhz = cs[idx_915mhz][0, 0] print(rs_144mhz, cs_144mhz, rs_915mhz, cs_915mhz) cl_points = calc_circle(cl_915mhz, rl_915mhz) cs_points = calc_circle(cs_915mhz, rs_915mhz) plot_smith(cl_points) plot_smith(cs_points)
0.962850018361 (0.64561388404+1.3232778444j) 15.1519702283 (13.7246198854+3.34314489994j)
In [5]:
cl_points = calc_circle(cl_144mhz, rl_144mhz) cs_points = calc_circle(cs_144mhz, rs_144mhz) plot_smith(cl_points) plot_smith(cs_points)
In [12]:
# so the amplifier's pretty stable at 915 MHz, and we need to avoid inductive loads at 144 MHz # eh let's try a simultaneous conjugate match at 144 MHz after adding some shunt resistance, and see how stable that is # it looks like a little series output resistance would stabilize 915 MHz, so let's add some and then do a simultaneous # conjugate match there as well def conjugate_match(ntwk, idx): # that doesn't look too bad, so let's move forward and try to conjugate match delta2 = ntwk.s11.s[idx, 0, 0]*ntwk.s22.s[idx, 0, 0] - ntwk.s12.s[idx, 0, 0]*ntwk.s21.s[idx, 0, 0] B1 = 1 + sqabs(ntwk.s11.s[idx, 0, 0]) - sqabs(ntwk.s22.s[idx, 0, 0]) - sqabs(delta2) B2 = 1 + sqabs(ntwk.s22.s[idx, 0, 0]) - sqabs(ntwk.s11.s[idx, 0, 0]) - sqabs(delta2) C1 = ntwk.s11.s[idx, 0, 0] - delta2*np.conj(ntwk.s22.s[idx, 0, 0]) C2 = ntwk.s22.s[idx, 0, 0] - delta2*np.conj(ntwk.s11.s[idx, 0, 0]) gamma_s = (B1 - np.sqrt(np.square(B1) - 4*sqabs(C1) + 0j))/(2*C1) gamma_l = (B2 - np.sqrt(np.square(B2) - 4*sqabs(C2) + 0j))/(2*C2) z_s = net.s2z(np.array([[[gamma_s]]]))[0,0,0] z_l = net.s2z(np.array([[[gamma_l]]]))[0,0,0] return z_s, z_l bjt_144 = bjt ** tem.shunt(tem.resistor(110.) ** tem.short()) zs_144mhz, zl_144mhz = conjugate_match(bjt_144, idx_144mhz) zs_144mhz, zl_144mhz
Out[12]:
((84.016417525460881+116.58199865471924j), (79.988423988583222+49.292756871047388j))
In [13]:
def K(ntwk): delta2 = ntwk.s11.s*ntwk.s22.s - ntwk.s12.s*ntwk.s21.s k = ((1 - sqabs(ntwk.s11.s) - sqabs(ntwk.s22.s) + sqabs(delta2))/(2*np.absolute(ntwk.s12.s*ntwk.s21.s)))[:,0,0] return k plt.plot(bjt_144.f, K(bjt_144))
Out[13]:
[<matplotlib.lines.Line2D at 0x7f6214dabf28>]
In [29]:
def calc_matching_network(z1, z2): flipped = ((abs(np.imag(z2)) < 1e-6 and np.real(z1) < np.real(z2)) or (abs(np.imag(z2)) > 1e-6 and np.real(z1) < np.real(1/(1/z2-1/(1.j*np.imag(z2)))))) if flipped: z2, z1 = z1, z2 # cancel out the imaginary parts of both input and output impedances z1_par = 1e+10 if abs(np.imag(z1)) > 1e-6: # parallel something to cancel out the imaginary part of # z1's impedance z1_par = 1/(-1j*np.imag(1/z1)) z1 = 1/(1./z1 + 1/z1_par) z2_ser = 0.0 if abs(np.imag(z2)) > 1e-6: z2_ser = -1j*np.imag(z2) z2 = z2 + z2_ser Q = np.sqrt((np.real(z1) - np.real(z2))/np.real(z2)) x1 = -1.j * np.real(z1)/Q x2 = 1.j * np.real(z2)*Q x1_tot = 1/(1/z1_par + 1/x1) x2_tot = z2_ser + x2 if flipped: return x2_tot, x1_tot else: return x1_tot, x2_tot zs_144mhz_1, zs_144mhz_2 = calc_matching_network(50., np.conj(zs_144mhz)) zl_144mhz_1, zl_144mhz_2 = calc_matching_network(np.conj(zl_144mhz), 50.) zs_144mhz_1, zs_144mhz_2, zl_144mhz_1, zl_144mhz_2
Out[29]:
(98.94107678366402j, -415.7338067603979j, -228.72461381828086j, 54.93861027793749j)
In [30]:
ls_144mhz = np.real(zs_144mhz_1/(2.j*np.pi*144e+6)) cs_144mhz = np.real(1/(2.j*np.pi*144e+6*zs_144mhz_2)) cl_144mhz = np.real(1/(2.j*np.pi*144e+6*zl_144mhz_1)) ll_144mhz = np.real(zl_144mhz_2/(2.j*np.pi*144e+6)) ls_144mhz, cs_144mhz, cl_144mhz, ll_144mhz
Out[30]:
(1.0935389892329788e-07, 2.6585344814100594e-12, 4.8321981701474735e-12, 6.072049578008999e-08)
In [60]:
# a little bit of playing around lets me figure out which one's the shunt and which is in series #input_network_144 = tem.inductor(ls_144mhz) ** tem.shunt_capacitor(cs_144mhz) input_network_144 = tem.inductor(120.e-9) ** tem.shunt_capacitor(3e-12) output_network_144 = tem.shunt_capacitor(4.7e-12) ** tem.inductor(ll_144mhz) amplifier_144 = input_network_144 ** bjt ** tem.shunt(tem.resistor(120.) ** tem.short()) ** output_network_144 amplifier_144.plot_s_smith()
In [61]:
amplifier_144.s21.plot_s_db()
In [62]:
amplifier_144.s11.plot_s_db()
In [53]:
amplifier_144.s22.plot_s_db()
In [42]:
# that looks pretty good, I'm going to set it up and see how well it actually performs # quick stability check (K>1 for stability) plt.plot(amplifier_144.f, K(amplifier_144))
Out[42]:
[<matplotlib.lines.Line2D at 0x7f62140c70b8>]
In [63]:
zs_915mhz, zl_915mhz = conjugate_match(bjt, idx_915mhz) zs_915mhz, zl_915mhz
Out[63]:
((5.9492313221354651-5.9181565487569099j), (14.408813054677903+96.001906707542361j))
In [64]:
zs_915mhz_1, zs_915mhz_2 = calc_matching_network(50., np.conj(zs_915mhz)) zl_915mhz_1, zl_915mhz_2 = calc_matching_network(np.conj(zl_915mhz), 50.) zs_915mhz_1, zs_915mhz_2, zl_915mhz_1, zl_915mhz_2
Out[64]:
((3.3763493241407094e-08-18.374845099049704j), 10.270364470239715j, 118.64758530389355j, (1.0121054038471538e-07-31.81360406881235j))
In [71]:
ls_915mhz = np.real(zs_915mhz_2/(2.j*np.pi*915e+6)) cs_915mhz = np.real(1/(2.j*np.pi*915e+6*zs_915mhz_1)) cl_915mhz = np.real(1/(2.j*np.pi*915e+6*zl_915mhz_2)) ll_915mhz = np.real(zl_915mhz_1/(2.j*np.pi*915e+6)) ls_915mhz, cs_915mhz, cl_915mhz, ll_915mhz
Out[71]:
(1.786425434747569e-09, 9.466192916354343e-12, 5.467466940856602e-12, 2.0637540641565e-08)
In [73]:
# a little bit of playing around lets me figure out which one's the shunt and which is in series #input_network_915 = tem.inductor(ls_915mhz) ** tem.shunt_capacitor(cs_915mhz) input_network_915 = tem.shunt_capacitor(cs_915mhz) ** tem.inductor(ls_915mhz) output_network_915 = tem.inductor(ll_915mhz) ** tem.shunt_capacitor(cl_915mhz) amplifier_915 = input_network_915 ** bjt ** output_network_915 amplifier_915.plot_s_smith()
In [74]:
amplifier_915.s11.plot_s_db() amplifier_915.s22.plot_s_db()
In [75]:
amplifier_915.s21.plot_s_db()
In [ ]: