Ngspice is always right (KiCAD-ngspice transient analysis simulation debugging)

Obviously that is not true but helps to find your mistakes in your “Transient Analysis”!

Time step is too small:

  • This is the most frequent error and is very annoying because it has nothing to do with the problem
  • “Often stems from numerical instability caused by floating (unconnected) nodes, inconsistent definitions, or problematic source configurations.” - ChatGPT (It actually helped.)
  • Something is not right in your circuit. This does not mean changing the timestep or putting in control statements does not help to get a result. It will not remove the problem and more headache is coming.
  • Check: missing SPICE model or subcircuit
  • Check: if you used the correct file of the model you wanted, copy all model files in the working directory! Do not link, or browse from distant folders! Prefer one model per file, no big bundles! (Those burn energy.)
  • Check: if the model’s pinout is connected correctly to the symbol
  • Run Electrical Rules Checker, look for unconnected, multiple labels in one node
  • Have you moved a label, added a new label, deleted a label from somewhere and now there is a lonely label not connected to anything
  • Is there a lot of switching:
    .options method=gear chgtol=1e-11 reltol=0.01 rshunt=1G rseries=0.05 cshunt=1p trtol=1 - Holger’s tip
    (ngspice manual 43plus: 11.1.4 Transient Analysis Options)

The graph does not look like it should:

  • Circuit is just warming up, caps are charging. The time-frame is too short and you only see the startup of the circuit
  • Are the opamps in the correct direction? Noninv ↔ Inv!
  • “Timestep is too long so it just jumps over rapid changes and shows a line” - You could think that but that timestep in the settings is just “drawing” timestep and if you set 1sec and 1 sec to Timestep and Final time it still will show the 100hz wave. So you still have a problem in your circuit. If you set it smaller you can make cleaner graphs, spikes and ripples vanish etc. and it slows the calculation a lot.
    “runs into trouble and keeps backing up, making the
    internal timestep smaller in an attempt to not guess so far into the future
    from the last known good point.” - Re: [Ngspice-users] Timestep too small: how to avoid it?
    So “Max timestep does that” and when it is not given it is 50 step resolution between start_time and end_time.

Simulation just calculates, just calculates, rows are not changing in the output:

  • Something is not right in your circuit
  • I made this by putting a voltage source - or on top of another - somewhere inside to simulate a changing voltage
  • Run Electrical Rules Checker, look for the “power” message, add PWR_FLAG

Simulation was good a second ago and now is acting weird:

  • Do not think you found every mistake. Many times something very obvious is there. Leave it alone for a day.
  • KiCad creates many backups. Make a backup of the the backup with a telling name when you reached progress because you will mess it up again when you are trying to find your next bug!
  • Divide the circuit into blocks and shut them off one by one with the Attributes->Exclude from simulation
  • Do not forget there can be excluded parts in your circuit! :slightly_smiling_face:
  • “Excluding from simulation” function sometimes make very unexpected things. Sometimes everything breaks down after I turn on something that was good before.
  • Sometimes I need to restart everything or just close the simulation window and start a new one.
  • When you work out a problem in one project and copy it back to the main schematic … it can bring back something (scary) that messes up the whole simulation. Having the separate test project is reassuring that part is working. (KiCAD 8.0.8.)

Make labels group by parts of your circuit: supply_…, pwm_in, pwm_out, pwm_trigger so it is easy to find them in the list.

Make dual/quad models easy to import in KiCad (less wasted energy when you need to check if everything is in place):

.subckt LMX24_LM2902_QUAD U1_out U1_inv U1_noninv Vpoz U2_noninv U2_inv U2_out U3_out U3_inv U3_noninv Vneg U4_noninv U4_inv U4_out
XU1 U1_noninv U1_inv Vpoz Vneg U1_out LMX24_LM2902
XU2 U2_noninv U2_inv Vpoz Vneg U2_out LMX24_LM2902
XU3 U3_noninv U3_inv Vpoz Vneg U3_out LMX24_LM2902
XU4 U4_noninv U4_inv Vpoz Vneg U4_out LMX24_LM2902
.ends LMX24_LM2902_QUAD
.subckt LM339_QUAD U2_out U1_out Vpoz U1_inv U1_noninv U2_inv U2_noninv U4_inv U4_noninv U3_inv U3_noninv Vneg U3_out U4_out
XU1 U1_noninv U1_inv Vpoz Vneg U1_out LM339A
XU2 U2_noninv U2_inv Vpoz Vneg U2_out LM339A
XU3 U3_noninv U3_inv Vpoz Vneg U3_out LM339A
XU4 U4_noninv U4_inv Vpoz Vneg U4_out LM339A
.ends LM339_QUAD

