However:
1) many models use "gm" to compute noise
2) the HiCUM model (at one point, I don't know if it's
still the case) used Cjci=ddx(Qjci,V(ci)) to compute Iavl
For the noise, the second derivative is not necessary,
so the restriction should presumably be loosened to
allow 1).
In 2), the simulator needs the derivatives of Iavl,
which means the second derivative of Qjci. If we restrict
the use of ddx in this case, the developer will have to
manually write the expression for Cjci -- and we always
say that Verilog-A saves you from having to write
derivatives (and from the possibility of incorrect
derivatives).
If using ddx() is not restricted it will open the door for other developers to rely on its use but this will reflect on the final model speed as the second derivative calculation will add many lines of code and this can be costly.
The point that Verilog-A saves from possible problems due to derivatives is correct when we are talking about a full model with all derivatives needed for all equations w.r.t. all voltages. In the case for HiCUM (or any other model that would need ddx() use) we are discussing a single derivative (or at most few derivatives) that need to be analytically computed and these can be considered as extra model equations that have to be written and checked correctly by the developer.
A good compiler might optimize this (with still some overhead to add), another compiler might not be as good to do the same hence it would be good to consider both cases.
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Geoffrey Coram
We expect modern compilers to be "smarter" than this.
(And any "overhead" as you mention would only be added during the
compilation phase; it should not affect the run-time of the
compiled model.)
As for Verilog-A compilers inside the simulator to simulate Verilog-A instances directly, I totally agree with your comments.
If you use Cjci to compute Iavl, I think the same number of
derivatives would be needed in either case:
(a) user writes Qjci equation, sets Cjci = ddx(Qjci),
simulator computes second derivative of Qjci
for use in Iavl derivatives
(b) user writes Qjci *and* Cjci equations,
simulator computes first derivatives of Cjci
for use in Iavl derivatives
In fact, a compiler might not recognize the Cjci
expression as being the derivative of Qjci, and
so there might be the user's Cjci equations *and*
the automatic derivatives of Qjci, so that (b)
would be less efficient!
-Geoffrey
My opinion...
Cjci=ddx(Qjci,V(ci)) is OK if Cjci is not propagated into the right hand side expression of a any contribution statement. This condition is very easy to detect.
Cjci can then be used for OP or noise.
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Geoffrey Coram
Sent: Tuesday, December 13, 2011 3:13 PM
To: cmc-ve...@googlegroups.com
Subject: [cmc-verilog-a] restricting ddx()
I(a,b) <+ white_noise( 8/3 kT (gm + gms + gmbs), "thermal");
has a ddx expression (gm = ddx(Ids, V(g)) etc.) that ends up in a
contribution.
Perhaps the noise functions (white_noise, flicker_noise, and noise_table)
are the only exceptions.
But: if ddx() used in a contribution is "very easy to detect"
and compilers already know how to compute derivatives, why
is it a problem?
-Geoffrey
You are totally right. My statement needed refinement. What I was trying to ban was using it in those cases where it introduces 2nd order derivatives.
I think that additional restrictions need to be enforced on how ddx is used, but I am not sure what they are yet. Let me share something I saw in the Cadence compiler (I believe).
Cjci=ddx(Qjci,V(ci)) worked, but
Cjci=ddx(Qjci,V(ci,bi)) didn't, even when Qjci was an expression written explicitly in terms of V(ci,bi). That did not make sense to me.
My conclusion was that in Cadence, the ddx operator allowed one to access quantities that the compiler already had access to, rather than producing the desired derivative. If we wanted to be able to use the ddx operator as a approach to produce derivatives of a given variable (function) respect to and input variable, then ANY input should be allowed in the ddx operator, like in Mathematica.
If ddx operator only allows accessing quantities that already exist (as in Cadence), then I really doubt that the second derivatives will be correctly implemented or even created in those environments. Since the Mathematica approach is not viable or considered in the LRM, then we need to ban generating second derivatives altogether. Perhaps if what I saw in Cadence is common practice, then we should recommend the user to only use derivative respect to node voltages. Branch voltages in the ddx operator should not be allowed/recommended, because are not generally supported.
Alfredo
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Geoffrey Coram
Sent: Friday, December 16, 2011 5:16 AM
To: cmc-ve...@googlegroups.com
Subject: Re: [cmc-verilog-a] restricting ddx()
> the ddx operator allowed one to access quantities that the
> compiler already had access to
Indeed! That's exactly what we wanted to do when we wrote
the LRM!
Please do check if your compiler generates the right 2nd
derivatives. It would be unfortunate to introduce
unnecessary restrictions.
I completely don't understand what the "Mathematica approach"
has to do with allowing second derivatives or not. The
second derivative with respect to node voltage is always
unambiguously defined.
-Geoffrey
The capacitance is the derivative of the charge respect to the voltage the charge depends on.
C=d/dV (Q(V)) The capacitance is not the derivative of the charge respect to an arbitrary node voltage.
In the expression below
Cjci=ddx(Qjci,V(ci))
one "defines"
Cjci as the derivative of Qjci respect to V(ci). This only makes sense because in this particular case the voltage Qjci depends on, is defined between nodes c and b.
I think that what I don't like is using a node voltage in the definition of capacitance or conductance. This is only true because this node is one of the nodes the branch voltage is defined between.
I think that if one ACCEPTS Cjci=ddx(Qjci,V(ci)), then there is no reason to restrict how it is used.
If you wrote Q=x*b*b-3*r and asked for the "derivative" of Q
with respect to r, you might get -3, but only if x and b aren't
themselves functions of r (or if Mathematica assumes that you
want the partial derivative to hold the other values constant).
If you wrote
x = 3*b
Q = x*b*b-3*r
what is ddx(Q,x)?
It would be easy to say that ddx only looks at the single
equation Q=x*b*b-3*r, so that you only get non-zero derivatives
for r, b, and x; but that would force model developers to write
the whole expression for Q on one line. If you say that ddx
should look back into the expressions that defined r, b, and x,
and try to make guesses as to what to hold constant, it quickly
becomes complicated (in my example, you can't vary x but hold b
constant!)-- unless you say that the second argument has to be
a node voltage, and all other node voltages are held constant,
and we happen to know that these derivatives are exactly what
the simulator has to compute anyway!
In MOS models, we have Cxy, which are the derivative of Qx with
respect to Vy (times -1 when x != y); the Hicum example is the
simplest case, because it's a 2-terminal capacitance ... unless
you have self-heating, in which case it gets a little more
complicated. In fact, that's an interesting point, because if
you change the collector voltage, then you might increase the
amount of self-heating, so that Qjci would change partly because
V(ci) changes, and partly because Temp(t) changes, and Cjci is
really only the part of the change in Qjci that is due to the
change in V(ci) -- that is, the partial derivative, holding all
other node voltages constant.
People wanted to write Cgd = ddx(Qg, V(g,d)), but even that
gets complicated. Suppose one had:
Vgs = V(g,s); Vbs = V(b,s); Vds = V(d,s);
if (Vds >= 0) begin
vds = Vds; vgs = Vgs; vbs = Vbs; vgd=Vgs-Vds;
end else begin
vds = -Vds; vgs = Vgs-Vds; vbs = Vbs-Vds; vgd=Vgs;
endif
Qg = Covgd*vgd + ...
Well, V(g,d) never appeared in any of my equations, so is Cgd = 0?
That's certainly not what the model writer wanted!
I think you just have to get over your dislike of using a node
voltage in the definition of a capacitance.
-Geoffrey
I will go with the flow, in the sense that if this OK for everyone, I am OK with it
The real issue here is that when ddx is used this way (as in Hicum) things can get ugly. We would need to accept that the person that wrote the equation knew exactly what he was doing.
There are two issues here
1.- ddx operator that uses V(x) as second argument
2.- Creating an unphysical model, because branch contributions depend on ddx(Q,V(x))
1.- Using V(x) as a second argument is only OK if we prevent the possible consequences of this definition. If ddx(Q,V(x)) is used as a mechanism to access existing quantities and using them only in noise calculations or OP info. This is OK.
2 If ddx(Q,V(x)) makes its way into current or charge contributions, then can we be sure that the model is physical? I have not worked the details, but I would argue that it is very easy to write models that do not satisfy charge conservation using ddx(Q,V(x)) in charge or current contributions. If this is a real risk, then we need to warn or recommend.
I am not sure this has been addressed yet, but it is definitely related.
How do most compilers handle
Q<+C(V(p,n))*ddt(V(p,n)); ???
We warn, but support it.
If the user splits the contribution above in two lines the model might unphysical, but we won't be able to notice it.
I(t0)<+ ddt(V(p,n));
I(t0)<+ V(t0)
Q<+ C(V(p,n))*(-V(t0));
My conclusion
I think we should follow a similar approach for ddx when it is propagated to current or charge contributions (noise is OK). We need at least to to issue a warning (banning is another possibility). Here it is easier than the case I described above, because we could propagate the "ddx based" attribute.
This
Q<+C(V(p,n))*ddt(V(p,n)); ???
is the sort of formulation that causes charge conservation problems,
and it's ddt -- not ddx.
ddx is a symbolic derivative; using it doesn't allow anything new.
In some versions of Hicum, the explicit equations for Cjci were
written out, as a work-around for compilers that objected.
1) I<+C(V(p,n))*ddt(V(p,n)); will cause conservation charge problems.
2) I<+ddx(Q(V(p))*ddt(V(p,n)); won't because this is exactly ddt(Q(V(p,n))
I understand that part.
However, if you allow users to write either of these expressions, you open the door for model developers to implement unphysical models. Shouldn't we try to encourage them to write good models?
It is very to leave out some terms, if the charge based current contributions are not written as I<+ddt(Q). That is what we need to encourgage.
If he/she wrote
I<+ ddx( Q(V(p),V(temp)), V(p))*ddt(V(p,n));
Instead of
I<+ ddt( Q(V(p),V(temp)));
Which using the explicit approach would need to be written as
I<+ ddx( Q(V(p),V(temp)), V(p))*ddt(V(p,n))+ ddx( Q(V(p),V(temp)), V(temp))*ddt(V(temp));
Then he would be missing
I<+ ddx( Q(V(p),V(temp)), V(temp))*ddt(V(temp));
This is the type of mistakes that could/should be prevented. That is what I am trying to say.
Alfredo
PD
" I think you just have to get over your dislike of using a node voltage in the definition of a capacitance."
I am OK with this. Nothing can be gained from the "Mathematica" approach, except for (according to me) a more meaningful interface when somebody want to generate gm from Id without needing to write the expression for gm.
Qjci = function of V(bi,ci)
Cjci = ddx(Qjci, V(bi));
Iavl = function of Cjci
I(ci,bi) <+ Iavl;
If we restrict the use of ddx, then the model writer has to explicitly
write all the equations for Cjci. This is inefficient for two reasons:
a) the user has to write the derivative (and could make a mistake)
b) the simulator has to calculate the automatic derivatives of Qjci
for stamping in the matrix, and it has to evaluate the Cjci
equations to compute Iavl, and it may not recognize that these
quantities are the same.
Hicum was not trying to use ddx() for the charge contributions.
1) I<+C(V(p,n))*ddt(V(p,n));
2) I<+ddx(Q(V(p,n)),V(p))*ddt(V(p,n));
I think one recommendation that we could make is that a compact-model
compiler would issue a diagnostic any time a ddt-expression was
branchified (ie, forced the introduction of a new state variable and
branch). In other words,
parameter A = 1.0p;
real x, y;
x = A;
y = A*V(p, n)*V(p, n)*V(p, n); // just an illustrative example
... <+ ddt(x*V(p, n)); // Ok
... <+ x*ddt(V(p, n)); // Ok
... <+ ddt(y*whatever...) // Ok;
... <+ y*ddt(...); // Emit diagnostic, but allow
Isn't this identical to
I<+ddt(Q(V(p,n));
?
I think they're exactly identical in infinite precision, yes. It's
probably been a good decade or more since I've put pencil to paper on
this, but here's my recollection of why they're different in finite
precision (hopefully, some of the compact model experts on the list can
correct us if the following argument is flawed):
For simplicity, let's let v = V(p, n). So in one case, we have
I <+ ddt(Q(v)) [1]
and in the other case we have
I <+ Q'(v)*dv/dt [2]
(I've gotten rid of Verilog-A notation, since this isn't really Verilog-A
specific). Mathematically, in infinite precision, the two are identical.
Also, if the compact model compiler is somehow smart enough to manually
take the antiderivative of Q'(v) in case [2] and convert it into case [1],
then obviously they're identical as well. However, assuming it's not smart
enough to this, then [2] would be represented in MNA by introducing an
extra variable phi and an extra equation as follows:
I <+ Q'(v)*phi; [3a]
dv/dt - phi == 0 ; [3b]
Now, let's say we integrate [1] from time tA to time tB, such that v(tA)
== v(tB) == v0. We'd get Q(t=tA) == Q(t=tB) == Q(v0), since v is the state
variable that Q depends on. So "Q" is effectively the same if v(tA) ==
v(tB).
Now let's do this with system [2], which is actually represented by system
[3] in our MNA-based simulator. Q'(t==tA) is still equal to Q'(t==tB). So
that part is good. However, depending on what path the variable v is
traversing from t=tA to t=tB, the value of the variable phi at time tA may
not be the same as its value at time tB due to numerical error, even
though v(tA) == v(tB). So in this case, the effective charge may be
different depending on the numerical error in the solution of the system
of differential equations.
Does that make sense? If not, then perhaps one of the CM/math experts out
there can chime in and set us straight...
- Boris
But the compiler has to compute the second derivative of Qjci to get the first derivative of Iavl.
The analytical expression by the developer for Cjci will not be the same as the one computed using ddx() as the analytical expression will be done based on the derivative w.r.t. the branch V(bi,ci) not the node V(bi)
I still see that ddx() has to be restricted except for noise and OP.
One question raised in a previous mail:
If you wrote
x = 3*b
Q = x*b*b-3*r
what is ddx(Q,x)?
First we have to assume that b is the independent variable (voltage in case of models) and assume that a quantity I is needed: I <+ ddx(Q,b)
Here is what a compiler will do:
Case 1, ddx() used:
Verilog-A code:
X = 3 * V(N1,N2);
Q = X * V(N1,N2) * V(N1,N2) - 3 * K;
I(N1,N2) <+ ddx(Q,V(N1,N2));
Generated C code:
X_VN1N2 = 3;
X =3*vN1N2;
X_VN1N2_VN1N2 =0.0;
dQ_dVN1N2 = X_VN1N2*vN1N2*vN1N2+2*X*vN1N2;
Q =X*vN1N2*vN1N2-3*P1->K;
dQ_dVN1N2_VN1N2 =X_VN1N2_VN1N2*vN1N2*vN1N2+4* X_VN1N2*vN1N2+2*X;
dI_dVN1N2 = dQ_dVN1N2_VN1N2;
I =dQ_VN1N2;
Case 1, analytical derivative used:
Verilog-A code:
X = 3 * V(N1,N2);
Q = X * V(N1,N2) * V(N1,N2)- 3 * K;
dQ_VN1N2 = 9 * V(N1,N2) * V(N1,N2);
I(N1,N2) <+ dQ_VN1N2;
Generated C code:
X =3*vN1N2;
Q =X* vN1N2*vN1N2-3*P1->K;
dQ_dVN1N2_VN1N2 = 18*vN1N2;
dQ_dVN1N2 =9*vN1N2*vN1N2;
dI _dVN1N2 = dQ_dVN1N2_VN1N2; /* G = dI/dV */
I =dQ_VN1N2;
I see that the use of ddx() will generate more # of lines, 8 lines vs. 6, we are having a very simple case with only 1 voltage, in the real cases the added lines will be more.
Also the equations are more complicated to check when ddx() is used compared the analytical derivative addition.
One final point, I have never seen the case where you have ddt() inside a ddx() expression, why would this be used?
- MS
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Geoffrey Coram
Sent: Monday, December 19, 2011 9:12 PM
Selim said..
“One final point, I have never seen the case where you have ddt() inside a ddx() expression, why would this be used?”
Where did you see that? My guess is that either somebody forgot a parenthesis (perhaps me).
Where do I currently stand..
1.- I won’t question the form of ddx. It is what it is. The first argument is an arbitrary expression, the second one a current or source probe, as the LRM says. I don’t see why the second argument needs to be a single node probe. Since partially differentiating respect to delta=x2-x1 is the same as differentiating respect to x2 or x1. In the case of x1 a sign correction is needed.
2aEither ddx() is restricted to noise or OP, or,
2bWe warn the user when it is used for other purpose than OP and noise, or,
2cWe warn the user when he is combining attributes that should only conceptually appear as the compiler is differentiating expressions respect to time.
Alfredo
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com]
On Behalf Of Selim, Mohamed
Sent: Tuesday, December 20, 2011 4:50 AM
To: cmc-ve...@googlegroups.com
Subject: RE: [cmc-verilog-a] restricting ddx()
But the compiler has to compute the second derivative of Qjci to get the first derivative of Iavl.
My point with the ddx(Q,x) example was that one really has to
clearly understand about what a "partial derivative" is, and
how it's critical to know what the independent variables are
and which are held constant. I did not want ddx(Q,b); I was
asking about ddx(Q,x) to show how one can't simply pick any
variable in the expression to take a derivative with respect to.
-Geoffrey
Selim, Mohamed wrote:
> But the compiler has to compute the second derivative of Qjci to get the
> first derivative of Iavl.
>
> The analytical expression by the developer for Cjci will not be the same
> as the one computed using ddx() as the analytical expression will be
> done based on the derivative w.r.t. the branch V(bi,ci) not the node V(bi)
>
>
>
> I still see that ddx() has to be restricted except for noise and OP.
>
>
>
> One question raised in a previous mail:
>
>
>
> If you wrote
>
> x = 3*b
>
> Q = x*b*b-3*r
>
> what is ddx(Q,x)?
>
>
>
> First we have to assume that b is the independent variable (voltage in
> case of models) and assume that a quantity I is needed: I <+ ddx(Q,b)
>
> Here is what a compiler will do:
>
>
>
> *_Case 1, ddx() used:_*
>
> _Verilog-A code:_
>
> X = 3 * V(N1,N2);
>
> Q = X * V(N1,N2) * V(N1,N2) - 3 * K;
>
> I(N1,N2) <+ ddx(Q,V(N1,N2));
>
>
>
> _Generated C code:_
Qchan = W*L*Cox*(V(g,s) - V(b,s) - VFB);
QG = Cgso * V(g,s) + Cgdo * V(g,d) + Cgbo * V(g,b) + Qchan;
How would you compute ddx(QG,V(g,b)) ?
Well, V(g,b) doesn't appear in the expression for Qchan,
so you might say that ddx(QG,V(g,b)) = Cgbo.
But the problem is that your set of branch voltages is
overdetermined; you can't take the partial derivative
with respect to V(g,b) while holding V(g,s) *and* V(g,b)
constant!
With MOS models, it is very common to have this sort of
situation, where (Vgs,Vds,Vbs) are the three independent
branch voltages used for the core of the model, but the
overlap and junction equations also use Vbd, Vgd, Vgb.
These aren't all independent branches. However, node
voltages are independent, and what goes into the Jacobian
matrix are derivatives with respect to node voltages,
not wrt branch voltages.
-Geoffrey
Alfredo Piazza wrote:
> Selim said..
>
> “One final point, I have never seen the case where you have ddt() inside
> a ddx() expression, why would this be used?”
>
> Where did you see that? My guess is that either somebody forgot a
> parenthesis (perhaps me).
>
>
>
> Where do I currently stand..
>
> 1.- I won’t question the form of ddx. It is what it is. The first
> argument is an arbitrary expression, the second one a current or source
> probe, as the LRM says. I don’t see why the second argument needs to be
> a single node probe. Since partially differentiating respect to
> delta=x2-x1 is the same as differentiating respect to x2 or x1. In the
> case of x1 a sign correction is needed.
>
>
>
> 2aEither ddx() is restricted to noise or OP, or,
>
> 2bWe warn the user when it is used for other purpose than OP and noise, or,
>
> 2cWe warn the user when he is combining attributes that should only
> conceptually appear as the compiler is differentiating expressions
> respect to time.
>
>
>
> Alfredo
>
>
>
>
>
>
>
> *From:* cmc-ve...@googlegroups.com
> [mailto:cmc-ve...@googlegroups.com] *On Behalf Of *Selim, Mohamed
> *Sent:* Tuesday, December 20, 2011 4:50 AM
> *To:* cmc-ve...@googlegroups.com
> *Subject:* RE: [cmc-verilog-a] restricting ddx()
>
>
>
> But the compiler has to compute the second derivative of Qjci to get the
> first derivative of Iavl.
>
> The analytical expression by the developer for Cjci will not be the same
> as the one computed using ddx() as the analytical expression will be
> done based on the derivative w.r.t. the branch V(bi,ci) not the node V(bi)
>
>
>
> I still see that ddx() has to be restricted except for noise and OP.
>
>
>
> One question raised in a previous mail:
>
>
>
> If you wrote
>
> x = 3*b
>
> Q = x*b*b-3*r
>
> what is ddx(Q,x)?
>
>
>
> First we have to assume that b is the independent variable (voltage in
> case of models) and assume that a quantity I is needed: I <+ ddx(Q,b)
>
> Here is what a compiler will do:
>
>
>
> *_Case 1, ddx() used:_*
>
> _Verilog-A code:_
>
> X = 3 * V(N1,N2);
>
> Q = X * V(N1,N2) * V(N1,N2) - 3 * K;
>
> I(N1,N2) <+ ddx(Q,V(N1,N2));
>
>
>
> _Generated C code:_
In regards to ddx....
1.- I see another problem using ddx for purposes other than OP info and noise. In one of our simulators, the correct value of ddx is only available in the model code used to update the Jacobian. The Jacobian is not updated at every iteration. It is only updated when the current direction does not reduce the error anymore. This simply means that ddx does not have the correct value when the model code most commonly invoked, the one returning currents and charges only, is called. This is definitely introducing a convergence problem in Hicum that I need to address.
2.- The other issue I want to bring up has to do with the the second argument of the ddx operator. I read the LRM and it says exactly what Geoffrey explained to me, i.e., only node voltages are allowed. However, I don't agree with his argument regarding the impossibility of defining a partial derivative wrt an arbitrary function of the node voltages. The first thing we need to clarify is the meaning of the second argument of the ddx operator, i.e., whether this is simply a symbol or it is actually a voltage. We have followed the symbol approach. This is not surprising when one realizes the model API of many HB simulators rely on branch voltages rather than node voltages. Our translator then supports ddx operations respect to both node voltages and branch voltages.
By the symbol approach I mean that all the symbols are considered independent. This means that if
Ids=Ids(V(g,s), V(g), V(d), V(b,s), V(d,s), V(s,d)) (written in terms of those symbols, or, variables given in terms of the same voltage probes, then the following results follow:
ddx(Ids,V(s))=0 (symbol is not present).
ddx(Ids,V(d,s)) in general different than -ddx(Ids,V(s,d)) (V(s,d) and V(d,s) are simply different symbols).
ddx(Ids,V(s,g))=0. (symbol is not present).
ddx(Ids,V(g,s)) in general different than ddx(Ids,V(g)).
ddx(Ids,V(s,d)) in general different than -ddx(Ids,V(d)).
Here all the symbols are treated as independent variables (even V(d,s) and V(s,d)). We actually do something slightly different, because we consider V(d,s) as the negative of symbol V(s,d).
If we consider that V(g) is a node voltage and V(g,s) is a branch voltage, then things are quite different. Then V(g,s), V(g), V(d), V(b,s), V(d,s), and, V(s,d) are a set of linearly dependent variables (directions) as Geoffrey pointed out. However, the partial derivative respect to any of the variables in the list is well defined as I will explain. We know that the node voltages are a set of independent vectors in a n-dimensional space, where n-is the number of nodes used in defining Ids (directly as node voltages or indirectly as branch voltages). When we say ddx(Ids,V(d,s)) we just want the ratio of change of dIds/dS_n. This is the ratio of an Ids differential and the projection of dS along the n direction. Here n is normal to the plane defined by V(d,s), in the node voltage n-dimensional space. dS is a differential displacement vector in the same node-voltage n-dimensional plane. The definition of ddx(Ids,V(d,s)) pays no attention to any of the vectors employed in the definition of I(d,s) (node voltages or branch voltages), but the one that determines the direction respect to which the differentiation needs to be performed. It is precisely due to this fact that it is possible to express ddx(Ids,V(d,s)) in terms of partial derivatives respect to node voltages only.
I can share the derivation for the interested ones, but for the case under consideration ddx(Ids,V(d,s)) can be expressed in terms of ddx operators that use node voltages as the second argument as follows:
ddx(Ids,V(d,s))=1/2*ddx(Ids,V(d))- 1/2*ddx(Ids,V(s))
This result comes from the more general expression
F_n= F_x * i.n * ds_x/ds_n + F_y * j.n * ds_y/ds_n + F_z * k.n * ds_z/ds_n,
which is the result of expressing the differential of a function as the internal product of its Gradient and a differential displacement vector, in two different systems of reference, one of them containing the direction of interest and two arbitrary directions perpendicular to it. Then both sides of the expression are projected onto the n direction.
F_x, F_y, and, F_z are strictly speaking the components of the gradient of F along node voltages (x, y and z)
F_n component of F gradient along direction defined by the function of (x, y, and z)
i.n, j.n, and k.n projections of unitary vectors (i,j, and k) and on normal to plane defined by n=n(x,y,z)
ds_x, ds_y, ds_z, and ds_n) displacement components along the x, y, z and n directions.
In general F_x, F_y and F_z, and F_n are gradient components, but for a transformation as simple as delta=x1-x2, then gradient component and partial derivatives are the same (not the case in polar coordinates, where the partial derivatives need to be scaled to obtain the gradient components).
Now lets compute ddx(QG,V(g,b)) for
Qchan = W*L*Cox*(V(g,s) - V(b,s) - VFB);
QG = Cgso * V(g,s) + Cgdo * V(g,d) + Cgbo * V(g,b) + Qchan;
To avoid confusion I will re-write the above expression using node voltages, i.e.,
Qchan = W*L*Cox*(V(g)- V(s) - V(b)+ V(s) - VFB);
QG = Cgso * (V(g)-V(s)) + Cgdo * (V(g)- V(d)) + Cgbo * (V(g)- V(b)) + Qchan;
As a single line
QG = Cgso * (V(g)-V(s)) + Cgdo * (V(g)- V(d)) + Cgbo * (V(g)- V(b)) + W*L*Cox*(V(g)- V(b) - VFB);
Finally
ddx(QG,V(g,b)) = 1/2*(Cgso + Cgdo + Cgbo + W*L*Cox)+ 1/2*(Cgbo + W*L*Cox)
Geoffrey wrote...
"Cjci=ddx(Qjci,V(ci,bi)) is not legal, per the Verilog-AMS LRM -- I helped define this, and I thought very hard about what should and should not be allowed. The problem has to do with what is held constant when taking the partial derivative; it's clear when you take ddx wrt a node voltage that all other nodes are held constant. If you try to take a derivative wrt a branch, you might have your branches be (Vgs, Vgd, Vgb) or you might have them be (Vgs, Vds, Vbs). If you were allowed to write ddx(Ids, V(d,s)), you might get a different answer depending on what you picked to be your independent variables (and whether the simulator understood what you intended to be independent, and whether drain/source swapping confused it)."
branch (G1FIN2,G1FIN1) br_ind_g1_1;
branch (G1FIN2,G1FIN1) br_res_g1_1;
...
V(br_ind_g1_1) <+ LG1FIN1*ddt(I(br_ind_g1_1));
Are br_ind_g1_1 and br_res_g1_1 parallel branches or aliases for a single branch? In my opinion the person who wrote the model was trying to implement two branches in parallel. Is this what the language supposed to produce?
I have been trying to ask this to the group for quite some time. The LRM says " There can be any number of named branches between any two signals."
Thank you
Alfredo
Those are two branches in parallel, yes. It looks like the author is
putting an inductor in parallel with a resistor.
- Boris
For (1) below, are you referring to the Samanskii method? If so, then yes,
any ddx terms that are contributing to current would have to be computed
correctly even though the Jacobian itself isn't being calculated. I think
this applies to any type of pure-rhs load -- for instance, some simulators
may choose to do a pure-rhs load to check KCL or to do post-processing to
evaluate terminal currents or something along those lines. But from a
language-specification point of view, I don't think that's a roadblock.
(And if ddx-terms are being contributed, then in fact only the 2nd-deriv
terms are going into the Jacobian -- the 1-st deriv terms are being put
into the rhs, and aren't going out to the Jacobian).
On point (2) below: Suppose we have
real x, y, z1, z2;
x = V(a, b);
y = V(a) - V(b);
z1 = ddx(x, V(a));
z2 = ddx(y, V(a));
In my opinion, any valid definition of ddx would ensure that z1 and z2
always have the same value. The language currently does that. Allowing
V(a, b) as a valid with-respect-to target would violate this principle
(and a bunch of other stuff as well, I think...)
- Boris
I am not trying to change the standard. I think that allowing V(a,b) as a valid target for ddx will only bring confusion. The point that I am trying to make is, that from a mathematical point of view, partial differentiation respect to V(a,b), when V(a,b) is interpreted a voltage between nodes V(a) and V(b) is well defined. In this interpretation, differentiating x and y in your example always produce identical results, whether the differentiation is performed wrt V(b), V(b), V(a,b), or, V(b,a).
The situation you are describing only happens when the V(a) and V(a,b) are considered independent symbols. I am planning to modify our handling of ddx, to be consistent with the voltage interpretation, because this seems to be the correct interpretation.
Still I find extremely counter intuitive that when somebody writes the expression of the charge in terms of the branch voltage, then it is forced to differentiate respect to a node voltage to compute the capacitance. That is really what got me in to the Mathematica idea. In my opinion an ideal ddx operator should allow differentiating respect to the symbol an arbitrary symbol, but that is very difficult to implement.
Alfredo
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Boris Troyanovsky
Sent: Tuesday, December 27, 2011 10:19 AM
To: cmc-ve...@googlegroups.com
Subject: RE: [cmc-verilog-a] restricting ddx()
Alfredo
-----Original Message-----
From: cmc-ve...@googlegroups.com [mailto:cmc-ve...@googlegroups.com] On Behalf Of Boris Troyanovsky
Sent: Tuesday, December 27, 2011 10:19 AM
To: cmc-ve...@googlegroups.com
Subject: RE: [cmc-verilog-a] restricting ddx()