Qucs-core  0.0.19
tunneldiode.cpp
Go to the documentation of this file.
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 };