File indexing completed on 2024-04-28 05:43:14
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 "bjt.h" 0012 #include "diode.h" 0013 #include "elementset.h" 0014 0015 #include <cmath> 0016 using namespace std; 0017 0018 // BEGIN class BJTSettings 0019 BJTSettings::BJTSettings() 0020 { 0021 I_S = 1e-16; 0022 N_F = 1.0; 0023 N_R = 1.0; 0024 B_F = 100.0; 0025 B_R = 1.0; 0026 } 0027 // END class BJTSettings 0028 0029 // BEGIN class BJTState 0030 BJTState::BJTState() 0031 { 0032 reset(); 0033 } 0034 0035 void BJTState::reset() 0036 { 0037 for (unsigned i = 0; i < 3; ++i) { 0038 for (unsigned j = 0; j < 3; ++j) 0039 A[i][j] = 0.0; 0040 0041 I[i] = 0.0; 0042 } 0043 } 0044 0045 BJTState BJTState::operator-(const BJTState &s) const 0046 { 0047 BJTState newState(*this); 0048 0049 for (unsigned i = 0; i < 3; ++i) { 0050 for (unsigned j = 0; j < 3; ++j) 0051 newState.A[i][j] -= s.A[i][j]; 0052 0053 newState.I[i] -= s.I[i]; 0054 } 0055 0056 return newState; 0057 } 0058 // END class BJTState 0059 0060 // BEGIN class BJT 0061 BJT::BJT(bool isNPN) 0062 { 0063 V_BE_prev = 0.0; 0064 V_BC_prev = 0.0; 0065 m_pol = isNPN ? 1 : -1; 0066 m_numCNodes = 3; 0067 updateLim(); 0068 } 0069 0070 BJT::~BJT() 0071 { 0072 } 0073 0074 void BJT::add_initial_dc() 0075 { 0076 V_BE_prev = 0.0; 0077 V_BC_prev = 0.0; 0078 m_os.reset(); 0079 update_dc(); 0080 } 0081 0082 void BJT::updateCurrents() 0083 { 0084 if (!b_status) 0085 return; 0086 0087 double V_B = p_cnode[0]->v; 0088 double V_C = p_cnode[1]->v; 0089 double V_E = p_cnode[2]->v; 0090 0091 double V_BE = (V_B - V_E) * m_pol; 0092 double V_BC = (V_B - V_C) * m_pol; 0093 0094 double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; 0095 calcIg(V_BE, V_BC, &I_BE, &I_BC, &I_T, &g_BE, &g_BC, &g_IF, &g_IR); 0096 0097 m_cnodeI[1] = I_BC - I_T; 0098 m_cnodeI[2] = I_BE + I_T; 0099 m_cnodeI[0] = -(m_cnodeI[1] + m_cnodeI[2]); 0100 } 0101 0102 void BJT::update_dc() 0103 { 0104 if (!b_status) 0105 return; 0106 0107 calc_eq(); 0108 0109 BJTState diff = m_ns - m_os; 0110 for (unsigned i = 0; i < 3; ++i) { 0111 for (unsigned j = 0; j < 3; ++j) 0112 A_g(i, j) += diff.A[i][j]; 0113 0114 b_i(i) += diff.I[i]; 0115 } 0116 0117 m_os = m_ns; 0118 } 0119 0120 void BJT::calc_eq() 0121 { 0122 double V_B = p_cnode[0]->v; 0123 double V_C = p_cnode[1]->v; 0124 double V_E = p_cnode[2]->v; 0125 0126 double V_BE = (V_B - V_E) * m_pol; 0127 double V_BC = (V_B - V_C) * m_pol; 0128 0129 double N_F = m_bjtSettings.N_F; 0130 double N_R = m_bjtSettings.N_R; 0131 0132 // adjust voltage to help convergence 0133 V_BE_prev = V_BE = diodeVoltage(V_BE, V_BE_prev, N_F, V_BE_lim); 0134 V_BC_prev = V_BC = diodeVoltage(V_BC, V_BC_prev, N_R, V_BC_lim); 0135 0136 double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; 0137 calcIg(V_BE, V_BC, &I_BE, &I_BC, &I_T, &g_BE, &g_BC, &g_IF, &g_IR); 0138 0139 double I_eq_B = I_BE - V_BE * g_BE; 0140 double I_eq_C = I_BC - V_BC * g_BC; 0141 double I_eq_E = I_T - V_BE * g_IF + V_BC * g_IR; 0142 0143 m_ns.A[0][0] = g_BC + g_BE; 0144 m_ns.A[0][1] = -g_BC; 0145 m_ns.A[0][2] = -g_BE; 0146 0147 m_ns.A[1][0] = -g_BC + (g_IF - g_IR); 0148 m_ns.A[1][1] = g_IR + g_BC; 0149 m_ns.A[1][2] = -g_IF; 0150 0151 m_ns.A[2][0] = -g_BE - (g_IF - g_IR); 0152 m_ns.A[2][1] = -g_IR; 0153 m_ns.A[2][2] = g_BE + g_IF; 0154 0155 m_ns.I[0] = (-I_eq_B - I_eq_C) * m_pol; 0156 m_ns.I[1] = (+I_eq_C - I_eq_E) * m_pol; 0157 m_ns.I[2] = (+I_eq_B + I_eq_E) * m_pol; 0158 } 0159 0160 void BJT::calcIg(double V_BE, double V_BC, double *I_BE, double *I_BC, double *I_T, double *g_BE, double *g_BC, double *g_IF, double *g_IR) const 0161 { 0162 double I_S = m_bjtSettings.I_S; 0163 double N_F = m_bjtSettings.N_F; 0164 double N_R = m_bjtSettings.N_R; 0165 double B_F = m_bjtSettings.B_F; 0166 double B_R = m_bjtSettings.B_R; 0167 0168 // BE diodes 0169 double g_tiny = (V_BE < (-10 * V_T * N_F)) ? I_S : 0; 0170 0171 double I_F; 0172 diodeJunction(V_BE, I_S, N_F, &I_F, g_IF); 0173 0174 double I_BEI = I_F / B_F; 0175 double g_BEI = *g_IF / B_F; 0176 double I_BEN = g_tiny * V_BE; 0177 double g_BEN = g_tiny; 0178 *I_BE = I_BEI + I_BEN; 0179 *g_BE = g_BEI + g_BEN; 0180 0181 // BC diodes 0182 g_tiny = (V_BC < (-10 * V_T * N_R)) ? I_S : 0; 0183 0184 double I_R; 0185 diodeJunction(V_BC, I_S, N_R, &I_R, g_IR); 0186 0187 double I_BCI = I_R / B_R; 0188 double g_BCI = *g_IR / B_R; 0189 double I_BCN = g_tiny * V_BC; 0190 double g_BCN = g_tiny; 0191 *I_BC = I_BCI + I_BCN; 0192 *g_BC = g_BCI + g_BCN; 0193 0194 *I_T = I_F - I_R; 0195 } 0196 0197 void BJT::setBJTSettings(const BJTSettings &settings) 0198 { 0199 m_bjtSettings = settings; 0200 updateLim(); 0201 if (p_eSet) 0202 p_eSet->setCacheInvalidated(); 0203 } 0204 0205 void BJT::updateLim() 0206 { 0207 double I_S = m_bjtSettings.I_S; 0208 double N_F = m_bjtSettings.N_F; 0209 double N_R = m_bjtSettings.N_R; 0210 0211 V_BE_lim = diodeLimitedVoltage(I_S, N_F); 0212 V_BC_lim = diodeLimitedVoltage(I_S, N_R); 0213 } 0214 // END class BJT