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