''' Script to design tee and pi attenuators. ''' from __future__ import division import sys, getopt, functools, fpformat from math import sqrt debug = 0 # Turns on debug printing nl = "\n" def StreamOut(stream, *s, **kw): k = kw.setdefault # Process keyword arguments sep = k("sep", "") auto_nl = k("auto_nl", True) prefix = k("prefix", "") convert = k("convert", str) # Convert position arguments to strings strings = map(convert, s) # Dump them to the stream stream.write(prefix + sep.join(strings)) # Add a newline if desired if auto_nl: stream.write(nl) out = functools.partial(StreamOut, sys.stdout) outs = functools.partial(StreamOut, sys.stdout, sep=" ") dbg = functools.partial(StreamOut, sys.stdout, sep=" ", prefix="+ ") err = functools.partial(StreamOut, sys.stderr) manual = '''Usage: %s dB Z [Zout] Prints the design of tee and pi attenuators for a given dB loss. Z is the input and output impedance. If you just give Z, then the input and output impedance are the same. The circuits are: pi tee o--+---R3----+--o o---R1---+---R2---o | | | | | | R1 R2 R3 | | | | | | V V (ground) V Zin >= Zout Zin >= Zout Options -d n Set the output to n digits (default is 3) ''' def Dbg(msg, no_newline=0): if debug: err(msg) if not no_newline: err(nl) def Usage(status=1): out(manual % sys.argv[0]) sys.exit(status) def ParseCommandLine(d): d["digits"] = 3 if len(sys.argv) < 2: Usage() try: optlist, args = getopt.getopt(sys.argv[1:], "d:h") except getopt.GetoptError, str: msg, option = str out(msg + nl) sys.exit(1) for opt in optlist: if opt[0] == "-d": try: n = int(opt[1]) except ValueError: err("'%s' isn't a valid integer" % opt[1]) exit(1) if n < 1 or n > 15: err("Number of digits must be between 1 and 15") exit(1) d["digits"] = n if opt[0] == "-h": Usage(0) if len(args) < 2 or len(args) > 3: Usage() else: d["dB"] = float(args[0]) if d["dB"] <= 0: err("dB must be > 0") exit(1) d["Zin"] = float(args[1]) if len(args) == 3: d["Zout"] = float(args[2]) else: d["Zout"] = d["Zin"] if d["Zout"] > d["Zin"]: err("Zin must be >= Zout") exit(1) def Pad(s, length): if len(s) < length: s += " "*(length - len(s)) return s def main(): d = {} ParseCommandLine(d) L, Zin, Zout = d["dB"], d["Zin"], d["Zout"] # Equations from # http://www.rfcafe.com/references/electrical/attenuators.htm k = 10**(L/10) r = Zin/Zout kmin = 2*r - 1 + 2*sqrt(r*(r - 1)) if k < kmin: err("Attenuation is too low for the given impedances") exit(1) a, b, c = k+1, 2*sqrt(k*Zin*Zout), k-1 # tee R1tee = (a*Zin - b)/c R2tee = (a*Zout - b)/c R3tee = b/c # pi R1pi = c*Zin*sqrt(Zout)/(a*sqrt(Zout) - 2*sqrt(k*Zin)) R2pi = c*Zout*sqrt(Zin)/(a*sqrt(Zin) - 2*sqrt(k*Zout)) R3pi = c/2*sqrt(Zin*Zout/k) fp = fpformat.FPFormat(d["digits"]) f = fp.engsi Zin = f(Zin) Zout = f(Zout) R1pi = f(R1pi) L = len(R1pi) R2pi, R3pi = Pad(f(R2pi), L), Pad(f(R3pi), L) R1tee, R2tee, R3tee = Pad(f(R1tee), L), Pad(f(R2tee), L), Pad(f(R3tee), L) k = f(k) p, t, da = Pad("pi", L), "tee", Pad("-"*5, L) while len(p) < len(R1pi): p += " " out(''' Tee and pi attenuators ---------------------- Attenuation = %(L)s dB (ratio = %(k)s) Zin = %(Zin)s Zout = %(Zout)s %(p)s %(t)s %(da)s %(da)s R1 %(R1pi)s %(R1tee)s R2 %(R2pi)s %(R2tee)s R3 %(R3pi)s %(R3tee)s ''' % locals()) main()