32  Super node

Figure 32.1: super node circuit

A question posted on Electronics Stackexchange by Malek (2020) asked:

I have a circuit that I would like to convert into a conductance matrix for the node analysis by inspection method. I have, however, run into a problem. I have this 36V ideal voltage source with no resistance on its branch, which means that I cannot convert it into a current source with the Norton/Thenevin equivalent circuit theorem (or can I?). I have thought of making the third node connected to the voltage source dependent on the first node connected to the voltage source, i.e. v1 = v1 + 36. I have tried this method, but I do not get the correct values. Am I messing up? Is there no way to handle ideal voltage sources with the node analysis by inspection method?

The MNA solution provided below can work directly with the circuit netlist and the concept of a super node is not required.

The net list for Figure 5.1 was generated by LTSpice and show below:

V1 1 3 36
I1 0 1 12
I2 2 0 18
I3 0 3 24
R1 1 0 4
R4 3 0 6
R2 2 1 12
R3 3 2 15

The following Python modules are used in this notebook.

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()

32.1 Load the net list

The netlist for the circuit is pasted into the code cell below. In Python a triple-quoted string includes whitespace, tabs and newlines. The newlines characters are needed to mark the end of each SPICE statement in the netlist.

net_list = '''
V1 1 3 36
I1 0 1 12
I2 2 0 18
I3 0 3 24
R1 1 0 4
R4 3 0 6
R2 2 1 12
R3 3 2 15
'''

32.2 Call the symbolic modified nodal analysis function

report, network_df, i_unk_df, A, X, Z = SymMNA.smna(net_list)

The network equations for the circuit can be obtained from the A, X and Z values returned from the smna function. The A, X and Z are formuloated into equations and displayed below. Markdown is an IPython function and latex is a SymPy printing function.

# reform X and Z into Matrix type for printing
Xp = Matrix(X)
Zp = Matrix(Z)
temp = ''
for i in range(len(X)):
    temp += '${:s}$<br>'.format(latex(Eq((A*Xp)[i:i+1][0],Zp[i])))

Markdown(temp)

\(I_{V1} + v_{1} \cdot \left(\frac{1}{R_{2}} + \frac{1}{R_{1}}\right) - \frac{v_{2}}{R_{2}} = I_{1}\)
\(v_{2} \cdot \left(\frac{1}{R_{3}} + \frac{1}{R_{2}}\right) - \frac{v_{3}}{R_{3}} - \frac{v_{1}}{R_{2}} = - I_{2}\)
\(- I_{V1} + v_{3} \cdot \left(\frac{1}{R_{4}} + \frac{1}{R_{3}}\right) - \frac{v_{2}}{R_{3}} = I_{3}\)
\(v_{1} - v_{3} = V_{1}\)

32.2.1 Build the network equation matrix

# Put matrices into SymPy 
X = Matrix(X)
Z = Matrix(Z)

NE_sym = Eq(A*X,Z)
NE_sym

\(\displaystyle \left[\begin{matrix}I_{V1} + v_{1} \cdot \left(\frac{1}{R_{2}} + \frac{1}{R_{1}}\right) - \frac{v_{2}}{R_{2}}\\v_{2} \cdot \left(\frac{1}{R_{3}} + \frac{1}{R_{2}}\right) - \frac{v_{3}}{R_{3}} - \frac{v_{1}}{R_{2}}\\- I_{V1} + v_{3} \cdot \left(\frac{1}{R_{4}} + \frac{1}{R_{3}}\right) - \frac{v_{2}}{R_{3}}\\v_{1} - v_{3}\end{matrix}\right] = \left[\begin{matrix}I_{1}\\- I_{2}\\I_{3}\\V_{1}\end{matrix}\right]\)

# turn the free symbols into SymPy variables
var(str(NE_sym.free_symbols).replace('{','').replace('}',''))

