Python Modified Nodal Analysis test

This commit is contained in:
Folkert Kevelam 2024-06-09 17:52:33 +02:00
parent 2fe03bf8bf
commit daf176e918

329
test.py Normal file
View File

@ -0,0 +1,329 @@
import matplotlib.pyplot as plt
import numpy as np
from numpy import linalg
from math import pi, sin
def Create_MNA(mat_cons):
Y = np.zeros(mat_cons[0])
B = np.zeros(mat_cons[1])
C = np.zeros(mat_cons[2])
D = np.zeros(mat_cons[3])
return [Y,B,C,D]
class Voltage_Supply:
def __init__(self, func, a, b):
self.node_a = a - 1
self.node_b = b - 1
self.v = 0
self.func = func
self.branch_current_node = 0
self.vp = 0
self.ip = 0
def set_voltages_currents(self, v, c):
if self.node_b > 0 and self.node_a > 0:
self.vp = v[self.node_a] - v[self.node_b]
elif self.node_b <= 0 and self.node_a > 0:
self.vp = v[self.node_a]
elif self.node_b > 0 and self.node_b <= 0:
self.vp = v[self.node_b]
if self.needs_branches:
self.ip = c[self.branch_current_node]
def set_time(self, t):
self.v = self.func(t)
def needs_branches(self):
return True
def set_branch_current_node(self, a):
self.branch_current_node = a
def get_matrix(self, mat_cons):
Y,B,C,D = Create_MNA(mat_cons)
if self.node_b >= 0:
B[self.node_b][self.branch_current_node] = 1
C[self.branch_current_node][self.node_b] = 1
if self.node_a >= 0:
B[self.node_a][self.branch_current_node] = -1
C[self.branch_current_node][self.node_a] = -1
M = np.block([[Y,B],[C,D]])
RHS_Top = np.zeros((mat_cons[0][0], 1))
RHS_Bot = np.zeros((mat_cons[2][0], 1))
RHS_Bot[self.branch_current_node] = self.v
RHS = np.block([[RHS_Top], [RHS_Bot]])
return [M, RHS]
class Resistance:
def __init__(self, func, a, b):
self.node_a = a - 1
self.node_b = b - 1
self.r = 0
self.func = func
self.vp = 0
self.ip = 0
def set_voltages_currents(self, v, c):
if self.node_b > 0 and self.node_a > 0:
self.vp = v[self.node_a] - v[self.node_b]
elif self.node_b <= 0 and self.node_a > 0:
self.vp = v[self.node_a]
elif self.node_b > 0 and self.node_b <= 0:
self.vp = v[self.node_b]
def set_time(self, t):
self.r = self.func(t)
def needs_branches(self):
return False
def get_matrix(self, mat_cons):
Y,B,C,D = Create_MNA(mat_cons)
a = self.node_a
b = self.node_b
if b >= 0:
Y[b,b] = self.r
if a >= 0:
Y[a,a] = self.r
if a >= 0 and b >= 0:
Y[a,b] = -self.r
Y[b,a] = -self.r
M = np.block([[Y,B], [C,D]])
RHS = np.zeros((mat_cons[0][0] + mat_cons[2][0], 1))
return [M, RHS]
class Inductor:
def __init__(self, func, a, b):
self.node_a = a - 1
self.node_b = b - 1
self.l = 0
self.func = func
self.previous_t = 0.0
self.current_t = 0.0
self.vp = 0
self.ip = 0
def set_voltages_currents(self, v, c):
if self.node_b > 0 and self.node_a > 0:
self.vp = v[self.node_a] - v[self.node_b]
elif self.node_b <= 0 and self.node_a > 0:
self.vp = v[self.node_a]
elif self.node_b > 0 and self.node_b <= 0:
self.vp = -v[self.node_b]
if self.needs_branches:
self.ip = c[self.branch_current_node]
def set_time(self, t):
self.previous_t = self.current_t
self.current_t = t
self.l = self.func(t)
def needs_branches(self):
return True
def set_branch_current_node(self, a):
self.branch_current_node = a
def get_matrix(self, mat_cons):
Y,B,C,D = Create_MNA(mat_cons)
a = self.node_a
b = self.node_b
h = self.current_t - self.previous_t
lh = self.l / h
if self.node_b >= 0:
B[self.node_b][self.branch_current_node] = -1
C[self.branch_current_node][self.node_b] = -1
if self.node_a >= 0:
B[self.node_a][self.branch_current_node] = 1
C[self.branch_current_node][self.node_a] = 1
D[self.branch_current_node][self.branch_current_node] = -lh
M = np.block([[Y,B],[C,D]])
RHS_Top = np.zeros((mat_cons[0][0], 1))
RHS_Bot = np.zeros((mat_cons[2][0], 1))
RHS_Bot[self.branch_current_node] = -lh * self.ip
RHS = np.block([[RHS_Top], [RHS_Bot]])
return [M, RHS]
class Capacitor:
def __init__(self, func, a, b):
self.node_a = a - 1
self.node_b = b - 1
self.c = 0
self.func = func
self.previous_t = 0.0
self.current_t = 0.0
self.vp = 0
self.ip = 0
def set_voltages_currents(self, v, c):
if self.node_b > 0 and self.node_a > 0:
self.vp = v[self.node_a] - v[self.node_b]
elif self.node_b <= 0 and self.node_a > 0:
self.vp = v[self.node_a]
elif self.node_b > 0 and self.node_b <= 0:
self.vp = -v[self.node_b]
def set_time(self, t):
self.previous_t = self.current_t
self.current_t = t
self.c = self.func(t)
def needs_branches(self):
return False
def set_branch_current_node(self, a):
self.branch_current_node = a
def get_matrix(self, mat_cons):
Y,B,C,D = Create_MNA(mat_cons)
a = self.node_a
b = self.node_b
h = self.current_t - self.previous_t
ch = self.c / h
if b >= 0:
Y[b,b] = ch
if a >= 0:
Y[a,a] = ch
if a >= 0 and b >= 0:
Y[a,b] = -ch
Y[b,a] = -ch
M = np.block([[Y,B],[C,D]])
RHS_Top = np.zeros((mat_cons[0][0], 1))
RHS_Bot = np.zeros((mat_cons[2][0], 1))
if a > 0:
RHS_Top[a] = ch * self.vp
if b > 0:
RHS_Top[b] = - ch * self.vp
RHS = np.block([[RHS_Top], [RHS_Bot]])
return [M, RHS]
def run( netlist, t0, t1, points):
counter = 0
nodes = list()
for j in netlist:
if j.needs_branches():
j.set_branch_current_node(counter)
counter += 1
nodes.append(j.node_a)
nodes.append(j.node_b)
max_node = max(nodes) + 1
Y = (max_node,max_node)
B = (max_node,counter)
C = (counter,max_node)
D = (counter,counter)
M = (max_node+counter, max_node+counter)
RHS = (max_node+counter, 1)
mat_cons = [Y,B,C,D]
t_space = np.linspace(t0,t1,points)[1:]
answer_array = list()
answer_array.append(list())
for i in range(0,M[0]):
answer_array.append(list())
for t in range(0, len(t_space)):
mat = np.zeros(M)
rhs = np.zeros(RHS)
for i in netlist:
i.set_time(t_space[t])
m, r = i.get_matrix(mat_cons)
mat += m
rhs += r
ans = linalg.lstsq(mat,rhs)[0]
voltages = ans[:max_node]
currents = ans[max_node:]
voltages = [v[0] for v in voltages]
currents = [c[0] for c in currents]
for j in netlist:
j.set_voltages_currents(voltages, currents)
answer_array[0].append(t_space[t])
for i in range(0, len(ans)):
answer_array[i+1].append(ans[i][0])
return answer_array
def R_func(t):
return 1/1000.0
def V1_func(t):
#if t > 0.00001 * 0.5:
# return 5
#else:
# return 0
v = 0
for i in range(1, 10, 2):
v += (10.0/i)*sin(2*pi*i*1000000.0*t)
return v
def L_func(t):
return 1.0e-9
def C_func(t):
return 1000.0e-12
def C1_func(t):
return 1.0e-12
def V2_func(t):
if t == 0.0:
return -2.5
else:
return 0
netlist = [
Voltage_Supply(V1_func, 0, 1),
#Inductor(L_func, 1, 2),
Capacitor(C1_func, 1, 2),
Resistance(R_func, 1, 2),
Capacitor(C_func, 2, 0),
Resistance(R_func, 2, 0)
#Voltage_Supply(V2_func, 0, 3)
]
ans = run(netlist, 0.0, 0.00001, 100000)
plt.plot(ans[0],ans[1], 'r')
plt.plot(ans[0],ans[2], 'g')
#plt.plot(t, outs[3])
plt.show()
plt.plot(ans[0], ans[3], 'r')
plt.show()