Logo Search packages:      
Sourcecode: ktechlab version File versions

bjt.cpp

/***************************************************************************
 *   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 "bjt.h"
#include "diode.h"
#include "elementset.h"
#include "matrix.h"

#include <cmath>
using namespace std;


//BEGIN class BJTSettings
BJTSettings::BJTSettings()
{
      I_S = 1e-16;
      N_F = 1.0;
      N_R = 1.0;
      B_F = 100.0;
      B_R = 1.0;
}
//END class BJTSettings



//BEGIN class BJTState
BJTState::BJTState()
{
      reset();
}


void BJTState::reset()
{
      for ( unsigned i = 0; i < 3; ++i )
      {
            for ( unsigned j = 0; j < 3; ++j )
                  A[i][j] = 0.0;
                  
            I[i] = 0.0;
      }
}


BJTState BJTState::operator-( const BJTState & s ) const
{
      BJTState newState( *this );
      
      for ( unsigned i = 0; i < 3; ++i )
      {
            for ( unsigned j = 0; j < 3; ++j )
                  newState.A[i][j] -= s.A[i][j];
                  
            newState.I[i] -= s.I[i];
      }
      
      return newState;
}
//END class BJTState



//BEGIN class BJT
BJT::BJT( bool isNPN )
{
      V_BE_prev = 0.0;
      V_BC_prev = 0.0;
      m_pol = isNPN ? 1 : -1;
      m_numCNodes = 3;
      updateLim();
}


BJT::~BJT()
{
}

00085 void BJT::add_initial_dc()
{
      V_BE_prev = 0.0;
      V_BC_prev = 0.0;
      m_os.reset();
      update_dc();
}


00094 void BJT::updateCurrents()
{
      if (!b_status)
            return;
      
      double V_B = p_cnode[0]->v;
      double V_C = p_cnode[1]->v;
      double V_E = p_cnode[2]->v;
      
      double V_BE = (V_B - V_E) * m_pol;
      double V_BC = (V_B - V_C) * m_pol;
      
      double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR;
      calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR );
      
      m_cnodeI[1] = I_BC - I_T;
      m_cnodeI[2] = I_BE + I_T;
      m_cnodeI[0] = -(m_cnodeI[1] + m_cnodeI[2]);
}


00115 void BJT::update_dc()
{
      if (!b_status)
            return;
      
      calc_eq();
      
      BJTState diff = m_ns - m_os;
      for ( unsigned i = 0; i < 3; ++i )
      {
            for ( unsigned j = 0 ; j < 3; ++j )
                  A_g( i, j ) += diff.A[i][j];
            
            b_i( i ) += diff.I[i];
      }
      
      m_os = m_ns;
}


00135 void BJT::calc_eq()
{
      double V_B = p_cnode[0]->v;
      double V_C = p_cnode[1]->v;
      double V_E = p_cnode[2]->v;
      
      double V_BE = (V_B - V_E) * m_pol;
      double V_BC = (V_B - V_C) * m_pol;
      
      double N_F = m_bjtSettings.N_F;
      double N_R = m_bjtSettings.N_R;
      
      // adjust voltage to help convergence
      V_BE_prev = V_BE = diodeVoltage( V_BE, V_BE_prev, N_F, V_BE_lim );
      V_BC_prev = V_BC = diodeVoltage( V_BC, V_BC_prev, N_R, V_BC_lim );
      
      double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR;
      calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR );
      
      double I_eq_B = I_BE - V_BE * g_BE;
      double I_eq_C = I_BC - V_BC * g_BC;
      double I_eq_E = I_T - V_BE * g_IF + V_BC * g_IR;
      
      m_ns.A[0][0] = g_BC + g_BE;
      m_ns.A[0][1] = -g_BC;
      m_ns.A[0][2] = -g_BE;
      
      m_ns.A[1][0] = -g_BC + (g_IF - g_IR);
      m_ns.A[1][1] = g_IR + g_BC;
      m_ns.A[1][2] = -g_IF;
      
      m_ns.A[2][0] = -g_BE - (g_IF - g_IR);
      m_ns.A[2][1] = -g_IR;
      m_ns.A[2][2] = g_BE + g_IF;
      
      m_ns.I[0] = (-I_eq_B - I_eq_C) * m_pol;
      m_ns.I[1] = (+I_eq_C - I_eq_E) * m_pol;
      m_ns.I[2] = (+I_eq_B + I_eq_E) * m_pol;
}


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
{
      double I_S = m_bjtSettings.I_S;
      double N_F = m_bjtSettings.N_F;
      double N_R = m_bjtSettings.N_R;
      double B_F = m_bjtSettings.B_F;
      double B_R = m_bjtSettings.B_R;
      
      // BE diodes
      double g_tiny = (V_BE < (-10 * V_T * N_F)) ? I_S : 0;
  
      double I_F;
      diodeJunction( V_BE, I_S, N_F, & I_F, g_IF );
      
      double I_BEI = I_F / B_F;
      double g_BEI = *g_IF / B_F;
      double I_BEN = g_tiny * V_BE;
      double g_BEN = g_tiny;
      *I_BE = I_BEI + I_BEN;
      *g_BE = g_BEI + g_BEN;
      
      // BC diodes
      g_tiny = (V_BC < (-10 * V_T * N_R)) ? I_S : 0;
      
      double I_R;
      diodeJunction( V_BC, I_S, N_R, & I_R, g_IR );
      
      double I_BCI = I_R / B_R;
      double g_BCI = *g_IR / B_R;
      double I_BCN = g_tiny * V_BC;
      double g_BCN = g_tiny;
      *I_BC = I_BCI + I_BCN;
      *g_BC = g_BCI + g_BCN;
      
      *I_T = I_F - I_R;
}


void BJT::setBJTSettings( const BJTSettings & settings )
{
      m_bjtSettings = settings;
      updateLim();
      if (p_eSet)
            p_eSet->setCacheInvalidated();
}


void BJT::updateLim()
{
      double I_S = m_bjtSettings.I_S;
      double N_F = m_bjtSettings.N_F;
      double N_R = m_bjtSettings.N_R;
      
      V_BE_lim = diodeLimitedVoltage( I_S, N_F );
      V_BC_lim = diodeLimitedVoltage( I_S, N_R );
}
//END class BJT



Generated by  Doxygen 1.6.0   Back to index