You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
3.8 KiB
199 lines
3.8 KiB
/***************************************************************************
|
|
* Copyright (C) 2003-2004 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 <vector>
|
|
#include "diode.h"
|
|
#include "elementset.h"
|
|
#include "matrix.h"
|
|
|
|
#include <cmath>
|
|
|
|
|
|
//BEGIN class Diode Settings
|
|
DiodeSettings::DiodeSettings()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
|
|
void DiodeSettings::reset()
|
|
{
|
|
I_S = 1e-15;
|
|
N = 1.0;
|
|
V_B = 4.7;
|
|
// R = 0.001;
|
|
}
|
|
//END class Diode Settings
|
|
|
|
|
|
|
|
//BEGIN class Diode
|
|
Diode::Diode()
|
|
: NonLinear()
|
|
{
|
|
m_numCNodes = 2;
|
|
g_new = g_old = I_new = I_old = V_prev = 0.0;
|
|
}
|
|
|
|
|
|
Diode::~Diode()
|
|
{
|
|
}
|
|
|
|
|
|
void Diode::add_map()
|
|
{
|
|
if (!b_status)
|
|
return;
|
|
|
|
if ( !p_cnode[0]->isGround )
|
|
{
|
|
p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false );
|
|
}
|
|
if ( !p_cnode[1]->isGround )
|
|
{
|
|
p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false );
|
|
}
|
|
|
|
if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround )
|
|
{
|
|
p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false );
|
|
p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false );
|
|
}
|
|
}
|
|
|
|
|
|
void Diode::add_initial_dc()
|
|
{
|
|
g_new = g_old = I_new = I_old = V_prev = 0.0;
|
|
update_dc();
|
|
}
|
|
|
|
|
|
double Diode::current() const
|
|
{
|
|
if (!b_status)
|
|
return 0.0;
|
|
|
|
double I;
|
|
calcIg( p_cnode[0]->v - p_cnode[1]->v, & I, 0 );
|
|
|
|
return I;
|
|
}
|
|
|
|
|
|
void Diode::updateCurrents()
|
|
{
|
|
if (!b_status)
|
|
return;
|
|
|
|
m_cnodeI[1] = current();
|
|
m_cnodeI[0] = -m_cnodeI[1];
|
|
}
|
|
|
|
|
|
void Diode::update_dc()
|
|
{
|
|
if (!b_status)
|
|
return;
|
|
|
|
calc_eq();
|
|
|
|
A_g( 0, 0 ) += g_new - g_old;
|
|
A_g( 1, 1 ) += g_new - g_old;
|
|
A_g( 0, 1 ) -= g_new - g_old;
|
|
A_g( 1, 0 ) -= g_new - g_old;
|
|
|
|
b_i( 0 ) -= I_new - I_old;
|
|
b_i( 1 ) += I_new - I_old;
|
|
|
|
g_old = g_new;
|
|
I_old = I_new;
|
|
}
|
|
|
|
|
|
|
|
#ifndef MIN
|
|
# define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
|
#endif
|
|
|
|
|
|
|
|
void Diode::calc_eq()
|
|
{
|
|
double I_S = m_diodeSettings.I_S;
|
|
double N = m_diodeSettings.N;
|
|
double V_B = m_diodeSettings.V_B;
|
|
// double R = m_diodeSettings.R;
|
|
|
|
double v = p_cnode[0]->v - p_cnode[1]->v;
|
|
|
|
// adjust voltage to help convergence
|
|
double V_crit = diodeCriticalVoltage( I_S, N * V_T );
|
|
if (V_B != 0 && v < MIN (0, -V_B + 10 * N * V_T))
|
|
{
|
|
double V = -(v + V_B);
|
|
V = diodeVoltage( V, -(V_prev + V_B), V_T * N, V_crit );
|
|
v = -(V + V_B);
|
|
}
|
|
else
|
|
v = diodeVoltage( v, V_prev, V_T * N, V_crit );
|
|
|
|
V_prev = v;
|
|
|
|
double I_D;
|
|
calcIg( v, & I_D, & g_new );
|
|
|
|
I_new = I_D - (v * g_new);
|
|
}
|
|
|
|
|
|
void Diode::calcIg( double V, double * I_D, double * g ) const
|
|
{
|
|
double I_S = m_diodeSettings.I_S;
|
|
double N = m_diodeSettings.N;
|
|
double V_B = m_diodeSettings.V_B;
|
|
// double R = m_diodeSettings.R;
|
|
|
|
double gtiny = (V < - 10 * V_T * N && V_B != 0) ? I_S : 0;
|
|
|
|
if ( V >= (-3 * N * V_T) )
|
|
{
|
|
if ( g )
|
|
*g = diodeConductance( V, I_S, V_T * N ) + gtiny;
|
|
*I_D = diodeCurrent( V, I_S, V_T * N ) + (gtiny * V);
|
|
}
|
|
else if ( V_B == 0 || V >= -V_B )
|
|
{
|
|
double a = (3 * N * V_T) / (V * M_E);
|
|
a = a * a * a;
|
|
*I_D = (-I_S * (1 + a)) + (gtiny * V);
|
|
if ( g )
|
|
*g = ((I_S * 3 * a) / V) + gtiny;
|
|
}
|
|
else
|
|
{
|
|
double a = exp( -(V_B + V) / N / V_T );
|
|
*I_D = (-I_S * a) + (gtiny * V);
|
|
if ( g )
|
|
*g = I_S * a / V_T / N + gtiny;
|
|
}
|
|
}
|
|
|
|
|
|
void Diode::setDiodeSettings( const DiodeSettings & settings )
|
|
{
|
|
m_diodeSettings = settings;
|
|
if (p_eSet)
|
|
p_eSet->setCacheInvalidated();
|
|
}
|
|
//END class Diode
|
|
|