File indexing completed on 2024-05-05 05:46:10

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2004 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 "diode.h"
0012 #include "elementset.h"
0013 
0014 #include <algorithm>
0015 #include <vector>
0016 
0017 #include <cmath>
0018 
0019 // BEGIN class Diode Settings
0020 DiodeSettings::DiodeSettings()
0021 {
0022     reset();
0023 }
0024 
0025 void DiodeSettings::reset()
0026 {
0027     I_S = 1e-15;
0028     N = 1.0;
0029     V_B = 4.7;
0030     //  R = 0.001;
0031 }
0032 // END class Diode Settings
0033 
0034 // BEGIN class Diode
0035 Diode::Diode()
0036     : NonLinear()
0037 {
0038     m_numCNodes = 2;
0039     g_new = g_old = I_new = I_old = V_prev = 0.0;
0040     updateLim();
0041 }
0042 
0043 Diode::~Diode()
0044 {
0045 }
0046 
0047 void Diode::add_initial_dc()
0048 {
0049     g_new = g_old = I_new = I_old = V_prev = 0.0;
0050     update_dc();
0051 }
0052 
0053 double Diode::current() const
0054 {
0055     if (!b_status)
0056         return 0.0;
0057 
0058     double I;
0059     calcIg(p_cnode[0]->v - p_cnode[1]->v, &I, nullptr);
0060 
0061     return I;
0062 }
0063 
0064 void Diode::updateCurrents()
0065 {
0066     if (!b_status)
0067         return;
0068 
0069     m_cnodeI[1] = current();
0070     m_cnodeI[0] = -m_cnodeI[1];
0071 }
0072 
0073 void Diode::update_dc()
0074 {
0075     if (!b_status)
0076         return;
0077 
0078     calc_eq();
0079 
0080     A_g(0, 0) += g_new - g_old;
0081     A_g(1, 1) += g_new - g_old;
0082     A_g(0, 1) -= g_new - g_old;
0083     A_g(1, 0) -= g_new - g_old;
0084 
0085     b_i(0) -= I_new - I_old;
0086     b_i(1) += I_new - I_old;
0087 
0088     g_old = g_new;
0089     I_old = I_new;
0090 }
0091 
0092 void Diode::calc_eq()
0093 {
0094     double N = m_diodeSettings.N;
0095     double V_B = m_diodeSettings.V_B;
0096     //  double R = m_diodeSettings.R;
0097 
0098     double v = p_cnode[0]->v - p_cnode[1]->v;
0099 
0100     // adjust voltage to help convergence
0101     if (V_B != 0 && v < std::min<double>(0, -V_B + 10 * N)) {
0102         double V = -(v + V_B);
0103         V = diodeVoltage(V, -(V_prev + V_B), N, V_lim);
0104         v = -(V + V_B);
0105     } else
0106         v = diodeVoltage(v, V_prev, N, V_lim);
0107 
0108     V_prev = v;
0109 
0110     double I_D;
0111     calcIg(v, &I_D, &g_new);
0112 
0113     I_new = I_D - (v * g_new);
0114 }
0115 
0116 void Diode::calcIg(double V, double *I_D, double *g) const
0117 {
0118     double I_S = m_diodeSettings.I_S;
0119     double N = m_diodeSettings.N;
0120     double V_B = m_diodeSettings.V_B;
0121     //  double R = m_diodeSettings.R;
0122 
0123     double g_tiny = (V < -10 * V_T * N && V_B != 0) ? I_S : 0;
0124 
0125     if (V >= (-3 * N * V_T)) {
0126         if (g)
0127             *g = diodeConductance(V, I_S, N) + g_tiny;
0128         *I_D = diodeCurrent(V, I_S, N) + (g_tiny * V);
0129     } else if (V_B == 0 || V >= -V_B) {
0130         double a = (3 * N * V_T) / (V * M_E);
0131         a = a * a * a;
0132         *I_D = (-I_S * (1 + a)) + (g_tiny * V);
0133         if (g)
0134             *g = ((I_S * 3 * a) / V) + g_tiny;
0135     } else {
0136         double a = exp(-(V_B + V) / N / V_T);
0137         *I_D = (-I_S * a) + (g_tiny * V);
0138         if (g)
0139             *g = I_S * a / V_T / N + g_tiny;
0140     }
0141 }
0142 
0143 void Diode::setDiodeSettings(const DiodeSettings &settings)
0144 {
0145     m_diodeSettings = settings;
0146     updateLim();
0147     if (p_eSet)
0148         p_eSet->setCacheInvalidated();
0149 }
0150 
0151 void Diode::updateLim()
0152 {
0153     double I_S = m_diodeSettings.I_S;
0154     double N = m_diodeSettings.N;
0155     V_lim = diodeLimitedVoltage(I_S, N);
0156 }
0157 // END class Diode