Skip to content

Instantly share code, notes, and snippets.

@Kenny2github
Last active April 17, 2022 02:05
Show Gist options
  • Save Kenny2github/a4e1b15b3a5ac78fe76fa017728b6427 to your computer and use it in GitHub Desktop.
Save Kenny2github/a4e1b15b3a5ac78fe76fa017728b6427 to your computer and use it in GitHub Desktop.
Compute the equivalent impedance between two nodes.
from __future__ import annotations
from itertools import combinations
class Node:
components: set[Component]
num: int = 1
def __init__(self, components: set = None) -> None:
self.num = type(self).num
type(self).num += 1
if components:
self.components = components.copy()
else:
self.components = set()
def __repr__(self) -> str:
return f'<Node #{self.num}>'
def connect(self, component: Component) -> None:
self.components.add(component)
def disconnect(self, component: Component) -> None:
self.components.discard(component)
class Component:
value: complex
left: Node
right: Node
num: int = 1
@property
def nodes(self) -> set[Node]:
return {self.left, self.right}
def __init__(self, value: complex, left: Node, right: Node) -> None:
self.value = value
self.left = left
self.right = right
left.connect(self)
right.connect(self)
self.num = type(self).num
type(self).num += 1
def __repr__(self) -> str:
return f'Component #{self.num}(value={self.value!r}, left={self.left!r}, right={self.right!r})'
def _combine(self, components: set[Component], other: Component,
value: complex, left: Node, right: Node) -> Component:
new = Component(value, left, right)
left.disconnect(self)
left.disconnect(other)
right.disconnect(self)
right.disconnect(other)
components.discard(self)
components.discard(other)
components.add(new)
# old components and common node get garbage collected
def combine_series(self, components: set[Component],
other: Component) -> Component:
"""Combine this component with the other in series."""
left, right = self.nodes ^ other.nodes
self._combine(components, other, self.value + other.value, left, right)
def combine_parallel(self, components: set[Component],
other: Component) -> Component:
"""Combine this component with the other in parallel."""
new_value = self.value * other.value / (self.value + other.value)
self._combine(components, other, new_value, self.left, self.right)
def wye_delta(nodes: list[Node], components: set[Component],
A: Node, B: Node) -> None:
"""Perform any Y-Δ transform on the network."""
for common_node in nodes:
if common_node is A or common_node is B:
continue # can't delete output node
if len(common_node.components) != 3:
continue
R1, R2, R3 = common_node.components
N1, N2, N3 = ((R.nodes ^ {common_node}).pop()
for R in (R1, R2, R3))
Rp = sum(a.value * b.value for a, b in combinations(
(R1, R2, R3), 2))
Ra = Component(Rp / R1.value, N2, N3)
Rb = Component(Rp / R2.value, N1, N3)
Rc = Component(Rp / R3.value, N1, N2)
for R, N in ((R1, N1), (R2, N2), (R3, N3)):
N.disconnect(R)
components.discard(R)
components.update({Ra, Rb, Rc})
nodes.remove(common_node)
return
def equivalent_impedance(nodes: list[Node], components: set[Component],
A: Node, B: Node) -> complex:
"""Find the equivalent impedance of a network between nodes A and B.
A and B must be present in the nodes list.
"""
nodes = nodes.copy()
components = components.copy()
while len(components) > 1:
#print(nodes, components, sep='\n', end='\n\n')
for R1, R2 in combinations(components, 2):
common = R1.nodes & R2.nodes
if len(common) == 1: # in series?
common_node = common.pop()
if common_node is A or common_node is B:
continue # not in series if crosses output node
if common_node.components != {R1, R2}:
continue # not connected to exactly these two components
R1.combine_series(components, R2)
nodes.remove(common_node) # common node vanishes
break
elif len(common) == 2: # in parallel
R1.combine_parallel(components, R2)
break
else: # everything is neither in series nor in parallel
wye_delta(nodes, components, A, B)
return components.pop().value
def main() -> None:
node_count = int(input('How many nodes? '))
component_count = int(input('How many components? '))
nodes = [Node() for _ in range(node_count)]
components = set()
for i in range(1, component_count + 1):
value = complex(input(f'Enter value of component {i} (a±bj, in Ω): '))
left, right = map(int, input(
f'Enter the two node numbers that component {i} is connected to (e.g. 1 2): ').split())
components.add(Component(value, nodes[left-1], nodes[right-1]))
A, B = [nodes[int(i) - 1] for i in input(
f'Enter the two nodes to find equivalent impedance between (e.g. 1 4): ').split()]
print()
print('\nEquivalent impedance is', equivalent_impedance(
nodes, components, A, B))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment