Branch data Line data Source code
1 : : /*
2 : : * triac.cpp - triac 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 "triac.h"
34 : :
35 : : #define NODE_A1 0 /* anode 1 */
36 : : #define NODE_A2 1 /* anode 2 (cathode) */
37 : : #define NODE_GA 2 /* gate */
38 : : #define NODE_IN 3 /* internal node */
39 : :
40 : : using namespace qucs;
41 : : using namespace qucs::device;
42 : :
43 : : // Constructor for the triac.
44 [ # # ][ # # ]: 0 : triac::triac () : circuit (4) {
45 : 0 : type = CIR_TRIAC;
46 : 0 : }
47 : :
48 : : // Callback for initializing the DC analysis.
49 : 0 : void triac::initDC (void) {
50 : 0 : Ud_last = 0.0;
51 : : // allocate MNA matrices
52 : 0 : allocMatrixMNA ();
53 : : // create internal node
54 : 0 : setInternalNode (NODE_IN, "int");
55 : 0 : }
56 : :
57 : : // Callback for DC analysis.
58 : 0 : void triac::calcDC (void) {
59 : 0 : calcTheModel (false);
60 : 0 : }
61 : :
62 : 0 : void triac::calcTheModel (bool last) {
63 : : // get device properties
64 : 0 : nr_double_t Ubo = getPropertyDouble ("Vbo");
65 : 0 : nr_double_t Ibo = getPropertyDouble ("Igt");
66 : 0 : nr_double_t Is = getPropertyDouble ("Is");
67 : 0 : nr_double_t N = getPropertyDouble ("N");
68 : 0 : nr_double_t Gg = 1.0 / getPropertyDouble ("Rg");
69 : 0 : nr_double_t T = getPropertyDouble ("Temp");
70 : 0 : gi = 1.0 / getPropertyDouble ("Ri");
71 : :
72 : : nr_double_t Ut, Ud_bo, Ieq, Vd;
73 : :
74 : 0 : Ut = N * kelvin (T) * kBoverQ;
75 : 0 : Ud_bo = std::log (Ibo / Is + 1.0);
76 : :
77 [ # # ][ # # ]: 0 : Vd = Ud = real (getV (NODE_IN) - getV (NODE_A2));
78 : 0 : Id = sign (Ud) * Is;
79 : 0 : Ud = fabs (Ud) / Ut;
80 : :
81 : : bool isOn;
82 [ # # ]: 0 : if (last)
83 : 0 : isOn = (Ud_last / Ut) > Ud_bo;
84 : : else
85 : 0 : isOn = Ud > Ud_bo;
86 : :
87 [ # # ]: 0 : if (Ud >= 80.0) {
88 : 0 : Id *= std::exp (80.0) * (1.0 + Ud - 80.0) - 1.0;
89 : 0 : Ud = 80.0;
90 : : }
91 : : else
92 : 0 : Id *= std::exp (Ud) - 1.0;
93 : :
94 : 0 : gd = Is / Ut * std::exp (Ud);
95 : 0 : Ieq = Id - Vd * gd;
96 : :
97 : : // fill in I-Vector
98 [ # # ]: 0 : setI (NODE_A2, +Ieq);
99 [ # # ]: 0 : setI (NODE_IN, -Ieq);
100 [ # # ]: 0 : setI (NODE_A1, +0.0);
101 [ # # ]: 0 : setI (NODE_GA, +0.0);
102 : :
103 [ # # ]: 0 : if (!isOn) {
104 : 0 : Ut = Ubo / std::log (Ibo / Is);
105 [ # # ][ # # ]: 0 : Vd = Ud = real (getV (NODE_A1) - getV (NODE_IN));
106 : 0 : Id = sign (Ud) * Is;
107 : 0 : Ud = fabs (Ud) / Ut;
108 : :
109 [ # # ]: 0 : if (Ud >= 80.0) {
110 : 0 : Id *= std::exp (80.0) * (1.0 + Ud - 80.0) - 1.0;
111 : 0 : Ud = 80.0;
112 : : }
113 : : else
114 : 0 : Id *= std::exp (Ud) - 1.0;
115 : :
116 : 0 : gi = Is / Ut * std::exp (Ud);
117 : 0 : Ieq = Id - Vd * gi;
118 : 0 : addI (NODE_A1, -Ieq);
119 : 0 : addI (NODE_IN, +Ieq);
120 : : }
121 : :
122 : : // fill in G-Matrix
123 [ # # ][ # # ]: 0 : setY (NODE_A2, NODE_A2, +gd); setY (NODE_IN, NODE_IN, +gd);
124 [ # # ][ # # ]: 0 : setY (NODE_A2, NODE_IN, -gd); setY (NODE_IN, NODE_A2, -gd);
125 [ # # ]: 0 : setY (NODE_A1, NODE_A1, +gi); addY (NODE_IN, NODE_IN, +gi);
126 [ # # ][ # # ]: 0 : setY (NODE_A1, NODE_IN, -gi); setY (NODE_IN, NODE_A1, -gi);
127 [ # # ]: 0 : setY (NODE_GA, NODE_GA, +Gg); addY (NODE_IN, NODE_IN, +Gg);
128 [ # # ][ # # ]: 0 : setY (NODE_GA, NODE_IN, -Gg); setY (NODE_IN, NODE_GA, -Gg);
129 : 0 : }
130 : :
131 : : // Saves operating points (voltages).
132 : 0 : void triac::saveOperatingPoints (void) {
133 [ # # ][ # # ]: 0 : nr_double_t Vd = real (getV (NODE_IN) - getV (NODE_A2));
134 [ # # ][ # # ]: 0 : nr_double_t Vi = real (getV (NODE_A1) - getV (NODE_IN));
135 : 0 : setOperatingPoint ("Vd", Vd);
136 : 0 : setOperatingPoint ("Vi", Vi);
137 : 0 : }
138 : :
139 : : // Loads operating points (voltages).
140 : 0 : void triac::loadOperatingPoints (void) {
141 : 0 : Ud = getOperatingPoint ("Vd");
142 : 0 : Ui = getOperatingPoint ("Vi");
143 : 0 : }
144 : :
145 : : // Calculates and saves operating points.
146 : 0 : void triac::calcOperatingPoints (void) {
147 : 0 : nr_double_t Cj0 = getPropertyDouble ("Cj0");
148 : : // calculate capacitances and charges
149 : : nr_double_t Ci;
150 : 0 : Ci = Cj0;
151 : 0 : Qi = Cj0 * Ui;
152 : : // save operating points
153 : 0 : setOperatingPoint ("gi", gi);
154 : 0 : setOperatingPoint ("gd", gd);
155 : 0 : setOperatingPoint ("Id", Id);
156 : 0 : setOperatingPoint ("Ci", Ci);
157 : 0 : }
158 : :
159 : : // Callback for initializing the AC analysis.
160 : 0 : void triac::initAC (void) {
161 : 0 : initDC ();
162 : 0 : }
163 : :
164 : : // Build admittance matrix for AC and SP analysis.
165 : 0 : matrix triac::calcMatrixY (nr_double_t frequency) {
166 [ # # ]: 0 : nr_double_t gd = getOperatingPoint ("gd");
167 [ # # ]: 0 : nr_double_t gi = getOperatingPoint ("gi");
168 [ # # ]: 0 : nr_double_t gg = 1.0 / getPropertyDouble ("Rg");
169 [ # # ]: 0 : nr_double_t Ci = getOperatingPoint ("Ci");
170 : 0 : nr_complex_t yi = nr_complex_t (gi, Ci * 2.0 * M_PI * frequency);
171 [ # # ]: 0 : matrix y (4);
172 [ # # ]: 0 : y.set (NODE_A2, NODE_A2, +gd);
173 [ # # ]: 0 : y.set (NODE_IN, NODE_IN, +gd +yi +gg);
174 [ # # ]: 0 : y.set (NODE_A2, NODE_IN, -gd);
175 [ # # ]: 0 : y.set (NODE_IN, NODE_A2, -gd);
176 [ # # ]: 0 : y.set (NODE_A1, NODE_A1, +yi);
177 [ # # ]: 0 : y.set (NODE_A1, NODE_IN, -yi);
178 [ # # ]: 0 : y.set (NODE_IN, NODE_A1, -yi);
179 [ # # ]: 0 : y.set (NODE_GA, NODE_GA, +gg);
180 [ # # ]: 0 : y.set (NODE_GA, NODE_IN, -gg);
181 [ # # ]: 0 : y.set (NODE_IN, NODE_GA, -gg);
182 : 0 : return y;
183 : : }
184 : :
185 : : // Callback for the AC analysis.
186 : 0 : void triac::calcAC (nr_double_t frequency) {
187 [ # # ]: 0 : setMatrixY (calcMatrixY (frequency));
188 : 0 : }
189 : :
190 : : // Callback for S-parameter analysis.
191 : 0 : void triac::calcSP (nr_double_t frequency) {
192 [ # # ][ # # ]: 0 : setMatrixS (ytos (calcMatrixY (frequency)));
[ # # ][ # # ]
[ # # ]
193 : 0 : }
194 : :
195 : : #define qState 0 // charge state
196 : : #define cState 1 // current state
197 : :
198 : : // Callback for initializing the TR analysis.
199 : 0 : void triac::initTR (void) {
200 : 0 : setStates (2);
201 : 0 : initDC ();
202 : 0 : time_prev = -1.0;
203 : 0 : }
204 : :
205 : : // Callback for the TR analysis.
206 : 0 : void triac::calcTR (nr_double_t time) {
207 [ # # ]: 0 : if (time_prev < time) {
208 : 0 : time_prev = time;
209 [ # # ][ # # ]: 0 : Ud_last = fabs (real (getV (NODE_IN) - getV (NODE_A2)));
210 : : }
211 : 0 : calcTheModel (true);
212 : :
213 : 0 : saveOperatingPoints ();
214 : 0 : loadOperatingPoints ();
215 : 0 : calcOperatingPoints ();
216 : :
217 : 0 : nr_double_t Ci = getOperatingPoint ("Ci");
218 : 0 : transientCapacitance (qState, NODE_A1, NODE_IN, Ci, Ui, Qi);
219 : 0 : }
220 : :
221 : : // properties
222 : : PROP_REQ [] = {
223 : : { "Igt", PROP_REAL, { 50e-6, PROP_NO_STR }, PROP_POS_RANGEX },
224 : : { "Vbo", PROP_REAL, { 30, PROP_NO_STR }, PROP_POS_RANGEX },
225 : : PROP_NO_PROP };
226 : : PROP_OPT [] = {
227 : : { "Cj0", PROP_REAL, { 10e-12, PROP_NO_STR }, PROP_POS_RANGE },
228 : : { "Is", PROP_REAL, { 1e-10, PROP_NO_STR }, PROP_POS_RANGE },
229 : : { "N", PROP_REAL, { 2.0, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
230 : : { "Ri", PROP_REAL, { 10.0, PROP_NO_STR }, PROP_POS_RANGEX },
231 : : { "Rg", PROP_REAL, { 5.0, PROP_NO_STR }, PROP_POS_RANGEX },
232 : : { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
233 : : PROP_NO_PROP };
234 : : struct define_t triac::cirdef =
235 : : { "Triac", 3, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };
|