3
\$\begingroup\$

I am trying to implement a subcircuit in LTSpice and I want the value of one input parameter to be a random value from a Gaussian distribution. However, LTspice is not recognizing the gauss() function even though it should and I do not know how to proceed.

.params Ron=4e5 Roff=3e10 Voff=0.1 mu=0.8690 sigma=0.1112 TAU=0.0001 T=298.5 x0=0 

* Function Gaussian Distribution
.func gc(a,b)=(a+a*gauss(b/3))

* Function F(V(t),x(t)) - Describes the SV motion
.func F(V1,V2) = (1/TAU)*((    1/(1+exp(-1/(T*boltz/echarge)*(V1-gc(mu,sigma))))   )*(1-V2)-(    1-(1/(1+exp(-1/(T*boltz/echarge)*(V1+Voff))))    )*V2

As you can see, I am trying to use the results of gc(mu,sigma) in the function F(V1,V2), but it is not working. How could I resolve this?

To specify "it's not working", I get an error message saying "syntax error - gauss(): no such function" when I try to run it.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ "It is not working" is never enough. "Doc, my leg hurts, what's the problem?". There simply isn't enough information for an answer. But you could try to conform with the rules for .func definitions, as per the manual: LTspice > Dot Commands > .FUNC, where it's specified that it must be of the form .func <name>([args]) {<expression>}, not .func <name>([args])=<expression>. E.g. func f(x) {x**2}, not .func f(x)=x**2. There have been discussions in the LTspice group about this, and it's related to parsing: it may work otherwise, but don't count on it. \$\endgroup\$ May 3, 2022 at 9:12
  • \$\begingroup\$ Thanks for your answer! To specify "it's not working", I get an error message saying "syntax error - gauss(): no such function" when I try to run it. \$\endgroup\$
    – user312677
    May 3, 2022 at 9:30

1 Answer 1

4
\$\begingroup\$

I see now. The problem is that the gauss() function cannot be called inside a .func, only in a .param; the same goes for flat(). I don't know why, or how it's implemented internally, but if it's an attempt at forbidding time-dependent arguments then it should be able to call it as gauss(3), for example, with a fixed argument -- yet it can't be done.

So, if what you want is a Gaussian distribution then you'll have to get a bit creative: use the central limit theorem to build an approximated Gaussian noise source from white noise, with white(): summing up several such white noise functions (of differently shifted arguments, to ensure uniqueness) will result in a Gaussian distribution. These functions are: rand() (generated sampled white noise from 0 to 1 V), random() (slightly smoothed out version of rand()), and white() (fully smoothed out rand(), from -0.5 V to 0.5 V). Summing 5 or so sources will give a good approximation for the noise. If you need 1 Vrms then consider that the white noise gives a flat distribution, and since it goes from -0.5 to 0.5, calculate the RMS of that ramp:

$$\sqrt{\int_{-\frac12}^\frac12{|x|^2\text{d}x}}=\dfrac{1}{\sqrt{12}} \tag{1}$$

With 5 such sources, the scaling needs to be done according to the summing of these sources, which increases their energy by the square root of their numbers. This normally counts for a bipolar signal, but the distribution, itself, will take place from 0 to 1 V (normal rand() output).

To give an example, for a 1000 s duration you can set the arguments for rand() to be equally spaced every other 1000 s, and for measurements use 0.2 scaling (5 equivalent sources). This is the result considering tests for steps of 0.1 V with 50 mV tolerance:

Gaussian distribution witn rand()

If you'll use random() or white() you will not get the same 1 Vrms with (1), but less, since they are smoothed out and so they lose high frequency energy.


As I see it in the OP, you are using a .func() with at least a voltage as argument, so you could simply use this voltage as V(x) instead of the gc(x,y) from the .func f(v1,v2) definition. Unfortunately, there's not much control over sigma, but it also looks like you're not interested in a time-dependent Gaussian distribution, so you can just define a .param, separately, and then use that inside the function:

.param a=<value> b=<value>
+ gc=a*(1+gauss(b/3))
.func f(v1,v2) {... gc ...}

Don't forget that LTspice (note the spelling), by default, uses a fixed seed for the random number generator, since SPICE is meant to be deterministic. You can override that by checking Control Panel > Hacks! > Use the clock to reseed the MC generator. The [*] means that the setting will be remembered across sessions.

\$\endgroup\$
5
  • \$\begingroup\$ That is really helpful, thank you! My question now would be: having this voltage source with a gaussian distribution, how could I feed these numbers back into my subcircuit as an input parameter? \$\endgroup\$
    – user312677
    May 3, 2022 at 12:29
  • 2
    \$\begingroup\$ @user312677 I've updated the answer. \$\endgroup\$ May 3, 2022 at 18:46
  • \$\begingroup\$ Thanks a lot!!! I solved the problem with your help. \$\endgroup\$
    – user312677
    May 4, 2022 at 12:35
  • \$\begingroup\$ Things get even more complicated. .function w() { flat(4) } and then a voltage source with value { w() } works .... it seems that they are not really functions ( which are callable per step ) but somehow a kind of substitutiuon feature which only runs at the start. If you put that (accidentally) as Value2 then you get an error showing a definition of V where the value is substituted directly \$\endgroup\$
    – PlasmaHH
    Feb 19, 2023 at 15:09
  • \$\begingroup\$ @PlasmaHH flat() and gauss() (IIRC) are not time dependent, so they may well be only evaluated prior to simulation start. Yet, they are still functions, so it makes sense to use curly braces for element's values. Quite frankly, given the new "owners" of LTspice, I'm not really sure how things progress, anymore. I suppose it's one of those "wait and see". \$\endgroup\$ Feb 21, 2023 at 11:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.