SkiDL+NgSpice (via PySpice): simulating a simple parallel resistors circuit's power outputs

Hi folks, this seems to be the first post over this forum, hopefully it’s not too soon to start asking questions? :slight_smile:

I’m extending a bit one of the SKiDL simulation tutorials, as presented in this Jupyter notebook with a simple resistor (among other more complex examples):

My intention is to extend the single resistor example with a netlist of several resistors in parallel (a 19x19 matrix), something like this:

#!/usr/bin/env python

from skidl.pyspice import R, V, gnd, u_V
from skidl.pyspice import u_Ohm, u_kOhm
from skidl.pyspice import generate_netlist, reset, lib_search_paths, node

reset()  # This will clear any previously defined circuitry.

# Voltage Source
vs = V(ref="VS", dc_value = 1 @ u_V)

rnet = []

# Create several resistors.
rnet = 19*19*R(value = 1.7 @ u_kOhm)

# Connect the nets and resistors.
vs['p'] += [rnet[n][1] for n in range(0, 19*19)]
gnd += [rnet[n][2] for n in range(0, 19*19)]
gnd += vs['n']

# Simulate the circuit.
circ = generate_netlist()              # Translate the SKiDL code into a PyCircuit Circuit object.
sim = circ.simulator()                 # Create a simulator for the Circuit object.
dc_vals = sim.dc(VS=slice(1, 24, 1))  # Run a DC simulation where the voltage ramps from 1 to 12V by 1V increments.

# Get the voltage applied to the resistor and the current coming out of the voltage source.
voltage = dc_vals[node(vs['p'])]
current = -dc_vals['VS']

# Print a table showing the current through the resistor for the various applied voltages.
print('{:^7s}{:^7s}{:^7s}'.format('V', ' I (A)', "P (W)"))
print('='*25)
for v, i, p in zip(voltage.as_ndarray(), current.as_ndarray(), voltage.as_ndarray()*current.as_ndarray()):
    print('{:6.2f} {:6.2f} {:6.2f}'.format(v, i, p))

Unfortunately the output looks something like this:

$ ./skidl_sim.py

No errors or warnings found during netlist generation.

warning, can't find model at
Warning: r1: resistance to low, set to 1 mOhm
Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Note: Starting dynamic gmin stepping
Trying gmin =   1.0000E-03 Note: One successful gmin step
Trying gmin =   1.0000E-04 Note: One successful gmin step
Trying gmin =   1.0000E-05 Note: One successful gmin step
Trying gmin =   1.0000E-06 Note: One successful gmin step
Trying gmin =   1.0000E-07 Note: One successful gmin step
Trying gmin =   1.0000E-08 Note: One successful gmin step
Trying gmin =   1.0000E-09 Note: One successful gmin step
Trying gmin =   1.0000E-10 Note: One successful gmin step
Trying gmin =   1.0000E-11 Note: One successful gmin step
Trying gmin =   1.0000E-12 Note: One successful gmin step
Trying gmin =   1.0000E-12 Note: One successful gmin step
Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Warning: Dynamic gmin stepping failed
Note: Starting source stepping
Supplies reduced to   0.0000% Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Trying gmin =   1.0000E-02 Note: One successful gmin step
Trying gmin =   1.0000E-03 Note: One successful gmin step
Trying gmin =   1.0000E-04 Note: One successful gmin step
Trying gmin =   1.0000E-05 Note: One successful gmin step
Trying gmin =   1.0000E-06 Note: One successful gmin step
Trying gmin =   1.0000E-07 Note: One successful gmin step
Trying gmin =   1.0000E-08 Note: One successful gmin step
Trying gmin =   1.0000E-09 Note: One successful gmin step
Trying gmin =   1.0000E-10 Note: One successful gmin step
Trying gmin =   1.0000E-11 Note: One successful gmin step
Trying gmin =   1.0000E-12 Note: One successful gmin step
Note: One successful source step
Supplies reduced to   0.1000% Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Supplies reduced to   0.0000% Warning: singular matrix:  check nodes <skidl.part.pinnumbersearch and <skidl.part.pinnumbersearch
Warning: source stepping failed
doAnalyses: iteration limit reached
run simulation(s) aborted
   V    I (A)  P (W)
=========================

Can anybody let me know what’s going on? Which syntax should I be using to define that resistor “network” so that ngspice accepts it as well-defined?

I edited your code. You only had a single, tiny mistake: you created an actual resistor that was added to the netlist, and then you created an additional 19*19=361 resistors from that one. This gave you a total of 362 resistors, but you only connected 361 of them. That dangling resistor seems to cause the problem.

By making the first resistor a TEMPLATE, then it isn’t actually added to the netlist but it can serve as a template for making other resistors. Once I did that, everything worked as expected.

#!/usr/bin/env python

from skidl import TEMPLATE
from skidl.pyspice import R, V, gnd, u_V
from skidl.pyspice import u_Ohm, u_kOhm
from skidl.pyspice import generate_netlist, reset, lib_search_paths, node

reset()  # This will clear any previously defined circuitry.

# Voltage Source
vs = V(ref="VS", dc_value = 1 @ u_V)

rnet = []

# Create several resistors.
# I changed it so the resistor was a template that is then replicated to create the actual resistors.
rnet = 19*19*R(value = 1.7 @ u_kOhm, dest=TEMPLATE)

# Connect the nets and resistors.
vs['p'] += [rnet[n][1] for n in range(0, 19*19)]
gnd += [rnet[n][2] for n in range(0, 19*19)]
gnd += vs['n']

# Simulate the circuit.
circ = generate_netlist()              # Translate the SKiDL code into a PyCircuit Circuit object.
sim = circ.simulator()                 # Create a simulator for the Circuit object.
dc_vals = sim.dc(VS=slice(1, 24, 1))  # Run a DC simulation where the voltage ramps from 1 to 12V by 1V increments.

# Get the voltage applied to the resistor and the current coming out of the voltage source.
voltage = dc_vals[node(vs['p'])]
current = -dc_vals['VS']

# Print a table showing the current through the resistor for the various applied voltages.
print('{:^7s}{:^7s}{:^7s}'.format('V', ' I (A)', "P (W)"))
print('='*25)
for v, i, p in zip(voltage.as_ndarray(), current.as_ndarray(), voltage.as_ndarray()*current.as_ndarray()):
    print('{:6.2f} {:6.2f} {:6.2f}'.format(v, i, p))
1 Like