Potentiometer model in Big Muff circuit

Hi,
I am using Kicad 8.0.5 on Linux with ngspice 42. I was trying to simulate the Big Muff equalizer with the potentiometer model provided by Kicad/Eeschema.
Some results of the AC simulation do not make sense for an entirely passive filter: the gain exceeds 0dB.
Instead, the results seem reasonable when using two resistors instead of the potentiometer.

The transient results are fine.

Any idea of what exactly the problem is ? I really appreciate Kicad’s potentiometer for the possibility of fine-tuning the wiper position in simulation GUI.


Bug.cir (356 Bytes)

The intrinsic potentiometer model seems to be buggy when simulating small signal ac.
It will need some time to figure out how to fix the error.

In the meantime you may use the following potentiometer model:

* potentiometer model
* wiper position limited between 0.001 and 0.999
* author Holger Vogt, Oct. 3rd 2024

.subckt pot1 r0 wiper r1  r = {r} pos = {pos}

rupper r1 wiper r = {(1 - ((pos >=1) ? 0.999 : ((pos <= 0) ? 0.001 : pos))) * r}
rlower wiper r0 r = {((pos >=1) ? 0.999 : ((pos <= 0) ? 0.001 : pos)) * r}

.ends

in a circuit (standard ngspice) like

.title KiCad schematic
.save all
.control
version -s
.endc
.include pot_mod1.lib

V1 /Vin 0 DC 0 SIN( 0 1 1k 0 0 0 ) AC 1  
xpot 0 /Vout1 /Vin pot1 r=100k pos=0.45

.control
ac dec 10 10 100k
plot mag("/vout1") mag("/vin")
.endc

.end

So put the model into a file (e.g. named pot_mod1.lib) and attach it to the potentiometer symbol in the usual way.

Thanks @holger for the reply. Do you confirm that there is no way to tune the wiper position in the simulation GUI using a model like yours, in a separate file ?

1 Like

Currently I confirm that I am not able to put the subcircuit parameters r and pos into the Sim.Params (or Value) field of the symbol and show them, make them editable on the Eeschema canvas.

This seem to be a regression bug, as it has been possible in the past. I have to check that issue.

With my setup (Kicad 8.0.5 on Linux), I do not observe this regression.

My formulation is not correct: It is not added automatically (which has been possible in the past), but you can do it manually. Then you will have the possibility to edit the potentiometer values in the Eeschema GUI.

I have modified the model a bit:

.subckt pot1 r0 wiper r1 params: r = 1k pos = 0.45
rupper r1 wiper r = {(1 - ((pos >=1) ? 0.999 : ((pos <= 0) ? 0.001 : pos))) * r}
rlower wiper r0 r = {((pos >=1) ? 0.999 : ((pos <= 0) ? 0.001 : pos)) * r}
.ends

so not using ngspice parameters in {}, but offereing default values directly…

See a small video attached:

Thanks @holger to take the time to provide all this explanations.
Indeed, I am able to modifiy the wiper position in the Eeschema GUI and I appreciate this possiblity.
But what I would like much better is to be able to obtain the vertical slider in the simulation GUI that changes the wiper position, with real-time updates of the Bode diagram.

Attached you will find a small project with an voltage controlled potentiometer.
epot.7z (4.6 KB)

Unfortunately you cannot tune voltage sources, but resistors for example. So create the voltage with a constant current source and a tuned resistor.

Unfortunately one cannot save the tuner in the *wbk file, so you have to add it anew when opening the simulator window.

1 Like

That’s a neat workaround. Thanks for sharing @holger !

I have a last question and if that is best I can open a new topic for that. In order to limit the value of the wiper parameter, you use quite a lot of ternary operators in your models. Is there a reason to prefer this approach over one-liners like

.param w=limit(pos,1m,.999)

?

I did not think about the limit function.

Probably it is not available for behavioral resistors R=‘expression’

@holger The solution to the issue might be easier than expected. I found out that the results are OK if I set the parameter r of the potentiometer to the opposite of the desired value. It looks like the values of ac_gain.real here should be negated.

I finally got my Big Muff working as expected !

Would it be a bit simpler to add series resistances to the model instead of limiting the wiper with this 0.001 and 0.999 stuff?

But my wish would be to handle this on a deeper level, so ngSpice would be able to handle zero ohm resistors in a “usable” way without any further hickups. Would unrealistically low ohmic resistors such as a nano Ohm be enough to satisfy the algorithm while have no practical detrimental effect?

@paulvdh it might be a good idea however to keep a constant factor between the smallest resistor value (wiper at extreme positions) and the total impedance. At least that is my understanding of the ill-conditioning problems occurring when solving the system of equations. My guess is that the effect of a 1nOhm resistor will not be the same with a pot of 1kOhm and one of 1MOhm.

Ngspice’s internal potentiometer model does limit the wiper position to the values 1e-9 or 0.999999999. Once the fix for this model (AC behavior) gets released, there will be no need for .subckt solution.

I am now attempting to sort and do “something” with the gazillion random spice models I have collected from random places (I actually just want an NE5532 BD139 / BD140 and TIP41C / TIP42C right now) and I have not decided on a way of organizing yet.

But I digress (again).
In the Bordodynovs Electronics Lib, I stumbled upon Pote.lib which has a library with about 25 different models for emulating potentiometers. and potentiometer.cir which has some more (also overlapping).

Pote.lib (16.3 KB)
potentiometer.cir (2.3 KB)

It also has a potentiometr.sub, R-poti.lib, pot.lib and probably more. It’s just a big mess.

There is also a potentiometer in the ngSpice manual, chapter 12.2.34 and that one “works” with nine decimals:

12.2.34 Potentiometer
NAME_TABLE:
Spice_Model_Name: potentiometer
C_Function_Name: cm_potentiometer
Description: “potentiometer”
. . .

Description: A resistance potentiometer with three connections: r0, wiper , and r1.
Parameter position determines the lower and upper portions of the resistance.
Rlower is located between r0 and wiper, Rupper between wiper and r1. If log is
set to FALSE, Rlower = position ∗ r. If log is set to TRUE, then
Rlower = r ∗ 10−position∗log_multiplier. For Rupper we always have
Rupper = r − Rlower. position <= 0 is resolved to position = 1e − 9,
position >= 1 is resolved to position = 0.999999999

On my breadboards, I tend to put a resistor in series with the wiper. I started doing this after I destroyed a few potentiometers by over current when they were set to one of the extreme positions.

And some are here: More simulation examples for KiCad/Eeschema/ngspice (scroll down a bit).