1 /* $Id: d_mos2.cc,v 1.2 2010-07-09 12:14:21 felix Exp $ -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 *------------------------------------------------------------------
22 * mos model equations: spice level 2 equivalent
24 /* This file is automatically generated. DO NOT EDIT */
27 #include "l_denoise.h"
31 /*--------------------------------------------------------------------------*/
32 const double NA(NOT_INPUT
);
33 const double INF(BIGBIG
);
34 /*--------------------------------------------------------------------------*/
35 int MODEL_BUILT_IN_MOS2::_count
= 0;
36 /*--------------------------------------------------------------------------*/
38 /*--------------------------------------------------------------------------*/
39 namespace MODEL_BUILT_IN_MOS2_DISPATCHER
{
40 static DEV_BUILT_IN_MOS p1d
;
41 static MODEL_BUILT_IN_MOS2
p1(&p1d
);
42 static DISPATCHER
<MODEL_CARD
>::INSTALL
43 d1(&model_dispatcher
, "nmos2|pmos2", &p1
);
45 /*--------------------------------------------------------------------------*/
46 void SDP_BUILT_IN_MOS2::init(const COMMON_COMPONENT
* cc
)
49 SDP_BUILT_IN_MOS123::init(cc
);
50 const COMMON_BUILT_IN_MOS
* c
= prechecked_cast
<const COMMON_BUILT_IN_MOS
*>(cc
);
52 const MODEL_BUILT_IN_MOS2
* m
= prechecked_cast
<const MODEL_BUILT_IN_MOS2
*>(c
->model());
54 const CARD_LIST
* par_scope
= m
->scope();
55 assert(par_scope
); USE(par_scope
);
59 relxj
= ((m
->xj
!= NA
&& m
->xj
> 0)
63 ? M_PI_4
* P_EPS_SI
* m
->delta
/ cgate
* l_eff
69 /*--------------------------------------------------------------------------*/
70 TDP_BUILT_IN_MOS2::TDP_BUILT_IN_MOS2(const DEV_BUILT_IN_MOS
* d
)
71 :TDP_BUILT_IN_MOS123(d
)
74 const COMMON_BUILT_IN_MOS
* c
= prechecked_cast
<const COMMON_BUILT_IN_MOS
*>(d
->common());
76 const SDP_BUILT_IN_MOS2
* s
= prechecked_cast
<const SDP_BUILT_IN_MOS2
*>(c
->sdp());
78 const MODEL_BUILT_IN_MOS2
* m
= prechecked_cast
<const MODEL_BUILT_IN_MOS2
*>(c
->model());
80 const CARD_LIST
* par_scope
= d
->scope();
81 assert(par_scope
); USE(par_scope
);
82 // final adjust: code_pre
84 double temp
= d
->_sim
->_temp_c
+ P_CELSIUS0
;
85 double tempratio
= temp
/ m
->tnom_k
; // ratio
86 double tempratio4
= tempratio
* sqrt(tempratio
);
87 double kt
= temp
* P_K
;
88 double egap
= 1.16 - (7.02e-4*temp
*temp
) / (temp
+1108.);
89 double arg
= (m
->egap
*tempratio
- egap
) / (2*kt
);
90 // final adjust: override
93 // final adjust: calculated
95 phi
= m
->phi
*tempratio
+ (-2*vt
*(1.5*log(tempratio
)+P_Q
*(arg
)));
97 phi_sqrt_phi
= phi
* sqrt_phi
;
98 beta
= (m
->kp
/ tempratio4
) * s
->w_eff
/ s
->l_eff
;
99 uo
= m
->uo
* tempratio4
;
101 (m
->vto
- m
->gamma
* sqrt(m
->phi
)
102 +.5*(m
->egap
-egap
) + m
->polarity
* .5 * (phi
-m
->phi
)), m
->phi
));
103 // final adjust: post
104 // final adjust: done
106 /*--------------------------------------------------------------------------*/
107 MODEL_BUILT_IN_MOS2::MODEL_BUILT_IN_MOS2(const BASE_SUBCKT
* p
)
108 :MODEL_BUILT_IN_MOS123(p
),
126 if (ENV::run_mode
!= rPRE_MAIN
) {
130 set_default(&mjsw
, .33);
131 set_default(&tox
, 1e-7);
132 set_default(&cox
, NA
);
133 set_default(&vto
, NA
);
134 set_default(&gamma
, NA
);
135 set_default(&phi
, NA
);
136 set_default(&mos_level
, LEVEL
);
138 /*--------------------------------------------------------------------------*/
139 MODEL_BUILT_IN_MOS2::MODEL_BUILT_IN_MOS2(const MODEL_BUILT_IN_MOS2
& p
)
140 :MODEL_BUILT_IN_MOS123(p
),
145 ucrit_cm(p
.ucrit_cm
),
158 if (ENV::run_mode
!= rPRE_MAIN
) {
160 }else{untested();//194
163 /*--------------------------------------------------------------------------*/
164 std::string
MODEL_BUILT_IN_MOS2::dev_type()const
166 if (polarity
== pN
) {
168 }else if (polarity
== pP
) {
170 }else{untested();//235
171 return MODEL_BUILT_IN_MOS123::dev_type();
174 /*--------------------------------------------------------------------------*/
175 void MODEL_BUILT_IN_MOS2::set_dev_type(const std::string
& new_type
)
177 if (Umatch(new_type
, "nmos2 ")) {
179 }else if (Umatch(new_type
, "pmos2 ")) {
182 MODEL_BUILT_IN_MOS123::set_dev_type(new_type
);
185 /*--------------------------------------------------------------------------*/
186 void MODEL_BUILT_IN_MOS2::precalc_first()
188 const CARD_LIST
* par_scope
= scope();
190 MODEL_BUILT_IN_MOS123::precalc_first();
191 e_val(&(this->kp
), NA
, par_scope
);
192 e_val(&(this->nfs_cm
), 0.0, par_scope
);
193 e_val(&(this->vmax
), NA
, par_scope
);
194 e_val(&(this->neff
), 1.0, par_scope
);
195 e_val(&(this->ucrit_cm
), 1e4
, par_scope
);
196 e_val(&(this->uexp
), NA
, par_scope
);
197 e_val(&(this->utra
), NA
, par_scope
);
198 e_val(&(this->delta
), 0.0, par_scope
);
199 // final adjust: code_pre
201 if (!has_good_value(tox
)) {
204 cox
= P_EPS_OX
/ tox
;
211 phi
= (2. * P_K_Q
) * tnom_k
* log(nsub
/NI
);
214 error(((!_sim
->is_first_expand()) ? (bDEBUG
) : (bWARNING
)),
215 long_label() + ": calculated phi too small, using .1\n");
221 gamma
= sqrt(2. * P_EPS_SI
* P_Q
* nsub
) / cox
;
225 double phi_ms
= (tpg
== gtMETAL
)
226 ? polarity
* (-.05 - (egap
+ polarity
* phi
) / 2.)
227 : -(tpg
* egap
+ phi
) / 2.;
228 double vfb
= phi_ms
- polarity
* P_Q
* nss
/ cox
;
229 vto
= vfb
+ phi
+ gamma
* sqrt(phi
);
233 // final adjust: override
251 e_val(&(this->kp
), 2e-5, par_scope
);
252 e_val(&(this->nfs_cm
), 0.0, par_scope
);
253 e_val(&(this->vmax
), NA
, par_scope
);
254 e_val(&(this->neff
), 1.0, par_scope
);
255 e_val(&(this->ucrit_cm
), 1e4
, par_scope
);
256 e_val(&(this->uexp
), NA
, par_scope
);
257 e_val(&(this->utra
), NA
, par_scope
);
258 e_val(&(this->delta
), 0.0, par_scope
);
260 // final adjust: calculated
262 ucrit
= ucrit_cm
*ICM2M
;
263 alpha
= ((nsub
!= NA
)
264 ? (2. * P_EPS_SI
) / (P_Q
* nsub
)
270 vbp
= ucrit
* P_EPS_SI
/ cox
;
271 cfsox
= P_Q
* nfs
/ cox
;
272 // final adjust: post
273 // final adjust: done
275 /*--------------------------------------------------------------------------*/
276 void MODEL_BUILT_IN_MOS2::precalc_last()
278 MODEL_BUILT_IN_MOS123::precalc_last();
280 /*--------------------------------------------------------------------------*/
281 SDP_CARD
* MODEL_BUILT_IN_MOS2::new_sdp(COMMON_COMPONENT
* c
)const
284 if (COMMON_BUILT_IN_MOS
* cc
= dynamic_cast<COMMON_BUILT_IN_MOS
*>(c
)) {
290 return new SDP_BUILT_IN_MOS2(c
);
293 return MODEL_BUILT_IN_MOS123::new_sdp(c
);
296 /*--------------------------------------------------------------------------*/
297 void MODEL_BUILT_IN_MOS2::set_param_by_index(int i
, std::string
& value
, int offset
)
299 switch (MODEL_BUILT_IN_MOS2::param_count() - 1 - i
) {
300 case 0: level
= value
; break; //2
301 case 1: unreachable(); break;
302 case 2: unreachable(); break;
303 case 3: unreachable(); break;
304 case 4: unreachable(); break;
305 case 5: unreachable(); break;
306 case 6: unreachable(); break;
307 case 7: mos_level
= value
; break;
308 case 8: kp
= value
; break;
309 case 9: nfs_cm
= value
; break;
310 case 10: vmax
= value
; break;
311 case 11: neff
= value
; break;
312 case 12: ucrit_cm
= value
; break;
313 case 13: uexp
= value
; break;
314 case 14: utra
= value
; break;
315 case 15: delta
= value
; break;
316 default: MODEL_BUILT_IN_MOS123::set_param_by_index(i
, value
, offset
); break;
319 /*--------------------------------------------------------------------------*/
320 bool MODEL_BUILT_IN_MOS2::param_is_printable(int i
)const
322 switch (MODEL_BUILT_IN_MOS2::param_count() - 1 - i
) {
323 case 0: return (true);
324 case 1: return (false);
325 case 2: return (false);
326 case 3: return (false);
327 case 4: return (false);
328 case 5: return (false);
329 case 6: return (false);
330 case 7: return (mos_level
!= LEVEL
);
331 case 8: return (!calc_kp
);
332 case 9: return (true);
333 case 10: return (vmax
.has_hard_value());
334 case 11: return (neff
!= 1.0 || lambda
== NA
);
335 case 12: return (ucrit_cm
!= 1e4
|| uexp
!= NA
);
336 case 13: return (uexp
.has_hard_value());
337 case 14: return (false);
338 case 15: return (true);
339 default: return MODEL_BUILT_IN_MOS123::param_is_printable(i
);
342 /*--------------------------------------------------------------------------*/
343 std::string
MODEL_BUILT_IN_MOS2::param_name(int i
)const
345 switch (MODEL_BUILT_IN_MOS2::param_count() - 1 - i
) {
346 case 0: return "level";
347 case 1: return "=====";
348 case 2: return "=====";
349 case 3: return "=====";
350 case 4: return "=====";
351 case 5: return "=====";
352 case 6: return "=====";
353 case 7: return "diodelevel";
355 case 9: return "nfs";
356 case 10: return "vmax";
357 case 11: return "neff";
358 case 12: return "ucrit";
359 case 13: return "uexp";
360 case 14: return "utra";
361 case 15: return "delta";
362 default: return MODEL_BUILT_IN_MOS123::param_name(i
);
365 /*--------------------------------------------------------------------------*/
366 std::string
MODEL_BUILT_IN_MOS2::param_name(int i
, int j
)const
369 return param_name(i
);
371 switch (MODEL_BUILT_IN_MOS2::param_count() - 1 - i
) {
388 default: return MODEL_BUILT_IN_MOS123::param_name(i
, j
);
393 return MODEL_BUILT_IN_MOS123::param_name(i
, j
);
396 /*--------------------------------------------------------------------------*/
397 std::string
MODEL_BUILT_IN_MOS2::param_value(int i
)const
399 switch (MODEL_BUILT_IN_MOS2::param_count() - 1 - i
) {
401 case 1: unreachable(); return "";
402 case 2: unreachable(); return "";
403 case 3: unreachable(); return "";
404 case 4: unreachable(); return "";
405 case 5: unreachable(); return "";
406 case 6: unreachable(); return "";
407 case 7: return mos_level
.string();
408 case 8: return kp
.string();
409 case 9: return nfs_cm
.string();
410 case 10: return vmax
.string();
411 case 11: return neff
.string();
412 case 12: return ucrit_cm
.string();
413 case 13: return uexp
.string();
414 case 14: return utra
.string();
415 case 15: return delta
.string();
416 default: return MODEL_BUILT_IN_MOS123::param_value(i
);
419 /*--------------------------------------------------------------------------*/
420 bool MODEL_BUILT_IN_MOS2::is_valid(const COMPONENT
* d
)const
423 return MODEL_BUILT_IN_MOS123::is_valid(d
);
425 /*--------------------------------------------------------------------------*/
426 void MODEL_BUILT_IN_MOS2::tr_eval(COMPONENT
* brh
)const
428 DEV_BUILT_IN_MOS
* d
= prechecked_cast
<DEV_BUILT_IN_MOS
*>(brh
);
430 const COMMON_BUILT_IN_MOS
* c
= prechecked_cast
<const COMMON_BUILT_IN_MOS
*>(d
->common());
432 const SDP_BUILT_IN_MOS2
* s
= prechecked_cast
<const SDP_BUILT_IN_MOS2
*>(c
->sdp());
434 const MODEL_BUILT_IN_MOS2
* m
= this;
435 const TDP_BUILT_IN_MOS2
T(d
);
436 const TDP_BUILT_IN_MOS2
* t
= &T
;
438 #define short_channel (m->xj != NOT_INPUT && m->xj > 0.)
439 #define do_subthreshold (m->nfs != 0.)
440 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
441 // trace1(d->long_label().c_str(), d->evaliter());
442 trace3("", d
->vds
, d
->vgs
, d
->vbs
);
443 assert(m
->tnom_k
> 0);
444 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
445 d
->reverse_if_needed();
446 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
447 double v_phi_s
= t
->phi
- d
->vbs
;
448 double sarg
, dsarg_dvbs
, d2sdb2
, sarg3
;
451 sarg
= sqrt(v_phi_s
);
452 dsarg_dvbs
= -.5 / sarg
;
453 d2sdb2
= .5 * dsarg_dvbs
/ v_phi_s
;
455 trace3("sb-ok", sarg
, v_phi_s
, dsarg_dvbs
);
457 if (OPT::mosflags
& 01000) {
458 sarg
= t
->sqrt_phi
/ (1. + .5 * d
->vbs
/ t
->phi
);
459 dsarg_dvbs
= -.5 * sarg
* sarg
/ t
->phi_sqrt_phi
;
460 d2sdb2
= -dsarg_dvbs
* sarg
/ t
->phi_sqrt_phi
;
462 trace3("***sb-reversed(01000)***", sarg
, v_phi_s
, dsarg_dvbs
);
465 / (1. + .5 * d
->vbs
/ t
->phi
466 + .375 * d
->vbs
* d
->vbs
/ (t
->phi
* t
->phi
));
467 dsarg_dvbs
= (-.5 * sarg
* sarg
/ t
->phi_sqrt_phi
)
468 * (1. + 1.5 * d
->vbs
/ t
->phi
);
469 d2sdb2
= (-dsarg_dvbs
* sarg
/ t
->phi_sqrt_phi
)
470 - (.75 * sarg
/ (t
->phi_sqrt_phi
* t
->phi
))
471 * (2. * d
->vbs
* dsarg_dvbs
+ sarg
);
472 trace3("***sb-reversed(00000)***", sarg
, v_phi_s
, dsarg_dvbs
);
476 sarg3
= sarg
*sarg
*sarg
;
478 assert(dsarg_dvbs
< 0.);
479 assert(up_order(-1/t
->phi
, d2sdb2
, 1/t
->phi
));
480 trace2("", d2sdb2
, sarg3
);
482 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
483 double barg
, dbarg_dvbs
, d2bdb2
;
485 double vbd
= d
->vbs
- d
->vds
;
486 double v_phi_d
= t
->phi
- vbd
;
488 barg
= sqrt(v_phi_d
);
489 dbarg_dvbs
= -.5 / barg
;
490 d2bdb2
= .5 * dbarg_dvbs
/ v_phi_d
;
492 trace4("db-ok", barg
, v_phi_d
, dbarg_dvbs
, d2bdb2
);
494 if (OPT::mosflags
& 01000) {
495 barg
= t
->sqrt_phi
/ (1. + .5 * vbd
/ t
->phi
);
496 dbarg_dvbs
= -.5 * barg
* barg
/ t
->phi_sqrt_phi
;
497 d2bdb2
= -dbarg_dvbs
* barg
/ t
->phi_sqrt_phi
;
499 trace4("***db-reversed(00000)***",barg
, v_phi_d
, dbarg_dvbs
, d2bdb2
);
502 / (1. + .5 * vbd
/ t
->phi
503 + .375 * vbd
* vbd
/ (t
->phi
* t
->phi
));
504 dbarg_dvbs
= (-.5 * barg
* barg
/ t
->phi_sqrt_phi
)
505 * (1. + 1.5 * vbd
/ t
->phi
);
506 d2bdb2
= (-dbarg_dvbs
* barg
/ t
->phi_sqrt_phi
)
507 - (.75 * barg
/ (t
->phi_sqrt_phi
* t
->phi
))
508 * (2. * vbd
* dbarg_dvbs
+ barg
);
509 trace4("***db-reversed(00000)***",barg
, v_phi_d
, dbarg_dvbs
, d2bdb2
);
514 assert(dbarg_dvbs
< 0.);
515 assert(up_order(-1/t
->phi
, d2bdb2
, 1/t
->phi
));
517 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
518 double gamma_s
, dgamma_s_dvds
, dgamma_s_dvbs
, dgddb2
;
521 double argxd
= 1. + 2. * barg
* m
->xd
/ m
->xj
;
523 double argd
= sqrt(argxd
);
524 trace2("", argxd
, argd
);
526 double alpha_d
= s
->relxj
* (argd
- 1.);
527 double dalpha_d_dvds
= m
->xd
/ (4. * s
->l_eff
* argd
* barg
);
528 double dalpha_d_dvbs
= -dalpha_d_dvds
;
529 trace3("", alpha_d
, dalpha_d_dvds
, dalpha_d_dvbs
);
531 double argxs
= 1. + 2. * sarg
* m
->xd
/ m
->xj
;
533 double args
= sqrt(argxs
);
534 trace2("", argxs
, args
);
536 double alpha_s
= s
->relxj
* (args
- 1.);
537 double dalpha_s_dvbs
= -m
->xd
/ (4. * s
->l_eff
* args
* sarg
);
538 trace2("", alpha_s
, dalpha_s_dvbs
);
540 gamma_s
= m
->gamma
* (1. - alpha_s
- alpha_d
);
541 dgamma_s_dvds
= -m
->gamma
* dalpha_d_dvds
;
542 dgamma_s_dvbs
= -m
->gamma
* (dalpha_d_dvbs
+ dalpha_s_dvbs
);
544 double dasdb2
=-m
->xd
*(d2sdb2
+dsarg_dvbs
*dsarg_dvbs
*m
->xd
/(m
->xj
*argxs
))
546 double daddb2
=-m
->xd
*(d2bdb2
+dbarg_dvbs
*dbarg_dvbs
*m
->xd
/(m
->xj
*argxd
))
548 dgddb2
= -.5 * m
->gamma
* (dasdb2
+ daddb2
);
550 if (gamma_s
<= 0. && m
->gamma
> 0.) {
552 error(bTRACE
, d
->long_label() + ": gamma is negative\n");
553 error(bTRACE
, "+ gamma_s=%g, alpha_s=%g, alpha_d=%g\n",
554 gamma_s
, alpha_s
, alpha_d
);
556 trace4("no short chan", gamma_s
, dgamma_s_dvds
, dgamma_s_dvds
, dgddb2
);
559 dgamma_s_dvds
= dgamma_s_dvbs
= 0.;
561 trace4("short channel", gamma_s
, dgamma_s_dvds
, dgamma_s_dvds
, dgddb2
);
564 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
565 /* von, subthreshold, cutoff, vgst */
566 double vc
, vc_eta
, dvon_dvbs
;
567 double xn
, vtxn
, dxn_dvbs
; /* subthreshold only */
569 double vbin
= t
->vbi
+ s
->eta_1
* v_phi_s
;
570 d
->von
= vbin
+ gamma_s
* sarg
;
571 dvon_dvbs
= -s
->eta_1
+ dgamma_s_dvbs
* sarg
+ gamma_s
* dsarg_dvbs
;
572 trace3("guess", vbin
, d
->von
, dvon_dvbs
);
574 if (do_subthreshold
) {
575 double cdonco
= -(gamma_s
*dsarg_dvbs
+ dgamma_s_dvbs
*sarg
) + s
->eta_1
;
576 xn
= 1. + m
->cfsox
+ cdonco
;
578 dxn_dvbs
= 2. * dgamma_s_dvbs
* dsarg_dvbs
579 + gamma_s
* d2sdb2
+ dgddb2
* sarg
;
580 trace3("do_sub", xn
, vtxn
, dxn_dvbs
);
583 dvon_dvbs
+= t
->vt
* dxn_dvbs
;
584 d
->vgst
= d
->vgs
- d
->von
;
585 trace3("", d
->von
, dvon_dvbs
, d
->vgst
);
587 d
->subthreshold
= (d
->vgs
< d
->von
);
590 xn
= vtxn
= dxn_dvbs
= 0.;
591 d
->vgst
= d
->vgs
- d
->von
;
592 trace3("no_sub", xn
, vtxn
, dxn_dvbs
);
593 trace3("", d
->von
, dvon_dvbs
, d
->vgst
);
595 d
->subthreshold
= false;
596 d
->cutoff
= (d
->vgs
< d
->von
);
598 trace0("***** cut off *****");
600 d
->gmf
= d
->gmr
= 0.;
602 d
->gmbf
= d
->gmbr
= 0.;
606 double vgsx
= (d
->subthreshold
) ? d
->von
: d
->vgs
;
608 vc_eta
= vc
/ s
->eta
;
609 trace3("", vgsx
, vc
, vc_eta
);
611 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
613 double ufact
, duf_dvgs
, duf_dvds
, duf_dvbs
, ueff
;
615 if (m
->uexp
!= NOT_INPUT
&& d
->vgst
> m
->vbp
) {
616 ufact
= pow(m
->vbp
/d
->vgst
, m
->uexp
);
617 duf_dvgs
= -ufact
* m
->uexp
/ d
->vgst
;
618 duf_dvds
= 0.; /* wrong, but as per spice2 */
619 duf_dvbs
= dvon_dvbs
* ufact
* m
->uexp
/ d
->vgst
;
620 trace4("calc ufact", ufact
, duf_dvgs
, duf_dvds
, duf_dvbs
);
623 duf_dvgs
= duf_dvds
= duf_dvbs
= 0.;
624 trace4("def ufact", ufact
, duf_dvgs
, duf_dvds
, duf_dvbs
);
626 ueff
= t
->uo
* ufact
; /* ???? */
627 trace2("", ufact
, ueff
);
629 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
630 /* vdsat according to Baum's Theory of scattering velocity saturation */
631 int use_vmax
= m
->vmax
!= NOT_INPUT
;
633 double gammad
= gamma_s
/ s
->eta
;
634 double v1
= vc_eta
+ v_phi_s
;
636 double xv
= m
->vmax
* s
->l_eff
/ ueff
;
637 double a1
= gammad
* (4./3.);
638 double b1
= -2. * (v1
+xv
);
639 double c1
= -2. * gammad
* xv
; /* end of scope */
640 double d1
= 2.*v1
*(v2
+xv
) - v2
*v2
- (4./3.)*gammad
*sarg3
;
641 double a
= -b1
; /* xv, v1, v2, sarg3 */
642 double b
= a1
* c1
- 4. * d1
;
643 double C
= -d1
* (a1
*a1
- 4.*b1
) - c1
*c1
;
644 double r
= -a
*a
/ 3. + b
;
645 double r3
= r
*r
*r
; /* r */
646 double S
= 2. * a
*a
*a
/ 27. - a
*b
/ 3. + C
; /* b, c */
648 double p
= s2
/ 4. + r3
/ 27.; /* r */
650 if (p
< 0.) { /* p */
651 double ro
= pow((-r3
/ 27), (1./6.)); /* s2, r3 */
652 double fi
= atan(-2. * sqrt(-p
) / S
);
653 y3
= 2. * ro
* cos(fi
/3.) - a
/ 3.;
656 double p3
= pow((fabs(-S
/2.+p2
)), (1./3.));
657 double p4
= pow((fabs(-S
/2.-p2
)), (1./3.)); /* s */
658 y3
= p3
+ p4
- a
/ 3.; /* a */
663 if (a1
*a1
/ 4. - b1
+ y3
< 0. && y3
*y3
/ 4. - d1
< 0.) {
666 "%s: internal error: a3,b4, a1=%g, b1=%g, y3=%g, d1=%g\n",
667 d
->long_label().c_str(), a1
, b1
, y3
, d1
);
669 double a3
= sqrt(a1
*a1
/ 4. - b1
+ y3
);
670 double b3
= sqrt(y3
*y3
/ 4. - d1
);
671 for (int i
= 0; i
< 4; i
++) {
672 static const double sig1
[4] = {1., -1., 1., -1.};
673 static const double sig2
[4] = {1., 1., -1., -1.};
674 double a4
= a1
/ 2. + sig1
[i
] * a3
;
675 double b4
= y3
/ 2. + sig2
[i
] * b3
; /* y3 */
676 double delta4
= a4
*a4
/ 4. - b4
;
678 double sd4
= sqrt(delta4
);
679 x4
[iknt
++] = - a4
/ 2. + sd4
;
680 x4
[iknt
++] = - a4
/ 2. - sd4
; /* i */
687 for (int j
= 0; j
< iknt
; j
++) { /* iknt */
689 double poly4
= x4
[j
]*x4
[j
]*x4
[j
]*x4
[j
]/* ~= 0, used as check */
690 + a1
* x4
[j
]*x4
[j
]*x4
[j
] /* roundoff error not */
691 + b1
* x4
[j
]*x4
[j
] /* propagated, so ok */
693 + d1
; /* a1, b1, c1, d1 */
694 if (fabs(poly4
) <= 1e-6) {
696 if (root_count
<= 1) { /* xvalid = min(x4[j]) */
699 if (x4
[j
] <= xvalid
) {
700 xvalid
=x4
[j
]; /* x4[], j */
707 if (root_count
<= 0) { /* root_count */
708 error(bTRACE
, d
->long_label() + ": Baum's theory rejected\n");
711 trace1("use_vmax rejected", d
->vdsat
);
713 d
->vdsat
= xvalid
*xvalid
- v_phi_s
;
714 trace1("use_vmax", d
->vdsat
);
718 trace1("!use_vmax", d
->vdsat
);
720 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
721 /* vdsat according to Grove-Frohman equation */
722 double dvdsat_dvgs
= NOT_VALID
;
723 double dvdsat_dvbs
= NOT_VALID
;
726 double argv
= vc_eta
+ v_phi_s
;
728 double gammad
= gamma_s
/ s
->eta
;
729 double gammd2
= gammad
* gammad
;
730 double arg1
= sqrt(1. + 4. * argv
/ gammd2
);
731 d
->vdsat
= vc_eta
+ gammd2
* (1.-arg1
) / 2.;
732 dvdsat_dvgs
= (1. - 1./arg1
) / s
->eta
;
733 dvdsat_dvbs
= (gammad
* (1.-arg1
) + 2.*argv
/ (gammad
*arg1
))
734 / s
->eta
* dgamma_s_dvbs
735 + 1./arg1
+ s
->eta_1
* dvdsat_dvgs
;
736 trace3("!use_vmax,gamma>0,argv>0",d
->vdsat
,dvdsat_dvgs
,dvdsat_dvbs
);
739 dvdsat_dvgs
= dvdsat_dvbs
= 0.;
740 error(bTRACE
, d
->long_label() + ": argv is negative\n");
741 trace2("argv<0", argv
, vc
);
742 trace3("!use_vmax,gamma>0,argv<=0",d
->vdsat
,dvdsat_dvgs
,dvdsat_dvbs
);
748 trace3("!use_vmax, gamma<=0", d
->vdsat
, dvdsat_dvgs
, dvdsat_dvbs
);
751 /* dvdsat_dvgs, dvdsat_dvbs deferred */
752 trace3("use_vmax", d
->vdsat
, dvdsat_dvgs
, dvdsat_dvbs
);
754 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
757 "%s: calculated vdsat (%g) < 0. using vdsat = 0.\n",
758 d
->long_label().c_str(), d
->vdsat
);
761 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
762 double bsarg
, dbsarg_dvbs
;
764 double vbdsat
= d
->vbs
- d
->vdsat
;
766 double v_phi_ds
= t
->phi
- vbdsat
;
767 bsarg
= sqrt(v_phi_ds
);
768 dbsarg_dvbs
= -.5 / bsarg
;
769 trace3("vbdsat <= 0", vbdsat
, bsarg
, dbsarg_dvbs
);
771 bsarg
= t
->sqrt_phi
/ (1. + .5 * vbdsat
/ t
->phi
);
772 dbsarg_dvbs
= -.5 * bsarg
* bsarg
/ t
->phi_sqrt_phi
;
773 trace3("vbdsat > 0", vbdsat
, bsarg
, dbsarg_dvbs
);
776 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
777 /* local dvdsat_dvgs, dvdsat_dvbs maybe */
780 double bodys
= bsarg
*bsarg
*bsarg
- sarg3
;
782 2. * gamma_s
* (bsarg
*bsarg
*dbsarg_dvbs
- sarg
*sarg
*dsarg_dvbs
);
783 double argv
= vc_eta
- d
->vdsat
;
784 double vqchan
= argv
- gamma_s
* bsarg
;
785 double dqdsat
= -1. + gamma_s
* dbsarg_dvbs
;
786 double vl
= m
->vmax
* s
->l_eff
;
787 double dfunds
= vl
* dqdsat
- ueff
* vqchan
;
788 double dfundg
= (vl
- ueff
* d
->vdsat
) / s
->eta
;
789 double dfundb
= -vl
* (1. + dqdsat
- s
->eta_1
/ s
->eta
)
790 + ueff
* (gdbdvs
- dgamma_s_dvbs
* bodys
/ 1.5) / s
->eta
;
791 dvdsat_dvgs
= -dfundg
/ dfunds
;
792 dvdsat_dvbs
= -dfundb
/ dfunds
;
793 trace2("use_vmax", dvdsat_dvgs
, dvdsat_dvbs
);
795 /* dvdsat_dvgs, dvdsat_dvbs already set */
796 trace2("!use_vmax", dvdsat_dvgs
, dvdsat_dvbs
);
798 assert(dvdsat_dvgs
!= NOT_VALID
);
799 assert(dvdsat_dvbs
!= NOT_VALID
);
801 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
802 double dl_dvgs
, dl_dvds
, dl_dvbs
, clfact
;
805 if (m
->lambda
== NOT_INPUT
) {
808 double xdv
= m
->xd
/ sqrt(m
->neff
);
809 double xlv
= m
->vmax
* xdv
/ (2. * ueff
);
810 double argv
= d
->vds
- d
->vdsat
;
814 double xls
= sqrt(xlv
*xlv
+ argv
);
815 double dl
= (xls
-xlv
) * xdv
;
816 /* lambda = dl / (s->l_eff * d->vds); */
817 clfact
= (1. - dl
/ s
->l_eff
);
818 dldsat
= xdv
/ (2. * xls
* s
->l_eff
);
820 double argv
= (d
->vds
- d
->vdsat
) / 4.;
821 double sargv
= sqrt(1. + argv
*argv
);
822 if (argv
+ sargv
>= 0.) {
823 double dl
= m
->xd
* sqrt(argv
+ sargv
);
824 /* lambda = dl / (s->l_eff * d->vds); */
825 clfact
= (1. - dl
/ s
->l_eff
);
826 /* dldsat = lambda * d->vds / (8. * sargv); */
827 dldsat
= dl
/ (s
->l_eff
* 8. * sargv
);
834 "%s: internal error: vds(%g) < vdsat(%g)\n",
835 d
->long_label().c_str(), d
->vds
, d
->vdsat
);
838 dl_dvgs
= dvdsat_dvgs
* dldsat
;
840 dl_dvbs
= dvdsat_dvbs
* dldsat
;
842 /* lambda = m->lambda; */
843 clfact
= (1. - m
->lambda
* d
->vds
);
844 dl_dvgs
= dl_dvbs
= 0.;
845 dl_dvds
= -m
->lambda
;
848 /* clfact = (1. - lambda * d->vds); */
849 if (clfact
< m
->xwb
/s
->l_eff
) {
850 double leff
= m
->xwb
/ (2. - (clfact
* s
->l_eff
/ m
->xwb
));
851 double dfact
= (leff
* leff
) / (m
->xwb
* m
->xwb
);
852 clfact
= leff
/ s
->l_eff
;
857 }else{ /* vds <= 0. */
860 dl_dvgs
= dl_dvds
= dl_dvbs
= 0.;
861 trace1("*** vds < 0 ***", d
->vds
);
863 trace4("", dl_dvgs
, dl_dvds
, dl_dvbs
, clfact
);
865 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
866 /* ids, gmf, gds, gmbf */
868 d
->saturated
= (d
->vds
> d
->vdsat
);
869 double vdsx
= (d
->saturated
) ? d
->vdsat
: d
->vds
;
870 double bargx
= (d
->saturated
) ? bsarg
: barg
;
871 double body
= bargx
*bargx
*bargx
- sarg3
;
872 double expg
= (d
->subthreshold
) ? exp(d
->vgst
/ vtxn
) : 1.;
873 trace4("", vdsx
, bargx
, body
, expg
);
875 trace3("", t
->beta
, ufact
, clfact
);
876 double beta
= t
->beta
* ufact
/ clfact
;
878 beta
* ((vc
- s
->eta_2
* vdsx
) * vdsx
- (2./3.) * gamma_s
* body
);
879 trace4("", beta
, vc
, (s
->eta
*vdsx
), (gamma_s
*bargx
));
880 double didvds
= beta
* (vc
- s
->eta
* vdsx
- gamma_s
* bargx
);
881 fixzero(&didvds
, ids_on
);
882 trace4("", beta
, ids_on
, didvds
, d
->saturated
);
884 d
->ids
= ids_on
* expg
;
886 d
->gmf
= beta
* vdsx
;
887 d
->gmf
+= ids_on
* (duf_dvgs
/ufact
- dl_dvgs
/clfact
);
889 d
->gmf
+= didvds
* dvdsat_dvgs
;
891 if (d
->subthreshold
) {
892 d
->gmf
= ids_on
/ vtxn
;
894 d
->gmf
+= didvds
* dvdsat_dvgs
;
899 d
->gds
= (d
->saturated
) ? 0.: didvds
;
900 d
->gds
+= ids_on
* (duf_dvds
/ufact
- dl_dvds
/clfact
);
902 d
->gds
-= beta
* (2./3.) * body
* dgamma_s_dvds
;
904 if (d
->subthreshold
) {
905 double dxndvd
= dgamma_s_dvds
* dsarg_dvbs
;
906 double dodvds
= dgamma_s_dvds
* sarg
+ t
->vt
* dxndvd
;
907 double gmw
= d
->ids
* d
->vgst
/ (vtxn
* xn
);
909 d
->gds
-= d
->gmf
* dodvds
+ gmw
* dxndvd
;
912 d
->gmbf
= beta
* (s
->eta_1
* vdsx
- gamma_s
* (sarg
- bargx
));
913 d
->gmbf
+= ids_on
* (duf_dvbs
/ufact
- dl_dvbs
/clfact
);
915 d
->gmbf
-= beta
* (2./3.) * body
* dgamma_s_dvbs
;
918 d
->gmbf
+= didvds
* dvdsat_dvbs
;
920 if (d
->subthreshold
) {
921 double gmw
= d
->ids
* d
->vgst
/ (vtxn
* xn
);
922 d
->gmbf
+= beta
* dvon_dvbs
* vdsx
;
924 d
->gmbf
-= d
->gmf
* dvon_dvbs
+ gmw
* dxn_dvbs
;
926 trace4("", d
->ids
, d
->gmf
, d
->gds
, d
->gmbf
);
932 d
->gmf
= d
->gmbf
= 0;
934 d
->gmr
= d
->gmbr
= 0.;
937 /*--------------------------------------------------------------------------*/
938 /*--------------------------------------------------------------------------*/
939 /*--------------------------------------------------------------------------*/
940 /*--------------------------------------------------------------------------*/
941 // vim:ts=8:sw=2:noet