def loop_analysis(g, ctrl_src, tree, types={}): """Loop analysis respect to the tree of the network graph g""" eqs = [] vars = [] # loop equations of the cobranch voltages cobranches = g.branches() - tree.branches() for cobranch in cobranches: if btype(cobranch, types) not in 'IFG': lpos, lneg = g.loop(cobranch, tree, include_cobranch=True) lhs_pos = [Calculus(f_u(b, ctrl_src, types)) for b in lpos] lhs_neg = [Calculus(f_u(b, ctrl_src, types)) for b in lneg] lhs = Add(*lhs_pos) - Add(*lhs_neg) eqs.append(lhs) if btype(cobranch, types) not in 'U': vars.append(Calculus('I_' + cobranch)) if btype(cobranch, types) in 'N': vars.append(Calculus('V_' + cobranch)) # cut equations of the tree currents (for substitution or additional) tcur = {} for tb in tree.branches(): bpos, bneg = g.cut(tb, tree, include_tree_branch=False) # moving (bpos, bneg) from lhs to rhs by negation rhs_pos = [Calculus(branch_current(b, ctrl_src, types)) for b in bneg] rhs_neg = [Calculus(branch_current(b, ctrl_src, types)) for b in bpos] rhs = Add(*rhs_pos) - Add(*rhs_neg) if btype(tb, types) not in 'IFGU': tcur[Calculus('I_' + tb)] = rhs.expand() if btype(tb, types) in 'N': vars.append(Calculus('V_' + tb)) else: eqs.append(Calculus(f_i(tb, ctrl_src, types)) - rhs) if btype(tb, types) not in 'U': vars.append(Calculus('V_' + tb)) # finally add variables and equations of controlled sources for src, ctrl in ctrl_src.items(): if btype(src, types) in 'EG' and btype(ctrl, types) != 'V': v_ctrl = Calculus('V_' + ctrl) if v_ctrl not in vars: # ctrl is no 'IFG' in tree # control voltage is unknown vars.append(v_ctrl) # try if control voltage can be substituted # then control branch is a (controlled) voltage source lhs = v_ctrl - f_u(ctrl, ctrl_src, types) if lhs == 0: # ctrl is a current source if ctrl in cobranches: # add missing loop equation for v_ctrl which # was omitted due to: btype(cobranch, types) not in 'IFG' lpos, lneg = g.loop(ctrl, tree, include_cobranch=False) lhs_pos = [ Calculus(f_u(b, ctrl_src, types)) for b in lpos ] lhs_neg = [ Calculus(f_u(b, ctrl_src, types)) for b in lneg ] lhs = v_ctrl + Add(*lhs_pos) - Add(*lhs_neg) # if v_ctrl is in tree then var and cut equation are # already added because ctrl is a current source eqs.append(lhs) elif btype(src, types) in 'F' and src in cobranches: if ctrl in tree.branches() and btype(ctrl, types) not in 'IFG': i_ctrl = Calculus('I_' + ctrl) # just a test avoiding duplication if i_ctrl not in vars: # control current is unknown vars.append(i_ctrl) # remove cut equation for ctrl from tcur and add it to eqs eqs.append(i_ctrl - tcur.pop(i_ctrl)) # substitute tree currents by cobranch currents eqs = [e.subs(tcur).expand() for e in eqs] return eqs, vars
def cut_analysis(g, ctrl_src, tree, types={}): """Cut analysis respect to the tree of the network graph g""" eqs = [] vars = [] # cut equations of the tree currents for tb in tree.branches(): if btype(tb, types) not in 'VEH': bpos, bneg = g.cut(tb, tree) lhs_pos = [Calculus(f_i(b, ctrl_src, types)) for b in bpos] lhs_neg = [Calculus(f_i(b, ctrl_src, types)) for b in bneg] lhs = Add(*lhs_pos) - Add(*lhs_neg) eqs.append(lhs) if btype(tb, types) not in 'U': vars.append(Calculus(branch_voltage(tb, ctrl_src, types))) if btype(tb, types) in 'N': vars.append(Calculus(branch_current(tb, ctrl_src, types))) # loop equations of the cobranch voltages cobranches = g.branches() - tree.branches() covolts = {} for cobranch in cobranches: lpos, lneg = g.loop(cobranch, tree) # moving (bpos, bneg) from lhs to rhs by negation rhs_pos = [Calculus(branch_voltage(b, ctrl_src, types)) for b in lneg] rhs_neg = [Calculus(branch_voltage(b, ctrl_src, types)) for b in lpos] rhs = Add(*rhs_pos) - Add(*rhs_neg) rhs = rhs.expand() if btype(cobranch, types) not in 'VEHU': covolts[Calculus(branch_voltage(cobranch, ctrl_src, types))] = rhs if btype(cobranch, types) in 'N': vars.append(Calculus('I_' + cobranch)) else: eqs.append(Calculus(f_u(cobranch, ctrl_src, types)) - rhs) if btype(cobranch, types) not in 'U': vars.append(Calculus('I_' + cobranch)) # finally add variables and equations of controlled sources for src, ctrl in ctrl_src.items(): if btype(src, types) in 'FH' and btype(ctrl, types) != 'I': i_ctrl = Calculus('I_' + ctrl) if i_ctrl not in vars: # ctrl is no 'VEH' in cotree # control current is unknown vars.append(i_ctrl) # try if control current can be substituted # then control branch is a (controlled) current source lhs = i_ctrl - Calculus(f_i(ctrl, ctrl_src, types)) if lhs == 0: # ctrl is a voltage source if ctrl in tree.branches(): # add missing cut equation for i_ctrl which # was omitted due to: btype(tb, types) not in 'VEH' bpos, bneg = g.cut(ctrl, tree, include_tree_branch=False) lhs_pos = [ Calculus(f_i(b, ctrl_src, types)) for b in bpos ] lhs_neg = [ Calculus(f_i(b, ctrl_src, types)) for b in bneg ] lhs = i_ctrl + Add(*lhs_pos) - Add(*lhs_neg) # if i_ctrl is in cotree then var and loop equation are # already added because ctrl is a voltage source eqs.append(lhs) elif btype(src, types) in 'E' and src in tree.branches(): if ctrl in cobranches and btype(ctrl, types) not in 'VEH': v_ctrl = Calculus('V_' + ctrl) # just a test avoiding duplication if v_ctrl not in vars: # control voltage is unknown vars.append(v_ctrl) # remove loop equation for ctrl from covolts and add to eqs eqs.append(v_ctrl - covolts.pop(v_ctrl)) # substitute cobranch voltages by tree voltages eqs = [e.subs(covolts).expand() for e in eqs] return eqs, vars