Qucs-core
0.0.19
|
00001 /* 00002 * diac.cpp - diac class implementation 00003 * 00004 * Copyright (C) 2008 Stefan Jahn <stefan@lkcc.org> 00005 * Copyright (C) 2008 Michael Margraf <Michael.Margraf@alumni.TU-Berlin.DE> 00006 * 00007 * This is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2, or (at your option) 00010 * any later version. 00011 * 00012 * This software is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this package; see the file COPYING. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 * 00022 * $Id$ 00023 * 00024 */ 00025 00026 #if HAVE_CONFIG_H 00027 # include <config.h> 00028 #endif 00029 00030 #include "component.h" 00031 #include "device.h" 00032 #include "devstates.h" 00033 #include "diac.h" 00034 00035 #define NODE_A1 0 /* anode 1 */ 00036 #define NODE_A2 1 /* anode 2 (cathode) */ 00037 #define NODE_IN 2 /* internal node */ 00038 00039 using namespace qucs; 00040 using namespace qucs::device; 00041 00042 // Constructor for the diac. 00043 diac::diac () : circuit (3) { 00044 type = CIR_DIAC; 00045 } 00046 00047 // Callback for initializing the DC analysis. 00048 void diac::initDC (void) { 00049 Ud_last = 0.0; 00050 // allocate MNA matrices 00051 allocMatrixMNA (); 00052 // create internal node 00053 setInternalNode (NODE_IN, "int"); 00054 } 00055 00056 // Callback for DC analysis. 00057 void diac::calcDC (void) { 00058 calcTheModel (false); 00059 } 00060 00061 void diac::calcTheModel (bool last) { 00062 // get device properties 00063 nr_double_t Ubo = getPropertyDouble ("Vbo"); 00064 nr_double_t Ibo = getPropertyDouble ("Ibo"); 00065 nr_double_t Is = getPropertyDouble ("Is"); 00066 nr_double_t N = getPropertyDouble ("N"); 00067 nr_double_t gi = 1.0 / getPropertyDouble ("Ri"); 00068 nr_double_t T = getPropertyDouble ("Temp"); 00069 00070 bool isOn; 00071 if (last) 00072 Ud = fabs (Ud_last); 00073 else 00074 Ud = fabs (real (getV (NODE_A1) - getV (NODE_IN))); 00075 isOn = Ud > (Ibo / gi); 00076 00077 nr_double_t Ut, Ieq, Vd; 00078 00079 if (isOn) 00080 Ut = N * celsius2kelvin (T) * kBoverQ; 00081 else 00082 Ut = Ubo / std::log (Ibo / Is); 00083 00084 Vd = Ud = real (getV (NODE_IN) - getV (NODE_A2)); 00085 Ud = fabs (Ud) / Ut; 00086 Id = sign (Vd) * Is; 00087 00088 if (Ud >= 80.0) { 00089 Id *= std::exp (80.0) * (1.0 + Ud - 80.0) - 1.0; 00090 Ud = 80.0; 00091 } 00092 else 00093 Id *= std::exp (Ud) - 1.0; 00094 00095 gd = Is / Ut * std::exp (Ud); 00096 Ieq = Id - Vd * gd; 00097 00098 // fill in I-Vector 00099 setI (NODE_A2, +Ieq); 00100 setI (NODE_IN, -Ieq); 00101 setI (NODE_A1, +0.0); 00102 00103 // fill in G-Matrix 00104 setY (NODE_A2, NODE_A2, +gd); setY (NODE_IN, NODE_IN, +gd); 00105 setY (NODE_A2, NODE_IN, -gd); setY (NODE_IN, NODE_A2, -gd); 00106 setY (NODE_A1, NODE_A1, +gi); addY (NODE_IN, NODE_IN, +gi); 00107 setY (NODE_A1, NODE_IN, -gi); setY (NODE_IN, NODE_A1, -gi); 00108 } 00109 00110 // Saves operating points (voltages). 00111 void diac::saveOperatingPoints (void) { 00112 nr_double_t Vd = real (getV (NODE_IN) - getV (NODE_A2)); 00113 nr_double_t Vi = real (getV (NODE_A1) - getV (NODE_IN)); 00114 setOperatingPoint ("Vd", Vd); 00115 setOperatingPoint ("Vi", Vi); 00116 } 00117 00118 // Loads operating points (voltages). 00119 void diac::loadOperatingPoints (void) { 00120 Ud = getOperatingPoint ("Vd"); 00121 Ui = getOperatingPoint ("Vi"); 00122 } 00123 00124 // Calculates and saves operating points. 00125 void diac::calcOperatingPoints (void) { 00126 nr_double_t Cj0 = getPropertyDouble ("Cj0"); 00127 // calculate capacitances and charges 00128 nr_double_t Ci; 00129 Ci = Cj0; 00130 Qi = Cj0 * Ud; 00131 // save operating points 00132 setOperatingPoint ("gi", gi); 00133 setOperatingPoint ("gd", gd); 00134 setOperatingPoint ("Id", Id); 00135 setOperatingPoint ("Ci", Ci); 00136 } 00137 00138 // Callback for initializing the AC analysis. 00139 void diac::initAC (void) { 00140 initDC (); 00141 } 00142 00143 // Build admittance matrix for AC and SP analysis. 00144 matrix diac::calcMatrixY (nr_double_t frequency) { 00145 nr_double_t gd = getOperatingPoint ("gd"); 00146 nr_double_t gi = getOperatingPoint ("gi"); 00147 nr_double_t Ci = getOperatingPoint ("Ci"); 00148 nr_complex_t yd = nr_complex_t (gd, Ci * 2.0 * pi * frequency); 00149 matrix y (3); 00150 y.set (NODE_A2, NODE_A2, +yd); 00151 y.set (NODE_IN, NODE_IN, +yd +gi); 00152 y.set (NODE_A2, NODE_IN, -yd); 00153 y.set (NODE_IN, NODE_A2, -yd); 00154 y.set (NODE_A1, NODE_A1, +gi); 00155 y.set (NODE_A1, NODE_IN, -gi); 00156 y.set (NODE_IN, NODE_A1, -gi); 00157 return y; 00158 } 00159 00160 // Callback for the AC analysis. 00161 void diac::calcAC (nr_double_t frequency) { 00162 setMatrixY (calcMatrixY (frequency)); 00163 } 00164 00165 // Callback for S-parameter analysis. 00166 void diac::calcSP (nr_double_t frequency) { 00167 setMatrixS (ytos (calcMatrixY (frequency))); 00168 } 00169 00170 #define qState 0 // charge state 00171 #define cState 1 // current state 00172 00173 // Callback for initializing the TR analysis. 00174 void diac::initTR (void) { 00175 setStates (2); 00176 initDC (); 00177 time_prev = -1.0; 00178 } 00179 00180 // Callback for the TR analysis. 00181 void diac::calcTR (nr_double_t time) { 00182 if (time_prev < time) { 00183 time_prev = time; 00184 Ud_last = real (getV (NODE_A1) - getV (NODE_IN)); 00185 } 00186 calcTheModel (true); 00187 00188 saveOperatingPoints (); 00189 loadOperatingPoints (); 00190 calcOperatingPoints (); 00191 00192 nr_double_t Ci = getOperatingPoint ("Ci"); 00193 transientCapacitance (qState, NODE_IN, NODE_A2, Ci, Ud, Qi); 00194 } 00195 00196 // properties 00197 PROP_REQ [] = { 00198 { "Ibo", PROP_REAL, { 50e-6, PROP_NO_STR }, PROP_POS_RANGEX }, 00199 { "Vbo", PROP_REAL, { 30, PROP_NO_STR }, PROP_POS_RANGEX }, 00200 PROP_NO_PROP }; 00201 PROP_OPT [] = { 00202 { "Cj0", PROP_REAL, { 10e-12, PROP_NO_STR }, PROP_POS_RANGE }, 00203 { "Is", PROP_REAL, { 1e-10, PROP_NO_STR }, PROP_POS_RANGE }, 00204 { "N", PROP_REAL, { 2.0, PROP_NO_STR }, PROP_RNGII (0.1, 100) }, 00205 { "Ri", PROP_REAL, { 10.0, PROP_NO_STR }, PROP_POS_RANGEX }, 00206 { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) }, 00207 PROP_NO_PROP }; 00208 struct define_t diac::cirdef = 00209 { "Diac", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };