Branch data Line data Source code
1 : : /*
2 : : * tunneldiode.cpp - resonance tunnel diode class implementation
3 : : *
4 : : * Copyright (C) 2011 Michael Margraf <michael.margraf@alumni.tu-berlin.de>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : #if HAVE_CONFIG_H
26 : : # include <config.h>
27 : : #endif
28 : :
29 : : #include "component.h"
30 : : #include "device.h"
31 : : #include "devstates.h"
32 : : #include "tunneldiode.h"
33 : :
34 : : #define NODE_A1 0 /* cathode node */
35 : : #define NODE_A2 1 /* anode node */
36 : :
37 : : using namespace qucs;
38 : : using namespace qucs::device;
39 : :
40 : : // Constructor for the diode.
41 : 0 : tunneldiode::tunneldiode () : circuit (2) {
42 : 0 : type = CIR_TUNNELDIODE;
43 : 0 : }
44 : :
45 : : // Callback for initializing the DC analysis.
46 : 0 : void tunneldiode::initDC (void) {
47 : : // allocate MNA matrices
48 : 0 : allocMatrixMNA ();
49 : 0 : }
50 : :
51 : : // Calculate one branch of the tunnel current.
52 : 0 : void tunneldiode::calcId (nr_double_t U, nr_double_t& I, nr_double_t& G) {
53 : 0 : nr_double_t eta = getPropertyDouble ("eta");
54 : 0 : nr_double_t Wr = getPropertyDouble ("Wr");
55 : 0 : nr_double_t dv = getPropertyDouble ("dv");
56 : 0 : nr_double_t de = getPropertyDouble ("de");
57 : 0 : nr_double_t dW = getPropertyDouble ("dW");
58 : :
59 : 0 : U = Wr - Q_e*U/dv;
60 : 0 : de *= kB * kelvin (getPropertyDouble ("Temp"));
61 : :
62 : 0 : nr_double_t a = M_PI_2 + qucs::atan ( U / dW );
63 : :
64 : 0 : nr_double_t e = (eta - U) / de;
65 : 0 : nr_double_t b = e;
66 [ # # ]: 0 : if (e < 15.0) // avoid numerical overflow
67 : 0 : b = qucs::log (1.0 + qucs::exp ( e ));
68 : :
69 : : // current
70 : 0 : I = b * a;
71 : :
72 : : // derivative
73 : 0 : G = Q_e / dv / de / (1.0 + qucs::exp(-e)) * a - b * Q_e / dv / dW / (1.0 + sqr (U/dW));
74 : 0 : }
75 : :
76 : : // Callback for DC analysis.
77 : 0 : void tunneldiode::calcDC (void) {
78 : : // get device properties
79 [ # # ]: 0 : nr_double_t Ip = getPropertyDouble ("Ip");
80 [ # # ]: 0 : nr_double_t A = getPropertyDouble ("Area");
81 [ # # ]: 0 : nr_double_t Tmax = getPropertyDouble ("Tmax");
82 [ # # ]: 0 : nr_double_t de = getPropertyDouble ("de");
83 [ # # ]: 0 : nr_double_t eta = getPropertyDouble ("eta");
84 [ # # ]: 0 : nr_double_t Iv = getPropertyDouble ("Iv");
85 [ # # ]: 0 : nr_double_t Vv = getPropertyDouble ("Vv");
86 [ # # ]: 0 : nr_double_t nv = getPropertyDouble ("nv");
87 [ # # ]: 0 : nr_double_t T = kB * kelvin (getPropertyDouble ("Temp"));
88 : :
89 : : // diode voltage
90 [ # # ][ # # ]: 0 : Ud = real (getV (NODE_A1) - getV (NODE_A2));
[ # # ]
91 : :
92 : : // bi-directional tunnel current
93 : : nr_double_t Ipos, Ineg, Gpos, Gneg;
94 : 0 : gd = Id = A * Ip * Tmax * de * T / eta / M_PI_2;
95 [ # # ]: 0 : calcId ( Ud, Ipos, Gpos);
96 [ # # ]: 0 : calcId (-Ud, Ineg, Gneg);
97 : 0 : Id *= Ipos - Ineg;
98 : 0 : gd *= Gpos + Gneg;
99 : :
100 : : // thermal-ionic current
101 : 0 : nv *= T / Q_e;
102 [ # # ]: 0 : nr_double_t c = A * Iv / qucs::sinh (Vv / nv);
103 [ # # ]: 0 : Id += c * qucs::sinh (Ud / nv);
104 [ # # ]: 0 : gd += c * qucs::cosh (Ud / nv) / nv;
105 : :
106 : 0 : nr_double_t Ieq = Id - Ud * gd;
107 : :
108 : : // fill in I-Vector
109 [ # # ]: 0 : setI (NODE_A2, +Ieq);
110 [ # # ]: 0 : setI (NODE_A1, -Ieq);
111 : :
112 : : // fill in G-Matrix
113 [ # # ][ # # ]: 0 : setY (NODE_A1, NODE_A1, +gd); setY (NODE_A2, NODE_A2, +gd);
114 [ # # ][ # # ]: 0 : setY (NODE_A1, NODE_A2, -gd); setY (NODE_A2, NODE_A1, -gd);
115 : 0 : }
116 : :
117 : : // Saves operating points (voltages).
118 : 0 : void tunneldiode::saveOperatingPoints (void) {
119 [ # # ][ # # ]: 0 : nr_double_t Vd = real (getV (NODE_A1) - getV (NODE_A2));
120 : 0 : setOperatingPoint ("Vd", Vd);
121 : 0 : }
122 : :
123 : : // Loads operating points (voltages).
124 : 0 : void tunneldiode::loadOperatingPoints (void) {
125 : 0 : Ud = getOperatingPoint ("Vd");
126 : 0 : }
127 : :
128 : : // Calculates and saves operating points.
129 : 0 : void tunneldiode::calcOperatingPoints (void) {
130 : 0 : nr_double_t A = getPropertyDouble ("Area");
131 : 0 : nr_double_t Cj0 = getPropertyDouble ("Cj0");
132 : 0 : nr_double_t M = getScaledProperty ("M");
133 : 0 : nr_double_t Vj = getScaledProperty ("Vj");
134 : 0 : nr_double_t te = getScaledProperty ("te");
135 : :
136 : : // calculate capacitances and charges
137 : : nr_double_t Cd;
138 : :
139 : : // depletion capacitance
140 : 0 : nr_double_t c = 1.0 + fabs(Ud) / Vj;
141 : 0 : Cd = A * Cj0 / qucs::pow (c, M);
142 : 0 : Qd = A * Cj0 * Vj / (1.0-M) * (1.0 - qucs::pow (c, 1.0 - M));
143 : :
144 : : // quantum well (diffusion) capacitance (negative because of NDR region)
145 : 0 : Cd -= te * gd;
146 : 0 : Qd -= te * Id;
147 : :
148 : : // save operating points
149 : 0 : setOperatingPoint ("gd", gd);
150 : 0 : setOperatingPoint ("Id", Id);
151 : 0 : setOperatingPoint ("Cd", Cd);
152 : 0 : }
153 : :
154 : : // Callback for initializing the AC analysis.
155 : 0 : void tunneldiode::initAC (void) {
156 : 0 : initDC ();
157 : 0 : }
158 : :
159 : : // Build admittance matrix for AC and SP analysis.
160 : 0 : matrix tunneldiode::calcMatrixY (nr_double_t frequency) {
161 [ # # ]: 0 : nr_double_t gd = getOperatingPoint ("gd");
162 [ # # ]: 0 : nr_double_t Cd = getOperatingPoint ("Cd");
163 : 0 : nr_complex_t yd = nr_complex_t (gd, Cd * 2.0 * M_PI * frequency);
164 [ # # ]: 0 : matrix y (2);
165 [ # # ]: 0 : y.set (NODE_A1, NODE_A1, +yd);
166 [ # # ]: 0 : y.set (NODE_A2, NODE_A2, +yd);
167 [ # # ]: 0 : y.set (NODE_A1, NODE_A2, -yd);
168 [ # # ]: 0 : y.set (NODE_A2, NODE_A1, -yd);
169 : 0 : return y;
170 : : }
171 : :
172 : : // Callback for the AC analysis.
173 : 0 : void tunneldiode::calcAC (nr_double_t frequency) {
174 [ # # ]: 0 : setMatrixY (calcMatrixY (frequency));
175 : 0 : }
176 : :
177 : : // Callback for S-parameter analysis.
178 : 0 : void tunneldiode::calcSP (nr_double_t frequency) {
179 [ # # ][ # # ]: 0 : setMatrixS (ytos (calcMatrixY (frequency)));
[ # # ][ # # ]
[ # # ]
180 : 0 : }
181 : :
182 : : #define qState 0 // charge state
183 : : #define cState 1 // current state
184 : :
185 : : // Callback for initializing the TR analysis.
186 : 0 : void tunneldiode::initTR (void) {
187 : 0 : setStates (2);
188 : 0 : initDC ();
189 : 0 : }
190 : :
191 : : // Callback for the TR analysis.
192 : 0 : void tunneldiode::calcTR (nr_double_t) {
193 : 0 : calcDC ();
194 : :
195 : 0 : saveOperatingPoints ();
196 : 0 : loadOperatingPoints ();
197 : 0 : calcOperatingPoints ();
198 : :
199 : 0 : nr_double_t Cd = getOperatingPoint ("Cd");
200 : 0 : transientCapacitance (qState, NODE_A1, NODE_A2, Cd, Ud, Qd);
201 : 0 : }
202 : :
203 : : // properties
204 : : PROP_REQ [] = {
205 : : { "Ip", PROP_REAL, { 4.0e-3, PROP_NO_STR }, PROP_POS_RANGE },
206 : : { "Iv", PROP_REAL, { 0.6e-3, PROP_NO_STR }, PROP_POS_RANGE },
207 : : { "Vv", PROP_REAL, { 0.8, PROP_NO_STR }, PROP_POS_RANGE },
208 : :
209 : : { "Cj0", PROP_REAL, { 80e-15, PROP_NO_STR }, PROP_POS_RANGE },
210 : : { "M", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 2) },
211 : : { "Vj", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGXI (0, 10) },
212 : : PROP_NO_PROP };
213 : : PROP_OPT [] = {
214 : : { "Wr", PROP_REAL, { 2.7e-20, PROP_NO_STR }, PROP_POS_RANGE },
215 : : { "eta", PROP_REAL, { 1e-20, PROP_NO_STR }, PROP_POS_RANGE },
216 : : { "dW", PROP_REAL, { 4.5e-21, PROP_NO_STR }, PROP_POS_RANGE },
217 : : { "Tmax", PROP_REAL, { 0.95, PROP_NO_STR }, PROP_POS_RANGE },
218 : : { "de", PROP_REAL, { 0.9, PROP_NO_STR }, PROP_POS_RANGE },
219 : : { "dv", PROP_REAL, { 2.0, PROP_NO_STR }, PROP_POS_RANGE },
220 : : { "nv", PROP_REAL, { 16, PROP_NO_STR }, PROP_POS_RANGE },
221 : : { "te", PROP_REAL, { 0.6e-12, PROP_NO_STR }, PROP_POS_RANGE },
222 : : { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
223 : : { "Area", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX },
224 : : PROP_NO_PROP };
225 : : struct define_t tunneldiode::cirdef =
226 : : { "RTD", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };
|