\(\displaystyle \left( I_{V1}, \ R_{3}, \ v_{2}, \ I_{2}, \ I_{1}, \ R_{2}, \ R_{4}, \ V_{1}, \ I_{3}, \ v_{3}, \ v_{1}, \ R_{1}\right)\)

32.3 Symbolic solution

The newtork equations can be solved symbolically.

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)

\(v_{1} = \frac{I_{1} R_{1} R_{4} - I_{2} R_{1} R_{4} + I_{3} R_{1} R_{4} + R_{1} V_{1}}{R_{1} + R_{4}}\)
\(v_{2} = \frac{I_{1} R_{1} R_{2} R_{4} + I_{1} R_{1} R_{3} R_{4} - I_{2} R_{1} R_{2} R_{3} - I_{2} R_{1} R_{2} R_{4} - I_{2} R_{1} R_{3} R_{4} - I_{2} R_{2} R_{3} R_{4} + I_{3} R_{1} R_{2} R_{4} + I_{3} R_{1} R_{3} R_{4} + R_{1} R_{3} V_{1} - R_{2} R_{4} V_{1}}{R_{1} R_{2} + R_{1} R_{3} + R_{2} R_{4} + R_{3} R_{4}}\)
\(v_{3} = \frac{I_{1} R_{1} R_{4} - I_{2} R_{1} R_{4} + I_{3} R_{1} R_{4} - R_{4} V_{1}}{R_{1} + R_{4}}\)
\(I_{V1} = \frac{I_{1} R_{1} R_{2} + I_{1} R_{1} R_{3} - I_{2} R_{1} R_{3} + I_{2} R_{2} R_{4} - I_{3} R_{2} R_{4} - I_{3} R_{3} R_{4} - R_{1} V_{1} - R_{2} V_{1} - R_{3} V_{1} - R_{4} V_{1}}{R_{1} R_{2} + R_{1} R_{3} + R_{2} R_{4} + R_{3} R_{4}}\)

32.4 Construct a dictionary of element values

element_values = SymMNA.get_part_values(network_df)
element_values

\(\displaystyle \left\{ I_{1} : 12.0, \ I_{2} : 18.0, \ I_{3} : 24.0, \ R_{1} : 4.0, \ R_{2} : 12.0, \ R_{3} : 15.0, \ R_{4} : 6.0, \ V_{1} : 36.0\right\}\)

32.5 Numerical solution

NE = NE_sym.subs(element_values)
NE

\(\displaystyle \left[\begin{matrix}I_{V1} + 0.333333333333333 v_{1} - 0.0833333333333333 v_{2}\\- 0.0833333333333333 v_{1} + 0.15 v_{2} - 0.0666666666666667 v_{3}\\- I_{V1} - 0.0666666666666667 v_{2} + 0.233333333333333 v_{3}\\v_{1} - v_{3}\end{matrix}\right] = \left[\begin{matrix}12.0\\-18.0\\24.0\\36.0\end{matrix}\right]\)

U = solve(NE,X)

Display the numerical solution. Six significant digits are displayed so that results can be compared to LTSpice.

table_header = ['unknown', 'mag']
table_row = []

for name, value in U.items():
    table_row.append([str(name),float(value)])

print(tabulate(table_row, headers=table_header,colalign = ('left','decimal'),tablefmt="simple",floatfmt=('5s','.6f')))
unknown           mag
---------  ----------
v1          57.600000
v2         -78.400000
v3          21.600000
I_V1       -13.733333

The node voltages and current through the sources are solved for. The Sympy generated solution matches the LTSpice results:

       --- Operating Point ---

V(1):    2      voltage
V(2):    4      voltage
V(4):    -1.14286   voltage
V(3):    6.28571    voltage
V(5):    0      voltage
I(F1):   -4     device_current
I(I1):   9      device_current
I(R2):   -2     device_current
I(R3):   -7.42857   device_current
I(R4):   2      device_current
I(R1):   1.57143    device_current
I(E1):   -11.4286   device_current
I(V1):   0.428571   device_current
I(V2):   -2     device_current

The results from LTSpice agree with the SymPy results.