It is winter again and I am buried in snow in Toronto. I am not much into winter activities and this means only coding can stop me for going crazy. So I am back again to this project. After weeks of dithering, pretending to review code and thinking of future strategies, I finally gotten around to taking this project further.
Like I said before, the diode model is not complete because the diode doesn't know when and where to freewheel. To highlight this, I made the ideal switch model and tried to simulate a buck converter. Here's the code for the ideal switch (click on view raw below the code box to see the code in another window):
This is the circuit for the buck converter.
And this is the control code - actually just an open loop with a constant 50% duty ratio (click on view raw below the code box to see the code in another window):
And on execution, the current (measured by Ammeter_La) through the inductor La is:
And as can be seen, the diode does not free wheel at all. The current rises when the switch turns on and drops to zero when it is turned off.
The strategy to overcome this will be my next blog entry as it is a fairly detailed algorithm.
Like I said before, the diode model is not complete because the diode doesn't know when and where to freewheel. To highlight this, I made the ideal switch model and tried to simulate a buck converter. Here's the code for the ideal switch (click on view raw below the code box to see the code in another 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
class Switch: | |
""" Ideal switch class. Contains functions to initiliaze | |
the switch according to name tag, unique cell position, | |
update system matrix on each iteration. """ | |
def __init__(self, switch_index, switch_pos, switch_tag): | |
""" Constructor to initialize value. | |
Also, takes in the identifiers - | |
index (serial number), cell position and tag. """ | |
self.type="Switch" | |
self.number=switch_index | |
self.pos=switch_pos | |
self.tag=switch_tag | |
self.has_voltage="yes" | |
self.switch_level=120.0 | |
self.current=0.0 | |
self.voltage=0.0 | |
self.polrty=[-1, -1] | |
self.resistor_on=0.01 | |
self.status="off" | |
self.control_tag=["Control"] | |
self.control_values=[0.0] | |
def display(self): | |
print "Switch is ", | |
print self.tag, | |
print " located at ", | |
print self.pos, | |
print " with negative polarity towards %s" %(csv_element(self.polrty)) | |
return | |
def ask_values(self, x_list, ckt_mat, sys_branch): | |
""" Writes the values needed to the spreadsheet.""" | |
switch_params=["Switch"] | |
switch_params.append(self.tag) | |
switch_params.append(self.pos) | |
switch_params.append("Voltage level (V) = %f" %self.switch_level) | |
if self.polrty==[-1, -1]: | |
# Looking for a default value of polarity | |
# in the neighbouring cells | |
self.switch_elem=csv_tuple(self.pos) | |
if self.switch_elem[0]>0: | |
if ckt_mat[self.switch_elem[0]-1][self.switch_elem[1]]: | |
self.polrty=[self.switch_elem[0]-1, self.switch_elem[1]] | |
if self.switch_elem[1]>0: | |
if ckt_mat[self.switch_elem[0]][self.switch_elem[1]-1]: | |
self.polrty=[self.switch_elem[0], self.switch_elem[1]-1] | |
if self.switch_elem[0]<len(ckt_mat)-1: | |
if ckt_mat[self.switch_elem[0]+1][self.switch_elem[1]]: | |
self.polrty=[self.switch_elem[0]+1, self.switch_elem[1]] | |
if self.switch_elem[1]<len(ckt_mat)-1: | |
if ckt_mat[self.switch_elem[0]][self.switch_elem[1]+1]: | |
self.polrty=[self.switch_elem[0], self.switch_elem[1]+1] | |
else: | |
for c1 in range(len(sys_branch)): | |
if csv_tuple(self.pos) in sys_branch[c1]: | |
if not self.polrty in sys_branch[c1]: | |
print "!"*50 | |
print "ERROR!!! Switch polarity should be in the same branch as the switch. Check switch at %s" %self.pos | |
print "!"*50 | |
switch_params.append("Negative polarity towards (cell) = %s" %csv_element(self.polrty)) | |
switch_params.append("Name of control signal = %s" %self.control_tag[0]) | |
print switch_params | |
x_list.append(switch_params) | |
return | |
def get_values(self, x_list, ckt_mat): | |
""" Takes the parameter from the spreadsheet.""" | |
self.switch_level=float(x_list[0].split("=")[1]) | |
# Choosing 1 micro Amp as the leakage current that | |
# is drawn by the switch in off state. | |
self.resistor_off=self.switch_level/1.0e-6 | |
self.resistor=self.resistor_off | |
switch_polrty=x_list[1].split("=")[1] | |
# Convert the human readable form of cell | |
# to [row, column] form | |
while switch_polrty[0]==" ": | |
switch_polrty=switch_polrty[1:] | |
self.polrty=csv_tuple(switch_polrty) | |
if not ckt_mat[self.polrty[0]][self.polrty[1]]: | |
print "Polarity incorrect. Branch does not exist at %s" %csv_element(self.polrty) | |
self.control_tag[0]=x_list[2].split("=")[1] | |
while self.control_tag[0][0]==" ": | |
self.control_tag[0]=self.control_tag[0][1:] | |
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 of the switch.""" | |
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.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] | |
# If the positive polarity appears before the voltage position | |
# it means as per KVL, we are moving from +ve to -ve | |
# and so the voltage will be taken negative | |
if sys_loops[c1][c1][c2].index(self.polrty)>sys_loops[c1][c1][c2].index(csv_tuple(self.pos)): | |
if sys_loops[c1][c1][c2][-1]=="forward": | |
mat_b.data[c1][source_list.index(self.pos)]=-1.0 | |
else: | |
mat_b.data[c1][source_list.index(self.pos)]=1.0 | |
else: | |
if sys_loops[c1][c1][c2][-1]=="forward": | |
mat_b.data[c1][source_list.index(self.pos)]=1.0 | |
else: | |
mat_b.data[c1][source_list.index(self.pos)]=-1.0 | |
return | |
def transfer_to_branch(self, sys_branch, source_list): | |
""" Update the resistor info of the switch | |
to the branch list """ | |
if csv_tuple(self.pos) in sys_branch: | |
sys_branch[-1][0][0]+=self.resistor | |
# For the switch forward voltage drop. | |
if csv_tuple(self.pos) in sys_branch: | |
if sys_branch.index(self.polrty)>sys_branch.index(csv_tuple(self.pos)): | |
sys_branch[-1][1][source_list.index(self.pos)]=-1.0 | |
else: | |
sys_branch[-1][1][source_list.index(self.pos)]=1.0 | |
return | |
def generate_val(self, source_lst, sys_loops, mat_e, mat_a, mat_b, mat_u, t, dt): | |
""" The switch forward drop voltage is updated | |
in the matrix u in E.dx/dt=Ax+Bu .""" | |
if self.status=="on": | |
mat_u.data[source_lst.index(self.pos)][0]=0.7 | |
else: | |
mat_u.data[source_lst.index(self.pos)][0]=0.0 | |
return | |
def update_val(self, sys_loops, lbyr_ratio, mat_e, mat_a, mat_b, state_vec, mat_u, sys_branches, sys_events): | |
""" This function calculates the actual current in the | |
switch branch. With this, the branch voltage is found | |
with respect to the existing switch resistance. The switch | |
voltage is then used to decide the turn on condition. """ | |
# 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.pos) in sys_loops[c1][c1][c2]: | |
# If switch negative polarity is after the switch | |
# position, the current is positive. | |
if sys_loops[c1][c1][c2].index(self.polrty)>sys_loops[c1][c1][c2].index(csv_tuple(self.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] | |
self.current=act_current | |
self.voltage=self.current*self.resistor | |
# Identifying the position of the switch branch | |
# to generate events. | |
for c1 in range(len(sys_branches)): | |
if csv_tuple(self.pos) in sys_branches[c1]: | |
branch_pos=c1 | |
# Switch will turn on when it is forward biased | |
# and it is gated on. | |
if self.control_values[0]>=1.0 and self.voltage>1.0: | |
if self.status=="off": | |
sys_events[branch_pos]="yes" | |
self.status="on" | |
# Switch will turn off when gated off or | |
# when current becomes negative. | |
if self.control_values[0]==0.0 or self.current<0.0: | |
if self.status=="on": | |
sys_events[branch_pos]="yes" | |
self.status="off" | |
if self.status=="off": | |
self.resistor=self.resistor_off | |
else: | |
self.resistor=self.resistor_on | |
return |
This is the circuit for the buck converter.
And this is the control code - actually just an open loop with a constant 50% duty ratio (click on view raw below the code box to see the code in another 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
import math | |
carr_freq=5000.0 | |
if (x_tri>1.0): | |
x_tri=1.0 | |
if (x_tri<0.0): | |
x_tri=0.0 | |
dt_sample=10.0e-6 | |
try: | |
str(switch_control) | |
except: | |
switch_control=0.0 | |
else: | |
pass | |
if t_clock>t1: | |
x_tri+=(0.5*carr_freq)*dt_sample | |
if (x_tri>1.0): | |
x_tri=0.0 | |
if (x_tri<0.5): | |
switch_control=1.0 | |
else: | |
switch_control=0.0 | |
t1=t1+10.0e-6 |
And on execution, the current (measured by Ammeter_La) through the inductor La is:
And as can be seen, the diode does not free wheel at all. The current rises when the switch turns on and drops to zero when it is turned off.
The strategy to overcome this will be my next blog entry as it is a fairly detailed algorithm.
No comments:
Post a Comment