Skip to content

Instantly share code, notes, and snippets.

@cibomahto
Last active March 9, 2021 13:46
Show Gist options
  • Save cibomahto/0d0985336346e7f7b7f6597b127ce6da to your computer and use it in GitHub Desktop.
Save cibomahto/0d0985336346e7f7b7f6597b127ce6da to your computer and use it in GitHub Desktop.
Power supply graph generator
{
"type": "powersupply",
"name": "5V wall wart",
"voltage": 5,
"loads" : [
{
"type": "dcdc",
"name": "12V supply for control boards",
"voltage": 12,
"efficiency": 0.85,
"loads": [
{
"type": "load",
"name": "button controller",
"max_current": 0.1
}
]
},
{
"type": "load",
"name": "LED buffer",
"max_current": 0.05
},
{
"type": "linear",
"name": "3.3V linear supply",
"voltage": 3.3,
"loads" : [
{
"type": "load",
"name": "ESP32, BLE enabled",
"max_current": 0.25
},
{
"type": "load",
"name": "microSD card, writing",
"max_current": 0.2
},
{
"type": "load",
"name": "FPGA",
"max_current": 0.05
},
{
"type": "load",
"name": "RS422 transceiver, short condition",
"max_current": 0.3
}
]
}
]
}
import json
# types supported:
# "input": input from an external supply (wall wart, etc)
# "dcdc": DC-DC switching regulator, either boost or buck. These are assumed to have a fixed efficiency
# "linear": Linear regulator. The efficiency of these is determined by the difference between the input and output voltages.
# "load": Something that sinks power, modeled as a current sink
class powersupply:
def __init__(self, name, voltage, loads):
self.name = name
self.voltage = voltage
self.loads = loads
def maxWattage(self, supply):
state = {}
state["efficiency"] = 1
# Output load is equal to voltage * sum of current to all loads
state["output_power"] = sum([load.maxWattage(self)["input_power"] for load in self.loads])
state["output_voltage"] = self.voltage
state["output_current"] = state["output_power"]/state["output_voltage"]
state["input_voltage"] = state["output_voltage"]
state["input_power"] = state["output_power"]
state["input_current"] = state["output_current"]
return state
class dcdc:
def __init__(self, name, voltage, efficiency, loads):
self.name = name
self.voltage = voltage
self.efficiency = efficiency
self.loads = loads
def maxWattage(self, supply):
""" Calculate the maximum expected load on this supply, in Watts """
state = {}
state["efficiency"] = self.efficiency
# Output load is equal to voltage * sum of current to all loads
state["output_power"] = sum([load.maxWattage(self)["input_power"] for load in self.loads])
state["output_voltage"] = self.voltage
state["output_current"] = state["output_power"]/state["output_voltage"]
state["input_voltage"] = supply.voltage
state["input_power"] = state["output_power"]/state["efficiency"]
state["input_current"] = state["input_power"]/state["input_voltage"]
return state
class linear:
def __init__(self, name, voltage, loads):
self.name = name
self.voltage = voltage
self.loads = loads
def maxWattage(self, supply):
""" Calculate the maximum expected load on this supply, in Watts """
state = {}
# # Efficiency is the ratio of output voltage to input voltage
state["efficiency"] = self.voltage/supply.voltage
# Output load is equal to voltage * sum of current to all loads
state["output_power"] = sum([load.maxWattage(self)["input_power"] for load in self.loads])
state["output_voltage"] = self.voltage
state["output_current"] = state["output_power"]/state["output_voltage"]
state["input_voltage"] = supply.voltage
state["input_power"] = state["output_power"]/state["efficiency"]
state["input_current"] = state["input_power"]/state["input_voltage"]
return state
class load:
def __init__(self, name, max_current):
self.name = name
self.max_current = max_current
def maxWattage(self, supply):
""" Calculate the maximum expected load, in Watts """
# l = self.max_current*supply.voltage
# return self.max_current*supply.voltage
state = {}
state["input_voltage"] = supply.voltage
state["input_current"] = self.max_current
state["input_power"] = state["input_voltage"] * state["input_current"]
return state
def decode_tree(dct):
if "type" not in dct:
# TODO: Raise exception
return dct
t = dct.pop("type")
if t == "powersupply":
return powersupply(**dct)
elif t == "dcdc":
return dcdc(**dct)
elif t == "linear":
return linear(**dct)
elif t == "load":
return load(**dct)
with open('power.json', 'r') as json_file:
powertree = json.load(json_file, object_hook=decode_tree)
def write_dot_node(node, supply, file):
# if this is a voltage supply
if hasattr(node,"loads"):
state = node.maxWattage(supply)
if supply==None:
file.write(' "{}" [label="{}\\ninput: {:.2f}W ({:.2f}A@{:.2f}V)",style="filled"];\n'
.format(node.name,node.name,
state["input_power"],state["input_current"],state["input_voltage"],
)
)
else:
file.write(' "{}" [label="{}\\ninput: {:.2f}W ({:.2f}A@{:.2f}V)\\noutput: {:.2f}W ({:.2f}A@{:.2f}V)\\nEfficiency:{:.0f}% waste:{:.2f}W",style="filled"];\n'
.format(node.name,node.name,
state["input_power"],state["input_current"],state["input_voltage"],
state["output_power"],state["output_current"],state["output_voltage"],
state["efficiency"]*100,state["input_power"]-state["output_power"]
)
)
for load in node.loads:
file.write(' "{}":e -> "{}":w [];\n'.format(node.name,load.name))
write_dot_node(load, node, file)
else:
state = node.maxWattage(supply)
file.write(' "{}" [label="{}\\n{:.2f}W ({:.2f}A@{:.2f}V)"];\n'
.format(node.name,node.name,state["input_power"],state["input_current"],state["input_voltage"]))
dotfile_header="""digraph test {
rankdir=LR;
splines=false;
rank="same";
node [fixedsize="true", width="3", height="1", shape="polygon",sides=4]
graph [style="invis"]"""
with open('power.dot', 'w') as dotfile:
#dotfile.write("digraph test {\n")
#dotfile.write(" rankdir=LR;\n")
dotfile.write(dotfile_header)
write_dot_node(powertree, None, dotfile)
dotfile.write("}")
#commands.executeCommand('graphviz.preview', Uri.parse('power.dot'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment