PDA

View Full Version : [WIP] Circuit Solver - Capacitance



klange
February 26th, 2009, 05:48 PM
Bored as hell today, doing capacitance in AP Physics.
Easy stuff, right? But it's long and easy to lose track of what you're doing.

But not any more!

This ~300 line Python script does all the work for you!
Simply enter in a circuit:

Enter # of microcoloumbs OR p for parallel, s for series:
├p
│├p
││├4
││├4
││├
│├3
│├p
││├4
││├2
││├
│├4
│├2
│├
├2
├5

Battery Voltage: 12And out come the results:

┌◐┐Battery +12V
│ │Series 1.35μF 12V 16.1μC
│ └┬┬┬┬┐Parallel 23.0μF 0.702V 16.1μC
│ ││││└┬┐Parallel 8μF 0.702V 5.61μC
│ ││││ │╪C1 4μF 0.702V 2.81μC
│ ││││ ╪C2 4μF 0.702V 2.81μC
│ ││││┌┴┘
│ │││╪C3 3μF 0.702V 2.11μC
│ ││└┬┐Parallel 6μF 0.702V 4.21μC
│ ││ │╪C4 4μF 0.702V 2.81μC
│ ││ ╪C5 2μF 0.702V 1.4μC
│ ││┌┴┘
│ │╪C6 4μF 0.702V 2.81μC
│ ╪C7 2μF 0.702V 1.4μC
│ ┌┴┴┴┴┘
│ ╪C8 2μF 8.07V 16.1μC
│ ╪C9 5μF 3.23V 16.1μC
└─┘No external modules are used. To use the colored output, you need an ANSI-capable terminal (standard Windows terminals don't normally accept ANSI codes and require a driver be set in cmd). Obviously, do not enter capacitances of 0, or use 0 as the voltage for the battery, as this will result in a division-by-zero that is not checked for.

e: I realize the above circuit is horribly redundant, so here's a better output:

┌◐┐Battery +9V
│ │Series 1.28μF 9V 11.5μC
│ ╪C₁ 2μF 5.76V 11.5μC
│ └┬┐Parallel 3.56μF 3.24V 11.5μC
│ ││Series 0.563μF 3.24V 1.82μC
│ │╪C₂ 4μF 0.455V 1.82μC
│ │╪C₃ 1μF 1.82V 1.82μC
│ │└┬┐Parallel 3.06μF 0.596V 1.82μC
│ │ ││Series 1.56μF 0.596V 0.927μC
│ │ │╪C₄ 3μF 0.309V 0.927μC
│ │ │└┬┐Parallel 6μF 0.154V 0.927μC
│ │ │ │╪C₅ 2μF 0.154V 0.309μC
│ │ │ ╪C₆ 4μF 0.154V 0.618μC
│ │ │┌┴┘
│ │ │╪C₇ 7μF 0.132V 0.927μC
│ │ │Series 1.5μF 0.596V 0.894μC
│ │ ╪C₈ 2μF 0.447V 0.894μC
│ │ ╪C₉ 6μF 0.149V 0.894μC
│ │┌┴┘
│ │╪C₁₀ 5μF 0.364V 1.82μC
│ ╪C₁₁ 3μF 3.24V 9.71μC
│ ┌┴┘
└─┘And here's the code:

#!/usr/bin/python
# -*- coding: utf-8 -*-

USE_COLOR=True

def Format(val):
if val < 100:
o = "%.3gf" % val
if o.find("e-07f") > -1:
o = str(float(o.replace("e-07f","")) / 10) + "u"
if o.find("e-05f") > -1:
o = str(float(o.replace("e-05f","")) * 10) + "u"
o = o.replace( "e-06f", "u" )
o = o.replace( "f", "" )
return o
return "%.3f" % val
def ss(val):
o = val
if USE_COLOR:
o = o.replace("1","₁")
o = o.replace("2","₂")
o = o.replace("3","₃")
o = o.replace("4","₄")
o = o.replace("5","₅")
o = o.replace("6","₆")
o = o.replace("7","₇")
o = o.replace("8","₈")
o = o.replace("9","₉")
o = o.replace("0","₀")
return o
if USE_COLOR:
class Color():
Blue = chr(27) + "[1;94m"
Red = chr(27) + "[1;91m"
Green = chr(27) + "[1;92m"
Yellow = chr(27) + "[1;93m"
Reset = chr(27) + "[m"
else:
class Color():
Blue = ""
Red = ""
Green = ""
Yellow = ""
Reset = ""
class Capacitor():
def __init__(self, cap=0.0, i=-1):
self.capacitance = cap
self.knowCap = (cap != 0.0)
self.potential = 0.0
self.knowPot = False
self.charge = 0.0
self.knowCharge = 0.0
self.index = i
def getCap(self):
if self.knowCap:
return self.capacitance
elif self.knowCharge and self.knowPot:
return self.charge / self.potential
raise TransitionError,"Can not compute capacitance."
def setCap(self, cap):
self.capacitance = cap
self.knowCap = True
if self.knowPot and not self.knowCharge:
self.setCharge(self.capacitance * self.potential)
if self.knowCharge and not self.knowPot:
self.setPot(self.charge / self.capacitance)
return cap
def getPot(self):
if self.knowPot:
return self.potential
elif self.knowCap and self.knowCharge:
return self.setPot(self.charge / self.capacitance)
raise TransitionError,"Can not compute potential."
def setPot(self, pot):
self.potential = pot
self.knowPot = True
if self.knowCap and not self.knowCharge:
self.setCharge(self.capacitance * self.potential)
if self.knowCharge and not self.knowCap:
self.setCap(self.charge / self.potential)
return pot
def getCharge(self):
if self.knowCharge:
return self.charge
elif self.knowCap and self.knowPot:
return self.capacitance * self.potential
raise TransitionError,"Can not compute charge."
def setCharge(self,charge):
self.charge = charge
self.knowCharge = True
if self.knowCap and not self.knowPot:
self.setPot(self.charge / self.capacitance)
if self.knowPot and not self.knowCap:
self.setCap(self.charge / self.potential)
return charge
def prnt(self,t="",p=0):
ca = "?"
po = "?"
ch = "?"
if self.knowCap:
ca = Format(self.getCap()) + "F"
if self.knowPot:
po = Format(self.getPot()) + "V"
if self.knowCharge:
ch = Format(self.getCharge()) + "C"
a = "%sC%s%s" % (Color.Red,self.index,Color.Reset)
a = a.replace("C" + str(self.index),"C" + ss(str(self.index)))
b = "%s %s %s" % (ca.ljust(10),po.ljust(10),ch.ljust(10))
tmp = len((t + "_C" + str(self.index)).replace("│","_").replace("╪","_"))
dlp = p - len("C" + str(self.index))
if dlp < 0:
dlp = 0
print t + "╪" + a + "│" * dlp + " " * (30 - (tmp + dlp)) + b.replace("u","μ")
class Series():
def __init__(self,children=[]):
self.children = children
self.knowCap = False
self.knowCharge = False
self.knowPot = False
self.capacitance = 0.0
self.charge = 0.0
self.potential = 0.0
def getCap(self):
if self.knowCap:
return self.capacitance
elif self.knowCharge and self.knowPotential:
return self.setCap(self.charge / self.potential)
tmp = 0.0
for i in self.children:
tmp += 1.0 / i.getCap()
return self.setCap(1.0 / tmp)
def setCap(self,cap):
self.capacitance = cap
self.knowCap = True
return cap
def getPot(self):
if self.knowPot:
return self.potential
tmp = 0.0
for i in self.children:
tmp += i.getPot()
self.potential = tmp
self.knowPot = True
return tmp
def setPot(self,pot):
self.potential = pot
self.knowPot = True
if self.knowCap and not self.knowCharge:
self.setCharge(self.capacitance * self.potential)
if self.knowCharge and not self.knowCap:
self.setCap(self.charge / self.potential)
return pot
def getCharge(self):
if self.knowCharge:
return self.charge
elif self.knowPot and self.knowCap:
return self.setCharge(self.capacitance * self.potential)
else:
if len(self.children) > 0:
return self.children[0].getCharge()
raise Error,"Gah!"
def setCharge(self, charge):
self.charge = charge
self.knowCharge = True
if self.knowCap and not self.knowPot:
self.setPot(self.charge / self.capacitance)
if self.knowPot and not self.knowCap:
self.setCap(self.charge / self.potential)
for i in self.children:
i.setCharge(charge)
return charge
def prnt(self,t="",p=0):
ca = "?"
po = "?"
ch = "?"
if self.knowCap:
ca = Format(self.getCap()) + "F"
if self.knowPot:
po = Format(self.getPot()) + "V"
if self.knowCharge:
ch = Format(self.getCharge()) + "C"
a = "%sSeries%s" % (Color.Green,Color.Reset)
b = "%s %s %s" % (ca.ljust(10),po.ljust(10),ch.ljust(10))
tmp = len((t + "│" + "Series").replace("│","_"))
print t + "│" + a + " " * (30 - tmp) + b.replace("u","μ")
for i in self.children:
i.prnt(t,p)
class Parallel():
def __init__(self,children=[]):
self.children = children
self.knowCap = False
self.knowCharge = False
self.knowPot = False
self.capacitance = 0.0
self.charge = 0.0
self.potential = 0.0
def getCap(self):
if self.knowCap:
return self.capacitance
tmp = 0.0
for i in self.children:
tmp += i.getCap()
self.capacitance = tmp
self.knowCap = True
return tmp
def setCap(self,cap):
raise Error,"Can't set capacitance on a circuit system!"
def getPot(self):
if self.knowPot:
return self.potential
elif self.knowCharge and self.knowCap:
return self.setPot(self.charge / self.capacitance)
else:
if len(self.children) > 0:
return self.setPot(self.children[0].getPot())
raise Error,"Gah!"
def setPot(self,pot):
self.potential = pot
self.knowPot = True
if self.knowCap and not self.knowCharge:
self.setCharge(self.capacitance * self.potential)
if self.knowCharge and not self.knowCap:
self.setCap(self.charge / self.potential)
for i in self.children:
i.setPot(pot)
return pot
def getCharge(self):
if self.knowCharge:
return self.charge
tmp = 0.0
for i in self.children:
tmp += i.getCharge()
self.charge = tmp
self.knowCharge = True
return tmp
def setCharge(self, charge):
self.charge = charge
self.knowCharge = True
if self.knowCap and not self.knowPot:
self.setPot(self.charge / self.capacitance)
if self.knowPot and not self.knowCap:
self.setCap(self.charge / self.potential)
return charge
def prnt(self,t="",p=0):
ca = "?"
po = "?"
ch = "?"
if self.knowCap:
ca = Format(self.getCap()) + "F"
if self.knowPot:
po = Format(self.getPot()) + "V"
if self.knowCharge:
ch = Format(self.getCharge()) + "C"
a = "%sParallel%s" % (Color.Blue,Color.Reset)
b = "%s %s %s" % (ca.ljust(10),po.ljust(10),ch.ljust(10))
d = len(self.children)
tmp = len((t + "└" + "┬" * (d - 1) + "┐" + "Parallel").replace("│","_" \
).replace("┐","_").replace("┬","_").replace("└","_"))
print t + "└" + "┬" * (d - 1) + "┐" + a + " " * (30 - tmp) + \
b.replace("u","μ")
f = p
if p > 1:
f = p - 2
for i in self.children:
i.prnt(t + " " + "│" * (d - 1),f + len(self.children) - d)
d -= 1
print t + "┌" + "┴" * (len(self.children) - 1) + "┘" + "│" * (p - len(self.children))
def RequestCircuit(ind=[1],t=""):
raw = "Null"
tmp = []
while not raw == "":
raw = raw_input(t + "├")
if raw == "p":
tmp.append(Parallel(RequestCircuit(ind,t + "│")))
elif raw == "s":
tmp.append(Series(RequestCircuit(ind,t + " ")))
elif not raw == "":
try:
tmp.append(Capacitor(float(raw) * (10 ** -6),ind[0]))
ind[0] += 1
except:
print t + "│ " + Color.Red + "Try again..." + Color.Reset
return tmp
def SolveSeries(series,potential):
series.getCap()
series.setPot(potential)
print "┌◐┐%sBattery%s +%sV" % (Color.Yellow,Color.Reset,Format(potential))
series.prnt("│ ")
print "└─┘"
""""Sample Circuit
test = Series([ \
Capacitor(0.000002,1), \
Parallel([ \
Series([ \
Capacitor(0.000004,2), \
Capacitor(0.000001,3), \
Parallel([ \
Series([ \
Capacitor(0.000003,4), \
Parallel([ \
Capacitor(0.000002,5), \
Capacitor(0.000004,6) \
]), \
Capacitor(0.000007,7) \
]), \
Series([ \
Capacitor(0.000002,9), \
Capacitor(0.000006,8) \
]) \
]), \
Capacitor(0.000005,10) \
]), \
Capacitor(0.000003,11) \
])
])
SolveSeries(test,9.0)
""" # """

voltage = float(raw_input(Color.Yellow + "Battery" + Color.Reset + " (V): "))
print "Enter %s# of microcoloumbs%s OR %sp for parallel%s, %ss for series%s:" \
% (Color.Red,Color.Reset,Color.Blue,Color.Reset,Colo r.Green,Color.Reset)
test = Series(RequestCircuit())
print ""
SolveSeries(test,voltage)Looking forward, I will add resistors and other such things to the system in due time, but for now, as something I wrote over the course of a few hours, it's going to stay a capacitance solver.

Update (2/27/09):
I updated the code. It now prints cleaner output and has a bit less redundancy. Also, I've added subscripts to the capacitor indexes. If the subscripts don't show up for you and you want to use colored output, edit the if: line to say "if False" so you can get your indexes and have color.

PlasbianX
February 26th, 2009, 09:05 PM
Oh my god I love you. We're doing the exact same thing in my AP Physics class. This helps a lot! +++++++REP

Syuusuke
February 26th, 2009, 09:45 PM
Oh for a second I thought you meant you were coding this in that class...

Nifty man, I think I'll put this to good use.

klange
February 27th, 2009, 10:16 AM
Updates!
- Width issues with ANSI sequences has been fixed. This makes color/non-color output the same width, and gives more space for the circuit.
- Branches on parallel circuits now follow through to the end. In the first example above, C7 would now have two extra vertical bars after it, and C6 would have one. Obviously, capacitor labels and other branches cover parallel wires.
Example:

┌◐┐Battery +4V
│ │Series 43.2μF 4V 0.000173C
│ └┬┬┬┬┬┬┬┬┬┐Parallel 43.2μF 4V 0.000173C
│ │││││││││╪C₁ 4μF 4V 16.0μC
│ ││││││││╪C₂ 4μF 4V 16.0μC
│ │││││││╪C₃ 4μF 4V 16.0μC
│ ││││││╪C₄│ 4μF 4V 16.0μC
│ │││││╪C₅││ 4μF 4V 16.0μC
│ ││││╪C₆│││ 4μF 4V 16.0μC
│ │││└┬┐Parallel 12.0μF 4V 48.0μC
│ │││ │╪C₇││ 5μF 4V 20.0μC
│ │││ ╪C₈│││ 7μF 4V 28.0μC
│ │││┌┴┘││││
│ │││Series 1.19μF 4V 4.75μC
│ ││╪C₉│││││ 5μF 0.949V 4.75μC
│ ││╪C₁₀││││ 7μF 0.678V 4.75μC
│ ││╪C₁₁││││ 2μF 2.37V 4.75μC
│ │╪C₁₂│││││ 4μF 4V 16.0μC
│ ╪C₁₃││││││ 2μF 4V 8μC
│ ┌┴┴┴┴┴┴┴┴┴┘
└─┘- Less code redundancy. I had a few things left over from earlier testing that was no longer used. It has been removed.
- Battery input has been moved. You now enter the battery voltage first. This makes a bit more sense as it is usually the first thing in the circuit. Later you will be able to add batteries as regular items in the circuit.

Battery (V): 9
Enter # of microcoloumbs OR p for parallel, s for series:- Subscripts have been added for indexes. This is dependent on whether you have color enabled, but you can change that. Not all terminals may display the subscripts.

Tips:
Want to keep circuits so they are easy to enter multiple times? You can make a text file containing your inputs and pipe it into the script.

9
2
p
s
4
1
p
s
3
p
2
4

7

s
2
6


5

3


(this line included for the forum's sake)Be sure to include all new lines!
To pipe the data in a Bash terminal:

cat circuit_file | python main.py(this produces the second example in the first post)

Future:
- Add resistors and other such things.
- Make better output.

klange
February 27th, 2009, 08:10 PM
Wrote a script to convert my color codes to forum tags so I could show the colorization:

┌◐┐Battery +9V
│ │Series 1.28μF 9V 11.5μC
│ ╪C₁ 2μF 5.76V 11.5μC
│ └┬┐Parallel 3.56μF 3.24V 11.5μC
│ ││Series 0.563μF 3.24V 1.82μC
│ │╪C₂ 4μF 0.455V 1.82μC
│ │╪C₃ 1μF 1.82V 1.82μC
│ │└┬┐Parallel 3.06μF 0.596V 1.82μC
│ │ ││Series 1.56μF 0.596V 0.927μC
│ │ │╪C₄ 3μF 0.309V 0.927μC
│ │ │└┬┐Parallel 6μF 0.154V 0.927μC
│ │ │ │╪C₅ 2μF 0.154V 0.309μC
│ │ │ ╪C₆ 4μF 0.154V 0.618μC
│ │ │┌┴┘
│ │ │╪C₇ 7μF 0.132V 0.927μC
│ │ │Series 1.5μF 0.596V 0.894μC
│ │ ╪C₈ 2μF 0.447V 0.894μC
│ │ ╪C₉ 6μF 0.149V 0.894μC
│ │┌┴┘
│ │╪C₁₀ 5μF 0.364V 1.82μC
│ ╪C₁₁ 3μF 3.24V 9.71μC
│ ┌┴┘
└─┘

Rob Oplawar
March 1st, 2009, 09:48 PM
It never occurred to me to visualize circuits in minimum spanning tree form like that. That's why my major is CS instead of EE. :P

props on the useful script.