/*************************************************************************** * Copyright (C) 2003-2005 by David Saxton * * david@bluehaze.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "matrix.h" #include "nonlinear.h" #include using namespace std; const double KTL_MAX_DOUBLE = 1.7976931348623157e+308; ///< 7fefffff ffffffff const int KTL_MAX_EXPONENT = int( log( KTL_MAX_DOUBLE ) ); NonLinear::NonLinear() : Element() { } #ifndef MIN # define MIN(x,y) (((x) < (y)) ? (x) : (y)) #endif // The function computes the exponential pn-junction current. double NonLinear::diodeCurrent( double v, double I_S, double Vte ) const { return I_S * (exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) - 1); } double NonLinear::diodeConductance( double v, double I_S, double Vte ) const { return I_S * exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) / Vte; } double NonLinear::diodeVoltage( double V, double V_prev, double V_T, double Vcrit ) const { if ( V > Vcrit && fabs( V - V_prev ) > 2 * V_T ) { if ( V_prev > 0 ) { double arg = (V - V_prev) / V_T; if (arg > 0) V = V_prev + V_T * (2 + log( arg - 2 )); else V = V_prev - V_T * (2 + log( 2 - arg )); } else V = (V_prev < 0) ? (V_T * log (V / V_T)) : Vcrit; } else { if ( V < 0 ) { double arg = (V_prev > 0) ? (-1 - V_prev) : (2 * V_prev - 1); if (V < arg) V = arg; } } return V; } double NonLinear::diodeCriticalVoltage( double I_S, double V_Te ) const { return V_Te * log( V_Te / M_SQRT2 / I_S ); } void NonLinear::diodeJunction( double V, double I_S, double V_Te, double * I, double * g ) const { if (V < -3 * V_Te) { double a = 3 * V_Te / (V * M_E); a = a * a * a; *I = -I_S * (1 + a); *g = +I_S * 3 * a / V; } else { double e = exp( MIN( V / V_Te, KTL_MAX_EXPONENT ) ); *I = I_S * (e - 1); *g = I_S * e / V_Te; } }