B2 Spice V5 Logical Expressions (revised)
About the writer: Harvey Morehouse is a contractor/consultant with many years of experience using circuit analysis programs. His primary activities are in Reliability, Safety, Testability and Circuit Analysis. He may be reached at firstname.lastname@example.org. Simple questions regarding my articles for which I know the answer are free. Complex questions, especially where I am ignorant of the answers, are costly!!!
Summary: Version 5.14 has added to/improved the logical expression features of v5.13. While there are a few problems still remaining in the implementation, or lack thereof, these can be overcome without much difficulty. All of the features have not been extensively and fully tested, but the changes are significant and part of the ever-growing capabilities of their product.
Logical expressions are equations/expressions where the result/outputs are binary in nature. That is to say, the result after evaluation of the expression/equation will be bipolar in nature, such as one value or another, or one function/expression will be created as an output or a second one will.
By combining these logical expressions, one can create complex functions, where, dependent of the results of variables or expressions taking on different values, different outputs may be provided.
Logical values are the result of operations by logical expressions or operators, on values produced by logical expressions.
The logical value of a variable or expression, not to be confused with a logical value produced by operations on a variable or expression, is that, if the variable or resultant expression value is greater in magnitude than zero it will be represented as a logic ONE and logical ZERO otherwise. Certain operators should automatically convert or otherwise interpret variables or expressions as their logical value equivalents where they are not already explicitly defined themselves as logical values.
If you are confused, it is harder to write it than to understand it. Look at it this way. Suppose you had a unary expression such as the ~ or negate operator. This makes no sense to use other than with a logical operand. Consequently, an expression using this operator should have its operand either as a logical value or it should be converted automatically if not. An example of its use with logical operands is:
Now here it is assumed v(3), v(5) and v(7) are some arbitrary real function of time. V(3)>0 clearly returns a logical value. u(v(5)*v(7)) clearly also returns a logical value. These two logical values are subtracted to produce an argument that could have the values over time of +1, 0 or 1. It would still be a logical operand, sort of at least. So, the ~ operator would cause a value to be returned respectively, of 0, 1 and 1 respectively.
Now were the operand not a logical value, what are the implications and what should happen? Suppose the expression were:
How would this be operated upon and how should it be? IF one were to use the expression:
Were v(3), v(5) and v(7) logical values, each produced as the output from another generator or generators with a logical argument there would be no ambiguity. The argument would take on the values of 1, 0, and 1 as possible values. And as before, the output would respectively be 0, 1 and 1.
Now suppose they were not logical values. Unless the expression were evaluated using that assumption, the argument would be meaningless. So if the argument is not composed of clearly logical values as the results of operands or expressions that returned such values, the resultant should be converted. Now the argument for the implied ustep function could be greater than zero, equal to zero or less than zero, which would produce a ustep output value of 1 or 0 respectively. This, operated on by the ~ operator, would produce an output of 0 and 1 respectively. The results are not necessarily the same in either instance, but it makes sense.
When one reads a document, the assumption is that the writer knows what they are doing, at least as a start. Therefore, the expression V = ~(v(3)*v(5) v(7)) should be interpreted as being equivalent to V = ~u((v(3)*v(5) v(7))). In fact, if the argument of a ~ function is ALWAYS treated as if there were an implied ustep of the argument, it is a clear and understandable rule. The ~ function is not implemented, and hopefully it will be, but in so doing it should have an implicit ustep function included for its argument. Other functions should also have such an implicit rule.
Logical Expression Primitives:
To be really useful an instruction set should include items such as operators as well as expressions. Some of the operators are unary. Meaning, they are effective with just one operand. This would be the case for a logical negate. Others are useful with two operands. Such would be the case for a logical AND.
Some of the operators that a full-featured SPICE with a logical expression format would include are shown in the following:
There is one other problem. That is, to quote the persons at B2SPICE directly, "I think that they may still fail for logical expressions that require parentheses grouping for overriding operator precedence, but they work for the test cases you sent in.". This takes a lot or work to verify fully and report on all the instances and cases, however, from a very brief look so far, extraneous parentheses or parenthesis groupings not recognized may cause the SPICE engine to choke, as well as perhaps in other cases of grouping of variables into IF .. THEN ELSE expressions. This will be discussed in a later section.
The first operator to be tested is the AND or '&' function. Refer to Figure 1 following:
The sources V1 through V4 are 1 volt sine sources of 1K, 3K, 5K and 7K frequencies respectively.
Although the operator does not automatically use the logical values of variables and expressions, it apparently is usable in more complex expressions by the use of parenthesis groupings.
next function to be examined is the OR operator. The same essential
test circuit is used as in Figure 1.
There is of course no graph to present for the fail cases, and the pass cases are really not that interesting. Therefore, it is suggested that the interested reader recreate the Figure 1 circuit and experiment with it.
The rule is that, as presently implemented, only logical variables may be 'OR'ed. But just as in the case of the nonexistent '~' negate operator, it is suggested that an implied ustep of the arguments of each '|' operator be provided.
The next symbol to be examined is the EQUATE or' ==' operator. See Figure 3 following:
The equate function does not work using the logical values of real variables. It will work with logical variables, however. Three or higher level equates seem to fail, as well as, as mentioned in the comments given to me and related earlier, where grouping by parentheses is used to try to change the order of function evaluation.
The rule for the present implementation seems to be that logical functions can be used with the '==' function, but external parentheses are not allowed. Moreover, it seems that the precedence of operators and their evaluation needs to be considered when parsing an expression. As in the case of:
In the above, which fails, it would seem that one would first evaluate the terms to the left and right of the '==' operator, and then use the equate operator. And, were there several instances of the operator, one should start from the right of the last argument, and work to the left. (Lest one wonder, v = u(v(v1)) == v(v2)>0 also fails.)
Next we will look at the '>' and '<' operators.
Apparently only variables, not even simple expressions are usable with the < and > operators.
The XOR function, '||' is not implemented. The uramp and ustep functions function as before.
Other logical expression capabilities:
Some other logical functions/capabilities that are desirable are:
What is new and very powerful in Version 5 is the incorporation of the logical "IF THAN . ELSE " function into the instruction set.
from the previous articles on logical functions, I devised a method
Recalling, the u() function returns a '1' when the argument is greater than zero, and zero otherwise. Thus, when v1(t) > 0, u(v1(t)) =1 and the equation becomes:
Whereas, if v1(t) were equal to or less that zero, the result is:
Now, what Version 5 does is precisely the same thing, but the syntax is cleaned up. Using a different syntax, the same functions have been used to produce the output. A ustep function is still used, but it becomes invisible to the user.
There are actually two different ways the "IF THAN . ELSE " function has been incorporated into the instruction set. The reasons why are for another reason I will not reveal here, but the two means are described in the following.
The preceding equation should be rather easy to understand. Within the brackets are three items, separated by commas. The first is the actual test expression. IF this expression results in a true value, the second expression is the voltage that 'v' will present as an output. If the test presents a false output, then the third expression is the voltage output. This is best seen by an illustration. Figure 1 following is a small test circuit.
A netlist for the circuit follows:
The leftmost generator V1, is a sine wave source with an amplitude of 5V peak, centered about zero volts. B1 generator is used to create a logical output voltage. The requirement for B1 is that, IF the voltage output of generator V1 is less than one volt, that the B1 output will be zero volts. And if the output of generator V1 is equal to or greater than 1 volt, then the B1 generator will be 1 volt. (Note that the output probe for generator V1 is voltage V2, and the output probe for generator B1 is V3. Whereas in the equation for generator B1, the node voltage at node 3 with respect to node 0 is understood.)
An output graph showing the input voltage v2 and the output voltage v3 is shown in Figure 2 following:
Here we see that when the green input voltage at v2 is less than 1v, the output is zero, and 1 volt otherwise. Now the test was :
This could have been performed in nearly the same manner with a B1 source equation of:
This would for all practical purposes be the same circuit, IF the voltage generator V1 did not dwell at zero. For, the first equation is equivalent to:
But there is no >= operator, so they are NOT precisely the same even were that operator available.
The point that should be remembered is that for real variables the use of an '=' (or an '==' ) operator for a test, other than was done through inclusion in an else condition by implication, is problematic at best. Remembering that SPICE produces a numerical output, at solution times that might not EVER be precisely right to produce a given value, let alone have two real solution values both meet at the same time, it is best NEVER to use an equality test save for logical values.
Now of course some care must always be used in creating tests, however I believe it is clear that the logical expressions are far, far easier to produce and understand than the ustep method.
The next question that arises is, can these expressions be nested? The answer right now is YES, you can nest these conditions under certain conditions. Refer to Figure 7 following:
The results indicate that ITE nesting can only occur in the 'else' section of the expression. Here, a first level of nesting works. For reference a 'working' netlist of the circuit of Figure 7 is as follows:
Notice from the above netlist the v5 output creates logical type outputs (1,0 values), the v6 generator produces real variable outputs, and v7 produces a combination of logical and analog output signals. These are shown in the graph of Figure 8 following:
The question remains, how many nesting levels can one perform? Well, one first question should be, how many does one need, and how many can one conveniently implement and stay sane? IF we could nest loops in the THAN as well as in the ELSE portions of the test, I would say that one level of nesting would be sufficient for most needs, but this is of course just my opinion. With a little work, one can see that one can do two nested THAN's.
The rule is that at least at least three 'than' statements can be in nested IF loops. However, no IF loop resultant seems to be capable of being used as an intermediate product in a more complex expression. That is to say, one could not multiply the result of an IF..THAN..ELSE loop resultant value by another variable.
The second method of creating a logical IF THEN . ELSE . Expression uses the syntax:
Other than the slight format difference, it should be evident that there is very little difference between the two methods. If the reader is interested, one can easily perform the tests on this second method to see what the capabilities and restrictions are.
There are now very few features lacking in the enhanced logical equation capability in Version 5.14, and it represents a SIGNIFICANT improvement in the ease of implementation of logical expressions, consistent with that used by competing products in most cases.
However it is not yet fully tested. It may never be. What needs to be done is to create a matrix of operators/functions, and using a binary type process select and test combinations of usage of these items, in varying complexity, to determine the capabilities and limitations under those conditions.
Just such testing and reporting, as is done here, represents important feedback to the B2SPICE programmers. Even with some of the limitations found here, most logical expressions desired can be formulated easily with the existing tools. Moreover, some of the 'limitations' if and when corrected will represent an advance over and above what competing products have.