turn {DEV,MODEL}_SUBCKT into base class
[gnucap-felix.git] / include / u_limit.h
blobe76fbdff4a59e19b70ed1b89499cc775ca47dc06
1 /* $Id: u_limit.h,v 26.81 2008/05/27 05:34:00 al Exp $ -*- C++ -*-
2 * Copyright (C) 2006 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)
10 * any later version.
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
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * device limiting library
24 //testing=script 2006.07.14
25 #ifndef U_LIMIT_H
26 #define U_LIMIT_H
27 #include "md.h"
28 /*--------------------------------------------------------------------------*/
29 /* Spice style PN junction limiting */
30 inline double pnj_limit(double vnew, double vold, double vt, double vcrit)
32 trace4("limit-in", vnew, vold, vt, vcrit);
33 if ((vnew > vcrit) && (std::abs(vnew - vold) > (2 * vt))) {
34 if (vold > 0) {
35 double arg = 1 + (vnew - vold) / vt;
36 double vlim = (arg > 0) ? (vold + vt * log(arg)) : vcrit;
37 trace3("limit-1", vlim, vt*log(arg), arg);
38 return vlim;
39 }else{
40 double vlim = vt * log(vnew/vt);
41 trace3("limit-2", vlim, vt*log(vnew/vt), vnew/vt);
42 return vlim;
44 }else{
45 trace1("limit-3", vnew);
46 return vnew;
49 /*--------------------------------------------------------------------------*/
50 inline double fet_limit_vds(double vnew, double vold)
52 if (vold >= 3.5) {
53 if (vnew > (3*vold + 2)) {itested();
54 return 3 * vold + 2;
55 }else if (vnew < 2) {
56 return 2;
57 }else{
58 return vnew;
60 }else{
61 if (vnew > 4) {
62 return 4;
63 }else if (vnew < -.5) {
64 return -.5;
65 }else{
66 return vnew;
70 /*--------------------------------------------------------------------------*/
71 inline double fet_limit_vgs(double vnew, double vold, double vto)
73 assert(vnew == vnew);
74 assert(vold == vold);
76 double vgst_old = vold - vto;
77 double vgst_new = vnew - vto;
78 double v_limited;
79 if (vgst_old >= 3.5) { /* was strong on */
80 if (vgst_new < 2) {
81 v_limited = 2;
82 }else if (vgst_new > (3 * vgst_old + 2)) {itested();
83 v_limited = 3*vgst_old + 2;
84 }else{
85 v_limited = vgst_new;
87 }else if (vgst_old >= 0) { /* middle region, on */
88 assert(vgst_old < 3.5);
89 if (vgst_new < -.5) {
90 v_limited = -.5;
91 }else if (vgst_new > 4) {
92 v_limited = 4;
93 }else{
94 v_limited = vgst_new;
96 }else if (vgst_old <= 0) { /* was off, vgst_old < 0 */
97 assert(vgst_old < 0);
98 if (vgst_new < (3 * vgst_old - 2)) {
99 v_limited = 3*vgst_old - 2;
100 }else if (vgst_new > .5) {
101 v_limited = .5;
102 }else{
103 v_limited = vgst_new;
105 }else{ /* overflow or other numeric error */
106 // not sure what to do in this case.
107 // It could actually happen with overflow or divide by zero.
108 // but supposedly this is trapped elsewhere.
109 unreachable();
110 v_limited = 0.;
111 trace3("huh?", vnew, vold, vto);
112 trace3(" ", vgst_new, vgst_old, v_limited);
114 return v_limited + vto;
116 /*--------------------------------------------------------------------------*/
117 /*--------------------------------------------------------------------------*/
118 #endif
119 // vim:ts=8:sw=2:noet: