Wednesday, January 2, 2013

Branch identification

The previous program was to find the number of nodes in the circuit. A node was defined as a junction of three or four nodes. The next step is to be able to identify the branches between these nodes.

The method I have used is a search routine that starts from a node and continues until another node has reached. This is because of one major constraint imposed on the spreadsheet. Connections have to be made either vertical or horizontal and can't be made diagonal. So if you need a diagonal connection you have to go along a column and then a row.

So when starting from a node, there are certain search directions depending on the number of branches at that node - if is a +, all four search directions (up, down, right and left) are possible while if it is a T junction, three search directions may be possible (for example, up, right and left).

If the next element in the search direction is not a node, there can be two directions of searching - forward or backward. To ensure forward search, check if the new element has already been encountered. If so, that is the wrong direction.

If the next element is a node, stop the search.

If it is not a node, but another new element, continue as above.

Another test circuit has been taken:




Anyway, here is the code:


#! /usr/bin/env python
import sys, math, matrix
new_file = open("testckt.csv","r")
# This matrix will read the .csv file
# The .csv file will contain the string "wire" where a zero impedance direct connection exists.
# Where no connection nor device (resitor, inductor etc) exists, a '' will be found.
# The devices will be strings. Maybe later will be actual object constructor calls.
conn_matrix=[]
for line in new_file:
conn_matrix.append(line.split(","))
conn_rows=len(conn_matrix)
conn_columns=len(conn_matrix[0])
# A node is defined as a junction of 3 or more branches.
node_list=[]
for c1 in range(0, conn_rows):
for c2 in range(0, conn_columns):
if not (conn_matrix[c1][c2]==''):
if ((c1==0 and c2==0) or (c1==conn_rows-1 and c2==conn_columns-1) or (c1==0 and c2==conn_columns-1) or (c1==conn_rows-1 and c2==0)):
# If its a corner point it can't be a node. This prevents array index going out of range.
pass
# The next cases, can't be outer edges or corner points.
else:
if (c1==0):
# If it is the first row,
# check if the element in the next and previous columns and same row are connected.
if not (conn_matrix[c1][c2+1]=='' or conn_matrix[c1][c2-1]==''):
# Then check if the element in next row and same column is connected. Look for a T junction.
if not (conn_matrix[c1+1][c2]==''):
node_list.append([c1, c2])
if (c1==conn_rows-1):
# If it is the last row,
# check if the elements in the next and previous columns and same row are connected.
if not (conn_matrix[c1][c2+1]=='' or conn_matrix[c1][c2-1]==''):
if not (conn_matrix[c1-1][c2]==''):
# Then check if element in the previous row and same column is connected. Look for a T junction.
node_list.append([c1, c2])
if (c2==0):
# If it is the first column,
# check if the element in the next column and same row is connected.
if not (conn_matrix[c1][c2+1]==''):
# Then check if the elements in next and previous row and same column are connected. Look for a T junction.
if not (conn_matrix[c1+1][c2]=='' or conn_matrix[c1-1][c2]==''):
node_list.append([c1, c2])
if (c2==conn_columns-1):
# If it is the last column,
# check if the element in the previous column and same row is connected.
if not (conn_matrix[c1][c2-1]==''):
# Then check if the elements in next and previous row and same column are connected. Look for a T junction.
if not (conn_matrix[c1+1][c2]=='' or conn_matrix[c1-1][c2]==''):
node_list.append([c1, c2])
if (c1>0 and c1<conn_rows-1 and c2>0 and c2<conn_columns-1):
# If the element is not on the outer boundary
if (conn_matrix[c1][c2+1]!='' and conn_matrix[c1][c2-1]!=''):
# Check if the elements in next and previous columns and same row are connected
if (conn_matrix[c1+1][c2]!='' or conn_matrix[c1-1][c2]!=''):
# Then check if elements in either the next and previous row and same column are connected
node_list.append([c1, c2])
elif (conn_matrix[c1+1][c2]!='' and conn_matrix[c1-1][c2]!=''):
if (conn_matrix[c1][c2+1]!='' or conn_matrix[c1][c2-1]!=''):
node_list.append([c1, c2])
else:
pass
# This list contains all the nodes that are T or + junctions.
print "*"*60
print node_list
print "*"*60
print "*"*60
print "*"*60
print "*"*60
# Map of branches between nodes in node_list
branch_map=[]
# Creating an square of the dimension of node_list.
# Each element will be a list of the series connection of branches between the nodes.
for c1 in range(len(node_list)):
branch_rows=[]
for c2 in range(len(node_list)):
branch_rows.append([])
branch_map.append(branch_rows)
# Generate a search rule for each node.
# The concept is to start at a node and search until another node is reached.
node_iter_rule=[]
for c1 in range(len(node_list)):
node_row=node_list[c1][0]
node_column=node_list[c1][1]
iter_rule={"left":0, "down":1, "right":2, "up":3}
# For nodes in the outer edges, the rules going outwards will be removed.
if (node_row==0):
del(iter_rule["up"])
if (node_row==conn_rows-1):
del(iter_rule["down"])
if (node_column==0):
del(iter_rule["left"])
if (node_column==conn_columns-1):
del(iter_rule["right"])
# Depending on the non-existence of elements in a direction, those rules will be removed.
if (node_row>0) and (node_row<conn_rows-1) and (node_column>0) and (node_column<conn_columns-1):
if (conn_matrix[node_row-1][node_column]==''):
del(iter_rule["up"])
if (conn_matrix[node_row+1][node_column]==''):
del(iter_rule["down"])
if (conn_matrix[node_row][node_column+1]==''):
del(iter_rule["right"])
if (conn_matrix[node_row][node_column-1]==''):
del(iter_rule["left"])
node_iter_rule.append(iter_rule)
# For each node in node_list perform the search operation.
# Each node has a list of possible search rules.
# Perform a search for each rule.
# From the starting node, advance in the direction of the rule.
# After advancing, check if the next element is a node.
# If it is a node, stop.
# If it is not a node, there can be only two directions of movement.
# Move in a direction and check is an element exists.
# If it exists, check if it is not already an element encountered - shouldn't be moving backwards.
# If a new element is encountered, update the element is branch iter and continue.
for c1 in range(len(node_list)):
node_row=node_list[c1][0]
node_column=node_list[c1][1]
for branch_dir in node_iter_rule[c1].keys():
branch_iter=[]
branch_iter.append([node_row, node_column])
# Initial advancement.
if (branch_dir=="left"):
if (node_column>0):
next_node_row=node_row
next_node_column=node_column-1
if (branch_dir=="down"):
if (node_row<conn_rows-1):
next_node_row=node_row+1
next_node_column=node_column
if (branch_dir=="right"):
if (node_column<conn_columns-1):
next_node_row=node_row
next_node_column=node_column+1
if (branch_dir=="up"):
if (node_row>0):
next_node_row=node_row-1
next_node_column=node_column
print branch_dir
# Termination condition - next element is a node.
while not ([next_node_row, next_node_column] in node_list):
branch_iter.append([next_node_row, next_node_column])
# This temporary variable is to ensure, two advancements don't take place in one loop.
branch_proceed=0
if ((next_node_column>0) and branch_proceed==0):
if not (conn_matrix[next_node_row][next_node_column-1]==''):
# Next check is if we are going backwards.
if not ([next_node_row, next_node_column-1] in branch_iter):
next_node_column=next_node_column-1
branch_proceed=1
if ((next_node_row>0) and branch_proceed==0):
if not (conn_matrix[next_node_row-1][next_node_column]==''):
if not ([next_node_row-1, next_node_column] in branch_iter):
next_node_row=next_node_row-1
branch_proceed=1
if ((next_node_column<conn_columns-1) and branch_proceed==0):
if not (conn_matrix[next_node_row][next_node_column+1]==''):
if not ([next_node_row, next_node_column+1] in branch_iter):
next_node_column=next_node_column+1
branch_proceed=1
if ((next_node_row<conn_rows-1) and branch_proceed==0):
if not (conn_matrix[next_node_row+1][next_node_column]==''):
if not ([next_node_row+1, next_node_column] in branch_iter):
next_node_row=next_node_row+1
branch_proceed=1
# If no advancement is possible, it means circuit is broken.
# Can improve on this error message later.
if ([next_node_row, next_node_column] in branch_iter):
print "Error. Circuit broken! Close all branches."
break
else:
branch_iter.append([next_node_row, next_node_column])
branch_map[c1][node_list.index([next_node_row, next_node_column])]=branch_iter
print branch_iter
print "*"*70
view raw branch1.py hosted with ❤ by GitHub


