summaryrefslogtreecommitdiffstats
path: root/src/electronics/simulation/diode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/simulation/diode.cpp')
-rw-r--r--src/electronics/simulation/diode.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/electronics/simulation/diode.cpp b/src/electronics/simulation/diode.cpp
new file mode 100644
index 0000000..e13d478
--- /dev/null
+++ b/src/electronics/simulation/diode.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+ * 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
+