Because of my struggle getting analog multipliers and voltage-controlled amplifiers to work correctly, I decided to write a behavioural spice model for a magical component with ideal functionality.

I found a page in the Ngspice manual to learn how to write behavioural models. I also tried asking ChatGPT for help.

Here is a spice model which should work, but doesn’t:

.SUBCKT VoltageMultiplier IN1 IN2 OUT VCC VEE
VOUT OUT VEE DC {V(IN1) * V(IN2)}
.ENDS VoltageMultiplier

Here is the output when trying to run a transient simulation with this component in Kicad:

Note: Compatibility modes selected: ps a
Circuit: KiCad schematic
Netlist line no. 0:
Undefined parameter [v]
Netlist line no. 0:
Expression err: v(in1)*v(in2)}
Netlist line no. 0:
Cannot compute substitute
Please check your input netlist.
Error: ngspice.dll cannot recover and awaits to be detached
******
** ngspice-41 shared library
** Creation Date: Thu Aug 17 08:23:22 UTC 2023
******
Note: No compatibility mode selected!
Circuit: *
Warning: No job (tran, ac, op etc.) defined:
run simulation not started

It doesn’t understand the V() function? Why not? Why wouldn’t it? This function is supposed to return the voltage at the specified pin. It shows it in the Ngspice manual, and it’s very basic, so I don’t see why it wouldn’t work.

It’s clear that the V() function is the problem, as it does allow me to make a fixed voltage source like this:

.SUBCKT VoltageMultiplier IN1 IN2 OUT VCC VEE
VOUT OUT VEE DC {2}
.ENDS VoltageMultiplier

I’m not sure that you can do math / call functions in the parameter list for a V source (linear independent). At least I would be very surprised if you could make the voltage of an independent source dependent on the voltage at another node - that’s contrary to the definition of an independent source.

I suspect you need to use a B source (behavioral) - see chapter 5.

I found a solution that works from the Ngspice manual Chapter 12. The voltage multiplier is now doing what it’s supposed to using XSPICE extensions. Here is my properly working model:

.SUBCKT VoltageMultiplier IN1 IN2 OUT VCC VEE
a1 [%vd(IN1, VEE) %vd(IN2, VEE)] OUT multiply
.ENDS VoltageMultiplier
.model multiply mult( out_gain =2.0)

It would be more convenient if I could just use mathematical expressions rather than these functions, but I’m happy that I found a way to get it working.

Unfortunately, the limit and sqrt functions didn’t work using a B source, though Ngspice didn’t explicitly say that these functions were unrecognized. It just gave the dubious “timestep too small” error when I tried adding them.

sqrt should work in B sources per the manual, although it wouldn’t shock me if one math function or another might provoke convergence issues (“timestep too small” is often caused by discontinuities in model behavior).

Offhand I’m not exactly sure what limit does / what your goal is, but if it’s a clamping type of function, you can probably model that as a piecewise B-source using the ternary syntax. That also would also make me look out for simulation issues at the discontinuities.

Sometimes you can work around convergence issues by adding weak (large) parallel resistors which shouldn’t affect the simulation accuracy but help the the matrix be less pathological. There are also a lot of simulator options (manual section 15.1) that you can play with, some of which may help.

Or keep using what you have if that’s working Just options.

I have gotten the sqrt working in a simple circuit, but it makes it more likely to result in the mysterious error. Strangely, I once got the simulation to run partially, and it stopped prematurely because there was a value (presumably negative) that can’t be square-rooted. Weirdly, using the max function to prevent a negative number just made the simulation not work at all.