File indexing completed on 2024-05-05 05:46:12
0001 /************************************************************************** 0002 * Copyright (C) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "nonlinear.h" 0012 0013 #include <algorithm> 0014 0015 #include <cmath> 0016 using namespace std; 0017 0018 const double KTL_MAX_DOUBLE = 1.7976931348623157e+308; ///< 7fefffff ffffffff 0019 const int KTL_MAX_EXPONENT = int(log(KTL_MAX_DOUBLE)); 0020 0021 NonLinear::NonLinear() 0022 : Element() 0023 { 0024 } 0025 0026 double NonLinear::diodeCurrent(double v, double I_S, double N) const 0027 { 0028 return I_S * (exp(std::min<double>(v / (N * V_T), KTL_MAX_EXPONENT)) - 1); 0029 } 0030 0031 double NonLinear::diodeConductance(double v, double I_S, double N) const 0032 { 0033 double Vt = V_T * N; 0034 return I_S * exp(std::min<double>(v / Vt, KTL_MAX_EXPONENT)) / Vt; 0035 } 0036 0037 double NonLinear::diodeVoltage(double V, double V_prev, double N, double V_lim) const 0038 { 0039 double Vt = V_T * N; 0040 0041 if (V > V_lim && fabs(V - V_prev) > 2 * Vt) { 0042 if (V_prev > 0) { 0043 double arg = (V - V_prev) / Vt; 0044 if (arg > 0) 0045 V = V_prev + Vt * (2 + log(arg - 2)); 0046 else 0047 V = V_prev - Vt * (2 + log(2 - arg)); 0048 } else 0049 V = (V_prev < 0) ? (Vt * log(V / Vt)) : V_lim; 0050 } else { 0051 if (V < 0) { 0052 double arg = (V_prev > 0) ? (-1 - V_prev) : (2 * V_prev - 1); 0053 if (V < arg) 0054 V = arg; 0055 } 0056 } 0057 return V; 0058 } 0059 0060 double NonLinear::diodeLimitedVoltage(double I_S, double N) const 0061 { 0062 double Vt = N * V_T; 0063 0064 return Vt * log(Vt / M_SQRT2 / I_S); 0065 } 0066 0067 void NonLinear::diodeJunction(double V, double I_S, double N, double *I, double *g) const 0068 { 0069 double Vt = N * V_T; 0070 0071 if (V < -3 * Vt) { 0072 double a = 3 * Vt / (V * M_E); 0073 a = a * a * a; 0074 *I = -I_S * (1 + a); 0075 *g = +I_S * 3 * a / V; 0076 } else { 0077 double e = exp(std::min<double>(V / Vt, KTL_MAX_EXPONENT)); 0078 *I = I_S * (e - 1); 0079 *g = I_S * e / Vt; 0080 } 0081 } 0082 0083 double NonLinear::fetVoltage(double V, double V_prev, double Vth) const 0084 { 0085 double V_tst_hi = fabs(2 * (V_prev - Vth)) + 2.0; 0086 double V_tst_lo = V_tst_hi / 2; 0087 double V_tox = Vth + 3.5; 0088 double delta_V = V - V_prev; 0089 0090 if (V_prev >= Vth) { 0091 // on 0092 if (V_prev >= V_tox) { 0093 if (delta_V <= 0) { 0094 // going off 0095 if (V >= V_tox) { 0096 if (-delta_V > V_tst_lo) 0097 return V_prev - V_tst_lo; 0098 0099 return V; 0100 } 0101 0102 return std::max(V, Vth + 2); 0103 } 0104 0105 // staying on 0106 if (delta_V >= V_tst_hi) 0107 return V_prev + V_tst_hi; 0108 0109 return V; 0110 } 0111 0112 // middle region 0113 if (delta_V <= 0) { 0114 // decreasing 0115 return std::max(V, Vth - 0.5); 0116 } 0117 0118 // increasing 0119 return std::min(V, Vth + 4); 0120 } 0121 0122 // off 0123 if (delta_V <= 0) { 0124 // staying off 0125 if (-delta_V > V_tst_hi) 0126 return V_prev - V_tst_hi; 0127 0128 return V; 0129 } 0130 0131 // going on 0132 if (V <= Vth + 0.5) { 0133 if (delta_V > V_tst_lo) 0134 return V_prev + V_tst_lo; 0135 0136 return V; 0137 } 0138 0139 return Vth + 0.5; 0140 } 0141 0142 double NonLinear::fetVoltageDS(double V, double V_prev) const 0143 { 0144 if (V_prev >= 3.5) { 0145 if (V > V_prev) 0146 return std::min(V, 3 * V_prev + 2); 0147 else if (V < 3.5) 0148 return std::max<double>(V, 2); 0149 0150 return V; 0151 } 0152 0153 if (V > V_prev) 0154 return std::min<double>(V, 4); 0155 0156 return std::max(V, -0.5); 0157 } 0158 0159 void NonLinear::mosDiodeJunction(double V, double I_S, double N, double *I, double *g) const 0160 { 0161 double Vt = N * V_T; 0162 0163 if (V <= 0) { 0164 *g = I_S / Vt; 0165 *I = *g * V; 0166 } else { 0167 double e = exp(std::min<double>(V / Vt, KTL_MAX_EXPONENT)); 0168 *I = I_S * (e - 1); 0169 *g = I_S * e / Vt; 0170 } 0171 0172 *I += V * I_S; 0173 *g += I_S; 0174 }