Xyce  6.1
N_DEV_DeviceSupport.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_DeviceSupport.C,v $
27 //
28 // Purpose : This file contains similar functions to the spice3f5
29 // file, devsup.c. It contains support routines for
30 // device models
31 //
32 // Special Notes :
33 //
34 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
35 //
36 // Creation Date : 01/17/01
37 //
38 // Revision Information:
39 // ---------------------
40 //
41 // Revision Number: $Revision: 1.48 $
42 //
43 // Revision Date : $Date: 2015/04/22 20:35:05 $
44 //
45 // Current Owner : $Author: erkeite $
46 //-------------------------------------------------------------------------
47 
48 #include <Xyce_config.h>
49 
50 // ---------- Standard Includes ----------
51 #include <N_UTL_Math.h>
52 
53 #if( defined HAVE_FLOAT_H && defined HAVE__ISNAN_AND__FINITE_SUPPORT )
54 #include <float.h>
55 #define isnan(x) _isnan(x)
56 #define isinf(x) (!_finite(x))
57 #else
58 #define isnan(x) std::isnan(x)
59 #define isinf(x) std::isinf(x)
60 #endif
61 
62 
63 // ---------- Xyce Includes ----------
64 #include <N_DEV_DeviceSupport.h>
65 #include <N_DEV_Const.h>
66 
67 namespace Xyce {
68 namespace Device {
69 
70 //-----------------------------------------------------------------------------
71 // Function : DeviceSupport::lambertw
72 // Purpose : provides a lambert-w function for diodes and BJT's.
73 // Special Notes :
74 //
75 // Purpose. Evaluate principal branch of Lambert W function at x.
76 //
77 // w = w(x) is the value of Lambert's function.
78 // ierr = 0 indicates a safe return.
79 // ierr = 1 if x is not in the domain.
80 // ierr = 2 if the computer arithmetic contains a bug.
81 // xi may be disregarded (it is the error).
82 //
83 // Prototype: void lambertw( double, double, int, double);
84 //
85 // Reference:
86 // T.C. Banwell
87 // Bipolar transistor circuit analysis using the Lambert W-function,
88 // IEEE Transactions on Circuits and Systems I: Fundamental Theory
89 // and Applications
90 //
91 // vol. 47, pp. 1621-1633, Nov. 2000.
92 //
93 // Scope : public
94 // Creator : David Day, SNL
95 // Creation Date : 04/16/02
96 //-----------------------------------------------------------------------------
97 void DeviceSupport::lambertw(double x, double &w, int &ierr, double &xi)
98 {
99  int i=0, maxit = 10;
100  const double turnpt = -exp(-1.), c1 = 1.5, c2 = .75;
101  double r, r2, r3, s, mach_eps, relerr = 1., diff;
102  mach_eps = 2.e-15; // float:2e-7
103  ierr = 0;
104 
105  if( x > c1)
106  {
107  w = c2*log(x);
108  xi = log( x/ w) - w;
109  }
110  else
111  {
112  if( x >= 0.0)
113  {
114  w = x;
115  if( x == 0. ) return;
116  if( x < (1-c2) ) w = x*(1.-x + c1*x*x);
117  xi = - w;
118  }
119  else
120  {
121  if( x >= turnpt)
122  {
123  if( x > -0.2 )
124  {
125  w = x*(1.0-x + c1*x*x);
126  xi = log(1.0-x + c1*x*x) - w;
127  }
128  else
129  {
130  diff = x-turnpt;
131  if( diff < 0.0 ) diff = -diff;
132  w = -1 + sqrt(2.0*exp(1.))*sqrt(x-turnpt);
133  if( diff == 0.0 ) return;
134  xi = log( x/ w) - w;
135  }
136  }
137  else
138  {
139  ierr = 1; // x is not in the domain.
140  w = -1.0;
141  return;
142  }
143  }
144  }
145 
146  while( relerr > mach_eps && i<maxit)
147  {
148  r = xi/(w+1.0); //singularity at w=-1
149  r2 = r*r;
150  r3 = r2*r;
151  s = 6.*(w+1.0)*(w+1.0);
152  w = w * ( 1.0 + r + r2/(2.0*( w+1.0)) - (2. * w -1.0)*r3/s );
153  if( w * x < 0.0 ) w = -w;
154  xi = log( x/ w) - w;
155 
156  if( x>1.0 )
157  {
158  relerr = xi / w;
159  }
160  else
161  {
162  relerr = xi;
163  }
164  if(relerr < 0.0 ) relerr = -relerr;
165  ++i;
166  }
167  if( i == maxit ) ierr = 2;
168 }
169 
170 //-----------------------------------------------------------------------------
171 // Function : DeviceSupport::limvds
172 // Purpose : limit the per-iteration change of VDS
173 // Special Notes :
174 // Scope : public
175 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
176 // Creation Date : 01/17/01
177 //-----------------------------------------------------------------------------
178 double DeviceSupport::limvds ( double vnew, double vold)
179 {
180 
181  if(vold >= 3.5)
182  {
183  if(vnew > vold) vnew = std::min(vnew,(3.0 * vold) + 2.0);
184  else
185  {
186  if (vnew < 3.5) vnew = std::max(vnew,2.0);
187  }
188  }
189  else
190  {
191  if(vnew > vold) vnew = std::min(vnew, 4.0);
192  else vnew = std::max(vnew,-0.5);
193  }
194  return(vnew);
195 }
196 
197 //-----------------------------------------------------------------------------
198 // Function : DeviceSupport::pnjlim
199 // Purpose : limit the per-iteration change of PN junction voltages
200 // Special Notes :
201 // Scope : public
202 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
203 // Creation Date : 01/17/01
204 //-----------------------------------------------------------------------------
206  double vnew,
207  double vold,
208  double vt,
209  double vcrit,
210  int *icheck
211  )
212 {
213  double arg;
214 
215  if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt)))
216  {
217  if(vold > 0)
218  {
219  arg = 1 + (vnew - vold) / vt;
220 
221  if(arg > 0)
222  {
223  vnew = vold + vt * log(arg);
224  }
225  else
226  {
227  vnew = vcrit;
228  }
229  }
230  else
231  {
232  vnew = vt *log(vnew/vt);
233  }
234 
235  *icheck = 1;
236  }
237  else
238  {
239  *icheck = 0;
240  }
241 
242  return(vnew);
243 }
244 
245 //-----------------------------------------------------------------------------
246 // Function : DeviceSupport::pnjlim_new
247 // Purpose : limit the per-iteration change of PN junction voltages
248 // Special Notes : Copied from NGSpice, which has the following comment:
249 // This code has been fixed by Alan Gillespie adding limiting
250 // for negative voltages
251 // Scope : public
252 // Creator : Tom Russo, SNL 1445, Electrical Systems Modeling
253 // Creation Date : 11/19/2012
254 //-----------------------------------------------------------------------------
256  double vnew,
257  double vold,
258  double vt,
259  double vcrit,
260  int *icheck
261  )
262 {
263  double arg;
264 
265  if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt)))
266  {
267  if(vold > 0)
268  {
269  arg = (vnew - vold) / vt;
270 
271  if(arg > 0)
272  {
273  vnew = vold + vt * (2+log(arg-2));
274  }
275  else
276  {
277  vnew = vold - vt*(2+log(2-arg));
278  }
279  }
280  else
281  {
282  vnew = vt *log(vnew/vt);
283  }
284 
285  *icheck = 1;
286  }
287  else
288  {
289  if (vnew < 0)
290  {
291  if (vold > 0)
292  {
293  arg= -vold -1;
294  }
295  else
296  {
297  arg = 2*vold -1;
298  }
299  if (vnew < arg)
300  {
301  vnew = arg;
302  *icheck=1;
303  }
304  else
305  {
306  *icheck = 0;
307  }
308  }
309  else
310  {
311  *icheck = 0;
312  }
313  }
314 
315  return(vnew);
316 }
317 
318 //-----------------------------------------------------------------------------
319 // Function : DeviceSupport::fetlim
320 // Purpose : limit the per-iteration change of FET voltages
321 // Special Notes :
322 // Scope : public
323 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
324 // Creation Date : 01/17/01
325 //-----------------------------------------------------------------------------
327  double vnew,
328  double vold,
329  double vto
330  )
331 {
332  double vtsthi;
333  double vtstlo;
334  double vtox;
335  double delv;
336  double vtemp;
337 
338 #ifdef Xyce_FETLIM_NAN_CHECK
339  // Make sure that vto is not a Nan.
340  if (finiteNumberTest(vto) < 0)
341  {
342  vto = 1.0; // kludge.
343  }
344 #endif
345 
346  vtsthi = fabs(2*(vold-vto))+2;
347  vtstlo = vtsthi/2 +2;
348  vtox = vto + 3.5;
349  delv = vnew-vold;
350 
351  if (vold >= vto)
352  {
353  if(vold >= vtox)
354  {
355  if(delv <= 0)
356  {
357  // going off
358  if(vnew >= vtox)
359  {
360  if(-delv >vtstlo) vnew = vold - vtstlo;
361  }
362  else
363  {
364  vnew = std::max(vnew,vto+2.0);
365  }
366  }
367  else
368  {
369  // staying on
370  if(delv >= vtsthi) vnew = vold + vtsthi;
371  }
372  }
373  else
374  {
375  // middle region
376  if(delv <= 0)
377  {
378  // decreasing
379  vnew = std::max(vnew,vto-0.5);
380  }
381  else
382  {
383  // increasing
384  vnew = std::min(vnew,vto+4.0);
385  }
386  }
387  }
388  else
389  {
390  // off
391  if(delv <= 0)
392  {
393  if(-delv >vtsthi) vnew = vold - vtsthi;
394  }
395  else
396  {
397  vtemp = vto + 0.5;
398  if(vnew <= vtemp)
399  {
400  if(delv >vtstlo) vnew = vold + vtstlo;
401  }
402  else
403  {
404  vnew = vtemp;
405  }
406  }
407  }
408  return(vnew);
409 }
410 
411 //-----------------------------------------------------------------------------
412 // Function : DeviceSupport::cmeyer
413 // Purpose : Compute the MOS overlap capacitances as functions of the
414 // device terminal voltages
415 // Special Notes :
416 // Scope : public
417 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
418 // Creation Date : 01/17/01
419 //-----------------------------------------------------------------------------
421  double vgs0, // initial voltage gate-source
422  double vgd0, // initial voltage gate-drain
423  double vgb0, // initial voltage gate-bulk
424  double von0,
425  double vdsat0,
426  double vgs1, // final voltage gate-source
427  double vgd1, // final voltage gate-drain
428  double vgb1, // final voltage gate-bulk
429  double covlgs, // overlap capacitance gate-source
430  double covlgd, // overlap capacitance gate-drain
431  double covlgb, // overlap capacitance gate-bulk
432  register double *cgs,
433  register double *cgd,
434  register double *cgb,
435  double phi,
436  double cox,
437  double von,
438  double vdsat
439  )
440 {
441  double vdb;
442  double vdbsat;
443  double vddif;
444  double vddif1;
445  double vddif2;
446  double vgbt;
447 
448  *cgs = 0;
449  *cgd = 0;
450  *cgb = 0;
451 
452  vgbt = vgs1-von;
453  if (vgbt <= -phi)
454  {
455  *cgb = cox;
456  }
457  else if (vgbt <= -phi/2)
458  {
459  *cgb = -vgbt*cox/phi;
460  }
461  else if (vgbt <= 0)
462  {
463  *cgb = -vgbt*cox/phi;
464  *cgs = cox/(7.5e-1*phi)*vgbt+cox/1.5;
465  }
466  else
467  {
468  vdbsat = vdsat-(vgs1-vgb1);
469  vdb = vgb1-vgd1;
470  if (vdbsat <= vdb)
471  {
472  *cgs = cox/1.5;
473  }
474  else
475  {
476  vddif = 2.0*vdbsat-vdb;
477  vddif1 = vdbsat-vdb-1.0e-12;
478  vddif2 = vddif*vddif;
479  *cgd = cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
480  *cgs = cox*(1.0-vddif1*vddif1/vddif2)/1.5;
481  }
482  }
483 
484  vgbt = vgs0-von0;
485  if (vgbt <= -phi)
486  {
487  *cgb += cox;
488  }
489  else if (vgbt <= -phi/2)
490  {
491  *cgb += -vgbt*cox/phi;
492  }
493  else if (vgbt <= 0)
494  {
495  *cgb += -vgbt*cox/phi;
496  *cgs += cox/(7.5e-1*phi)*vgbt+cox/1.5;
497  }
498  else
499  {
500  vdbsat = vdsat0-(vgs0-vgb0);
501  vdb = vgb0-vgd0;
502  if (vdbsat <= vdb)
503  {
504  *cgs += cox/1.5;
505  }
506  else
507  {
508  vddif = 2.0*vdbsat-vdb;
509  vddif1 = vdbsat-vdb-1.0e-12;
510  vddif2 = vddif*vddif;
511  *cgd += cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
512  *cgs += cox*(1.0-vddif1*vddif1/vddif2)/1.5;
513  }
514  }
515 
516  *cgs = *cgs *.5 + covlgs;
517  *cgd = *cgd *.5 + covlgd;
518  *cgb = *cgb *.5 + covlgb;
519 }
520 
521 //-----------------------------------------------------------------------------
522 // Function : DeviceSupport::qmeyer
523 // Purpose : Compute the MOS overlap capacitances as functions of the
524 // device terminal voltages
525 //
526 // Special Notes : ARGSUSED because vgb is no longer used
527 //
528 // Scope : public
529 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
530 // Creation Date : 01/17/01
531 //-----------------------------------------------------------------------------
533  double vgs, // initial voltage gate-source
534  double vgd, // initial voltage gate-drain
535  double vgb, // initial voltage gate-bulk
536  double von,
537  double vdsat,
538  double & capgs, // non-constant portion of g-s overlap capacitance
539  double & capgd, // non-constant portion of g-d overlap capacitance
540  double & capgb, // non-constant portion of g-b overlap capacitance
541  double phi,
542  double cox // oxide capactiance
543  )
544 {
545  double vds;
546  double vddif;
547  double vddif1;
548  double vddif2;
549  double vgst;
550 
551  //double vgdt;
552  //double vdenom;
553  //double vdenom2;
554 
555 
556  vgst = vgs-von;
557  if (vgst <= -phi)
558  {
559  capgb = cox/2;
560  capgs = 0;
561  capgd = 0;
562  }
563  else if (vgst <= -phi/2)
564  {
565  capgb = -vgst*cox/(2*phi);
566  capgs = 0;
567  capgd = 0;
568  }
569  else if (vgst <= 0)
570  {
571  capgb = -vgst*cox/(2*phi);
572  capgs = vgst*cox/(1.5*phi)+cox/3;
573  capgd = 0;
574  }
575  else
576  {
577  vds = vgs-vgd;
578  if (vdsat <= vds)
579  {
580  capgs = cox/3;
581  capgd = 0;
582  capgb = 0;
583  }
584  else
585  {
586 
587  vddif = 2.0*vdsat-vds;
588  vddif1 = vdsat-vds/*-1.0e-12*/;
589  vddif2 = vddif*vddif;
590  capgd = cox*(1.0-vdsat*vdsat/vddif2)/3;
591  capgs = cox*(1.0-vddif1*vddif1/vddif2)/3;
592  capgb = 0;
593 
594 
595  //vgdt = vgd-von;
596  //vdenom=vgst + vgdt;
597  //vdenom2=vdenom*vdenom;
598 
599  //capgd = cox*(1.0-vgst*vgst/vdenom2)/3.0;
600  //capgs = cox*(1.0-vgdt*vgdt/vdenom2)/3.0;
601 
602  }
603  }
604 }
605 
606 //-----------------------------------------------------------------------------
607 // Function : DeviceSupport::qmeyerderivs
608 // Purpose : Computes the partial derivatives of the Meyer capacitances
609 // with respect to various voltages.
610 //
611 // Special Notes : We need this in order to make the Meyer model MPDE
612 // compatible.
613 //
614 // Scope : public
615 // Creator : Keith R. Santarelli, SNL, Electrical & Microsystems Modeling
616 // Creation Date : 02/08/08
617 //-----------------------------------------------------------------------------
619  (
620  double vgs, // initial voltage gate-source
621  double vgd, // initial voltage gate-drain
622  double vgb, // initial voltage gate-bulk
623  double von,
624  double vdsat,
625  double & dcapgsdvgs, //partial deriv. of capgs with respect to vgs
626  double & dcapgsdvgb, //partial deriv. of capgs with respect to vgb
627  double & dcapgsdvgd, //partial deriv. of capgs with respect to vgd
628  double & dcapgddvgs, //partial deriv. of capgd with respect to vgs
629  double & dcapgddvgb, //partial deriv. of capgd with respect to vgb
630  double & dcapgddvgd, //partial deriv. of capgd with respect to vgd
631  double & dcapgbdvgs, //partial deriv. of capgb with respect to vgs
632  double & dcapgbdvgb, //partial deriv. of capgb with respect to vgb
633  double & dcapgbdvgd, //partial deriv. of capgb with respect to vgd
634  double phi,
635  double cox, // oxide capactiance
636  int Dtype //transistor type
637  )
638 {
639  double vgst;
640  double vds;
641  double vdenom, vdenom3;
642  double vgdt;
643 
644  vgst = vgs-von;
645  if (vgst <= -phi)
646  {
647  dcapgsdvgs=0;
648  dcapgsdvgb=0;
649  dcapgsdvgd=0;
650  dcapgddvgs=0;
651  dcapgddvgb=0;
652  dcapgddvgd=0;
653  dcapgbdvgs=0;
654  dcapgbdvgb=0;
655  dcapgbdvgd=0;
656 
657  }
658  else if (vgst <= -phi/2)
659  {
660  dcapgsdvgs=0;
661  dcapgsdvgb=0;
662  dcapgsdvgd=0;
663  dcapgddvgs=0;
664  dcapgddvgb=0;
665  dcapgddvgd=0;
666  dcapgbdvgs=-1.0*cox/(2.0*phi);
667  dcapgbdvgb=0;
668  dcapgbdvgd=0;
669  }
670  else if (vgst <= 0)
671  {
672  dcapgsdvgs=cox/(1.5*phi);
673  dcapgsdvgb=0;
674  dcapgsdvgd=0;
675  dcapgddvgs=0;
676  dcapgddvgb=0;
677  dcapgddvgd=0;
678  dcapgbdvgs=-1.0*cox/(2.0*phi);
679  dcapgbdvgb=0;
680  dcapgbdvgd=0;
681  }
682  else
683  {
684  vds = vgs-vgd;
685  if (vdsat <= vds)
686  {
687  dcapgsdvgs=0;
688  dcapgsdvgb=0;
689  dcapgsdvgd=0;
690  dcapgddvgs=0;
691  dcapgddvgb=0;
692  dcapgddvgd=0;
693  dcapgbdvgs=0;
694  dcapgbdvgb=0;
695  dcapgbdvgd=0;
696  }
697  else
698  {
699  vgdt = vgd-von;
700  vdenom=vgst + vgdt;
701  vdenom3=vdenom*vdenom*vdenom;
702 
703  dcapgsdvgs=4.0/3.0*cox*vgdt*vgdt/vdenom3;
704  dcapgsdvgb=0;
705  dcapgsdvgd=-4.0/3.0*cox*vgst*vgdt/vdenom3;
706  dcapgddvgs=-4.0/3.0*cox*vgst*vgdt/vdenom3;
707  dcapgddvgb=0;
708  dcapgddvgd=4.0/3.0*cox*vgst*vgst/vdenom3;
709  dcapgbdvgs=0;
710  dcapgbdvgb=0;
711  dcapgbdvgd=0;
712 
713  }
714  }
715 
716  //Now have to "type-ize" the cap. derivatives:
717 
718  //dcapgsdvgs=Dtype*dcapgsdvgs;
719  //dcapgsdvgb=Dtype*dcapgsdvgb;
720  //dcapgsdvgd=Dtype*dcapgsdvgd;
721  //dcapgddvgs=Dtype*dcapgddvgs;
722  //dcapgddvgb=Dtype*dcapgddvgb;
723  //dcapgddvgd=Dtype*dcapgddvgd;
724  //dcapgbdvgs=Dtype*dcapgbdvgs;
725  //dcapgbdvgb=Dtype*dcapgbdvgb;
726  //dcapgbdvgd=Dtype*dcapgbdvgd;
727 }
728 
729 //-----------------------------------------------------------------------------
730 // Function : DeviceSupport::noiseSupport
731 //
732 // Purpose : Related to the NevalSrc function in spice, but with many
733 // differences.
734 // Special Notes :
735 // Scope : public
736 // Creator : Eric Keiter
737 // Creation Date : 12/17/2014
738 //-----------------------------------------------------------------------------
740  double & noise, double & lnNoise,
741  const int type, const double param, const double temp)
742 {
743  switch (type)
744  {
745  case SHOTNOISE: // param is the dc current in a semiconductor
746  noise = 2.0 * CONSTQ * fabs(param);
747  lnNoise = log( std::max(noise,N_MINLOG) );
748  break;
749 
750  case THERMNOISE: // param is the conductance of a resistor
751  noise = 4.0 * CONSTboltz * temp * param;
752  lnNoise = log( std::max(noise,N_MINLOG) );
753  break;
754  }
755 }
756 
757 #ifdef notdef
758 //-----------------------------------------------------------------------------
759 // Function : DeviceSupport::cap
760 // Purpose : compute equivalent conductances
761 // divide up the channel charge (1-xqc)/xqc to
762 // source and drain
763 //
764 // Special Notes : XXX This is no longer used, apparently
765 //
766 // Scope : public
767 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
768 // Creation Date : 01/17/01
769 //-----------------------------------------------------------------------------
770 void DeviceSupport::cap (
771  register CKTcircuit *ckt,
772  double vgd,
773  double vgs,
774  double vgb,
775  double covlgd,
776  double covlgs,
777  double covlgb,
778  double capbd,
779  double capbs,
780  double cggb,
781  double cgdb,
782  double cgsb,
783  double cbgb,
784  double cbdb,
785  double cbsb,
786  double *gcggb,
787  double *gcgdb,
788  double *gcgsb,
789  double *gcbgb,
790  double *gcbdb,
791  double *gcbsb,
792  double *gcdgb,
793  double *gcddb,
794  double *gcdsb,
795  double *gcsgb,
796  double *gcsdb,
797  double *gcssb,
798  double qgate,
799  double qchan,
800  double qbulk,
801  double *qdrn,
802  double *qsrc,
803  double xqc)
804 {
805  double gcd;
806  double gcdxd;
807  double gcdxs;
808  double gcg;
809  double gcgxd;
810  double gcgxs;
811  double gcs;
812  double gcsxd;
813  double gcsxs;
814  double qgb;
815  double qgd;
816  double qgs;
817 
818  gcg = (cggb+cbgb)*ckt->CKTag[1];
819  gcd = (cgdb+cbdb)*ckt->CKTag[1];
820  gcs = (cgsb+cbsb)*ckt->CKTag[1];
821  gcgxd = -xqc*gcg;
822  gcgxs = -(1-xqc)*gcg;
823  gcdxd = -xqc*gcd;
824  gcdxs = -(1-xqc)*gcd;
825  gcsxd = -xqc*gcs;
826  gcsxs = -(1-xqc)*gcs;
827  *gcdgb = gcgxd-covlgd*ckt->CKTag[1];
828  *gcddb = gcdxd+(capbd+covlgd)*ckt->CKTag[1];
829  *gcdsb = gcsxd;
830  *gcsgb = gcgxs-covlgs*ckt->CKTag[1];
831  *gcsdb = gcdxs;
832  *gcssb = gcsxs+(capbs+covlgs)*ckt->CKTag[1];
833  *gcggb = (cggb+covlgd+covlgs+covlgb)*ckt->CKTag[1];
834  *gcgdb = (cgdb-covlgd)*ckt->CKTag[1];
835  *gcgsb = (cgsb-covlgs)*ckt->CKTag[1];
836  *gcbgb = (cbgb-covlgb)*ckt->CKTag[1];
837  *gcbdb = (cbdb-capbd)*ckt->CKTag[1];
838  *gcbsb = (cbsb-capbs)*ckt->CKTag[1];
839  /*
840  * compute total terminal charges
841  */
842  qgd = covlgd*vgd;
843  qgs = covlgs*vgs;
844  qgb = covlgb*vgb;
845  qgate = qgate+qgd+qgs+qgb;
846  qbulk = qbulk-qgb;
847  *qdrn = xqc*qchan-qgd;
848  *qsrc = (1-xqc)*qchan-qgs;
849  /*
850  * finished
851  */
852 }
853 #endif
854 
855 #if 0
856 double DeviceSupport::pred
857  (
858  CKTcircuit *ckt,
859  int loct
860  )
861 {
862 
863  /* predict a value for the capacitor at loct by
864  * extrapolating from previous values
865  */
866 
867 #ifndef NEWTRUNC
868  double xfact;
869  xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
870  return( ( (1+xfact) * *(ckt->CKTstate1+loct) ) -
871  ( xfact * *(ckt->CKTstate2+loct) ) );
872 #endif /*NEWTRUNC*/
873 
874 }
875 #endif
876 
877 //-----------------------------------------------------------------------------
878 // Function : DeviceSupport::contVds
879 // Purpose : continuation adjustment for MOSFET drain-source voltage.
880 //
881 // Special Notes : min*vds is the value returned for vds when alpha=0.
882 //
883 // This idea is based, loosely, on a paper by Jaijeet
884 // Rosychowdhury.
885 //
886 // Scope : public
887 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
888 // Creation Date : 09/04/03
889 //-----------------------------------------------------------------------------
890 double DeviceSupport::contVds (double vds, double alpha, double min)
891 {
892  if (min <= 0.0) min = 0.3;
893  return ( vds * (alpha*(1.0-min) + min) );
894 }
895 
896 //-----------------------------------------------------------------------------
897 // Function : DeviceSupport::contVgst
898 // Purpose : continuation adjustment for MOSFET drain-source voltage.
899 //
900 // Special Notes : vgstConst is the value returned for vgst when alpha=0.
901 //
902 // This idea is based, loosely, on a paper by Jaijeet
903 // Rosychowdhury.
904 //
905 // The alpha=0 condition, for which vgs, or vgst is
906 // considered constant, essentially makes the device a
907 // single-state device. No matter what actual voltage is
908 // applied across Vg-Vs, the device will act as though
909 // there is a fixed applied voltage. If vgstconst is set
910 // to a high voltage (like the default, 3.0) then the
911 // devices are all in an "on" state for alpha=0. If
912 // vgstconst is set to zero, then the devices are all in an
913 // off state for alpha=0.
914 //
915 // As the alpha parameter is swept from zero to 1, at some
916 // point the MOSFET will start behaving, functionally like
917 // a MOSFET. At alpha=0, it doesn't - it kind of acts like
918 // a capacitor. At what point in the sweep this
919 // functionality kicks in, depends on the point at which
920 // the Ids vs Vgs curve has an intersection with Ids=0, for
921 // reasonable values of Vgs. (reasonable values probably
922 // being -1 to +5 volts)
923 //
924 // If Vgstconst is set to zero, this intersection happens
925 // immediately, on the first step where alpha is nonzero.
926 // If Vgstconst is fairly high (say 4.0 volts), this
927 // intersection happens late. If it is too high, it never
928 // happens.
929 //
930 // Unfortunately, during the sweep, once it kicks in, it
931 // kicks in for every MOSFET almost all at once, and there
932 // is a sharp transition in the continuation curve. The
933 // trick to making this homotopy work well, is to make this
934 // transition as gentle as possible, I think.
935 //
936 // Scope : public
937 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
938 // Creation Date : 09/04/03
939 //-----------------------------------------------------------------------------
941  (double vgst, double alpha, double vgstConst)
942 {
943  return ((alpha)*vgst + (1.0-alpha)*vgstConst);
944 }
945 
946 //-----------------------------------------------------------------------------
947 // Function : DeviceSupport::getGainScaleBlockID
948 // Purpose : determines which block to associate the mosfet device
949 // This is used for a multi-block gainscale continuation.
950 // Scope : public
951 // Creator : Roger Pawlowski, SNL
952 // Creation Date : 01/28/05
953 //-----------------------------------------------------------------------------
955 {
956  double val = u.RandomDouble();
957 
958  // get rid of negatives
959  val = val * val;
960  val = sqrt(val);
961 
962  double interval = 1.0 / numBlocks;
963 
964  for (int i = 0; i < numBlocks; ++i) {
965  double lowBound = ((double) i) * interval;
966  double highBound = ((double) (i+1)) * interval;
967  if ((val >= lowBound) && (val < highBound)) {
968  return i;
969  }
970  }
971 
972  return (numBlocks-1);
973 }
974 
975 //-----------------------------------------------------------------------------
976 // Function : DeviceSupport::getGainScaleBlockID
977 // Purpose : computes random perturbation for stretched homotopy.
978 // Scope : public
979 // Creator : Roger Pawlowski, SNL
980 // Creation Date : 01/28/05
981 //-----------------------------------------------------------------------------
983 {
984  double val = u.RandomDouble();
985  val = val * val;
986  val = sqrt(val);
987  return val;
988 }
989 
990 //-----------------------------------------------------------------------------
991 // Function : DeviceSupport::getGainScaleBlockID
992 // Purpose : sets seed for random number generator used in getRandomPerturbation().
993 // Scope : public
994 // Creator : Richard Schie, Electrical Systems Modeling
995 // Creation Date : 10/01/12
996 //-----------------------------------------------------------------------------
997 int DeviceSupport::SetSeed(unsigned int seedIn)
998 {
999  int retVal = u.SetSeed( seedIn );
1000  return retVal;
1001 }
1002 
1003 //-----------------------------------------------------------------------------
1004 // Function : DeviceSupport::Xexp
1005 //
1006 // Purpose : Exponential function with range checking and truncation
1007 // for improved convergence when searching for DCOP
1008 //
1009 // Special Notes : This function provides a Taylor series approximation
1010 // to an exponential (out to N=order terms),
1011 // unless order >=20, in which case it just returns an
1012 // exponential.
1013 //
1014 // Scope : public
1015 //
1016 // Creator : Dave Shirley, PSSI
1017 // Creation Date : 01/13/06
1018 //-----------------------------------------------------------------------------
1019 double DeviceSupport::Xexp(double X, double &ddX, double order)
1020 {
1021  if (X > CONSTMAX_EXP_ARG)
1022  {
1023  X = CONSTMAX_EXP_ARG;
1024  }
1025 #if 1
1026  if (order > 19.999)
1027  {
1028  ddX=exp(X);
1029  return ddX;
1030  }
1031  int i, ord;
1032  double ans, term;
1033 
1034  double base;
1035 
1036  // It is very important to return and use the correct derivative, otherwise
1037  // conductances are not correct.
1038  {
1039  term = 1;
1040  ans = 1;
1041  ddX = 1;
1042  ord = static_cast<int>( order );
1043  for (i=1 ; i<=ord ; ++i)
1044  {
1045  term *= X/i;
1046  ans += term;
1047  if (i<ord)
1048  {
1049  ddX += term;
1050  }
1051  }
1052  // If we are partway between two integer orders "ord", linear combination
1053  // of the order=ord and order=ord+1 series.
1054  if (order > ord)
1055  {
1056  ddX += (order-ord)*term;
1057  term *= X/(ord+1);
1058  ans += (order-ord)*term;
1059  }
1060  }
1061  return ans;
1062 #else
1063 
1064  // An attempt at a lambertw replacement of the exponential.
1065  // At the moment it is not as effective a homotopy as the taylor series.
1066  // For NAND chains longer than 276 it starts to have big trouble around
1067  // order 9, getting NaN's in the RHS.
1068  if (order > 19.999)
1069  {
1070  ddX=exp(X);
1071  return ddX;
1072  }
1073 
1074  double rs,wreturn,xi;
1075  int i,ierr;
1076  // rs=1e-{order}
1077  rs=pow(10.0,-order);
1078  lambertw(rs*exp(X+rs),wreturn,ierr,xi);
1079  if (ierr != 0)
1080  {
1081  ddX = exp(X);
1082  return (ddX);
1083  }
1084  else
1085  {
1086  ddX = wreturn/(1+wreturn)/rs;
1087  return (wreturn/rs);
1088  }
1089 #endif
1090 }
1091 
1092 //-----------------------------------------------------------------------------
1093 // Function : DeviceSupport::finiteNumberTest
1094 //
1095 // Purpose : The motivation for this function is that as of
1096 // this writing, it is possible for some of the MOSFET
1097 // models to pass in Nan's for the "von" parameter.
1098 //
1099 // Special Notes : This is copied over from a similar
1100 // function in the nonlinear solver.
1101 //
1102 // Scope : public
1103 // Creator : Eric Keiter, SNL.
1104 // Creation Date : 01/05/07
1105 //-----------------------------------------------------------------------------
1107 {
1108 #if( defined HAVE_NAN_INF_SUPPORT || defined HAVE__ISNAN_AND__FINITE_SUPPORT )
1109  if (isnan(x))
1110  return -1;
1111 
1112  if (isinf(x))
1113  return -2;
1114 
1115 #else
1116 
1117  // Can pretty much use any number here
1118  double tol = 1.0e-6;
1119 
1120  // NaN check
1121  if (!(x <= tol) && !(x > tol))
1122  return -1;
1123 
1124  // Inf check:
1125  // Use the fact that: Inf * 0 = NaN
1126  double z = 0.0 * x;
1127  if (!(z <= tol) && !(z > tol))
1128  return -2;
1129 
1130 #endif
1131 
1132  return 0;
1133 }
1134 
1135 //-----------------------------------------------------------------------------
1136 // Function : DeviceSupport::spline
1137 // Purpose :
1138 // Special Notes : This method adapted from "Numerical Recipes in C++"
1139 // Scope : public
1140 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1141 // Creation Date : 4/12/06
1142 //-----------------------------------------------------------------------------
1144  std::vector<double> & x,
1145  std::vector<double> & y,
1146  std::vector<double> & y2)
1147 {
1148  double p=0;
1149  double qn=0;
1150  double sig=0;
1151  double un=0;
1152 
1153  int n = y2.size();
1154  std::vector<double> u(n-1,0.0);
1155 
1156  // Setting the upper and lower boundary conditions to a
1157  // "natural boundary condition".
1158  y2[0] = 0.0;
1159  y2[n-1] = 0.0;
1160 
1161  // This is the decomposition loop of the tridiagonal
1162  // algorithm. y2 and u are used for temporary storage
1163  // of the decomposed factors.
1164  for (int i=1; i<n-1; i++)
1165  {
1166  sig = (x[i]-x[i-1])/(x[i+1]-x[i-1]);
1167  p = sig*y2[i-1] + 2.0;
1168  y2[i] = (sig-1.0)/p;
1169  u[i] = (y[i+1]-y[i])/(x[i+1]-x[i]) -
1170  (y[i]-y[i-1])/(x[i]-x[i-1]);
1171  u[i] = (6.0*u[i]/(x[i+1]-x[i-1]) - sig*u[i-1])/p;
1172  }
1173 
1174  for (int l=n-2; l>=0; l--)
1175  {
1176  y2[l] = y2[l]*y2[l+1]+u[l];
1177  }
1178 }
1179 
1180 //-----------------------------------------------------------------------------
1181 // Function : DeviceSupport::splint
1182 // Purpose :
1183 // Special Notes : This method adapted from "Numerical Recipes in C++"
1184 // Scope : public
1185 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1186 // Creation Date : 4/12/06
1187 //-----------------------------------------------------------------------------
1189  std::vector<double> & xa,
1190  std::vector<double> & ya,
1191  std::vector<double> & y2a,
1192  double x_position,
1193  double & y_spline)
1194 {
1195  // This method taken from "Numerical Recipes in C++"
1196  int n = xa.size();
1197  // Find the right place in the table by means of bisection.
1198  double h = 0.0;
1199  double a = 0.0;
1200  double b = 0.0;
1201  int k = 0;
1202  int klo = 0;
1203  int khi = n-1;
1204  while (khi-klo > 1)
1205  {
1206  k = (khi+klo) >> 1;
1207  if (xa[k] > x_position) khi=k;
1208  else klo=k;
1209  }
1210 
1211  h = xa[khi] - xa[klo];
1212  if (h == 0.0)
1213  {
1214  //std::string err_msg =
1215  //"Bad input to cubic spline.";
1216  //throw charon::Exception("This shouldn't happen! Please notify "
1217  //"developers!", __FILE__, __LINE__);
1218 
1219  exit (0);
1220  }
1221  a = (xa[khi] - x_position)/h;
1222  b = (x_position - xa[klo])/h;
1223  // cubic spline polynomial is now evaluated
1224  y_spline = a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi])*(h*h)/6.0;
1225 
1226 
1227  // capping the spline value so that it doesn't extend
1228  // the bounds of the endpoints
1229  // this prevents wiggles and non-physical values
1230  if ( (y_spline > ya[klo]) && (y_spline > ya[khi]) )
1231  {
1232  if (ya[klo] > ya[khi]) y_spline = ya[klo];
1233  else y_spline = ya[khi];
1234  }
1235 
1236  if ( (y_spline < ya[klo]) && (y_spline < ya[khi]) )
1237  {
1238  if (ya[klo] < ya[khi]) y_spline = ya[klo];
1239  else y_spline = ya[khi];
1240  }
1241 
1242 }
1243 
1244 } // namespace Device
1245 } // namespace Xyce
double pnjlim_new(double vnew, double vold, double vt, double vcrit, int *icheck)
#define CONSTQ
Definition: N_DEV_Const.h:51
double pnjlim(double vnew, double vold, double vt, double vcrit, int *icheck)
void qmeyer(double vgs, double vgd, double vgb, double von, double vdsat, double &capgs, double &capgd, double &capgb, double phi, double cox)
Pure virtual class to augment a linear system.
#define CONSTMAX_EXP_ARG
Definition: N_DEV_Const.h:110
double fetlim(double vnew, double vold, double vto)
int SetSeed(unsigned int seedIn)
#define N_MINLOG
Definition: N_ANP_NOISE.C:108
double contVgst(double vgst, double alpha, double vgstConst=3.0)
void splint(std::vector< double > &xa, std::vector< double > &ya, std::vector< double > &y2a, double x_position, double &y_spline)
void spline(std::vector< double > &x, std::vector< double > &y, std::vector< double > &y2)
double Xexp(double, double &, double)
int finiteNumberTest(const double x)
void qmeyerderivs(double vgs, double vgd, double vgb, double von, double vdsat, double &dcapgsdvgs, double &dcapgsdvgb, double &dcapgsdvgd, double &dcapgddvgs, double &dcapgddvgb, double &dcapgddvgd, double &dcapgbdvgs, double &dcapgbdvgb, double &dcapgbdvgd, double phi, double cox, int Dtype)
double limvds(double vnew, double vold)
#define isnan(x)
int getGainScaleBlockID(int numBlocks)
void lambertw(double x, double &w, int &ierr, double &xi)
void noiseSupport(double &noise, double &lnNoise, const int type, const double param, const double temp)
double contVds(double vds, double alpha, double min=0.3)
#define isinf(x)
void cmeyer(double vgs0, double vgd0, double vgb0, double von0, double vdsat0, double vgs1, double vgd1, double vgb1, double covlgs, double covlgd, double covlgb, register double *cgs, register double *cgd, register double *cgb, double phi, double cox, double von, double vdsat)
#define CONSTboltz
Definition: N_DEV_Const.h:53