- I forgot completely "jump" labels. They do not need an object, but the code should ignore them while reading the cells or they will generate "Component not found" errors.
- Take the circuit layour file name as input from the user and generate the parameters files uniquely for the circuit.
The next stage is to generate the loop matrix for the circuit. The loops have been identified. However, every loop will interact with other loops. So, this has been coded.
Next stage is to read the parameters of every component and generate the ODE for solving the circuit KVL laws.
Anyway, here is the code (click on "view raw" below the code box for code in a new window)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
import sys, math | |
from network_reader import * | |
def csv_tuple(csv_elem): | |
""" Convert a cell position from spreadsheet form | |
to [row, tuple] form. """ | |
csv_elem.upper() | |
# Create a dictionary of alphabets | |
csv_col="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" | |
csv_dict={} | |
csv_col_list=csv_col.split(" ") | |
# Make the alphabets correspond to integers | |
for c1 in range(1, 27): | |
csv_dict[csv_col_list[c1-1]]=c1 | |
# The cell position starts with a number | |
flag="number" | |
c1=0 | |
while flag=="number": | |
# When conversion to int fails | |
# it means the element is an alphabet | |
try: | |
int(csv_elem[c1]) | |
except ValueError: | |
flag="alphabet" | |
else: | |
c1+=1 | |
# Split them up into numbers and alphabets | |
pol_row=int(csv_elem[0:c1]) | |
pol_col=csv_elem[c1:] | |
elem_tuple=[pol_row-1, 0] | |
# Convert the alphabets to number | |
# Similar to converting binary to decimal | |
for c1 in range(len(pol_col)-1, -1, -1): | |
if len(pol_col)-1-c1>0: | |
elem_tuple[1]+=26*(len(pol_col)-1-c1)*csv_dict[pol_col[c1]] | |
else: | |
elem_tuple[1]+=csv_dict[pol_col[c1]]-1 | |
return elem_tuple | |
def reading_params(param_file): | |
""" Read a file. Ramove additional quotes and | |
carriage returns. Remove leading spaces. """ | |
from_file=[] | |
for line in param_file: | |
from_file.append(line.split(",")) | |
for c1 in range(len(from_file)): | |
for c2 in range(len(from_file[c1])-1, -1, -1): | |
# Remove additional quotes and carriage returns | |
if from_file[c1][c2]: | |
scrub_elements(from_file, c1, c2) | |
# Remove blank spaces and null elements | |
if from_file[c1][c2]==" " or from_file[c1][c2]=="": | |
del from_file[c1][c2] | |
return from_file | |
class Resistor: | |
def __init__(self, res_index, res_pos, res_tag): | |
self.res_number=res_index | |
self.res_pos=res_pos | |
self.res_tag=res_tag | |
self.resistor=100.0 | |
def display(self): | |
print "Resistor is ", | |
print self.res_tag, | |
print "= %f" %self.resistor, | |
print " located at ", | |
print self.res_pos | |
def ask_values(self, x_list, ckt_mat): | |
res_params=["Resistor"] | |
res_params.append(self.res_tag) | |
res_params.append(self.res_pos) | |
res_params.append(self.resistor) | |
x_list.append(res_params) | |
def get_values(self, x_list, ckt_mat): | |
self.resistor=float(x_list[0]) | |
class Inductor: | |
def __init__(self, ind_index, ind_pos, ind_tag): | |
self.ind_number=ind_index | |
self.ind_pos=ind_pos | |
self.ind_tag=ind_tag | |
self.inductor=0.001 | |
def display(self): | |
print "Inductor is ", | |
print self.ind_tag, | |
print "=%f" %self.inductor, | |
print " located at ", | |
print self.ind_pos | |
def ask_values(self, x_list, ckt_mat): | |
ind_params=["Inductor"] | |
ind_params.append(self.ind_tag) | |
ind_params.append(self.ind_pos) | |
ind_params.append(self.inductor) | |
x_list.append(ind_params) | |
def get_values(self, x_list, ckt_mat): | |
self.inductor=float(x_list[0]) | |
class Capacitor: | |
def __init__(self, cap_index, cap_pos, cap_tag): | |
self.cap_number=cap_index | |
self.cap_pos=cap_pos | |
self.cap_tag=cap_tag | |
self.capacitor=10.0e-6 | |
def display(self): | |
print "Capacitor is ", | |
print self.cap_tag, | |
print "= %f" %self.capacitor, | |
print " located at ", | |
print self.cap_pos | |
def ask_values(self, x_list, ckt_mat): | |
cap_params=["Capacitor"] | |
cap_params.append(self.cap_tag) | |
cap_params.append(self.cap_pos) | |
cap_params.append(self.capacitor) | |
x_list.append(cap_params) | |
def get_values(self, x_list, ckt_mat): | |
self.capacitor=float(x_list[0]) | |
class Voltage_Source: | |
def __init__(self, volt_index, volt_pos, volt_tag): | |
self.volt_number=volt_index | |
self.volt_pos=volt_pos | |
self.volt_tag=volt_tag | |
self.v_peak=120.0 | |
self.v_freq=60.0 | |
self.v_phase=0.0 | |
def display(self): | |
print "Voltage Source is ", | |
print self.volt_tag, | |
print "of %f V(peak), %f Hz(frequency) and %f (degrees phase shift)" %(self.v_peak, self.v_freq, self.v_phase), | |
print " located at ", | |
print self.volt_pos, | |
print " with positive polarity towards %s %s" %(csv_element(self.v_polrty), self.v_polrty) | |
def ask_values(self, x_list, ckt_mat): | |
volt_params=["VoltageSource"] | |
volt_params.append(self.volt_tag) | |
volt_params.append(self.volt_pos) | |
volt_params.append("Peak (Volts) = %f" %self.v_peak) | |
volt_params.append("Frequency (Hertz) = %f" %self.v_freq) | |
volt_params.append("Phase (degrees) = %f" %self.v_phase) | |
# Looking for a default value of polarity | |
# in the neighbouring cells | |
self.volt_elem=csv_tuple(self.volt_pos) | |
if self.volt_elem[0]>0: | |
if ckt_mat[self.volt_elem[0]-1][self.volt_elem[1]]: | |
self.v_polrty=[self.volt_elem[0]-1, self.volt_elem[1]] | |
if self.volt_elem[1]>0: | |
if ckt_mat[self.volt_elem[0]][self.volt_elem[1]-1]: | |
self.v_polrty=[self.volt_elem[0], self.volt_elem[1]-1] | |
if self.volt_elem[0]<len(ckt_mat)-1: | |
if ckt_mat[self.volt_elem[0]+1][self.volt_elem[1]]: | |
self.v_polrty=[self.volt_elem[0]+1, self.volt_elem[1]] | |
if self.volt_elem[1]<len(ckt_mat)-1: | |
if ckt_mat[self.volt_elem[0]][self.volt_elem[1]+1]: | |
self.v_polrty=[self.volt_elem[0], self.volt_elem[1]+1] | |
volt_params.append("Positive polarity towards (cell) = %s" %csv_element(self.v_polrty)) | |
x_list.append(volt_params) | |
def get_values(self, x_list, ckt_mat): | |
self.v_peak=float(x_list[0].split("=")[1]) | |
self.v_freq=float(x_list[1].split("=")[1]) | |
self.v_phase=float(x_list[2].split("=")[1]) | |
volt_polrty=x_list[3].split("=")[1] | |
# Convert the human readable form of cell | |
# to [row, column] form | |
while volt_polrty[0]==" ": | |
volt_polrty=volt_polrty[1:] | |
self.v_polrty=csv_tuple(volt_polrty) | |
if not ckt_mat[self.v_polrty[0]][self.v_polrty[1]]: | |
print "Polarity incorrect. Branch does not exist at %s" %csv_element(self.v_polrty) | |
component_list={"resistor":Resistor, "inductor":Inductor, "capacitor":Capacitor, "voltagesource":Voltage_Source} | |
nw_input=raw_input("CSV file containing the network layout --> ") | |
nw_layout=nw_input+".csv" | |
test_ckt=open(nw_layout,"r") | |
# Read the circuit into tst_mat | |
# Also performs a scrubbing of tst_mat | |
tst_mat=csv_reader(test_ckt) | |
components_found={} | |
for c1 in range(len(tst_mat)): | |
for c2 in range(len(tst_mat[0])): | |
elem=tst_mat[c1][c2] | |
if elem: | |
# wire is a zero resistance connection | |
if elem.lower()!="wire": | |
if len(elem.split("_"))==1: | |
jump_det=elem.split("_")[0] | |
if len(jump_det)>3: | |
if jump_det.lower()[0:4]=="jump": | |
pass | |
else: | |
print "Error! Component at %s does not have a unique name/tag." %csv_element([c1, c2]) | |
else: | |
print "Error! Component at %s does not have a unique name/tag." %csv_element([c1, c2]) | |
else: | |
[elem_name, elem_tag]=elem.split("_") | |
elem_type=elem_name.lower() | |
if elem_type[0]==" ": | |
elem_type=elem_type[1:] | |
if elem_tag[0]==" ": | |
elem_tag=elem_tag[1:] | |
# Check if component exists | |
if elem_type in component_list.keys(): | |
# If found for the first time | |
# Create that dictionary element with key | |
# as component type | |
if elem_type not in components_found: | |
components_found[elem_type]=[[csv_element([c1, c2]), elem_tag]] | |
else: | |
# If already found, append it to | |
# dictionary item with that key. | |
components_found[elem_type].append([csv_element([c1, c2]), elem_tag]) | |
else: | |
print "Error! Component at %s doesn't exist." %csv_element([c1, c2]) | |
# Check if a component of the same type has the same tag. | |
for items in components_found.keys(): | |
for c1 in range(len(components_found[items])): | |
for c2 in range(len(components_found[items])): | |
if c1!=c2: | |
if components_found[items][c1][1]==components_found[items][c2][1]: | |
print "Duplicate labels found for components of type %s at %s and %s" %(items, components_found[items][c1][0], components_found[items][c2][0]) | |
component_objects={} | |
for items in components_found.keys(): | |
# Take every type of component found | |
# item -> resistor, inductor etc | |
for c1 in range(len(components_found[items])): | |
# Each component type will be occurring | |
# multiple times. Iterate through every find. | |
# The list corresponding to each component is | |
# the unique cell position in the spreadsheet | |
component_objects[components_found[items][c1][0]] = \ | |
component_list[items](c1+1, components_found[items][c1][0], components_found[items][c1][1]) | |
parameters_file=nw_input+"_params.csv" | |
# Check if the *_params.csv file exists. | |
try: | |
csv_check_values=open(parameters_file,"r") | |
# If not, it has to be created and filled | |
# with default values. | |
except: | |
#param_flag="no" | |
pass | |
# Check if any of the components with the same | |
# tags are present in nw_params.csv. If so, take | |
# those parameters from nw_params.csv and replace | |
# the default parameters in the component objects. | |
else: | |
params_from_file=reading_params(csv_check_values) | |
for c1 in range(len(params_from_file)): | |
# Remove leading spaces if any | |
# The first column is the type of element | |
if params_from_file[c1][0][0]==" ": | |
params_from_file[c1][0]=params_from_file[c1][0][1:] | |
name_from_file=params_from_file[c1][0].lower() | |
for c2 in range(len(components_found[name_from_file])): | |
# Remove leading spaces if any | |
if params_from_file[c1][1][0]==" ": | |
params_from_file[c1][1]=params_from_file[c1][1][1:] | |
# Check if the component tag exists in | |
# components found so far | |
if params_from_file[c1][1]==components_found[name_from_file][c2][1]: | |
# If so take the parameters and move them into the object | |
# having of that type and having the new cell position | |
component_objects[components_found[name_from_file][c2][0]].get_values(params_from_file[c1][3:], tst_mat) | |
csv_check_values.close() | |
values_to_file=[] | |
for items in component_objects.keys(): | |
# Each component object has a method | |
# ask_values that prints in the csv file | |
# default values for parameters. | |
component_objects[items].ask_values(values_to_file, tst_mat) | |
csv_ask_values=open(parameters_file,"w") | |
for c1 in range(len(values_to_file)): | |
for c2 in range(len(values_to_file[c1])): | |
csv_ask_values.write("%s" %values_to_file[c1][c2]) | |
csv_ask_values.write(", ") | |
csv_ask_values.write("\n") | |
csv_ask_values.close() | |
# Wait for the user to enter parameters before | |
# reading the nw_params.csv file. | |
cont_ans="n" | |
while cont_ans.lower()!="y": | |
cont_ans=raw_input("Enter parameters in file %s. When ready press y and enter to continue -> " %parameters_file) | |
csv_get_values=open(parameters_file,"r") | |
params_from_file=reading_params(csv_get_values) | |
csv_get_values.close() | |
for c1 in range(len(params_from_file)): | |
# Getting rid of the beginning spaces | |
# in the component keys | |
if params_from_file[c1][2][0]==" ": | |
params_from_file[c1][2]=params_from_file[c1][2][1:] | |
component_objects[params_from_file[c1][2]].get_values(params_from_file[c1][3:], tst_mat) | |
# Just checking the objects | |
for items in component_objects.keys(): | |
component_objects[items].display() | |
node_list, branch_map, loop_list, loop_branches, conn_matrix, \ | |
[number_of_nodes, number_of_branches, loop_count] = network_solver(nw_layout) | |
loop_count=len(loop_branches) | |
print "*"*50 | |
print "Number of nodes", | |
print number_of_nodes | |
print "Number of branches", | |
print number_of_branches | |
print "Number of loops", | |
print loop_count | |
print "*"*50 | |
def human_loop(loop): | |
""" Takes a loop as a list of tupes. | |
And prints a series of elements in spreadsheet format. """ | |
for c1 in range(len(loop)): | |
print csv_element(loop[c1]), | |
return | |
for c1 in range(len(loop_branches)): | |
human_loop(loop_branches[c1]) | |
print "*"*50 | |
def comm_elem_in_loop(loop1, loop2): | |
""" Takes two loops and returns a list | |
which has all the elements (tuples) that are | |
common between the loops. """ | |
loop_comm=[] | |
# Check every element of loop1 | |
# w.r.t to every element of loop2 | |
for c1 in range(len(loop1)): | |
for c2 in range(len(loop2)): | |
# Check if elements are equal | |
if loop1[c1]==loop2[c2]: | |
# Check if either of the elements | |
# are the last of the loops | |
if c1<len(loop1)-1 and c2<len(loop2)-1: | |
# Check if they have already been | |
# identified as common elements | |
if loop1[c1] not in loop_comm: | |
loop_comm.append(loop1[c1]) | |
elif loop2[c2-1]==loop_comm[-1]: | |
# This is a special condition. | |
# The first and last element of | |
# every loop are the same. | |
# Therefore, it will fail the condition that | |
# the element should not be found before. | |
# But, it may be possible that the segment of the | |
# loops that is common does not contain the last | |
# element. So, the check is: | |
# If the latest element to be found is loop2[c2-1] | |
# i.e is the second last element of loop2, in that | |
# case, the last element i.e loop2[c2] should | |
# also be appended to the common segment | |
loop_comm.append(loop2[c2]) | |
return loop_comm | |
def comm_branch_in_loop(loop1, loop2): | |
""" Takes the common elements (loop1) found between | |
two loops (out of which one is loop2) and break these | |
elements up into separate branches.""" | |
# The collection of branches | |
loop_comm=[] | |
# Each branch | |
loop_segment=[] | |
# starting element | |
prev_elem=loop1[0] | |
# Iterate from second to last element | |
for c1 in range(1, len(loop1)): | |
# Check if the index between this current element | |
# and the previous element is less than or equal to 1 | |
# This means it is a continuation of a branch | |
if abs(loop2.index(loop1[c1])-loop2.index(prev_elem))<=1: | |
loop_segment.append(prev_elem) | |
# If not, it means it is a new branch | |
else: | |
# Complete the branch with the previous element | |
loop_segment.append(prev_elem) | |
# If it is the final element of the loop | |
# Don't leave it out but add that too | |
if c1==len(loop1)-1: | |
loop_segment.append(loop1[c1]) | |
# Add that to the collection of branches | |
loop_comm.append(loop_segment) | |
loop_segment=[] | |
# Refresh the previous element | |
prev_elem=loop1[c1] | |
# This is a special condition. | |
# If there is only one common branch, the main | |
# condition will fail because a new branch will not be found | |
# In that case, the addition function needs to be repeated. | |
if not loop_comm: | |
loop_segment.append(prev_elem) | |
loop_comm.append(loop_segment) | |
return loop_comm | |
# A temporary list that stores the nodes | |
# common to two loops | |
nodes_in_loop=[] | |
# A array of all the loops of the system | |
# including common branches between loops. | |
system_loops=[] | |
for c1 in range(loop_count): | |
row_vector=[] | |
for c2 in range(loop_count): | |
row_vector.append([]) | |
system_loops.append(row_vector) | |
for c1 in range(len(loop_branches)): | |
# The diagonal elements of system_loops | |
# will be the loops themselves. | |
for c2 in range(len(loop_branches[c1])): | |
system_loops[c1][c1].append(loop_branches[c1][c2]) | |
# The system_loops array will be symmetric | |
for c2 in range(c1+1, len(loop_branches)): | |
# Find the nodes in loop1 | |
for c3 in range(len(node_list)): | |
if node_list[c3] in loop_branches[c1]: | |
nodes_in_loop.append(node_list[c3]) | |
# Find out the nodes common to loop1 | |
# and loop2. | |
for c3 in range(len(nodes_in_loop)-1, -1, -1): | |
if nodes_in_loop[c3] not in loop_branches[c2]: | |
del nodes_in_loop[c3] | |
# If there are two or more nodes common | |
# between loop1 and loop2, there are | |
# common elements. | |
if len(nodes_in_loop)>1: | |
comm_seg_in_loop=comm_elem_in_loop(loop_branches[c1], loop_branches[c2]) | |
print c1, c2 | |
#human_loop(comm_seg_in_loop) | |
sys_loop_off_diag=comm_branch_in_loop(comm_seg_in_loop, loop_branches[c1]) | |
for item in sys_loop_off_diag: | |
print "[", | |
human_loop(item), | |
print "]", | |
system_loops[c1][c2].append(sys_loop_off_diag) | |
system_loops[c2][c1].append(sys_loop_off_diag) | |
nodes_in_loop=[] |
No comments:
Post a Comment