Hi,
I hope this is just me being stupid but I have found what seems to be
a bug in parsing the expressions used for a behavioural resistor.
I have two soft switches made using the behavioural form of resistor.
One is normally closed (nc), the other normally open (no).
The expressions used for each are essentially the same except that one
uses a subtraction to invert the sense of the switch.
The subtracted form works but the basic form (without the subtraction)
does not (the switch is stuck open).
This is the working, subtracted form used for the no switch:
R_no 0 NO1 R=(1-0.5(tanh( (V(CONTROL)-nocloses)gain )+1))*Roff + Ron
This is the non-working form used for the nc switch:
R_nc 0 NC1 R=0.5(tanh( (V(CONTROL)-ncopens)gain )+1)*Roff + Ron
Please see the netlist below (but watch out for errors due to line wrapping):
* Bug in expression parsing for behavioural resistor?
*
.tran 200u 200m ; comment out for LTspice
.probe V(CONTROL) I(Vimonno) I(Vimonnc) ; comment out for LTspice
*.tran 200m ; uncomment for LTspice
*
V2 CONTROL 0 SINE(0.5 0.5 10 0 0 -90)
V1 VCC 0 1
Vimonno VCC NOx ; current in normally open switch
Vimonnc VCC NCx ; current in normally closed switch
R5 NOx NO1 1
R7 NCx NC1 1
.param
+ Ron = 1m ; Ohms. Contact resistance.
+ Roff = 1G ; Ohms. Open circuit resistance.
+ ncopens = 0.3 ; nc contact opens at 0.3V
+ nocloses = 0.7 ; no contact closes at 0.7V
+ gain = 1k ; gain of switch tanh function
**
* Switches
R_nc 0 NC1 R=0.5*(tanh( (V(CONTROL)-ncopens)*gain )+1)*Roff + Ron ;
this does not work
*R_nc 0 NC1 R=(1-0.5*(tanh( ((1-V(pullin1))-(1-ncopens))*gain )+1))*Roff + Ron ; this works but looks clumsy!
*R_nc 0 NC1 R=(1-0.5*(tanh( (V(CONTROL)-ncopens)*gain )+1))*Roff + Ron
; this works (but is the wrong polarity for the nc switch)
R_no 0 NO1 R=(1-0.5*(tanh( (V(CONTROL)-nocloses)*gain )+1))*Roff + Ron
; this works
*R_no 0 NO1 R=(0.5*(tanh( (V(CONTROL)-ncocloses)*gain )+1))*Roff + Ron
; this does not work
*
* Implementing the normally closed behavioural resistor as a B source works too, so is it only in
* the expression parsing for the behavioural resistor that the problem appears?
*B_nc COM1 NC1 I=V(NC1,COM1)/(0.5*(tanh( (V(pullin1)-ncopens)*gain )+1)*Roff + Ron) ; this works
*
.end
The same netlist runs with no problems in LTspice.
What am I missing?
Thanks,
Andy.
Quotes around the expressions :-)
Unfortunately, there is more. I suspect a bug
in the translation to a behavioral source
(what you view with "listing extended"). It might
be that we get negative resistance because
of a sign error somewhere in the translation.
This needs further investigation.
-marcel
Last edit: marcel hendrix 2015-05-21
Thanks Marcel,
I have seen a number of errors (some already reported here as bugs) to do
with differences in interpreting the sign in front of numbers, variables
and parameters.
There have been occasions when I have wanted to do things like:
B out 0 V=1-V(in)
but have had to write it as:
B out 0 V=1-1*V(in)
to make it work.
One of the "this works" versions is written in that sort of format.
It would be nice if ngspice could be made to treat the sign in front of
things the way it would be expected, i.e:
-anything is always interpreted as exactly equivalent to -1*(anything)
:)
Cheers,
signality.co.uk
On 21 May 2015 at 06:29, marcel hendrix mhx_at_sf@users.sf.net wrote:
Related
Bugs:
#308Where is "V(pullin1))" ?
-marcel
"Where is "V(pullin1))" ?"
Sorry about that: V(pullin1) should have been corrected to V(CONTROL).
The two lines with V(pullin1) in them were copied across from another
netlist that I had been trying things out in and I forgot to correct the
netname.
Cheers,
signality.co.uk
On 21 May 2015 at 21:18, marcel hendrix mhx_at_sf@users.sf.net wrote:
Related
Bugs:
#308What is not straightforward about the attached behavior?
-marcel
Last edit: marcel hendrix 2015-05-21
Hi Marcel,
Clearly there are many ways to implement a change over or SPDT switch and
of avoiding the bug I have reported at the same time.
I could simply have used a pair of voltage controlled switches instead of
behavioural resistors or I could have used a B source implementation of a
controlled resistor as in one of the commented out lines that did actually
work in my example. In fact I will be using the rearranged form of the
expression:
"R_nc 0 NC1 R=(1-0.5(tanh( ((1-V(CONTROL))-(1-ncopens))gain )+1))*Roff +
Ron ; this works but looks clumsy!".
Your alternative solution is also fine and is another way of avoiding the
bug I have found but there are two reasons I would not want to implement
the switches that way using an 'a > b ? c : d' type of function.
i) unless there is something special about the way it is implemented in
ngspice, 'a > b ? c : d' function introduces an inherent discontinuity.
There is no way to control the speed of the transition between the two
possible outcomes (I know of a sort of soft IF statement in SIMetrix but
not in any other spice).
Because the outcome of the 'a > b ? c : d' function is discontinuous and
drives the transition in the value of the resistors directly then the
change in the resistance is itself discontinuous.
In my experience and understanding of spice:
discontinuity = bad, bad, naughty bad, wicked bad;
smooth transition = goooooood.
ii) the switches in my netlist are based on a tanh function which allows
them to switch in a smooth, continuous transition between Ron and Roff. The
'gain' parameter allows the "sharpness" of the transition to be adjusted.
This forms a kind of soft switch. Again, in my experience, this improves
convergence in most simulations compared to having the discontinuous action
of something like the 'a > b ? c : d' function or simply using the voltage
controlled switch, which is a hard switching action.
The bug I found was in the course of developing a rather more complex
subcircuit where the V(CONTROL) input to the switches is a smoothly varying
voltage however, for the purpose of demonstrating the bug, rather than
confusing things with this complicated subcircuit, I put the same switches
and associated expressions which demonstrate the bug into a much simpler
test jig. It's the bug I'm reporting rather than a problem with the
implementation.
And as you say, there seems to be an underlying problem related to
differences in the parsing of signs in expressions used in B sources as
compared to those in expressions for parameters and so on, of which I
suspect this is just one manifestation.
:)
Cheers,
signality.co.uk
On 21 May 2015 at 22:03, marcel hendrix mhx_at_sf@users.sf.net wrote:
Related
Bugs:
#308Hi Andy,
As there were an uncharacteristically high amount of
puzzling inaccuracies in your test circuit I recreated
it such that, I at least, could understand what was
going on. My first attempt removed the tanh() because
I thought it was unimportant for the problem at hand.
I have put it back in now the main problem is clearer.
I hope that the new test file matches your
intention and its output (although mislabeled)
is correct. I checked it with LTspice -- the results
are the same (although LTspice takes much longer to
run the file, of course).
There are two other points you make that I want to
comment on:
You have to understand that these errors, that you
reported to the NGSPICE maintainers, thanks, are
not corrected within the 5-minute timespan that you
are used to from LTspice ;-) If you download the
latest GIT sources I think you will find that they
reproduce the results that I have attached.
Of course these are excellent points. Indeed,
current NGSPICE does not have the magic that is
present in SIMetrix, and indeed, LTspice is a lot
smarter in detecting discontinuities. We
are working on XSPICE code models that will lead
to large improvements in this area.
Making sure functions are smooth is not enough,
as it will cause big time steps being made, which
cause large errors when completely unpredictable
events take place (like a switch driven by
arbitrary timing signals.) The best solution that
I know for this is that all (user) models generate
breakpoints. Some current NGSPICE models already
implement this idea, but incorrectly.
Please keep the bug reports coming, they are really
appreciated.
-marcel
Hi Marcel,
I just realised that I bungled sending a reply to your last post about 9
days ago ... still getting the hang of emailing via smartphone.
Sorry about the mistakes in my original posting. It was done in too much of
a hurry.
Thanks for the switchbugs.cir
http://sourceforge.net/p/ngspice/bugs/_discuss/thread/3257a26d/0f1e/attachment/switchbugs.cir
netlist, I've tried it and it works exactly as required.
Looking at it carefully I realise that the problem was just me being stupid
after all.
In my original netlist I had:
R_nc 0 NC1 R=0.5(tanh( (V(CONTROL)-ncopens)gain )+1)*Roff + Ron ;
this does not work
R_nc 0 NC1 R=(1-0.5(tanh( ((1-V(CONTROL))-(1-ncopens))gain
)+1))Roff + Ron ; this works but looks clumsy!
R_nc 0 NC1 R=(1-0.5(tanh( (V(CONTROL)-ncopens)gain )+1))Roff + Ron
; this works (but is the wrong polarity for the nc switch)
R_no 0 NO1 R=(1-0.5(tanh( (V(CONTROL)-nocloses)gain )+1))*Roff + Ron
; this works
R_no 0 NO1 R=(0.5(tanh( (V(CONTROL)-ncocloses)gain )+1))Roff + Ron
; this does not work
My mistake was that I had not enclosed the expressions with apostrophes.
Your netlist correctly uses apostrophes around the expressions:
R_nc1 0 21 R= ' 0.5(tanh(( V(CONTROL) - ncopens) gain )+1 )*Roff +
Ron'
R_nc2 0 22 R= '(1-0.5(tanh( ((1-V(CONTROL))-(1-ncopens))gain )+1))*Roff +
Ron'
R_nc3 0 23 R= '(1-0.5(tanh( ( V(CONTROL) - ncopens) gain )+1))*Roff +
Ron'
R_no1 0 24 R= '(1-0.5(tanh( ( V(CONTROL) - nocloses) gain )+1))*Roff +
Ron'
R_no2 0 25 R= '( 0.5(tanh( ( V(CONTROL) - nocloses) gain )+1))*Roff +
Ron'
and all the variants of the expressions work as expected.
If I edit my original netlist to include the apostrophes then my problem
goes away.
So it was all my fault for being sloppy with the syntax differences between
my use of ngspice and LTspice.
"Making sure functions are smooth is not enough, as it will cause big
time steps being made, which cause large errors when completely
unpredictable events take place (like a switch driven by arbitrary timing
signals.) "
I was trying to use functions that are not only smooth and continuous but
are also continuous in their first derivative.
Is the problem then that by using smooth functions, this allows ngspice to
use big timesteps - because there is less change from point to point in the
short timescale - and so when an event such as a fast switching edge occurs
somewhere between these big timesteps, large errors can occur?
If that is the case then I think I understand why:
"The best solution that I know for this is that all (user) models
generate breakpoints."
I must read up about "breakpoints". I don't know enough about this to
understand the significance and how to make use of them yet.
Far from complaining about the speed of bug fixing in ngspice, I was just
trying to put my post Into a bit more context. I didn't have the bug report
numbers to hand to help bring the other instances of this type of problem
together.
In fact one of the things I've always been so impressed with in the ngspice
forums is the speed with which bug reports and user questions do get
sensible, constructive responses and actions.
As this thread has just demonstrated, the ngspice and the gEDA forums I
think showcase the best that FOSS communities have to offer. I often tell
people who are dubious about FOSS that the speed and quality of response of
FOSS communities puts many paid-for commercial support services well into
the shade.
Once again, many thanks for your help.
:)
Cheers,
signality.co.uk
On 22 May 2015 at 21:17, marcel hendrix mhx_at_sf@users.sf.net wrote:
Related
Bugs:
#308Yes. The following explanation may be inaccurate, but I hope it
illustrates the point...
Assume there is only a nice perfectly sinusoidal signal and a random signal that
triggers a switch that connects the sine to an output pin.
After each time step the simulator checks the errors made in each signal.
Actually it asks all circuit matrix elements in turn to check themselves.
Of course for the smooth continuous signal(s) the error is very low. Then
(we think that) the simulator should ask the random gate signal to
check itself. However, as this signal comes from a source and SPICE
sources have no memory, SPICE will simply not do that. It will query the
source if it is high or low and uses that for the next step.
This description suggests what one could do to improve performance with
event-based discontinuities. One possibility is to have continuous, smooth
sources. This helps speed-up the Newton-Raphson process but does not much
for timestep control - for that there also must be a mechanism that SPICE
asks sources their opinion on how the time step went, not only elements
in the circuit matrix.
An LTspice trick is to add a small RC low-pass filter over each voltage source
and let the circuit matrix handle it.
The other possibility, that NGSPICE uses, is to have (built-in) sources raise
events when they go discontinuous (breakpoints). This leaves B-sources a
problem (as they are user-defined and there is no mechanism to post a
breakpoint). Another tough problem is e.g. a diode, by nature discontinuous.
Posting a breakpoint will work, but that is conventionally not how diode
models are written.
This explains why a SPICE written especially for power electronics might be
quite different from one written for RF and low-voltage analog stuff.
XSPICE allows to write models that are specifically tuned for these problems
and still can be very efficient.
-marcel
Marcel,
Thanks for that. Your explanation is very helpful.
"An LTspice trick is to add a small RC low-pass filter over each voltage
source
and let the circuit matrix handle it. "
As far as I understand it, spice deals with Norton sources with parallel RC
circuits more efficiently than Thevenin sources with a series R followed by
a parallel C.
Therefore, where possible, instead of using a V source with a series R
followed by a parallel C, I try to use a current source with a parallel RC.
Also when using B sources, instead of using a BV source, I try to use a BI
sources with a 1R resistor and a capacitor in parallel (usualy 1pF works
OK) with it. That means I can use the same expression as for the intended
BV source but the source becomes a lowpass filtered Norton Source.
I think the only problem I have seen with this in LTspice is that for B
sources that need a very low source resistance (i.e. R << 1), the
multiplication factor applied to the expression to scale the output voltage
back up again can slow the simulation down quite significantly. Now, I
don't know if this is true in ngspice because I have not used it enough
yet. It may be that the slow down is a data compression thing in LTspice
and not a function of the multiplication itself. (Bump! I have just hit the
endstop of my understanding of spice again.)
A really dirty trick I have used once or twice is to set up a gated high
frequency (relative to the rest of the circuit) source that is off and so
does nothing for most of the simulation but is turned on only around some
event(s) that have been observed to cause a convergence problem - or needs
a higher time resolution - but which can be solved by using smaller step
sizes. That way the whole of the simulation is not slowed by the need for
small timesteps but does exercise them when needed bracketing the trouble
spots.
The hf source has to be something like a gated RC or behavioural schmitt
based oscillator or some function of TIME that completely stops when gated
off because obviously simply gating the output of a SIN() or PULSE() source
leaves the source itself always running and so slowing the simulation down.
I know what you're thinking: it is hard to believe that anyone could stoop
so low to achieve their murky goals ...
Cheers,
signality.co.uk
On 2 June 2015 at 12:37, marcel hendrix mhx_at_sf@users.sf.net wrote:
No Andy, to the contrary. I am always delighted to find such creative use of existing resources, that's why I became an engineer. What I don't like is premature optimizations, or 'optimizations' that are pointless or not the result of some hard constraints, or come from blindly following rules of thumb.
I think you have found a way of adding breakpoints to standard SPICE. The only way to improve on it would be to minimize the number of breakpoints.
-marcel
I'm glad you like the idea!
It's a bit inelegant to make it work well. The technique relies on running
the sim a few times to find the trouble spots first and then adjusting the
gating signal to the oscilaltor so that it just brackets them.
The frequency and the waveshape of the oscillator also affects where these
"breakpoints" actually end up in relation to the event you're trying to
work through.
The gating signal can be a PWL source to allow arbitrary placement of the
on/off pulses.
What would be good would be if someone could find a way to automate it or
to predict where the hf source needs to be switched on. Maybe that's
something that XSPICE can already deal with.
:)
Cheers,
signality.co.uk
p.s. I think you can probably close the bug report on my original question.