MSP Simulation Example - Modified Nodal Analysis - with DPsim

Sample Circuit

$R_1$=$1 \Omega$, $R_2$=$1 \Omega$, $R_3$=$10 \Omega$, $R_4$=$5 \Omega$
$I_1$=$1 A$, $V_{0}$=$10 V$

Run simulation

Using the MNA-based C++ solver DPsim for power system simulation

In [1]:
import dpsim

model_name = 'EMT_VS_CS_R4_AC'
final_time = 0.0002
time_step = 0.0001

# Nodes
gnd = dpsim.emt.Node.GND()
n1 = dpsim.emt.Node('n1')
n2 = dpsim.emt.Node('n2')
n3 = dpsim.emt.Node('n3')

# Components
vs = dpsim.emt.ph1.VoltageSource('vs')
vs.V_ref = complex(10,0)
vs.f_src = 0
r1 = dpsim.emt.ph1.Resistor('r1')
r1.R = 1
r2 = dpsim.emt.ph1.Resistor('r2')
r2.R = 1
r3 = dpsim.emt.ph1.Resistor('r3')
r3.R = 10
r4 = dpsim.emt.ph1.Resistor('r4')
r4.R = 5
cs = dpsim.emt.ph1.CurrentSource('cs')
cs.I_ref = complex(1,0)
cs.f_src = 0


vs.connect([gnd, n1])
r1.connect([n1, n2])
r2.connect([n2, gnd])
r3.connect([n2, n3])
r4.connect([n3, gnd])
cs.connect([gnd, n3])

system = dpsim.SystemTopology(0, [gnd, n1, n2, n3], [vs, r1, r2, r3, r4, cs])

logger = dpsim.Logger(model_name)
logger.log_attribute(n1, 'v');
logger.log_attribute(n2, 'v');
logger.log_attribute(n3, 'v');
logger.log_attribute(r1, 'i_intf');
logger.log_attribute(r3, 'i_intf');

sim = dpsim.Simulation(model_name, system, timestep=time_step, duration=final_time, pbar=True, sim_type=1, log_level=1)
sim.add_logger(logger)

sim.start()

Analyze simulation log

Read log

In [2]:
from villas.dataprocessing.readtools import *
from villas.dataprocessing.timeseries import *
import re

work_dir = 'logs/'
log_path = work_dir + model_name + '_Solver.log'
log_lines, log_sections = read_dpsim_log(log_path)

Show node detection log

In [3]:
for line_pos in log_sections['nodenumbers']:
    print(log_lines[line_pos])
[I] Number of network nodes: 3
[I] Number of network and virtual nodes: 4

Show matrix stamping log

In [4]:
for line_pos in log_sections['sysmat_stamp']:
    print(log_lines[line_pos])
[D] Stamping EMT::Ph1::VoltageSource vs into system matrix:
0.000000e+00 0.000000e+00 0.000000e+00 1.000000e+00
0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[D] Stamping EMT::Ph1::Resistor r1 into system matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  1.000000e+00  0.000000e+00  0.000000e+00
 0.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
[D] Stamping EMT::Ph1::Resistor r2 into system matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  2.000000e+00  0.000000e+00  0.000000e+00
 0.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
[D] Stamping EMT::Ph1::Resistor r3 into system matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  2.100000e+00 -1.000000e-01  0.000000e+00
 0.000000e+00 -1.000000e-01  1.000000e-01  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
[D] Stamping EMT::Ph1::Resistor r4 into system matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  2.100000e+00 -1.000000e-01  0.000000e+00
 0.000000e+00 -1.000000e-01  3.000000e-01  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
[D] Stamping EMT::Ph1::CurrentSource cs into system matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  2.100000e+00 -1.000000e-01  0.000000e+00
 0.000000e+00 -1.000000e-01  3.000000e-01  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00

Show source vector log

In [5]:
for line_pos in log_sections['sourcevec_stamp']:
    print(log_lines[line_pos])
[D] Stamping EMT::Ph1::VoltageSource vs into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)
[D] Stamping EMT::Ph1::Resistor r1 into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)
[D] Stamping EMT::Ph1::Resistor r2 into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)
[D] Stamping EMT::Ph1::Resistor r3 into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)
[D] Stamping EMT::Ph1::Resistor r4 into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)
[D] Stamping EMT::Ph1::CurrentSource cs into source vector:
(0.000000e+00,0.000000e+00)
(0.000000e+00,0.000000e+00)
(1.000000e+00,0.000000e+00)
(1.000000e+01,0.000000e+00)

Show LU decomposition of final system matrix

In [6]:
for line_pos in log_sections['sysmat_final']:
    print(log_lines[line_pos])
for line_pos in log_sections['ludecomp']:
    print(log_lines[line_pos])
[I] System matrix:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  2.100000e+00 -1.000000e-01  0.000000e+00
 0.000000e+00 -1.000000e-01  3.000000e-01  0.000000e+00
 1.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
[I] LU decomposition:
 1.000000e+00 -1.000000e+00  0.000000e+00  1.000000e+00
-1.000000e+00  1.100000e+00 -1.000000e-01  1.000000e+00
 0.000000e+00 -9.090909e-02  2.909091e-01  9.090909e-02
 1.000000e+00  9.090909e-01  3.125000e-01 -1.937500e+00

Read and show solution log

In [7]:
work_dir = 'logs/'
model_name = 'EMT_VS_CS_R4_AC'
log_path = work_dir + model_name + '.csv'
ts_dpsim_emt = read_timeseries_dpsim(log_path, print_status=False)
for key, val in ts_dpsim_emt.items():
    print(key + ': ' + str(val.values[0]))
n1.v: 10.0
n2.v: 5.0
n3.v: 5.0
r1.i_intf: -5.0
r3.i_intf: -0.0
In [ ]: