Branch data Line data Source code
1 : : /*
2 : : * diac.cpp - diac class implementation
3 : : *
4 : : * Copyright (C) 2008 Stefan Jahn <stefan@lkcc.org>
5 : : * Copyright (C) 2008 Michael Margraf <Michael.Margraf@alumni.TU-Berlin.DE>
6 : : *
7 : : * This is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2, or (at your option)
10 : : * any later version.
11 : : *
12 : : * This software is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this package; see the file COPYING. If not, write to
19 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 : : * Boston, MA 02110-1301, USA.
21 : : *
22 : : * $Id$
23 : : *
24 : : */
25 : :
26 : : #if HAVE_CONFIG_H
27 : : # include <config.h>
28 : : #endif
29 : :
30 : : #include "component.h"
31 : : #include "device.h"
32 : : #include "devstates.h"
33 : : #include "diac.h"
34 : :
35 : : #define NODE_A1 0 /* anode 1 */
36 : : #define NODE_A2 1 /* anode 2 (cathode) */
37 : : #define NODE_IN 2 /* internal node */
38 : :
39 : : using namespace qucs;
40 : : using namespace qucs::device;
41 : :
42 : : // Constructor for the diac.
43 [ # # ][ # # ]: 0 : diac::diac () : circuit (3) {
44 : 0 : type = CIR_DIAC;
45 : 0 : }
46 : :
47 : : // Callback for initializing the DC analysis.
48 : 0 : void diac::initDC (void) {
49 : 0 : Ud_last = 0.0;
50 : : // allocate MNA matrices
51 : 0 : allocMatrixMNA ();
52 : : // create internal node
53 : 0 : setInternalNode (NODE_IN, "int");
54 : 0 : }
55 : :
56 : : // Callback for DC analysis.
57 : 0 : void diac::calcDC (void) {
58 : 0 : calcTheModel (false);
59 : 0 : }
60 : :
61 : 0 : void diac::calcTheModel (bool last) {
62 : : // get device properties
63 : 0 : nr_double_t Ubo = getPropertyDouble ("Vbo");
64 : 0 : nr_double_t Ibo = getPropertyDouble ("Ibo");
65 : 0 : nr_double_t Is = getPropertyDouble ("Is");
66 : 0 : nr_double_t N = getPropertyDouble ("N");
67 : 0 : nr_double_t gi = 1.0 / getPropertyDouble ("Ri");
68 : 0 : nr_double_t T = getPropertyDouble ("Temp");
69 : :
70 : : bool isOn;
71 [ # # ]: 0 : if (last)
72 : 0 : Ud = fabs (Ud_last);
73 : : else
74 [ # # ][ # # ]: 0 : Ud = fabs (real (getV (NODE_A1) - getV (NODE_IN)));
75 : 0 : isOn = Ud > (Ibo / gi);
76 : :
77 : : nr_double_t Ut, Ieq, Vd;
78 : :
79 [ # # ]: 0 : if (isOn)
80 : 0 : Ut = N * kelvin (T) * kBoverQ;
81 : : else
82 : 0 : Ut = Ubo / std::log (Ibo / Is);
83 : :
84 [ # # ][ # # ]: 0 : Vd = Ud = real (getV (NODE_IN) - getV (NODE_A2));
85 : 0 : Ud = fabs (Ud) / Ut;
86 : 0 : Id = sign (Vd) * Is;
87 : :
88 [ # # ]: 0 : if (Ud >= 80.0) {
89 : 0 : Id *= std::exp (80.0) * (1.0 + Ud - 80.0) - 1.0;
90 : 0 : Ud = 80.0;
91 : : }
92 : : else
93 : 0 : Id *= std::exp (Ud) - 1.0;
94 : :
95 : 0 : gd = Is / Ut * std::exp (Ud);
96 : 0 : Ieq = Id - Vd * gd;
97 : :
98 : : // fill in I-Vector
99 [ # # ]: 0 : setI (NODE_A2, +Ieq);
100 [ # # ]: 0 : setI (NODE_IN, -Ieq);
101 [ # # ]: 0 : setI (NODE_A1, +0.0);
102 : :
103 : : // fill in G-Matrix
104 [ # # ][ # # ]: 0 : setY (NODE_A2, NODE_A2, +gd); setY (NODE_IN, NODE_IN, +gd);
105 [ # # ][ # # ]: 0 : setY (NODE_A2, NODE_IN, -gd); setY (NODE_IN, NODE_A2, -gd);
106 [ # # ]: 0 : setY (NODE_A1, NODE_A1, +gi); addY (NODE_IN, NODE_IN, +gi);
107 [ # # ][ # # ]: 0 : setY (NODE_A1, NODE_IN, -gi); setY (NODE_IN, NODE_A1, -gi);
108 : 0 : }
109 : :
110 : : // Saves operating points (voltages).
111 : 0 : void diac::saveOperatingPoints (void) {
112 [ # # ][ # # ]: 0 : nr_double_t Vd = real (getV (NODE_IN) - getV (NODE_A2));
113 [ # # ][ # # ]: 0 : nr_double_t Vi = real (getV (NODE_A1) - getV (NODE_IN));
114 : 0 : setOperatingPoint ("Vd", Vd);
115 : 0 : setOperatingPoint ("Vi", Vi);
116 : 0 : }
117 : :
118 : : // Loads operating points (voltages).
119 : 0 : void diac::loadOperatingPoints (void) {
120 : 0 : Ud = getOperatingPoint ("Vd");
121 : 0 : Ui = getOperatingPoint ("Vi");
122 : 0 : }
123 : :
124 : : // Calculates and saves operating points.
125 : 0 : void diac::calcOperatingPoints (void) {
126 : 0 : nr_double_t Cj0 = getPropertyDouble ("Cj0");
127 : : // calculate capacitances and charges
128 : : nr_double_t Ci;
129 : 0 : Ci = Cj0;
130 : 0 : Qi = Cj0 * Ud;
131 : : // save operating points
132 : 0 : setOperatingPoint ("gi", gi);
133 : 0 : setOperatingPoint ("gd", gd);
134 : 0 : setOperatingPoint ("Id", Id);
135 : 0 : setOperatingPoint ("Ci", Ci);
136 : 0 : }
137 : :
138 : : // Callback for initializing the AC analysis.
139 : 0 : void diac::initAC (void) {
140 : 0 : initDC ();
141 : 0 : }
142 : :
143 : : // Build admittance matrix for AC and SP analysis.
144 : 0 : matrix diac::calcMatrixY (nr_double_t frequency) {
145 [ # # ]: 0 : nr_double_t gd = getOperatingPoint ("gd");
146 [ # # ]: 0 : nr_double_t gi = getOperatingPoint ("gi");
147 [ # # ]: 0 : nr_double_t Ci = getOperatingPoint ("Ci");
148 : 0 : nr_complex_t yd = nr_complex_t (gd, Ci * 2.0 * M_PI * frequency);
149 [ # # ]: 0 : matrix y (3);
150 [ # # ]: 0 : y.set (NODE_A2, NODE_A2, +yd);
151 [ # # ]: 0 : y.set (NODE_IN, NODE_IN, +yd +gi);
152 [ # # ]: 0 : y.set (NODE_A2, NODE_IN, -yd);
153 [ # # ]: 0 : y.set (NODE_IN, NODE_A2, -yd);
154 [ # # ]: 0 : y.set (NODE_A1, NODE_A1, +gi);
155 [ # # ]: 0 : y.set (NODE_A1, NODE_IN, -gi);
156 [ # # ]: 0 : y.set (NODE_IN, NODE_A1, -gi);
157 : 0 : return y;
158 : : }
159 : :
160 : : // Callback for the AC analysis.
161 : 0 : void diac::calcAC (nr_double_t frequency) {
162 [ # # ]: 0 : setMatrixY (calcMatrixY (frequency));
163 : 0 : }
164 : :
165 : : // Callback for S-parameter analysis.
166 : 0 : void diac::calcSP (nr_double_t frequency) {
167 [ # # ][ # # ]: 0 : setMatrixS (ytos (calcMatrixY (frequency)));
[ # # ][ # # ]
[ # # ]
168 : 0 : }
169 : :
170 : : #define qState 0 // charge state
171 : : #define cState 1 // current state
172 : :
173 : : // Callback for initializing the TR analysis.
174 : 0 : void diac::initTR (void) {
175 : 0 : setStates (2);
176 : 0 : initDC ();
177 : 0 : time_prev = -1.0;
178 : 0 : }
179 : :
180 : : // Callback for the TR analysis.
181 : 0 : void diac::calcTR (nr_double_t time) {
182 [ # # ]: 0 : if (time_prev < time) {
183 : 0 : time_prev = time;
184 [ # # ][ # # ]: 0 : Ud_last = real (getV (NODE_A1) - getV (NODE_IN));
185 : : }
186 : 0 : calcTheModel (true);
187 : :
188 : 0 : saveOperatingPoints ();
189 : 0 : loadOperatingPoints ();
190 : 0 : calcOperatingPoints ();
191 : :
192 : 0 : nr_double_t Ci = getOperatingPoint ("Ci");
193 : 0 : transientCapacitance (qState, NODE_IN, NODE_A2, Ci, Ud, Qi);
194 : 0 : }
195 : :
196 : : // properties
197 : : PROP_REQ [] = {
198 : : { "Ibo", PROP_REAL, { 50e-6, PROP_NO_STR }, PROP_POS_RANGEX },
199 : : { "Vbo", PROP_REAL, { 30, PROP_NO_STR }, PROP_POS_RANGEX },
200 : : PROP_NO_PROP };
201 : : PROP_OPT [] = {
202 : : { "Cj0", PROP_REAL, { 10e-12, PROP_NO_STR }, PROP_POS_RANGE },
203 : : { "Is", PROP_REAL, { 1e-10, PROP_NO_STR }, PROP_POS_RANGE },
204 : : { "N", PROP_REAL, { 2.0, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
205 : : { "Ri", PROP_REAL, { 10.0, PROP_NO_STR }, PROP_POS_RANGEX },
206 : : { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
207 : : PROP_NO_PROP };
208 : : struct define_t diac::cirdef =
209 : : { "Diac", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };
|