Last update: 14 June 2022
Consider the circuit below, which contains independent and dependent current and voltage sources. The circuit is from [1], Figure 4.8. The schematic of the circuit was redrawn in LTspice [2]. Find voltages and currents in the circuit.
The zero volt source, V2, was added to the schematic so that the current through R4 could be measured since this current controls H1. LTspice generated the following net list:
R1 1 4 2
R2 1 2 1
R3 4 3 1
R4 2 5 2
V1 1 0 2
I1 4 0 9
H1 2 3 V2 3
G1 0 3 1 4 2
V2 0 5 0
from sympy import *
import numpy as np
init_printing()
Python code was used to generate the modified nodal equations from the net list. The link to the modified nodal equations Jupyter Notebook is here. The nodal equations were then copied to this Jupyter notebook for evaluation. Nodal analysis is a procedure for analyzing circuits using node voltages as the circuit variables and is based on the application of Kirchhoff's Current Law. Modified nodal analysis (MNA) is an extension of nodal analysis which in addition to the circuit's node voltages also uses some branch currents.
The equations are:
[[Eq(I_V1 + v1*(1/R2 + 1/R1) - v2/R2 - v4/R1, 0)],
[Eq(I_H1 + v2*(1/R4 + 1/R2) - v5/R4 - v1/R2, 0)],
[Eq(-I_H1 - g1*v1 + v4*(g1 - 1/R3) + v3/R3, 0)],
[Eq(v4*(1/R3 + 1/R1) - v3/R3 - v1/R1, -I1)],
[Eq(-I_V2 - v2/R4 + v5/R4, 0)],
[Eq(v1, V1)],
[Eq(-I_V2*h1 + v2 - v3, V2)],
[Eq(-v5, 0)]]
Define the SymPy symbols and declare the node equations generated by nodal analysis code.
V1, R2, v4, R4, I1, v3, v5, I_V2, R3, I_V1, h1, R1, V2, v1, g1, v2, I_H1 = symbols('V1 R2 v4 R4 I1 v3 v5 I_V2 R3 I_V1 h1 R1 V2 v1 g1 v2 I_H1')
equ = Matrix(
[[Eq(I_V1 + v1*(1/R2 + 1/R1) - v2/R2 - v4/R1, 0)],
[Eq(I_H1 + v2*(1/R4 + 1/R2) - v5/R4 - v1/R2, 0)],
[Eq(-I_H1 - g1*v1 + v4*(g1 - 1/R3) + v3/R3, 0)],
[Eq(v4*(1/R3 + 1/R1) - v3/R3 - v1/R1, -I1)],
[Eq(-I_V2 - v2/R4 + v5/R4, 0)],
[Eq(v1, V1)],
[Eq(-I_V2*h1 + v2 - v3, V2)],
[Eq(-v5, 0)]])
equ
A symbolic solution for the node equations is easily obtained by using the SymPy solve function.
solve(equ,[v1, v2, v3, v4, v5, I_V1, I_H1, I_V2])
A numerical solution for the equations can be obtained by substituting the element values into the equations.
# enter the element values
element_values = {R1:2,R2:1,R3:1,R4:2,V1:2,V2:0,I1:9,h1:3,g1:2}
equ_with_values = equ.subs(element_values)
equ_with_values # display the equations
solve(equ_with_values,[v1, v2, v3, v4, v5, I_V1, I_H1, I_V2])
Comparing these results to those obtained from LTspice, we see that they agree.
--- Operating Point ---
V(1): 2 voltage
V(4): -2 voltage
V(2): 2 voltage
V(3): 5 voltage
V(5): 0 voltage
I(H1): -1 device_current
I(I1): 9 device_current
I(R4): 1 device_current
I(R3): -7 device_current
I(R2): 2.22045e-016 device_current
I(R1): 2 device_current
I(G1): 8 device_current
I(V2): -1 device_current
I(V1): -2 device_current
Replace R2 and R3 with C1 and L1, set AC source,V1, amplitude to 1, phase to 0 and frequency to 1 radian per second.
LTspice generated the following net list:
R1 1 4 2
*R2 1 2 1
C1 1 2 1
*R3 4 3 1
L1 4 3 1
R4 2 5 2
V1 1 0 2
I1 4 0 9
H1 2 3 V2 3
G1 0 3 1 4 2
V2 0 5 0
Define the SymPy symbols and declare the node equations generated by nodal analysis code.
V1, v4, R4, I1, v3, v5, I_V2, I_V1, h1, I_L1, s, C1, R1, V2, v1, g1, L1, v2, I_H1 = symbols('V1 v4 R4 I1 v3 v5 I_V2 I_V1 h1 I_L1 s C1 R1 V2 v1 g1 L1 v2 I_H1')
equ_ac = Matrix(
[[Eq(-C1*s*v2 + I_V1 + v1*(C1*s + 1/R1) - v4/R1, 0)],
[Eq(-C1*s*v1 + I_H1 + v2*(C1*s + 1/R4) - v5/R4, 0)],
[Eq(-I_H1 - I_L1 - g1*v1 + g1*v4, 0)],
[Eq(I_L1 - v1/R1 + v4/R1, -I1)],
[Eq(-I_V2 - v2/R4 + v5/R4, 0)],
[Eq(v1, V1)],
[Eq(-v5, V2)],
[Eq(-I_V2*h1 + v2 - v3, 0)],
[Eq(-I_L1*L1*s - v3 + v4, 0)]])
equ_ac
A symbolic solution for the node equations is easily obtained by using the SymPy solve function.
solve(equ_ac,[v1, v2, v3, v4, v5, I_L1, I_V1, I_H1, I_V2])
# enter the element values,
# set V1 = 1
# set V2 to 0, since DC current is not considered for AC signal analysis
element_values = {R1:2,C1:1,L1:1,R4:2,V1:1,V2:0,I1:0,h1:3,g1:2}
equ_ac_with_values = equ_ac.subs(element_values)
equ_ac_with_values # display the equations
solve(equ_ac_with_values,[v1, v2, v3, v4, v5, I_L1, I_V1, I_H1, I_V2])
Solve for $\omega$ equal to 1 radian per second, s = 1j.
equ_ac_with_values_1rad_per_s = equ_ac_with_values.subs({s:1j})
equ_ac_with_values_1rad_per_s # display the equations
ans = solve(equ_ac_with_values_1rad_per_s,[v1, v2, v3, v4, v5, I_L1, I_V1, I_H1, I_V2])
ans
print('v1 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[v1])),float(arg(ans[v1])*180/np.pi)))
print('v2 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[v2])),float(arg(ans[v2])*180/np.pi)))
print('v3 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[v3])),float(arg(ans[v3])*180/np.pi)))
print('v4 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[v4])),float(arg(ans[v4])*180/np.pi)))
print('v5 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[v5])),float(arg(ans[v5])*180/np.pi)))
print('I_H1 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[I_H1])),float(arg(ans[I_H1])*180/np.pi)))
print('I_L1 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[I_L1])),float(arg(ans[I_L1])*180/np.pi)))
print('I_V1 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[I_V1])),float(arg(ans[I_V1])*180/np.pi)))
print('I_V2 mag: {:.4f} phase: {:.4f} deg'.format(float(abs(ans[I_V2])),float(arg(ans[I_V2])*180/np.pi)))
v1 mag: 1.0000 phase: 0.0000 deg v2 mag: 0.3508 phase: 15.2551 deg v3 mag: 0.8771 phase: 15.2551 deg v4 mag: 1.0000 phase: 14.2500 deg v5 mag: 0.0000 phase: nan deg I_H1 mag: 0.6202 phase: 97.1250 deg I_L1 mag: 0.1240 phase: -82.8750 deg I_V1 mag: 0.5491 phase: -101.3099 deg I_V2 mag: 0.1754 phase: -164.7449 deg
The solution agrees with LTspice.
--- AC Analysis ---
frequency:0.159155 Hz
V(1):mag: 1 phase: 1.59028e-015° voltage
V(4):mag: 1.00002 phase: 14.2492° voltage
V(2):mag: 0.350839 phase: 15.2626° voltage
V(5):mag: 0 phase: 0° voltage
V(3):mag: 0.877098 phase: 15.2626° voltage
I(C1):mag: 0.667951 phase: 82.0524° device_current
I(H1):mag: 0.620141 phase: 97.121° device_curren
I(L1):mag: 0.124028 phase: -82.879° device_current
I(I1):mag: 0 phase: 0° device_current
I(R4):mag: 0.17542 phase: 15.2626° device_current
I(R1):mag: 0.124028 phase: -82.879° device_current
I(G1):mag: 0.496112 phase: -82.879° device_current
I(V2):mag: 0.17542 phase: -164.737° device_current
I(V1):mag: 0.549135 phase: -101.314° device_current