Qucs-core
0.0.19
|
00001 /* 00002 * mstee.cpp - microstrip t-junction class implementation 00003 * 00004 * Copyright (C) 2004, 2005, 2006 Stefan Jahn <stefan@lkcc.org> 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 <algorithm> 00030 00031 #include "component.h" 00032 #include "substrate.h" 00033 #include "device.h" 00034 #include "msline.h" 00035 #include "mstee.h" 00036 00037 using namespace qucs; 00038 using namespace qucs::device; 00039 00040 mstee::mstee () : circuit (3) { 00041 lineA = lineB = line2 = NULL; 00042 type = CIR_MSTEE; 00043 } 00044 00045 void mstee::initSP (void) { 00046 allocMatrixS (); 00047 initLines (); 00048 lineA->initSP (); 00049 lineB->initSP (); 00050 line2->initSP (); 00051 } 00052 00053 void mstee::initNoiseSP (void) { 00054 allocMatrixN (); 00055 lineA->initNoiseSP (); 00056 lineB->initNoiseSP (); 00057 line2->initNoiseSP (); 00058 } 00059 00060 void mstee::initLines (void) { 00061 lineA = splitMicrostrip (this, lineA, getNet (), "LineA", "NodeA", NODE_1); 00062 lineA->setProperty ("W", getPropertyDouble ("W1")); 00063 lineA->setProperty ("Temp", getPropertyDouble ("Temp")); 00064 lineA->setProperty ("Model", getPropertyString ("MSModel")); 00065 lineA->setProperty ("DispModel", getPropertyString ("MSDispModel")); 00066 lineA->setSubstrate (getSubstrate ()); 00067 00068 lineB = splitMicrostrip (this, lineB, getNet (), "LineB", "NodeB", NODE_2); 00069 lineB->setProperty ("W", getPropertyDouble ("W2")); 00070 lineB->setProperty ("Temp", getPropertyDouble ("Temp")); 00071 lineB->setProperty ("Model", getPropertyString ("MSModel")); 00072 lineB->setProperty ("DispModel", getPropertyString ("MSDispModel")); 00073 lineB->setSubstrate (getSubstrate ()); 00074 00075 line2 = splitMicrostrip (this, line2, getNet (), "Line2", "Node2", NODE_3); 00076 line2->setProperty ("W", getPropertyDouble ("W3")); 00077 line2->setProperty ("Temp", getPropertyDouble ("Temp")); 00078 line2->setProperty ("Model", getPropertyString ("MSModel")); 00079 line2->setProperty ("DispModel", getPropertyString ("MSDispModel")); 00080 line2->setSubstrate (getSubstrate ()); 00081 } 00082 00083 void mstee::calcSP (nr_double_t frequency) { 00084 calcPropagation (frequency); 00085 00086 lineA->setProperty ("L", La); 00087 lineB->setProperty ("L", Lb); 00088 line2->setProperty ("L", L2); 00089 lineA->calcSP (frequency); 00090 lineB->calcSP (frequency); 00091 line2->calcSP (frequency); 00092 00093 // calculate S-parameters 00094 nr_complex_t n1 = Ta2 * nr_complex_t (1 + 1 / Tb2, Bt * z0); 00095 nr_complex_t n2 = Tb2 * nr_complex_t (1 + 1 / Ta2, Bt * z0); 00096 nr_complex_t n3 = nr_complex_t (1 / Ta2 + 1 / Tb2, Bt * z0); 00097 setS (NODE_1, NODE_1, (1.0 - n1) / (1.0 + n1)); 00098 setS (NODE_2, NODE_2, (1.0 - n2) / (1.0 + n2)); 00099 setS (NODE_3, NODE_3, (1.0 - n3) / (1.0 + n3)); 00100 setS (NODE_1, NODE_3, 2.0 * std::sqrt (Ta2) / (1.0 + n1)); 00101 setS (NODE_3, NODE_1, 2.0 * std::sqrt (Ta2) / (1.0 + n1)); 00102 setS (NODE_2, NODE_3, 2.0 * std::sqrt (Tb2) / (1.0 + n2)); 00103 setS (NODE_3, NODE_2, 2.0 * std::sqrt (Tb2) / (1.0 + n2)); 00104 setS (NODE_1, NODE_2, 2.0 / (std::sqrt (Ta2 * Tb2) * nr_complex_t (1, Bt * z0) + 00105 std::sqrt (Ta2 / Tb2) + std::sqrt (Tb2 / Ta2))); 00106 setS (NODE_2, NODE_1, 2.0 / (std::sqrt (Ta2 * Tb2) * nr_complex_t (1, Bt * z0) + 00107 std::sqrt (Ta2 / Tb2) + std::sqrt (Tb2 / Ta2))); 00108 } 00109 00110 void mstee::calcPropagation (nr_double_t f) { 00111 00112 const char * SModel = getPropertyString ("MSModel"); 00113 const char * DModel = getPropertyString ("MSDispModel"); 00114 substrate * subst = getSubstrate (); 00115 nr_double_t er = subst->getPropertyDouble ("er"); 00116 nr_double_t h = subst->getPropertyDouble ("h"); 00117 nr_double_t t = subst->getPropertyDouble ("t"); 00118 nr_double_t Wa = getPropertyDouble ("W1"); 00119 nr_double_t Wb = getPropertyDouble ("W2"); 00120 nr_double_t W2 = getPropertyDouble ("W3"); 00121 00122 nr_double_t Zla, Zlb, Zl2, Era, Erb, Er2; 00123 00124 // computation of impedances and effective dielectric constants 00125 nr_double_t ZlEff, ErEff, WEff; 00126 msline::analyseQuasiStatic (Wa, h, t, er, SModel, ZlEff, ErEff, WEff); 00127 msline::analyseDispersion (Wa, h, er, ZlEff, ErEff, f, DModel, 00128 Zla, Era); 00129 msline::analyseQuasiStatic (Wb, h, t, er, SModel, ZlEff, ErEff, WEff); 00130 msline::analyseDispersion (Wb, h, er, ZlEff, ErEff, f, DModel, 00131 Zlb, Erb); 00132 msline::analyseQuasiStatic (W2, h, t, er, SModel, ZlEff, ErEff, WEff); 00133 msline::analyseDispersion (W2, h, er, ZlEff, ErEff, f, DModel, 00134 Zl2, Er2); 00135 00136 // local variables 00137 nr_double_t Da, Db, D2, fpa, fpb, lda, ldb, da, db, d2, r, q; 00138 00139 // equivalent parallel plate line widths 00140 Da = Z0 / Zla * h / std::sqrt (Era); 00141 Db = Z0 / Zlb * h / std::sqrt (Erb); 00142 D2 = Z0 / Zl2 * h / std::sqrt (Er2); 00143 00144 // first higher order mode cut-off frequencies 00145 fpa = 0.4e6 * Zla / h; 00146 fpb = 0.4e6 * Zlb / h; 00147 00148 // effective wavelengths of quasi-TEM mode 00149 lda = C0 / std::sqrt (Era) / f; 00150 ldb = C0 / std::sqrt (Erb) / f; 00151 00152 // main arm displacements 00153 da = 0.055 * D2 * Zla / Zl2 * (1 - 2 * Zla / Zl2 * sqr (f / fpa)); 00154 db = 0.055 * D2 * Zlb / Zl2 * (1 - 2 * Zlb / Zl2 * sqr (f / fpb)); 00155 00156 // length of lines in the main arms 00157 La = 0.5 * W2 - da; 00158 Lb = 0.5 * W2 - db; 00159 00160 // displacement and length of line in the side arm 00161 r = std::sqrt (Zla * Zlb) / Zl2; 00162 q = sqr (f) / fpa / fpb; 00163 d2 = std::sqrt (Da * Db) * (0.5 - r * (0.05 + 0.7 * std::exp (-1.6 * r) + 00164 0.25 * r * q - 0.17 * std::log (r))); 00165 L2 = 0.5 * std::max (Wa, Wb) - d2; 00166 00167 // turn ratio of transformers in main arms 00168 Ta2 = 1 - pi * sqr (f / fpa) * 00169 (sqr (Zla / Zl2) / 12 + sqr (0.5 - d2 / Da)); 00170 Tb2 = 1 - pi * sqr (f / fpb) * 00171 (sqr (Zlb / Zl2) / 12 + sqr (0.5 - d2 / Db)); 00172 Ta2 = std::max (Ta2, NR_TINY); 00173 Tb2 = std::max (Tb2, NR_TINY); 00174 00175 // shunt susceptance 00176 Bt = 5.5 * std::sqrt (Da * Db / lda / ldb) * (er + 2) / er / 00177 Zl2 / std::sqrt (Ta2 * Tb2) * std::sqrt (da * db) / D2 * 00178 (1 + 0.9 * std::log (r) + 4.5 * r * q - 4.4 * std::exp (-1.3 * r) - 00179 20 * sqr (Zl2 / Z0)); 00180 } 00181 00182 /* This function can be used to create an extra microstrip circuit. 00183 If the 'line' argument is NULL then the new circuit is created, the 00184 nodes get re-arranged and it is inserted into the given 00185 netlist. The given arguments can be explained as follows. 00186 base: calling circuit (this) 00187 line: additional microstrip line circuit (can be NULL) 00188 subnet: the netlist object 00189 c: name of the additional circuit 00190 n: name of the inserted (internal) node 00191 internal: number of new internal node (the original external node) */ 00192 circuit * splitMicrostrip (circuit * base, circuit * line, net * subnet, 00193 const char * c, const char * n, int internal) { 00194 if (line == NULL) { 00195 line = new msline (); 00196 const std::string &name = circuit::createInternal (c, base->getName ()); 00197 const std::string &node = circuit::createInternal (n, base->getName ()); 00198 line->setName (name); 00199 line->setNode (0, base->getNode(internal)->getName ()); 00200 line->setNode (1, node, 1); 00201 subnet->insertCircuit (line); 00202 } 00203 base->setNode (internal, line->getNode(1)->getName (), 1); 00204 return line; 00205 } 00206 00207 /* This function is the counterpart of the above routine. It removes 00208 the microstrip circuit from the netlist and re-assigns the original 00209 node. */ 00210 void disableMicrostrip (circuit * base, circuit * line, net * subnet, 00211 int internal) { 00212 if (line != NULL) { 00213 subnet->removeCircuit (line, 0); 00214 base->setNode (internal, line->getNode(1)->getName (), 0); 00215 } 00216 } 00217 00218 void mstee::initDC (void) { 00219 setVoltageSources (2); 00220 setInternalVoltageSource (1); 00221 allocMatrixMNA (); 00222 voltageSource (VSRC_1, NODE_1, NODE_2); 00223 voltageSource (VSRC_2, NODE_1, NODE_3); 00224 if (deviceEnabled (lineA)) { 00225 disableMicrostrip (this, lineA, getNet (), NODE_1); 00226 } 00227 if (deviceEnabled (lineB)) { 00228 disableMicrostrip (this, lineB, getNet (), NODE_2); 00229 } 00230 if (deviceEnabled (line2)) { 00231 disableMicrostrip (this, line2, getNet (), NODE_3); 00232 } 00233 } 00234 00235 void mstee::initAC (void) { 00236 setVoltageSources (3); 00237 setInternalVoltageSource (1); 00238 allocMatrixMNA (); 00239 setB (NODE_1, VSRC_1, +1); setB (NODE_2, VSRC_2, +1); 00240 setB (NODE_3, VSRC_3, +1); 00241 setC (VSRC_1, NODE_1, -1); setC (VSRC_2, NODE_2, -1); 00242 setC (VSRC_3, NODE_3, -1); 00243 initLines (); 00244 lineA->initAC (); 00245 lineB->initAC (); 00246 line2->initAC (); 00247 } 00248 00249 void mstee::initNoiseAC (void) { 00250 allocMatrixN (getVoltageSources ()); 00251 lineA->initNoiseAC (); 00252 lineB->initNoiseAC (); 00253 line2->initNoiseAC (); 00254 } 00255 00256 void mstee::calcAC (nr_double_t frequency) { 00257 calcPropagation (frequency); 00258 00259 lineA->setProperty ("L", La); 00260 lineB->setProperty ("L", Lb); 00261 line2->setProperty ("L", L2); 00262 lineA->calcAC (frequency); 00263 lineB->calcAC (frequency); 00264 line2->calcAC (frequency); 00265 00266 // calculate Z-parameters 00267 setD (VSRC_1, VSRC_1, nr_complex_t (0, -1 / Ta2 / Bt)); 00268 setD (VSRC_1, VSRC_2, nr_complex_t (0, -1 / std::sqrt (Ta2 * Tb2) / Bt)); 00269 setD (VSRC_1, VSRC_3, nr_complex_t (0, -1 / std::sqrt (Ta2) / Bt)); 00270 setD (VSRC_2, VSRC_1, nr_complex_t (0, -1 / std::sqrt (Ta2 * Tb2) / Bt)); 00271 setD (VSRC_2, VSRC_2, nr_complex_t (0, -1 / Tb2 / Bt)); 00272 setD (VSRC_2, VSRC_3, nr_complex_t (0, -1 / std::sqrt (Tb2) / Bt)); 00273 setD (VSRC_3, VSRC_1, nr_complex_t (0, -1 / std::sqrt (Ta2) / Bt)); 00274 setD (VSRC_3, VSRC_2, nr_complex_t (0, -1 / std::sqrt (Tb2) / Bt)); 00275 setD (VSRC_3, VSRC_3, nr_complex_t (0, -1 / Bt)); 00276 } 00277 00278 void mstee::initTR (void) { 00279 initDC (); 00280 } 00281 00282 // properties 00283 PROP_REQ [] = { 00284 { "W1", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE }, 00285 { "W2", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE }, 00286 { "W3", PROP_REAL, { 2e-3, PROP_NO_STR }, PROP_POS_RANGE }, 00287 { "Subst", PROP_STR, { PROP_NO_VAL, "Subst1" }, PROP_NO_RANGE }, 00288 { "MSDispModel", PROP_STR, { PROP_NO_VAL, "Kirschning" }, PROP_RNG_DIS }, 00289 { "MSModel", PROP_STR, { PROP_NO_VAL, "Hammerstad" }, PROP_RNG_MOD }, 00290 PROP_NO_PROP }; 00291 PROP_OPT [] = { 00292 { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) }, 00293 PROP_NO_PROP }; 00294 struct define_t mstee::cirdef = 00295 { "MTEE", 3, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };