Fast Fourier Transform in SPICE

Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.
Hi Rüdiger,

looks like two basic things, in order of importance:

1) turn off data compression (can be done in control panel-->compression or include a ".opt plotwinsize=0" command. (EDIT: saw you did that already)

2) use a small maximum timestep in the .tran analysis, something like 1/1000th of the test freq period. This can easily be parametrized:
.param freq=20kHz
.param period=1/freq ncycles=2
.tran 0 {ncycles*period} 0 {pi/3.14*period/2e3}
.four {freq} xyz

that last value in the .tran is the max timestep, here about 1/2000 of the period length. I make it a little odd with the 3.14/pi stuff, to avoid some spurious harmonics from computation with exact integer multiples. If you want to sim at sub-ppm THD levels, you have go down to 1/10000 or even less.

3) use the alternate solver (also in control panel), this sometimes improves accuracy (ususally rather complex circuits).

".four" takes (by overridable default) only the last period (referring to the freq. it calculates the FFT upon), so usually 2 periods are enough to simulate (assuming that the circuit stabilizes quickly)


- Klaus

Does OrCad PSPICE support .four {freq} xyz ? If I write it this way, o without {} it just says that is is an invalid number. I can't find a way to batch simulate transient analysis with frequency sweep for plotting THD vs. frequency plots. Any ideas how to do that?
 
Since we also talk here of plotting formulas like v(a)-v(b),
Would it be appropriate thread to ask if we can integrate
or average power v(a)*i(B) over time?
The function is native in LTspice:
Place your mouse pointer over a component, press Alt, the pointer changes to a thermometer, left click, you have a display of instantaneous power, then place the pointer over the trace name, press Ctrl, left click and you get the average + integral:
 

Attachments

  • LTexample.GIF
    LTexample.GIF
    39.2 KB · Views: 214
That answer is just way too simple to be true, its like cheating!
There has to be a more needlessly complex and difficult way???
Of, course: you can do it all by yourself, using the nuts and bolts available:
Code:
.FUNC -- User Defined Functions
 

Syntax: .func <name>([args]) {<expression>}

 

Example: .func Pythag(x,y) {sqrt(x*x+y*y)}

 

The .func directive allows the creation of user-defined functions for use with user parameterized circuits and behavioral sources. This is useful for associating a name with a function for the sake of clarity and parameterizing subcircuits so that abstract circuits can be saved in libraries.

 

The .func statement can be included inside a subcircuit definition to limit the scope the function to that subcircuit and the subcircuits invoked by that subcircuit.

 

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.

 

Below is a example using both a .func and .param statements.

 

* Example deck using a .func statement

.func myfunc(x,y) {sqrt(x*x+y*y)}

.param u=100 v=600

V1 a 0 pulse(0 1 0 1n 1n .5µ 1µ)

R1 a b {myfunc(u,v/3)}

C1 b 0 100p

.tran 3µ

.end

 

All parameter substitution evaluation is done before the simulation begins.


Code:
Function Name
 Description
 
abs(x)
 Absolute value of x
 
absdelay(x,t[,tmax])
 x delayed by t. Optional max delay notification tmax.
 
acos(x)
 Real part of the arc cosine of x, e.g., acos(-5) returns 3.14159, not 3.14159+2.29243i
 
arccos(x)
 Synonym for acos()
 
acosh(x)
 Real part of the arc hyperbolic cosine of x, e.g., acosh(.5) returns 0, not 1.0472i
 
asin(x)
 Real part of the arc sine of x, asin(-5) is -1.57080, not -1.57080+2.29243i
 
arcsin(x)
 Synonym for asin()
 
asinh(x)
 Arc hyperbolic sine
 
atan(x)
 Arc tangent of x
 
arctan(x)
 Synonym for atan()
 
atan2(y, x)
 Four quadrant arc tangent of y/x
 
atanh(x)
 Arc hyperbolic tangent
 
buf(x)
 1 if x > .5, else 0
 
ceil(x)
 Integer equal or greater than x
 
cos(x)
 Cosine of x
 
cosh(x)
 Hyperbolic cosine of x
 
ddt(x)
 Time derivative of x
 
delay(x,t[,tmax])
 Same as absdelay()
 
exp(x)
 e to the x
 
floor(x)
 Integer equal to or less than x
 
hypot(x,y)
 sqrt(x**2 + y**2)
 
idt(x[,ic[,a]])
 Integrate x, optional initial condition ic, reset if a is true.
 
idtmod(x[,ic[,m[,o]]])
 Integrate x, optional initial condition ic, reset on reaching modulus m, offset output by o.
 
if(x,y,z)
 If x > .5, then y else z
 
int(x)
 Convert x to integer
 
inv(x)
 0. if x > .5, else 1.
 
limit(x,y,z)
 Intermediate value of x, y, and z
 
ln(x)
 Natural logarithm of x
 
log(x)
 Alternate syntax for ln()
 
log10(x)
 Base 10 logarithm
 
max(x,y)
 The greater of x or y
 
min(x,y)
 The smaller of x or y
 
pow(x,y)
 Real part of x**y, e.g., pow(-1,.5)=0, not i.
 
pwr(x,y)
 abs(x)**y
 
pwrs(x,y)
 sgn(x)*abs(x)**y
 
rand(x)
 Random number between 0 and 1 depending on the integer value of x.
 
random(x)
 Similar to rand(), but smoothly transitions between values.
 
round(x)
 Nearest integer to x
 
sdt(x[,ic[,assert]])
 Alternate syntax for idt()
 
sgn(x)
 Sign of x
 
sin(x)
 Sine of x
 
sinh(x)
 Hyperbolic sine of x
 
sqrt(x)
 Square root of x
 
table(x,a,b,c,d,...)
 Interpolate a value for x based on a look up table given as a set of pairs of points.
 
tan(x)
 Tangent of x.
 
tanh(x)
 Hyperbolic tangent of x
 
u(x)
 Unit step, i.e., 1 if x > 0., else 0.
 
uramp(x)
 x if x > 0., else 0.
 
white(x)
 Random number between -.5 and .5 smoothly transitions between values even more smoothly than random().
 
!(x)
 Alternative syntax for inv(x)
 
~(x)
 Alternative syntax for inv(x)
 

 

o The following operations, grouped in reverse order of precedence of evaluation:

 

Operand
 Description
 
&
 Convert the expressions to either side to Boolean, then AND.
 
|
 Convert the expressions to either side to Boolean, then OR.
 
^
 Convert the expressions to either side to Boolean, then XOR.
 
 
  
 
>
 True if expression on the left is greater than the expression on the right, otherwise false.
 
<
 True if expression on the left is less than the expression on the right, otherwise false.
 
>=
 True if expression on the left is less than or equal the expression on the right, otherwise false.
 
<=
 True if expression on the left is greater than or equal the expression on the right, otherwise false.
 
 
  
 
+
 Floating point addition
 
-
 Floating point subtraction
 
 
  
 
*
 Floating point multiplication
 
/
 Floating point division
 
 
  
 
**
 Raise left hand side to power of right hand side. Only the real part is returned, e.g., -1**1.5 gives zero not i.
 
 
  
 
!
 Convert the following expression to Boolean and invert.

See LTspice help, endless fun in perspective....
 
Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.