And this is the result:
---------------------------------------------------------------------------------------------------------
************************************************************
[[0, 4], [0, 6], [2, 1], [2, 4], [5, 0], [5, 4], [5, 8], [7, 8], [8, 4]]
************************************************************
************************************************************
************************************************************
************************************************************
down
[[0, 4], [1, 4], [2, 4]]
**********************************************************************
right
[[0, 4], [0, 5], [0, 6]]
**********************************************************************
left
[[0, 4], [0, 3], [0, 2], [0, 1], [1, 1], [2, 1]]
**********************************************************************
down
[[0, 6], [1, 6], [2, 6], [2, 5], [2, 4]]
**********************************************************************
right
[[0, 6], [0, 7], [0, 8], [1, 8], [2, 8], [3, 8], [4, 8], [5, 8]]
**********************************************************************
left
[[0, 6], [0, 5], [0, 4]]
**********************************************************************
right
[[2, 1], [2, 2], [2, 3], [2, 4]]
**********************************************************************
up
[[2, 1], [1, 1], [0, 1], [0, 2], [0, 3], [0, 4]]
**********************************************************************
left
[[2, 1], [2, 0], [3, 0], [4, 0], [5, 0]]
**********************************************************************
down
[[2, 4], [3, 4], [4, 4], [5, 4]]
**********************************************************************
right
[[2, 4], [2, 5], [2, 6], [1, 6], [0, 6]]
**********************************************************************
up
[[2, 4], [1, 4], [0, 4]]
**********************************************************************
left
[[2, 4], [2, 3], [2, 2], [2, 1]]
**********************************************************************
down
[[5, 0], [6, 0], [7, 0], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4]]
**********************************************************************
right
[[5, 0], [5, 1], [5, 2], [5, 3], [5, 4]]
**********************************************************************
up
[[5, 0], [4, 0], [3, 0], [2, 0], [2, 1]]
**********************************************************************
down
[[5, 4], [6, 4], [7, 4], [8, 4]]
**********************************************************************
right
[[5, 4], [5, 5], [5, 6], [5, 7], [5, 8]]
**********************************************************************
up
[[5, 4], [4, 4], [3, 4], [2, 4]]
**********************************************************************
left
[[5, 4], [5, 3], [5, 2], [5, 1], [5, 0]]
**********************************************************************
down
[[5, 8], [6, 8], [7, 8]]
**********************************************************************
up
[[5, 8], [4, 8], [3, 8], [2, 8], [1, 8], [0, 8], [0, 7], [0, 6]]
**********************************************************************
left
[[5, 8], [5, 7], [5, 6], [5, 5], [5, 4]]
**********************************************************************
down
[[7, 8], [8, 8], [9, 8], [10, 8], [10, 7], [10, 6], [10, 5], [10, 4], [9, 4], [8, 4]]
**********************************************************************
up
[[7, 8], [6, 8], [5, 8]]
**********************************************************************
left
[[7, 8], [7, 7], [7, 6], [8, 6], [8, 5], [8, 4]]
**********************************************************************
down
[[8, 4], [9, 4], [10, 4], [10, 5], [10, 6], [10, 7], [10, 8], [9, 8], [8, 8], [7, 8]]
**********************************************************************
right
[[8, 4], [8, 5], [8, 6], [7, 6], [7, 7], [7, 8]]
**********************************************************************
up
[[8, 4], [7, 4], [6, 4], [5, 4]]
**********************************************************************
left
[[8, 4], [8, 3], [8, 2], [8, 1], [8, 0], [7, 0], [6, 0], [5, 0]]
**********************************************************************


---------------------------------------------------------------------------------------------------------


Which is the correct result.

1. One thing I could do to speed up the result is take advantage of the symmetry of the matrix. If node 1 is connected to node 3, node 3 is connected to node 1. No need to do the search again. So I need to to do the search for node i and node k if k>i. Then just take the lower triangular part to be equal to the upper triangular part.

2. The diagonal elements are null. What will happen if there is a self loop - a loop originating and terminating at a node? But will something like that happen in practical electrical circuits?

More issues will be examined with other circuits. Probably will be at least two more versions of this code.

Here, I need to stop and comment about Python. The fact that an embedded objects are possible and that too of any dimension is fantastic. In the above code, we have an array with the elements being lists of lists! And add to that, the lists are not of the same length. Anything goes! Makes like a whole lot simpler.

No comments:

Post a Comment