The parameters in the order of the KiCAD symbol, so the pins should be in the correct order. I put these in the bottom of the original SPICE-model file.
Rename the model file if you mess with it! “LM324new.symforKiCAD.cir”

(I also have to say the residual-current device (RCD) is also always right. Except when it is not but that is an exception not a general thing. So you have to look for mice in the heating unit. That is the true backstory of this wise remark.)

Correct me if I am wrong!
Thanks!

2 Likes

Lots of good tips here. I will add:

Some circuits are difficult to simulate no matter what, like those that have time constants that are one or more orders of magnitude different. Switching power converters are one such type of circuit.

Do not trust vendors’ subcircuit models. They might be fine. They might be partially or completely wrong, they might only work in a narrow range, or they might contain hidden widely different time constants, discontinuities, or other such numerical bugaboos. Some of them have built-in spice errors and will bring the simulator to a grinding halt. If you have problems, it’s good practice to check vendor-supplied models.

Don’t put complete faith in results. Spice and its relatives are powerful, useful, and in many cases necessary to design and understand circuit behavior. However, you should have a qualitative idea of what to expect. Dig into the areas where expectations and results diverge.

John

3 Likes

There is no .step in ngspice but there are expressions for component values. If you want to see the effect of different values of a resistor for example choose “Behavioral” from the simulation model and give an expression instead of a static value: ‘200 + 40.18 * time’
(So it goes from 200ohms to 240.18ohms in 1 sec.)
Do not let it go to zero! Between " ’ " and use spaces! “time” is a builtin variable in seconds.

PT100 simulation with a simple resisitor (270-380°C): ’ 200 + 40.18 * (0.5 + 0.5 * cos( 2 * pi * time / 2)) ’

You can use c style expressions to set the value:
https://nmg.gitlab.io/ngspice-manual/interactiveinterpreter/expressions,functions,andconstants.html

Here is a pot turning itself:
spinningpot.lib

* "spinning" (+0.002ohm error to avoid zero)
* rt: one rotation's time in seconds

.subckt spiningpot r0 wiper r1 r=10k rt=1
rupper r1 wiper r = { (0.5 - 0.5 * cos( 2 * pi * time / rt )) * r + 0.001 }
rlower wiper r0 r = { (0.5 + 0.5 * cos( 2 * pi * time / rt )) * r + 0.001 }
.ends spiningpot

spinningpot is what you need to select in the simulation model after you choose the file
r0, wiper and r1 are the pins of the potentiometer
r and rt are variables in the simulation settings, total resistance and rotation time in seconds
rupper and rlower are resistors inside the model and starting with “r” declare they are resistors, they have inherently two nodes connected to the listed other nodes after their name

Then you can read the time of interesting point from the graph and put it in the formula above to get what is the resistance at that point.

2 Likes


switchingswitch.lib (525 Bytes)

* switchingswitch.lib
* a switch/resitor turning on and off 50% of the given time period
* save to a file in project library > switch symbol > "Simulation Model" button > SPICE model from file > File: switchingswitch.lib, Model: switchingswitch then set parameters at the bottom table
* starting OFF
* period in second
* Ron: on resistance
* Roff off resistance 

.subckt switchingswitch r0 r1 roff=100Meg ron=0.001 period=0.5
rinside r0 r1 r = { (time/period - floor(time/period)) > 0.5 ? ron : roff }
.ends switchingswitch

roff=100Meg or 100G might be better (Fixed. Thank you, Holger!)

Just beware of the spice trap:

1M == 1e-3
1Meg == 1e6

3 Likes