Branch data Line data Source code
1 : : /*
2 : : * mstee.cpp - microstrip t-junction class implementation
3 : : *
4 : : * Copyright (C) 2004, 2005, 2006 Stefan Jahn <stefan@lkcc.org>
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 "substrate.h"
31 : : #include "device.h"
32 : : #include "msline.h"
33 : : #include "mstee.h"
34 : :
35 : : using namespace qucs;
36 : : using namespace qucs::device;
37 : :
38 : 1 : mstee::mstee () : circuit (3) {
39 : 1 : lineA = lineB = line2 = NULL;
40 : 1 : type = CIR_MSTEE;
41 : 1 : }
42 : :
43 : 1 : void mstee::initSP (void) {
44 : 1 : allocMatrixS ();
45 : 1 : initLines ();
46 : 1 : lineA->initSP ();
47 : 1 : lineB->initSP ();
48 : 1 : line2->initSP ();
49 : 1 : }
50 : :
51 : 0 : void mstee::initNoiseSP (void) {
52 : 0 : allocMatrixN ();
53 : 0 : lineA->initNoiseSP ();
54 : 0 : lineB->initNoiseSP ();
55 : 0 : line2->initNoiseSP ();
56 : 0 : }
57 : :
58 : 1 : void mstee::initLines (void) {
59 : 1 : lineA = splitMicrostrip (this, lineA, getNet (), "LineA", "NodeA", NODE_1);
60 : 1 : lineA->setProperty ("W", getPropertyDouble ("W1"));
61 : 1 : lineA->setProperty ("Temp", getPropertyDouble ("Temp"));
62 : 1 : lineA->setProperty ("Model", getPropertyString ("MSModel"));
63 : 1 : lineA->setProperty ("DispModel", getPropertyString ("MSDispModel"));
64 : 1 : lineA->setSubstrate (getSubstrate ());
65 : :
66 : 1 : lineB = splitMicrostrip (this, lineB, getNet (), "LineB", "NodeB", NODE_2);
67 : 1 : lineB->setProperty ("W", getPropertyDouble ("W2"));
68 : 1 : lineB->setProperty ("Temp", getPropertyDouble ("Temp"));
69 : 1 : lineB->setProperty ("Model", getPropertyString ("MSModel"));
70 : 1 : lineB->setProperty ("DispModel", getPropertyString ("MSDispModel"));
71 : 1 : lineB->setSubstrate (getSubstrate ());
72 : :
73 : 1 : line2 = splitMicrostrip (this, line2, getNet (), "Line2", "Node2", NODE_3);
74 : 1 : line2->setProperty ("W", getPropertyDouble ("W3"));
75 : 1 : line2->setProperty ("Temp", getPropertyDouble ("Temp"));
76 : 1 : line2->setProperty ("Model", getPropertyString ("MSModel"));
77 : 1 : line2->setProperty ("DispModel", getPropertyString ("MSDispModel"));
78 : 1 : line2->setSubstrate (getSubstrate ());
79 : 1 : }
80 : :
81 : 39 : void mstee::calcSP (nr_double_t frequency) {
82 [ + - ]: 39 : calcPropagation (frequency);
83 : :
84 [ + - ]: 39 : lineA->setProperty ("L", La);
85 [ + - ]: 39 : lineB->setProperty ("L", Lb);
86 [ + - ]: 39 : line2->setProperty ("L", L2);
87 [ + - ]: 39 : lineA->calcSP (frequency);
88 [ + - ]: 39 : lineB->calcSP (frequency);
89 [ + - ]: 39 : line2->calcSP (frequency);
90 : :
91 : : // calculate S-parameters
92 : 39 : nr_complex_t n1 = Ta2 * nr_complex_t (1 + 1 / Tb2, Bt * z0);
93 : 39 : nr_complex_t n2 = Tb2 * nr_complex_t (1 + 1 / Ta2, Bt * z0);
94 : 39 : nr_complex_t n3 = nr_complex_t (1 / Ta2 + 1 / Tb2, Bt * z0);
95 [ + - ][ + - ]: 39 : setS (NODE_1, NODE_1, (1.0 - n1) / (1.0 + n1));
96 [ + - ][ + - ]: 39 : setS (NODE_2, NODE_2, (1.0 - n2) / (1.0 + n2));
97 [ + - ][ + - ]: 39 : setS (NODE_3, NODE_3, (1.0 - n3) / (1.0 + n3));
98 [ + - ][ + - ]: 39 : setS (NODE_1, NODE_3, 2.0 * std::sqrt (Ta2) / (1.0 + n1));
99 [ + - ][ + - ]: 39 : setS (NODE_3, NODE_1, 2.0 * std::sqrt (Ta2) / (1.0 + n1));
100 [ + - ][ + - ]: 39 : setS (NODE_2, NODE_3, 2.0 * std::sqrt (Tb2) / (1.0 + n2));
101 [ + - ][ + - ]: 39 : setS (NODE_3, NODE_2, 2.0 * std::sqrt (Tb2) / (1.0 + n2));
102 : 39 : setS (NODE_1, NODE_2, 2.0 / (std::sqrt (Ta2 * Tb2) * nr_complex_t (1, Bt * z0) +
103 [ + - ][ + - ]: 39 : std::sqrt (Ta2 / Tb2) + std::sqrt (Tb2 / Ta2)));
104 : 39 : setS (NODE_2, NODE_1, 2.0 / (std::sqrt (Ta2 * Tb2) * nr_complex_t (1, Bt * z0) +
105 [ + - ][ + - ]: 39 : std::sqrt (Ta2 / Tb2) + std::sqrt (Tb2 / Ta2)));
106 : 39 : }
107 : :
108 : 39 : void mstee::calcPropagation (nr_double_t f) {
109 : :
110 [ + - ]: 39 : const char * SModel = getPropertyString ("MSModel");
111 [ + - ]: 39 : const char * DModel = getPropertyString ("MSDispModel");
112 [ + - ]: 39 : substrate * subst = getSubstrate ();
113 [ + - ]: 39 : nr_double_t er = subst->getPropertyDouble ("er");
114 [ + - ]: 39 : nr_double_t h = subst->getPropertyDouble ("h");
115 [ + - ]: 39 : nr_double_t t = subst->getPropertyDouble ("t");
116 [ + - ]: 39 : nr_double_t Wa = getPropertyDouble ("W1");
117 [ + - ]: 39 : nr_double_t Wb = getPropertyDouble ("W2");
118 [ + - ]: 39 : nr_double_t W2 = getPropertyDouble ("W3");
119 : :
120 : : nr_double_t Zla, Zlb, Zl2, Era, Erb, Er2;
121 : :
122 : : // computation of impedances and effective dielectric constants
123 : : nr_double_t ZlEff, ErEff, WEff;
124 [ + - ]: 39 : msline::analyseQuasiStatic (Wa, h, t, er, SModel, ZlEff, ErEff, WEff);
125 : : msline::analyseDispersion (Wa, h, er, ZlEff, ErEff, f, DModel,
126 [ + - ]: 39 : Zla, Era);
127 [ + - ]: 39 : msline::analyseQuasiStatic (Wb, h, t, er, SModel, ZlEff, ErEff, WEff);
128 : : msline::analyseDispersion (Wb, h, er, ZlEff, ErEff, f, DModel,
129 [ + - ]: 39 : Zlb, Erb);
130 [ + - ]: 39 : msline::analyseQuasiStatic (W2, h, t, er, SModel, ZlEff, ErEff, WEff);
131 : : msline::analyseDispersion (W2, h, er, ZlEff, ErEff, f, DModel,
132 [ + - ]: 39 : Zl2, Er2);
133 : :
134 : : // local variables
135 : : nr_double_t Da, Db, D2, fpa, fpb, lda, ldb, da, db, d2, r, q;
136 : :
137 : : // equivalent parallel plate line widths
138 : 39 : Da = Z0 / Zla * h / std::sqrt (Era);
139 : 39 : Db = Z0 / Zlb * h / std::sqrt (Erb);
140 : 39 : D2 = Z0 / Zl2 * h / std::sqrt (Er2);
141 : :
142 : : // first higher order mode cut-off frequencies
143 : 39 : fpa = 0.4e6 * Zla / h;
144 : 39 : fpb = 0.4e6 * Zlb / h;
145 : :
146 : : // effective wavelengths of quasi-TEM mode
147 : 39 : lda = C0 / std::sqrt (Era) / f;
148 : 39 : ldb = C0 / std::sqrt (Erb) / f;
149 : :
150 : : // main arm displacements
151 [ + - ]: 39 : da = 0.055 * D2 * Zla / Zl2 * (1 - 2 * Zla / Zl2 * sqr (f / fpa));
152 [ + - ]: 39 : db = 0.055 * D2 * Zlb / Zl2 * (1 - 2 * Zlb / Zl2 * sqr (f / fpb));
153 : :
154 : : // length of lines in the main arms
155 : 39 : La = 0.5 * W2 - da;
156 : 39 : Lb = 0.5 * W2 - db;
157 : :
158 : : // displacement and length of line in the side arm
159 : 39 : r = std::sqrt (Zla * Zlb) / Zl2;
160 [ + - ]: 39 : q = sqr (f) / fpa / fpb;
161 : 39 : d2 = std::sqrt (Da * Db) * (0.5 - r * (0.05 + 0.7 * std::exp (-1.6 * r) +
162 : 39 : 0.25 * r * q - 0.17 * std::log (r)));
163 [ - + ]: 39 : L2 = 0.5 * MAX (Wa, Wb) - d2;
164 : :
165 : : // turn ratio of transformers in main arms
166 [ + - ]: 39 : Ta2 = 1 - M_PI * sqr (f / fpa) *
167 [ + - ][ + - ]: 39 : (sqr (Zla / Zl2) / 12 + sqr (0.5 - d2 / Da));
168 [ + - ]: 39 : Tb2 = 1 - M_PI * sqr (f / fpb) *
169 [ + - ][ + - ]: 39 : (sqr (Zlb / Zl2) / 12 + sqr (0.5 - d2 / Db));
170 [ + - ]: 39 : Ta2 = MAX (Ta2, NR_TINY);
171 [ + - ]: 39 : Tb2 = MAX (Tb2, NR_TINY);
172 : :
173 : : // shunt susceptance
174 : 39 : Bt = 5.5 * std::sqrt (Da * Db / lda / ldb) * (er + 2) / er /
175 : 78 : Zl2 / std::sqrt (Ta2 * Tb2) * std::sqrt (da * db) / D2 *
176 : 78 : (1 + 0.9 * std::log (r) + 4.5 * r * q - 4.4 * std::exp (-1.3 * r) -
177 [ + - ]: 39 : 20 * sqr (Zl2 / Z0));
178 : 39 : }
179 : :
180 : : /* This function can be used to create an extra microstrip circuit.
181 : : If the 'line' argument is NULL then the new circuit is created, the
182 : : nodes get re-arranged and it is inserted into the given
183 : : netlist. The given arguments can be explained as follows.
184 : : base: calling circuit (this)
185 : : line: additional microstrip line circuit (can be NULL)
186 : : subnet: the netlist object
187 : : c: name of the additional circuit
188 : : n: name of the inserted (internal) node
189 : : internal: number of new internal node (the original external node) */
190 : 3 : circuit * splitMicrostrip (circuit * base, circuit * line, net * subnet,
191 : : const char * c, const char * n, int internal) {
192 [ + - ]: 3 : if (line == NULL) {
193 [ + - ]: 3 : line = new msline ();
194 : 3 : char * name = circuit::createInternal (c, base->getName ());
195 : 3 : char * node = circuit::createInternal (n, base->getName ());
196 : 3 : line->setName (name);
197 : 3 : line->setNode (0, base->getNode(internal)->getName ());
198 : 3 : line->setNode (1, node, 1);
199 : 3 : subnet->insertCircuit (line);
200 : 3 : free (name);
201 : 3 : free (node);
202 : : }
203 : 3 : base->setNode (internal, line->getNode(1)->getName (), 1);
204 : 3 : return line;
205 : : }
206 : :
207 : : /* This function is the counterpart of the above routine. It removes
208 : : the microstrip circuit from the netlist and re-assigns the original
209 : : node. */
210 : 0 : void disableMicrostrip (circuit * base, circuit * line, net * subnet,
211 : : int internal) {
212 [ # # ]: 0 : if (line != NULL) {
213 : 0 : subnet->removeCircuit (line, 0);
214 : 0 : base->setNode (internal, line->getNode(1)->getName (), 0);
215 : : }
216 : 0 : }
217 : :
218 : 0 : void mstee::initDC (void) {
219 : 0 : setVoltageSources (2);
220 : 0 : setInternalVoltageSource (1);
221 : 0 : allocMatrixMNA ();
222 : 0 : voltageSource (VSRC_1, NODE_1, NODE_2);
223 : 0 : voltageSource (VSRC_2, NODE_1, NODE_3);
224 [ # # ]: 0 : if (deviceEnabled (lineA)) {
225 : 0 : disableMicrostrip (this, lineA, getNet (), NODE_1);
226 : : }
227 [ # # ]: 0 : if (deviceEnabled (lineB)) {
228 : 0 : disableMicrostrip (this, lineB, getNet (), NODE_2);
229 : : }
230 [ # # ]: 0 : if (deviceEnabled (line2)) {
231 : 0 : disableMicrostrip (this, line2, getNet (), NODE_3);
232 : : }
233 : 0 : }
234 : :
235 : 0 : void mstee::initAC (void) {
236 : 0 : setVoltageSources (3);
237 : 0 : setInternalVoltageSource (1);
238 : 0 : allocMatrixMNA ();
239 [ # # ][ # # ]: 0 : setB (NODE_1, VSRC_1, +1); setB (NODE_2, VSRC_2, +1);
240 [ # # ]: 0 : setB (NODE_3, VSRC_3, +1);
241 [ # # ][ # # ]: 0 : setC (VSRC_1, NODE_1, -1); setC (VSRC_2, NODE_2, -1);
242 [ # # ]: 0 : setC (VSRC_3, NODE_3, -1);
243 : 0 : initLines ();
244 : 0 : lineA->initAC ();
245 : 0 : lineB->initAC ();
246 : 0 : line2->initAC ();
247 : 0 : }
248 : :
249 : 0 : void mstee::initNoiseAC (void) {
250 : 0 : allocMatrixN (getVoltageSources ());
251 : 0 : lineA->initNoiseAC ();
252 : 0 : lineB->initNoiseAC ();
253 : 0 : line2->initNoiseAC ();
254 : 0 : }
255 : :
256 : 0 : void mstee::calcAC (nr_double_t frequency) {
257 : 0 : calcPropagation (frequency);
258 : :
259 : 0 : lineA->setProperty ("L", La);
260 : 0 : lineB->setProperty ("L", Lb);
261 : 0 : line2->setProperty ("L", L2);
262 : 0 : lineA->calcAC (frequency);
263 : 0 : lineB->calcAC (frequency);
264 : 0 : line2->calcAC (frequency);
265 : :
266 : : // calculate Z-parameters
267 [ # # ]: 0 : setD (VSRC_1, VSRC_1, nr_complex_t (0, -1 / Ta2 / Bt));
268 [ # # ]: 0 : setD (VSRC_1, VSRC_2, nr_complex_t (0, -1 / std::sqrt (Ta2 * Tb2) / Bt));
269 [ # # ]: 0 : setD (VSRC_1, VSRC_3, nr_complex_t (0, -1 / std::sqrt (Ta2) / Bt));
270 [ # # ]: 0 : setD (VSRC_2, VSRC_1, nr_complex_t (0, -1 / std::sqrt (Ta2 * Tb2) / Bt));
271 [ # # ]: 0 : setD (VSRC_2, VSRC_2, nr_complex_t (0, -1 / Tb2 / Bt));
272 [ # # ]: 0 : setD (VSRC_2, VSRC_3, nr_complex_t (0, -1 / std::sqrt (Tb2) / Bt));
273 [ # # ]: 0 : setD (VSRC_3, VSRC_1, nr_complex_t (0, -1 / std::sqrt (Ta2) / Bt));
274 [ # # ]: 0 : setD (VSRC_3, VSRC_2, nr_complex_t (0, -1 / std::sqrt (Tb2) / Bt));
275 [ # # ]: 0 : setD (VSRC_3, VSRC_3, nr_complex_t (0, -1 / Bt));
276 : 0 : }
277 : :
278 : 0 : void mstee::initTR (void) {
279 : 0 : initDC ();
280 : 0 : }
281 : :
282 : : // properties
283 : : PROP_REQ [] = {
284 : : { "W1", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE },
285 : : { "W2", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE },
286 : : { "W3", PROP_REAL, { 2e-3, PROP_NO_STR }, PROP_POS_RANGE },
287 : : { "Subst", PROP_STR, { PROP_NO_VAL, "Subst1" }, PROP_NO_RANGE },
288 : : { "MSDispModel", PROP_STR, { PROP_NO_VAL, "Kirschning" }, PROP_RNG_DIS },
289 : : { "MSModel", PROP_STR, { PROP_NO_VAL, "Hammerstad" }, PROP_RNG_MOD },
290 : : PROP_NO_PROP };
291 : : PROP_OPT [] = {
292 : : { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
293 : : PROP_NO_PROP };
294 : : struct define_t mstee::cirdef =
295 : : { "MTEE", 3, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };
|