import os
from sympy import *
import numpy as np
from tabulate import tabulate
from scipy import signal
import matplotlib.pyplot as plt
import pandas as pd
import SymMNA
from IPython.display import display, Markdown, Math, Latex
init_printing()
8 Test 4
Test circuit number 4 has 26 branches, 13 nodes, 18 resistors, 3 independent voltage sources and 1 independednt current source. There are 4 dependent sources, one of each type. Theere are 18 passive components, all resistors. This circuit will test a large network with at least one of each type of source.
The net list generated by LTSpice.
* test_4.asc
V4 1 2 10
I2 3 4 5
F1 5 9 V1 5
E1 12 3 10 1 3
G1 7 10 9 4 2
H1 2 12 V2 2
R3 5 1 10
R4 3 7 1
R5 4 8 5
R9 1 9 9
R1 1 5 3
R10 8 0 10
R13 9 11 7
R14 10 9 10
R15 0 11 3
R2 3 5 5
R6 7 1 2
R7 8 7 6
R11 10 9 5
R12 0 10 9
R16 12 11 10
R8 3 8 5
R17 2 6 8
V1 6 3 0
V2 13 5 0
R18 12 13 4
.op
.backanno
.end
8.1 Load the net list
= '''
net_list V4 1 2 10
I2 3 4 5
F1 5 9 V1 5
E1 12 3 10 1 3
G1 7 10 9 4 2
H1 2 12 V2 2
R3 5 1 10
R4 3 7 1
R5 4 8 5
R9 1 9 9
R1 1 5 3
R10 8 0 10
R13 9 11 7
R14 10 9 10
R15 0 11 3
R2 3 5 5
R6 7 1 2
R7 8 7 6
R11 10 9 5
R12 0 10 9
R16 12 11 10
R8 3 8 5
R17 2 6 8
V1 6 3 0
V2 13 5 0
R18 12 13 4
'''
8.2 Call the symbolic modified nodal analysis function
= SymMNA.smna(net_list) report, network_df, i_unk_df, A, X, Z
Display the equations
# reform X and Z into Matrix type for printing
= Matrix(X)
Xp = Matrix(Z)
Zp = ''
temp for i in range(len(X)):
+= '${:s}$<br>'.format(latex(Eq((A*Xp)[i:i+1][0],Zp[i])))
temp
Markdown(temp)
\(I_{V4} + v_{1} \cdot \left(\frac{1}{R_{9}} + \frac{1}{R_{6}} + \frac{1}{R_{3}} + \frac{1}{R_{1}}\right) + v_{5} \left(- \frac{1}{R_{3}} - \frac{1}{R_{1}}\right) - \frac{v_{9}}{R_{9}} - \frac{v_{7}}{R_{6}} = 0\)
\(I_{H1} - I_{V4} + \frac{v_{2}}{R_{17}} - \frac{v_{6}}{R_{17}} = 0\)
\(- I_{Ea1} - I_{V1} + v_{3} \cdot \left(\frac{1}{R_{8}} + \frac{1}{R_{4}} + \frac{1}{R_{2}}\right) - \frac{v_{8}}{R_{8}} - \frac{v_{7}}{R_{4}} - \frac{v_{5}}{R_{2}} = - I_{2}\)
\(\frac{v_{4}}{R_{5}} - \frac{v_{8}}{R_{5}} = I_{2}\)
\(I_{F1} - I_{V2} + v_{1} \left(- \frac{1}{R_{3}} - \frac{1}{R_{1}}\right) + v_{5} \cdot \left(\frac{1}{R_{3}} + \frac{1}{R_{2}} + \frac{1}{R_{1}}\right) - \frac{v_{3}}{R_{2}} = 0\)
\(I_{V1} - \frac{v_{2}}{R_{17}} + \frac{v_{6}}{R_{17}} = 0\)
\(- g_{1} v_{4} + g_{1} v_{9} + v_{7} \cdot \left(\frac{1}{R_{7}} + \frac{1}{R_{6}} + \frac{1}{R_{4}}\right) - \frac{v_{8}}{R_{7}} - \frac{v_{1}}{R_{6}} - \frac{v_{3}}{R_{4}} = 0\)
\(v_{8} \cdot \left(\frac{1}{R_{8}} + \frac{1}{R_{7}} + \frac{1}{R_{5}} + \frac{1}{R_{10}}\right) - \frac{v_{3}}{R_{8}} - \frac{v_{7}}{R_{7}} - \frac{v_{4}}{R_{5}} = 0\)
\(- I_{F1} + v_{10} \left(- \frac{1}{R_{14}} - \frac{1}{R_{11}}\right) + v_{9} \cdot \left(\frac{1}{R_{9}} + \frac{1}{R_{14}} + \frac{1}{R_{13}} + \frac{1}{R_{11}}\right) - \frac{v_{1}}{R_{9}} - \frac{v_{11}}{R_{13}} = 0\)
\(g_{1} v_{4} + v_{10} \cdot \left(\frac{1}{R_{14}} + \frac{1}{R_{12}} + \frac{1}{R_{11}}\right) + v_{9} \left(- g_{1} - \frac{1}{R_{14}} - \frac{1}{R_{11}}\right) = 0\)
\(v_{11} \cdot \left(\frac{1}{R_{16}} + \frac{1}{R_{15}} + \frac{1}{R_{13}}\right) - \frac{v_{12}}{R_{16}} - \frac{v_{9}}{R_{13}} = 0\)
\(I_{Ea1} - I_{H1} + v_{12} \cdot \left(\frac{1}{R_{18}} + \frac{1}{R_{16}}\right) - \frac{v_{13}}{R_{18}} - \frac{v_{11}}{R_{16}} = 0\)
\(I_{V2} - \frac{v_{12}}{R_{18}} + \frac{v_{13}}{R_{18}} = 0\)
\(v_{1} - v_{2} = V_{4}\)
\(- v_{3} + v_{6} = V_{1}\)
\(v_{13} - v_{5} = V_{2}\)
\(I_{F1} - I_{V1} f_{1} = 0\)
\(ea_{1} v_{1} - ea_{1} v_{10} + v_{12} - v_{3} = 0\)
\(- I_{V2} h_{1} - v_{12} + v_{2} = 0\)
8.2.1 Netlist statistics
print(report)
Net list report
number of lines in netlist: 26
number of branches: 26
number of nodes: 13
number of unknown currents: 6
number of RLC (passive components): 18
number of inductors: 0
number of independent voltage sources: 3
number of independent current sources: 1
number of Op Amps: 0
number of E - VCVS: 1
number of G - VCCS: 1
number of F - CCCS: 1
number of H - CCVS: 1
number of K - Coupled inductors: 0
8.2.2 Connectivity Matrix
A
\(\displaystyle \left[\begin{array}{ccccccccccccccccccc}\frac{1}{R_{9}} + \frac{1}{R_{6}} + \frac{1}{R_{3}} + \frac{1}{R_{1}} & 0 & 0 & 0 & - \frac{1}{R_{3}} - \frac{1}{R_{1}} & 0 & - \frac{1}{R_{6}} & 0 & - \frac{1}{R_{9}} & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\0 & \frac{1}{R_{17}} & 0 & 0 & 0 & - \frac{1}{R_{17}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 1\\0 & 0 & \frac{1}{R_{8}} + \frac{1}{R_{4}} + \frac{1}{R_{2}} & 0 & - \frac{1}{R_{2}} & 0 & - \frac{1}{R_{4}} & - \frac{1}{R_{8}} & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & -1 & 0\\0 & 0 & 0 & \frac{1}{R_{5}} & 0 & 0 & 0 & - \frac{1}{R_{5}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\- \frac{1}{R_{3}} - \frac{1}{R_{1}} & 0 & - \frac{1}{R_{2}} & 0 & \frac{1}{R_{3}} + \frac{1}{R_{2}} + \frac{1}{R_{1}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 0 & 0\\0 & - \frac{1}{R_{17}} & 0 & 0 & 0 & \frac{1}{R_{17}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\- \frac{1}{R_{6}} & 0 & - \frac{1}{R_{4}} & - g_{1} & 0 & 0 & \frac{1}{R_{7}} + \frac{1}{R_{6}} + \frac{1}{R_{4}} & - \frac{1}{R_{7}} & g_{1} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & - \frac{1}{R_{8}} & - \frac{1}{R_{5}} & 0 & 0 & - \frac{1}{R_{7}} & \frac{1}{R_{8}} + \frac{1}{R_{7}} + \frac{1}{R_{5}} + \frac{1}{R_{10}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\- \frac{1}{R_{9}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & \frac{1}{R_{9}} + \frac{1}{R_{14}} + \frac{1}{R_{13}} + \frac{1}{R_{11}} & - \frac{1}{R_{14}} - \frac{1}{R_{11}} & - \frac{1}{R_{13}} & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0\\0 & 0 & 0 & g_{1} & 0 & 0 & 0 & 0 & - g_{1} - \frac{1}{R_{14}} - \frac{1}{R_{11}} & \frac{1}{R_{14}} + \frac{1}{R_{12}} + \frac{1}{R_{11}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - \frac{1}{R_{13}} & 0 & \frac{1}{R_{16}} + \frac{1}{R_{15}} + \frac{1}{R_{13}} & - \frac{1}{R_{16}} & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - \frac{1}{R_{16}} & \frac{1}{R_{18}} + \frac{1}{R_{16}} & - \frac{1}{R_{18}} & 0 & 0 & 0 & 0 & 1 & -1\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - \frac{1}{R_{18}} & \frac{1}{R_{18}} & 0 & 0 & 1 & 0 & 0 & 0\\1 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & -1 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - f_{1} & 0 & 1 & 0 & 0\\ea_{1} & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & - ea_{1} & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & - h_{1} & 0 & 0 & 0\end{array}\right]\)
8.2.3 Unknown voltages and currents
X
\(\displaystyle \left[ v_{1}, \ v_{2}, \ v_{3}, \ v_{4}, \ v_{5}, \ v_{6}, \ v_{7}, \ v_{8}, \ v_{9}, \ v_{10}, \ v_{11}, \ v_{12}, \ v_{13}, \ I_{V4}, \ I_{V1}, \ I_{V2}, \ I_{F1}, \ I_{Ea1}, \ I_{H1}\right]\)
8.2.4 Known voltages and currents
Z
\(\displaystyle \left[ 0, \ 0, \ - I_{2}, \ I_{2}, \ 0, \ 0, \ 0, \ 0, \ 0, \ 0, \ 0, \ 0, \ 0, \ V_{4}, \ V_{1}, \ V_{2}, \ 0, \ 0, \ 0\right]\)
8.2.5 Network dataframe
network_df
element | p node | n node | cp node | cn node | Vout | value | Vname | Lname1 | Lname2 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | V4 | 1 | 2 | NaN | NaN | NaN | 10.0 | NaN | NaN | NaN |
1 | V1 | 6 | 3 | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN |
2 | V2 | 13 | 5 | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN |
3 | I2 | 3 | 4 | NaN | NaN | NaN | 5.0 | NaN | NaN | NaN |
4 | F1 | 5 | 9 | NaN | NaN | NaN | 5.0 | V1 | NaN | NaN |
5 | Ea1 | 12 | 3 | 10 | 1 | NaN | 3.0 | NaN | NaN | NaN |
6 | G1 | 7 | 10 | 9 | 4 | NaN | 2.0 | NaN | NaN | NaN |
7 | H1 | 2 | 12 | NaN | NaN | NaN | 2.0 | V2 | NaN | NaN |
8 | R3 | 5 | 1 | NaN | NaN | NaN | 10.0 | NaN | NaN | NaN |
9 | R4 | 3 | 7 | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN |
10 | R5 | 4 | 8 | NaN | NaN | NaN | 5.0 | NaN | NaN | NaN |
11 | R9 | 1 | 9 | NaN | NaN | NaN | 9.0 | NaN | NaN | NaN |
12 | R1 | 1 | 5 | NaN | NaN | NaN | 3.0 | NaN | NaN | NaN |
13 | R10 | 8 | 0 | NaN | NaN | NaN | 10.0 | NaN | NaN | NaN |
14 | R13 | 9 | 11 | NaN | NaN | NaN | 7.0 | NaN | NaN | NaN |
15 | R14 | 10 | 9 | NaN | NaN | NaN | 10.0 | NaN | NaN | NaN |
16 | R15 | 0 | 11 | NaN | NaN | NaN | 3.0 | NaN | NaN | NaN |
17 | R2 | 3 | 5 | NaN | NaN | NaN | 5.0 | NaN | NaN | NaN |
18 | R6 | 7 | 1 | NaN | NaN | NaN | 2.0 | NaN | NaN | NaN |
19 | R7 | 8 | 7 | NaN | NaN | NaN | 6.0 | NaN | NaN | NaN |
20 | R11 | 10 | 9 | NaN | NaN | NaN | 5.0 | NaN | NaN | NaN |
21 | R12 | 0 | 10 | NaN | NaN | NaN | 9.0 | NaN | NaN | NaN |
22 | R16 | 12 | 11 | NaN | NaN | NaN | 10.0 | NaN | NaN | NaN |
23 | R8 | 3 | 8 | NaN | NaN | NaN | 5.0 | NaN | NaN | NaN |
24 | R17 | 2 | 6 | NaN | NaN | NaN | 8.0 | NaN | NaN | NaN |
25 | R18 | 12 | 13 | NaN | NaN | NaN | 4.0 | NaN | NaN | NaN |
8.2.6 Unknown current dataframe
i_unk_df
element | p node | n node | |
---|---|---|---|
0 | V4 | 1 | 2 |
1 | V1 | 6 | 3 |
2 | V2 | 13 | 5 |
3 | F1 | 5 | 9 |
4 | Ea1 | 12 | 3 |
5 | H1 | 2 | 12 |
8.2.7 Build the network equations
# Put matrices into SymPy
= Matrix(X)
X = Matrix(Z)
Z
= Eq(A*X,Z) NE_sym
Turn the free symbols into SymPy variables.
str(NE_sym.free_symbols).replace('{','').replace('}','')) var(
\(\displaystyle \left( R_{5}, \ I_{V2}, \ v_{8}, \ h_{1}, \ v_{11}, \ R_{12}, \ R_{7}, \ I_{Ea1}, \ V_{4}, \ R_{1}, \ R_{3}, \ V_{1}, \ ea_{1}, \ v_{12}, \ R_{11}, \ g_{1}, \ R_{14}, \ v_{4}, \ I_{2}, \ v_{2}, \ v_{6}, \ v_{1}, \ v_{5}, \ R_{15}, \ V_{2}, \ I_{F1}, \ v_{13}, \ R_{18}, \ R_{17}, \ R_{4}, \ R_{6}, \ v_{10}, \ v_{3}, \ R_{13}, \ R_{8}, \ v_{9}, \ R_{16}, \ f_{1}, \ I_{H1}, \ v_{7}, \ R_{10}, \ R_{9}, \ R_{2}, \ I_{V4}, \ I_{V1}\right)\)
8.3 Symbolic solution
The symbolic solution was taking longer than a couple of minutes on my i3-8130U CPU @ 2.20GHz, so I interruped the kernel and commended the code.
#U_sym = solve(NE_sym,X)
Display the symbolic solution
#temp = ''
#for i in U_sym.keys():
# temp += '${:s} = {:s}$<br>'.format(latex(i),latex(U_sym[i]))
#Markdown(temp)
8.4 Construct a dictionary of element values
= SymMNA.get_part_values(network_df)
element_values
# display the component values
for k,v in element_values.items():
print('{:s} = {:s}'.format(str(k), str(v)))
V4 = 10.0
V1 = 0.0
V2 = 0.0
I2 = 5.0
f1 = 5.0
ea1 = 3.0
g1 = 2.0
h1 = 2.0
R3 = 10.0
R4 = 1.0
R5 = 5.0
R9 = 9.0
R1 = 3.0
R10 = 10.0
R13 = 7.0
R14 = 10.0
R15 = 3.0
R2 = 5.0
R6 = 2.0
R7 = 6.0
R11 = 5.0
R12 = 9.0
R16 = 10.0
R8 = 5.0
R17 = 8.0
R18 = 4.0
8.5 Numerical solution
Substitute numerical values in place the symbolic reference designators.
= NE_sym.subs(element_values) NE
Display the equations with numeric values.
= ''
temp for i in range(shape(NE.lhs)[0]):
+= '${:s} = {:s}$<br>'.format(latex(NE.rhs[i]),latex(NE.lhs[i]))
temp
Markdown(temp)
\(0 = I_{V4} + 1.04444444444444 v_{1} - 0.433333333333333 v_{5} - 0.5 v_{7} - 0.111111111111111 v_{9}\)
\(0 = I_{H1} - I_{V4} + 0.125 v_{2} - 0.125 v_{6}\)
\(-5.0 = - I_{Ea1} - I_{V1} + 1.4 v_{3} - 0.2 v_{5} - 1.0 v_{7} - 0.2 v_{8}\)
\(5.0 = 0.2 v_{4} - 0.2 v_{8}\)
\(0 = I_{F1} - I_{V2} - 0.433333333333333 v_{1} - 0.2 v_{3} + 0.633333333333333 v_{5}\)
\(0 = I_{V1} - 0.125 v_{2} + 0.125 v_{6}\)
\(0 = - 0.5 v_{1} - 1.0 v_{3} - 2.0 v_{4} + 1.66666666666667 v_{7} - 0.166666666666667 v_{8} + 2.0 v_{9}\)
\(0 = - 0.2 v_{3} - 0.2 v_{4} - 0.166666666666667 v_{7} + 0.666666666666667 v_{8}\)
\(0 = - I_{F1} - 0.111111111111111 v_{1} - 0.3 v_{10} - 0.142857142857143 v_{11} + 0.553968253968254 v_{9}\)
\(0 = 0.411111111111111 v_{10} + 2.0 v_{4} - 2.3 v_{9}\)
\(0 = 0.576190476190476 v_{11} - 0.1 v_{12} - 0.142857142857143 v_{9}\)
\(0 = I_{Ea1} - I_{H1} - 0.1 v_{11} + 0.35 v_{12} - 0.25 v_{13}\)
\(0 = I_{V2} - 0.25 v_{12} + 0.25 v_{13}\)
\(10.0 = v_{1} - v_{2}\)
\(0 = - v_{3} + v_{6}\)
\(0 = v_{13} - v_{5}\)
\(0 = I_{F1} - 5.0 I_{V1}\)
\(0 = 3.0 v_{1} - 3.0 v_{10} + v_{12} - v_{3}\)
\(0 = - 2.0 I_{V2} - v_{12} + v_{2}\)
Solve for voltages and currents.
= solve(NE,X) U
Display the numerical solution
Six significant digits are displayed so that results can be compared to LTSpice.
= ['unknown', 'mag']
table_header = []
table_row
for name, value in U.items():
str(name),float(value)])
table_row.append([
print(tabulate(table_row, headers=table_header,colalign = ('left','decimal'),tablefmt="simple",floatfmt=('5s','.6f')))
unknown mag
--------- ----------
v1 -2.528148
v2 -12.528148
v3 -26.854161
v4 18.928828
v5 -21.885182
v6 -26.854161
v7 -14.774289
v8 -6.071172
v9 16.675687
v10 1.207520
v11 1.418845
v12 -15.647159
v13 -21.885182
I_V4 -12.377360
I_V1 1.790752
I_V2 1.559506
I_F1 8.953758
I_Ea1 -14.021017
I_H1 -14.168112
The node voltages and current through the sources are solved for. The Sympy generated solution matches the LTSpice results:
--- Operating Point ---
V(1): -2.52815 voltage
V(2): -12.5281 voltage
V(3): -26.8542 voltage
V(4): 18.9288 voltage
V(5): -21.8852 voltage
V(9): 16.6757 voltage
V(12): -15.6472 voltage
V(10): 1.20752 voltage
V(7): -14.7743 voltage
V(8): -6.07117 voltage
V(11): 1.41885 voltage
V(6): -26.8542 voltage
V(13): -21.8852 voltage
I(F1): 8.95376 device_current
I(H1): -14.1681 device_current
I(I2): 5 device_current
I(R3): -1.9357 device_current
I(R4): -12.0799 device_current
I(R5): 5 device_current
I(R9): -2.13376 device_current
I(R1): 6.45234 device_current
I(R10): -0.607117 device_current
I(R13): 2.17955 device_current
I(R14): -1.54682 device_current
I(R15): -0.472948 device_current
I(R2): -0.993796 device_current
I(R6): -6.12307 device_current
I(R7): 1.45052 device_current
I(R11): -3.09363 device_current
I(R12): -0.134169 device_current
I(R16): -1.7066 device_current
I(R8): -4.1566 device_current
I(R17): 1.79075 device_current
I(R18): 1.55951 device_current
I(G1): -4.50628 device_current
I(E1): -14.021 device_current
I(V4): -12.3774 device_current
I(V1): 1.79075 device_current
I(V2): 1.55951 device_current
The results from LTSpice agree with the SymPy results.