# Understanding LTspice curly brace substitution

I am trying to get my head around the specific details of how to use curly braces in LTspice. My end goal is to have a random value be generated and used before the start of a simulation for e.g. a resistor value. While playing around I happened to have something like this:

R=myfunc({flat(1)})+1


as the value of a resistor.

Then I define the function

.func myfunc( x ) { ( x + x ) -  2*x }


Now the LTspice documentation states:

When curly braces are encountered, the enclosed expression is evaluated on the basis of all relations available at the scope and reduced to a floating point value.

or

To invoke parameter substitution and expression evaluation with these user-defined functions, enclose the expression in curly braces. The enclosed expression will be replaced with the floating-point value.

at various places in .func and .param documentation. From this I would expect the above to always return 1 Ω for the resistor, because the random value is passed as a float to the function, however, it looks like x is evaluated multiple times, as for many runs via .step I get multiple different values but never 1... For transient and DC operating point it's the same...

What is going on here? Did x become a reference to that flat(1) call and only really substituted for the float value when it is "really used"? That doesn't really sound like it's replaced with the floating-point value at that specific point where it is encountered...

As requested an example .asc file of the function in use ( I guess thats a bit more convenient than the netlist ):

Version 4
SHEET 1 880 680
FLAG 144 176 0
FLAG 64 96 0
SYMBOL res 128 80 R0
SYMATTR InstName R1
SYMATTR Value R=myfunc({flat(1)})+1
SYMBOL voltage 160 96 R90
SYMATTR InstName V1
SYMATTR Value 1
TEXT 206 210 Left 2 !.tran 1m
TEXT 424 48 Left 2 !.func myfunc( x ) { ( x + x ) -  2*x }
TEXT 208 240 Left 2 !.step param r 0 10 1
TEXT 208 272 Left 2 !.meas ii avg I(R1)

• Where is "x" originally defined? It would help to provide a sample simulation showing this usage - the ASCII netlist would be most helpful. I'm no expert at LTspice but I have used it extensively and only more recently for some { } usages. Feb 22 at 22:09
• @PStechPaul x is the parameter to the myfunc(x) function. Just take any simulation with a resistor and pluck in the mentioned R= expression for the value, and put that function in there. Feb 22 at 22:11
• Please post one as an example. Should be easy enough, but easier for you than me, and that way others can see the problem and help without duplication of effort Thanks. Feb 22 at 22:15
• @PStechPaul I cobbled together a probably minimal .asc file, I guess most people will be more familiar with them than with netlists Feb 22 at 22:31

First to clarify for others, you're asking why the flat(1) string is passed into your function instead of an already evaluated flat(1) (resulting in a constant value). This is proved to be what is happening because your function should return zero if the same number is passed into x because your function should equal zero if all the $$\x\$$'s are the same: $$\(x+x)-2x = 0\$$

The curly braces in LTspice aren't well suited for forcing parameter evaluation at such fine control. They basically just flag that anything inside might require substitution/evaluation and you have no control how that's done. Also, quite important, nested curly braces are ignored. You used R=F(...) to define your resistor, which implies a behavioral resistor (in reality, a behavioral current source using the voltage across your "resistor" divided by your resistance function). LTspice already implies (under the hood again, of course) curly braces around the entire expression on the right side of that equals symbol. So you adding your own curly braces around flat(1) doesn't do anything since the entire expression has its own set of outer curly braces.

Basically, what this means is you cannot use the flat(x) function in this way. You need to evaluate it in its own .param statement and then you can pass that parameter into your myfunc(x). I modified your example into something that will work and posted it below.

Version 4
SHEET 1 880 680
WIRE 144 32 32 32
WIRE 32 64 32 32
WIRE 144 64 144 32
WIRE 32 176 32 144
WIRE 144 176 144 144
FLAG 144 176 0
FLAG 32 176 0
SYMBOL res 128 48 R0
SYMATTR InstName R1
SYMATTR Value R=myfunc(hey)+1
SYMBOL voltage 32 48 R0
SYMATTR InstName V1
SYMATTR Value 1
TEXT 208 208 Left 2 !.tran 1m
TEXT 424 48 Left 2 !.func myfunc( x ) { ( x + x ) -  2*x }
TEXT 208 288 Left 2 !.step param r 0 10 1
TEXT 208 320 Left 2 !.meas ii avg I(R1)
TEXT 208 256 Left 2 !.param hey=flat(1)

• I was afraid so. For my real world example I rearranged things to ue the passed value only once, otherwise I would have to add tons of little parameters for them... Feb 23 at 21:24
• @PlasmaHH Maybe you can try asking using a more specific example of what you want to acheive on the LTspice user groups. It's possible someone there might know an obscure workaround for this. Feb 23 at 22:33

Here is a time domain simulation for your ASCII file. I'm not sure what you are trying to do, actually.

• I am trying to understand why I get different values as a return for myfunc, as I would expect it to return 0 regardless of the input Feb 23 at 7:47
• It might be rounding error due to floating point vs integer values. Feb 23 at 19:58
• definetly not, plot V(p001)/I(R1) to see that it returns like between -1.5 and 1.5 or so Feb 23 at 21:21