Sunday, May 5, 2013

Current Source

This current source turned out to be a little more tricky that I thought because I was looking for an elegant solution, something with cool network tricks or that uses object oriented programming inheritance techniques. Ended up using the easiest way - model the current source as a voltage source in series with a resistance. The end result is a little dirty - calculate one temporary value to update another temporary value. This is evident from the glitches in the first quarter cycle. Will have to test how this works particularly in an inductive-capacitive circuit. So nothing final yet.

Been a while since I released a version, so I am going to release it soon. Also, the next step will be to move on to version 0.2.0 which will look at structural changes to the code that will bring in error messages and directions of usage.

Anyway, here is the code (click on "view raw" below the code box to see it in a new window):


class Current_Source:
""" Current source class. Contains functions to initiliaze
the resistor according to name tag, unique cell position,
update system matrix on each iteration. """
def __init__(self, cs_index, cs_pos, cs_tag):
""" Constructor to initialize value.
Also, takes in the identifiers -
index (serial number), cell position and tag. """
self.type="CurrentSource"
self.cs_number=cs_index
self.cs_pos=cs_pos
self.cs_tag=cs_tag
self.cs_peak=5.0
self.cs_freq=60.0
self.cs_phase=0.0
self.cs_level=120.0
self.resistor=1.0
self.current=0.0
self.voltage=0.0
self.op_value=0.0
self.cs_polrty=[-1, -1]
def display(self):
print "Current Source is ",
print self.cs_tag,
print "of %f A (peak), %f Hz(frequency) and %f (degrees phase shift)" %(self.cs_peak, self.cs_freq, self.cs_phase),
print " located at ",
print self.cs_pos,
print " with positive polarity towards %s" %(csv_element(self.cs_polrty))
return
def ask_values(self, x_list, ckt_mat, sys_branch):
""" Writes the values needed to the spreadsheet."""
cs_params=["CurrentSource"]
cs_params.append(self.cs_tag)
cs_params.append(self.cs_pos)
cs_params.append("Peak (Amps) = %f" %self.cs_peak)
cs_params.append("Frequency (Hertz) = %f" %self.cs_freq)
cs_params.append("Phase (degrees) = %f" %self.cs_phase)
if self.cs_polrty==[-1, -1]:
# Looking for a default value of polarity
# in the neighbouring cells
self.cs_elem=csv_tuple(self.cs_pos)
if self.cs_elem[0]>0:
if ckt_mat[self.cs_elem[0]-1][self.cs_elem[1]]:
self.cs_polrty=[self.cs_elem[0]-1, self.cs_elem[1]]
if self.cs_elem[1]>0:
if ckt_mat[self.cs_elem[0]][self.cs_elem[1]-1]:
self.cs_polrty=[self.cs_elem[0], self.cs_elem[1]-1]
if self.cs_elem[0]<len(ckt_mat)-1:
if ckt_mat[self.cs_elem[0]+1][self.cs_elem[1]]:
self.cs_polrty=[self.cs_elem[0]+1, self.cs_elem[1]]
if self.cs_elem[1]<len(ckt_mat)-1:
if ckt_mat[self.cs_elem[0]][self.cs_elem[1]+1]:
self.cs_polrty=[self.cs_elem[0], self.cs_elem[1]+1]
else:
for c1 in range(len(sys_branch)):
if csv_tuple(self.cs_pos) in sys_branch[c1]:
if not self.cs_polrty in sys_branch[c1]:
print
print "!"*50
print "ERROR!!! Current source polarity should be in the same branch as the current source. Check source at %s" %self.cs_pos
print "!"*50
print
cs_params.append("Positive polarity towards (cell) = %s" %csv_element(self.cs_polrty))
x_list.append(cs_params)
return
def get_values(self, x_list, ckt_mat):
""" Takes the parameter from the spreadsheet."""
self.cs_peak=float(x_list[0].split("=")[1])
self.cs_freq=float(x_list[1].split("=")[1])
self.cs_phase=float(x_list[2].split("=")[1])
curr_polrty=x_list[3].split("=")[1]
# Convert the human readable form of cell
# to [row, column] form
while curr_polrty[0]==" ":
curr_polrty=curr_polrty[1:]
self.cs_polrty=csv_tuple(curr_polrty)
if not ckt_mat[self.cs_polrty[0]][self.cs_polrty[1]]:
print "Polarity incorrect. Branch does not exist at %s" %csv_element(self.cs_polrty)
return
def transfer_to_sys(self, sys_loops, mat_e, mat_a, mat_b, mat_u, source_list):
""" The matrix A in E.dx/dt=Ax+Bu will be updated by the
resistor value."""
for c1 in range(len(sys_loops)):
for c2 in range(c1, len(sys_loops)):
# Updating the elements depending
# on the sense of the loops (aiding or opposing)
for c3 in range(len(sys_loops[c1][c2])):
# Check if current source position is there in the loop.
if csv_tuple(self.cs_pos) in sys_loops[c1][c2][c3]:
# Add current source series resistor
# if branch is in forward direction
if sys_loops[c1][c2][c3][-1]=="forward":
mat_a.data[c1][c2]+=self.resistor
else:
# Else subtract if branch is in reverse direction
mat_a.data[c1][c2]-=self.resistor
# Because the matrices are symmetric
mat_a.data[c2][c1]=mat_a.data[c1][c2]
return
def transfer_to_branch(self, sys_branch, source_list):
""" Update the resistor info of the voltmeter
to the branch list """
if csv_tuple(self.cs_pos) in sys_branch:
sys_branch[-1][0][0]+=self.resistor
if csv_tuple(self.cs_pos) in sys_branch:
if sys_branch.index(self.cs_polrty)<sys_branch.index(csv_tuple(self.cs_pos)):
sys_branch[-1][1][source_list.index(self.cs_pos)]=-1.0
else:
sys_branch[-1][1][source_list.index(self.cs_pos)]=1.0
return
def generate_val(self, source_lst, sys_loops, mat_e, mat_a, mat_b, mat_u, state_vec, t, dt):
""" The source current is updated in the matrix u in
E.dx/dt=Ax+Bu. The matrix E has a row set to zero. The
matrix B has the diagonal element in the row set to 1,
others set to zero."""
# Updating the current source value
self.current=self.cs_peak*math.sin(2*math.pi*self.cs_freq*t+self.cs_phase)
# The value passed to the input matrix is
# the voltage calculated
mat_u.data[source_lst.index(self.cs_pos)][0]=self.voltage
# The output value of the source will the current
# even though it is actually modelled as a
# voltage source with a series resistance.
self.op_value=self.current
return
def update_val(self, sys_loops, lbyr_ratio, mat_e, mat_a, mat_b, state_vec, mat_u):
""" This function calculates the actual current in
the current source branch. With this, the branch voltage is
found with respect to the existing voltage source. The branch
voltage is then used to calculate the new voltage source value. """
# Local variable to calculate the branch
# current from all loops that contain
# the current source branch.
act_current=0.0
for c1 in range(len(sys_loops)):
for c2 in range(len(sys_loops[c1][c1])):
if csv_tuple(self.cs_pos) in sys_loops[c1][c1][c2]:
# If current source polarity is before the source
# position, it means actual current is negative.
if sys_loops[c1][c1][c2].index(self.cs_polrty)<sys_loops[c1][c1][c2].index(csv_tuple(self.cs_pos)):
# Then check is the loop is aiding or opposing
# the main loop.
if sys_loops[c1][c1][c2][-1]=="forward":
act_current+=state_vec.data[c1][0]
else:
act_current-=state_vec.data[c1][0]
else:
if sys_loops[c1][c1][c2][-1]=="forward":
act_current-=state_vec.data[c1][0]
else:
act_current+=state_vec.data[c1][0]
# The branch voltage is the KVL with the
# existing voltage source and the branch current
branch_voltage=self.voltage+act_current*self.resistor
# The new source voltage will be the branch voltage
# in addition to the desired value of current.
self.voltage=branch_voltage+self.current*self.resistor
return

No comments:

Post a Comment