class SmithChart:
'''a class for drawing and manipulating Smith Charts
by John D Sahr jdsahr@u.washington.edu'''
def __init__(self):
'''initialize a smith chart'''
self.chart = smithchart
self.last_rho = None
self.markradius = 0.015
self.mark_ind = 0
self.fontsize = 15
self.admittance_mode = True
self.annotation = []
def clear(self):
'''reset the smith chart'''
self.chart = smithchart
self.last_rho = None
self.mark_ind = 0
self.admittance_mode = True
self.annotation = []
def mark(self, label = True):
'''make a small circular mark at the last location on the chart'''
self.chart += circle(cart(self.last_rho), self.markradius, rgbcolor = (0,0,0))
center = (self.last_rho.real(), self.last_rho.imag())
polar = self.polar(self.last_rho)
if label == False: # don't label at all.
return
elif label == True: # generate a generic label
tag = chr(self.mark_ind + ord('A'))
self.mark_ind += 1
elif type(label) == type('a string'): # use a custom label
tag = label
else: # error out
raise 'improper label passed to mark'
tagloc = (center[0]+3*self.markradius, center[1]+3*self.markradius)
self.chart += text(tag, tagloc, fontsize=self.fontsize)
msg = '%4s :: rho %5.3f at %6.1f deg; ' % (tag, polar[0], polar[1])
z = zz(self.last_rho)
msg += '%6.3f + %6.3fj' % (z.real(),z.imag())
self.annotation.append(msg)
def markz(self, z, label = True):
'''mark a (normalized) impedance on the Smith Chart'''
center = rho(z)
self.last_rho = center.real() + 1j*center.imag()
self.mark(label)
def marky(self, z, label = True):
'''mark a (normalized) impedance at its admittance position on the Smith Chart'''
self.markz(1/z, label)
def markr(self, r, dolabel = True):
'''mark the smith chart given a (complex) reflection coefficient'''
self.markz(zz(r),dolabel)
def polar(self, r):
'''convert a complex number in cartesian format to mag, phase(degrees) format as a tuple'''
return( r.abs(), 180*r.arg()/math.pi)
def togen(self, wavelengths, rgbcolor=(1,0,1), dolabel = True):
'''start at the current point on the Smith Chart, and rotate <wavelengths> towards the generator'''
if self.last_rho == None:
raise "not anywhere yet!"
radius = sqrt(self.last_rho[0]^2 + self.last_rho[1]^2)
t1 = math.atan2(self.last_rho[1],self.last_rho[0])
t2 = t1 - 4*math.pi*wavelengths
self.last_rho *= exp(1j*(t2-t1))
t = var('t')
self.chart += parametric_plot((radius*cos(t), radius*sin(t)), (t,t1,t2), rgbcolor=rgbcolor)
self.mark(dolabel)
def singlestub(self, z, bottom = True):
'''solve a single stub match using shorted stub.
There are two solutions: inductive (bottom) or capacitive (top)'''
self.markz(z, 'Zl') # mark the location of the load impedance
self.marky(z, 'Yl') # mark the location of the load admittance
magRhoL = self.last_rho.abs()
argRhoL = self.last_rho.arg()
self.chart += circle((0,0), magRhoL, rgbcolor = (1,0,0)) # the circle of const |refcoef|
argMatch = acos(magRhoL) # the intersection of the circle with the 1 + jX circle
if bottom != True: # ... get the capacitive stub instead
argMatch = -argMatch
ym1 = zz(magRhoL*exp(1j*argMatch)) # ... get the intersection point
self.markz(ym1,'Ym1') # ... and mark it
stb1 = 0 - 1j*ym1.imag() # ... the input admittance of the stub
self.markz(stb1,'stb1') # ... and mark it
stubloc = 180*(argRhoL - argMatch)/math.pi - 360 # compute the location of the stub
while stubloc < 0.0:
stubloc += 360
stublength = -180.0*rho(stb1).arg()/math.pi - 360 # compute the length of the stub
while stublength < 0.0:
stublength += 360
print 'stub location: %6.3f :: ' % (stubloc*0.5/360),
print 'stub length: %6.3f' % (stublength*0.5/360)
def show(self):
'''draw the annotated smith chart'''
self.chart.show(aspect_ratio = 1, axes = False)
for x in self.annotation:
print x