Qucs-core
0.0.19
|
00001 /* 00002 * tunneldiode.cpp - resonance tunnel diode class implementation 00003 * 00004 * Copyright (C) 2011 Michael Margraf <michael.margraf@alumni.tu-berlin.de> 00005 * 00006 * This is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2, or (at your option) 00009 * any later version. 00010 * 00011 * This software is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this package; see the file COPYING. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 * $Id$ 00022 * 00023 */ 00024 00025 #if HAVE_CONFIG_H 00026 # include <config.h> 00027 #endif 00028 00029 #include "component.h" 00030 #include "device.h" 00031 #include "devstates.h" 00032 #include "tunneldiode.h" 00033 00034 #define NODE_A1 0 /* cathode node */ 00035 #define NODE_A2 1 /* anode node */ 00036 00037 using namespace qucs; 00038 using namespace qucs::device; 00039 00040 // Constructor for the diode. 00041 tunneldiode::tunneldiode () : circuit (2) { 00042 type = CIR_TUNNELDIODE; 00043 } 00044 00045 // Callback for initializing the DC analysis. 00046 void tunneldiode::initDC (void) { 00047 // allocate MNA matrices 00048 allocMatrixMNA (); 00049 } 00050 00051 // Calculate one branch of the tunnel current. 00052 void tunneldiode::calcId (nr_double_t U, nr_double_t& I, nr_double_t& G) { 00053 nr_double_t eta = getPropertyDouble ("eta"); 00054 nr_double_t Wr = getPropertyDouble ("Wr"); 00055 nr_double_t dv = getPropertyDouble ("dv"); 00056 nr_double_t de = getPropertyDouble ("de"); 00057 nr_double_t dW = getPropertyDouble ("dW"); 00058 00059 U = Wr - Q_e*U/dv; 00060 de *= kB * celsius2kelvin (getPropertyDouble ("Temp")); 00061 00062 nr_double_t a = pi_over_2 + qucs::atan ( U / dW ); 00063 00064 nr_double_t e = (eta - U) / de; 00065 nr_double_t b = e; 00066 if (e < 15.0) // avoid numerical overflow 00067 b = qucs::log (1.0 + qucs::exp ( e )); 00068 00069 // current 00070 I = b * a; 00071 00072 // derivative 00073 G = Q_e / dv / de / (1.0 + qucs::exp(-e)) * a - b * Q_e / dv / dW / (1.0 + sqr (U/dW)); 00074 } 00075 00076 // Callback for DC analysis. 00077 void tunneldiode::calcDC (void) { 00078 // get device properties 00079 nr_double_t Ip = getPropertyDouble ("Ip"); 00080 nr_double_t A = getPropertyDouble ("Area"); 00081 nr_double_t Tmax = getPropertyDouble ("Tmax"); 00082 nr_double_t de = getPropertyDouble ("de"); 00083 nr_double_t eta = getPropertyDouble ("eta"); 00084 nr_double_t Iv = getPropertyDouble ("Iv"); 00085 nr_double_t Vv = getPropertyDouble ("Vv"); 00086 nr_double_t nv = getPropertyDouble ("nv"); 00087 nr_double_t T = kB * celsius2kelvin (getPropertyDouble ("Temp")); 00088 00089 // diode voltage 00090 Ud = real (getV (NODE_A1) - getV (NODE_A2)); 00091 00092 // bi-directional tunnel current 00093 nr_double_t Ipos, Ineg, Gpos, Gneg; 00094 gd = Id = A * Ip * Tmax * de * T / eta / pi_over_2; 00095 calcId ( Ud, Ipos, Gpos); 00096 calcId (-Ud, Ineg, Gneg); 00097 Id *= Ipos - Ineg; 00098 gd *= Gpos + Gneg; 00099 00100 // thermal-ionic current 00101 nv *= T / Q_e; 00102 nr_double_t c = A * Iv / qucs::sinh (Vv / nv); 00103 Id += c * qucs::sinh (Ud / nv); 00104 gd += c * qucs::cosh (Ud / nv) / nv; 00105 00106 nr_double_t Ieq = Id - Ud * gd; 00107 00108 // fill in I-Vector 00109 setI (NODE_A2, +Ieq); 00110 setI (NODE_A1, -Ieq); 00111 00112 // fill in G-Matrix 00113 setY (NODE_A1, NODE_A1, +gd); setY (NODE_A2, NODE_A2, +gd); 00114 setY (NODE_A1, NODE_A2, -gd); setY (NODE_A2, NODE_A1, -gd); 00115 } 00116 00117 // Saves operating points (voltages). 00118 void tunneldiode::saveOperatingPoints (void) { 00119 nr_double_t Vd = real (getV (NODE_A1) - getV (NODE_A2)); 00120 setOperatingPoint ("Vd", Vd); 00121 } 00122 00123 // Loads operating points (voltages). 00124 void tunneldiode::loadOperatingPoints (void) { 00125 Ud = getOperatingPoint ("Vd"); 00126 } 00127 00128 // Calculates and saves operating points. 00129 void tunneldiode::calcOperatingPoints (void) { 00130 nr_double_t A = getPropertyDouble ("Area"); 00131 nr_double_t Cj0 = getPropertyDouble ("Cj0"); 00132 nr_double_t M = getScaledProperty ("M"); 00133 nr_double_t Vj = getScaledProperty ("Vj"); 00134 nr_double_t te = getScaledProperty ("te"); 00135 00136 // calculate capacitances and charges 00137 nr_double_t Cd; 00138 00139 // depletion capacitance 00140 nr_double_t c = 1.0 + fabs(Ud) / Vj; 00141 Cd = A * Cj0 / qucs::pow (c, M); 00142 Qd = A * Cj0 * Vj / (1.0-M) * (1.0 - qucs::pow (c, 1.0 - M)); 00143 00144 // quantum well (diffusion) capacitance (negative because of NDR region) 00145 Cd -= te * gd; 00146 Qd -= te * Id; 00147 00148 // save operating points 00149 setOperatingPoint ("gd", gd); 00150 setOperatingPoint ("Id", Id); 00151 setOperatingPoint ("Cd", Cd); 00152 } 00153 00154 // Callback for initializing the AC analysis. 00155 void tunneldiode::initAC (void) { 00156 initDC (); 00157 } 00158 00159 // Build admittance matrix for AC and SP analysis. 00160 matrix tunneldiode::calcMatrixY (nr_double_t frequency) { 00161 nr_double_t gd = getOperatingPoint ("gd"); 00162 nr_double_t Cd = getOperatingPoint ("Cd"); 00163 nr_complex_t yd = nr_complex_t (gd, Cd * 2.0 * pi * frequency); 00164 matrix y (2); 00165 y.set (NODE_A1, NODE_A1, +yd); 00166 y.set (NODE_A2, NODE_A2, +yd); 00167 y.set (NODE_A1, NODE_A2, -yd); 00168 y.set (NODE_A2, NODE_A1, -yd); 00169 return y; 00170 } 00171 00172 // Callback for the AC analysis. 00173 void tunneldiode::calcAC (nr_double_t frequency) { 00174 setMatrixY (calcMatrixY (frequency)); 00175 } 00176 00177 // Callback for S-parameter analysis. 00178 void tunneldiode::calcSP (nr_double_t frequency) { 00179 setMatrixS (ytos (calcMatrixY (frequency))); 00180 } 00181 00182 #define qState 0 // charge state 00183 #define cState 1 // current state 00184 00185 // Callback for initializing the TR analysis. 00186 void tunneldiode::initTR (void) { 00187 setStates (2); 00188 initDC (); 00189 } 00190 00191 // Callback for the TR analysis. 00192 void tunneldiode::calcTR (nr_double_t) { 00193 calcDC (); 00194 00195 saveOperatingPoints (); 00196 loadOperatingPoints (); 00197 calcOperatingPoints (); 00198 00199 nr_double_t Cd = getOperatingPoint ("Cd"); 00200 transientCapacitance (qState, NODE_A1, NODE_A2, Cd, Ud, Qd); 00201 } 00202 00203 // properties 00204 PROP_REQ [] = { 00205 { "Ip", PROP_REAL, { 4.0e-3, PROP_NO_STR }, PROP_POS_RANGE }, 00206 { "Iv", PROP_REAL, { 0.6e-3, PROP_NO_STR }, PROP_POS_RANGE }, 00207 { "Vv", PROP_REAL, { 0.8, PROP_NO_STR }, PROP_POS_RANGE }, 00208 00209 { "Cj0", PROP_REAL, { 80e-15, PROP_NO_STR }, PROP_POS_RANGE }, 00210 { "M", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 2) }, 00211 { "Vj", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGXI (0, 10) }, 00212 PROP_NO_PROP }; 00213 PROP_OPT [] = { 00214 { "Wr", PROP_REAL, { 2.7e-20, PROP_NO_STR }, PROP_POS_RANGE }, 00215 { "eta", PROP_REAL, { 1e-20, PROP_NO_STR }, PROP_POS_RANGE }, 00216 { "dW", PROP_REAL, { 4.5e-21, PROP_NO_STR }, PROP_POS_RANGE }, 00217 { "Tmax", PROP_REAL, { 0.95, PROP_NO_STR }, PROP_POS_RANGE }, 00218 { "de", PROP_REAL, { 0.9, PROP_NO_STR }, PROP_POS_RANGE }, 00219 { "dv", PROP_REAL, { 2.0, PROP_NO_STR }, PROP_POS_RANGE }, 00220 { "nv", PROP_REAL, { 16, PROP_NO_STR }, PROP_POS_RANGE }, 00221 { "te", PROP_REAL, { 0.6e-12, PROP_NO_STR }, PROP_POS_RANGE }, 00222 { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) }, 00223 { "Area", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX }, 00224 PROP_NO_PROP }; 00225 struct define_t tunneldiode::cirdef = 00226 { "RTD", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };