Qucs-core
0.0.19
|
00001 /* 00002 * rfedd.cpp - equation defined RF device class implementation 00003 * 00004 * Copyright (C) 2008 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 "component.h" 00030 #include "equation.h" 00031 #include "environment.h" 00032 #include "rfedd.h" 00033 00034 using namespace qucs; 00035 using namespace qucs::eqn; 00036 00037 // Constructor for the equation defined RF device. 00038 rfedd::rfedd () : circuit () { 00039 type = CIR_RFEDD; 00040 setVariableSized (true); 00041 peqn = NULL; 00042 } 00043 00044 // Destructor deletes equation defined RF device object from memory. 00045 rfedd::~rfedd () { 00046 free (peqn); 00047 } 00048 00049 // Callback for initializing the DC analysis. 00050 void rfedd::initDC (void) { 00051 00052 // get appropriate property value 00053 const char * const dc = getPropertyString ("duringDC"); 00054 00055 // a short during DC 00056 if (!strcmp (dc, "short")) { 00057 int v, n, lastnode = getSize () - 1; 00058 setVoltageSources (lastnode); 00059 allocMatrixMNA (); 00060 // place zero voltage sources 00061 for (v = VSRC_1, n = NODE_1; n < lastnode; n++, v++) { 00062 voltageSource (v, n, lastnode); 00063 } 00064 return; 00065 } 00066 // an open during DC 00067 else if (!strcmp (dc, "open")) { 00068 setVoltageSources (0); 00069 allocMatrixMNA (); 00070 return; 00071 } 00072 // zero frequency evaluation 00073 else if (!strcmp (dc, "zerofrequency")) { 00074 prepareModel (); 00075 initMNA (); 00076 calcMNA (0); 00077 return; 00078 } 00079 // none specified, DC value of IDFT ? 00080 else { 00081 setVoltageSources (0); 00082 allocMatrixMNA (); 00083 } 00084 } 00085 00086 // Some help macros. 00087 #define A(a) ((assignment *) (a)) 00088 00089 // Creates a parameter variable name from the given arguments. 00090 char * rfedd::createVariable (const char * base, int r, int c, bool pfx) { 00091 const char * str = strchr (getName (), '.'); 00092 if (str != NULL) 00093 str = strrchr (str, '.') + 1; 00094 else 00095 str = getName (); 00096 char * txt = (char *) malloc (strlen (str) + strlen (base) + 4); 00097 if (pfx) 00098 sprintf (txt, "%s.%s%d%d", str, base, r, c); 00099 else 00100 sprintf (txt, "%s%d%d", base, r, c); 00101 return txt; 00102 } 00103 00104 // Creates a variable name from the given arguments. 00105 char * rfedd::createVariable (const char * base, bool pfx) { 00106 const char * str = strchr (getName (), '.'); 00107 if (str != NULL) 00108 str = strrchr (str, '.') + 1; 00109 else 00110 str = getName (); 00111 char * txt = (char *) malloc (strlen (str) + strlen (base) + 2); 00112 if (pfx) 00113 sprintf (txt, "%s.%s", str, base); 00114 else 00115 sprintf (txt, "%s", base); 00116 return txt; 00117 } 00118 00119 // Saves the given real value into the equation result. 00120 void rfedd::setResult (void * eqn, nr_double_t val) { 00121 A(eqn)->evaluate (); 00122 constant * c = A(eqn)->getResult (); 00123 c->d = val; 00124 } 00125 00126 // Saves the given complex value into the equation result. 00127 void rfedd::setResult (void * eqn, nr_complex_t val) { 00128 A(eqn)->evaluate (); 00129 constant * c = A(eqn)->getResult (); 00130 *(c->c) = val; 00131 } 00132 00133 // Returns the result of the equation. 00134 nr_complex_t rfedd::getResult (void * eqn) { 00135 A(eqn)->evaluate (); 00136 return A(eqn)->getResultComplex (); 00137 } 00138 00139 // Initializes the equation defined device. 00140 void rfedd::initModel (void) { 00141 int i, j, k, ports = getSize (); 00142 char * pn, * sn, * snold, * fn, * fnold; 00143 const char * vr; 00144 eqn::node * pvalue; 00145 00146 // allocate space for equation pointers 00147 peqn = (void **) malloc (sizeof (assignment *) * ports * ports); 00148 00149 // first create frequency variables 00150 sn = createVariable ("S"); 00151 snold = createVariable ("S", false); 00152 fn = createVariable ("F"); 00153 fnold = createVariable ("F", false); 00154 seqn = getEnv()->getChecker()->addComplex ("#laplace", sn, nr_complex_t (0, 0)); 00155 feqn = getEnv()->getChecker()->addDouble ("#frequency", fn, 0); 00156 A(seqn)->evalType (); A(seqn)->skip = 1; 00157 A(feqn)->evalType (); A(feqn)->skip = 1; 00158 00159 // obtain type of parameters 00160 const char * const type = getPropertyString ("Type"); 00161 00162 // prepare device equations 00163 for (k = 0, i = 0; i < ports; i++) { 00164 for (j = 0; j < ports; j++, k++) { 00165 // find equation referenced in property 00166 pn = createVariable ("P", i + 1, j + 1, false); 00167 vr = getPropertyReference (pn); 00168 pvalue = getEnv()->getChecker()->findEquation (vr); 00169 if (!pvalue) { 00170 logprint (LOG_ERROR, "ERROR: %s-parameter equation `%s' not found for " 00171 "RFEDD `%s'\n", type, vr, getName ()); 00172 } 00173 else { 00174 // replace references to S and F by local references 00175 pvalue->replace (snold, sn); 00176 pvalue->replace (fnold, fn); 00177 // evaluate types of parameters 00178 A(pvalue)->evalType (); 00179 A(pvalue)->skip = 1; 00180 } 00181 // save equations for parameters 00182 peqn[k] = pvalue; 00183 free (pn); 00184 } 00185 } 00186 00187 free (sn); free (snold); 00188 free (fn); free (fnold); 00189 } 00190 00191 // Prepares model equations if necessary. 00192 void rfedd::prepareModel (void) { 00193 if (peqn == NULL) initModel (); 00194 } 00195 00196 // Update local variable equations. 00197 void rfedd::updateLocals (nr_double_t frequency) { 00198 00199 // update frequency variables for equations 00200 setResult (seqn, nr_complex_t (0, 2 * pi * frequency)); 00201 setResult (feqn, frequency); 00202 00203 // get local subcircuit values 00204 getEnv()->passConstants (); 00205 getEnv()->equationSolver (); 00206 } 00207 00208 // Callback for DC analysis. 00209 void rfedd::calcDC (void) { 00210 } 00211 00212 // Initializes MNA representation depending on parameter type. 00213 void rfedd::initMNA (void) { 00214 int i, ports = getSize (); 00215 const char * const type = getPropertyString ("Type"); 00216 switch (type[0]) { 00217 case 'Y': 00218 setVoltageSources (0); 00219 allocMatrixMNA (); 00220 break; 00221 case 'Z': 00222 setVoltageSources (ports); 00223 allocMatrixMNA (); 00224 for (i = 0; i < ports; i++) setC (i, i, -1); 00225 for (i = 0; i < ports; i++) setB (i, i, +1); 00226 break; 00227 case 'S': 00228 setVoltageSources (ports); 00229 allocMatrixMNA (); 00230 for (i = 0; i < ports; i++) setB (i, i, +1); 00231 break; 00232 case 'H': 00233 setVoltageSources (1); 00234 allocMatrixMNA (); 00235 setB (0, 0, +1); setC (0, 0, -1); 00236 break; 00237 case 'G': 00238 setVoltageSources (1); 00239 allocMatrixMNA (); 00240 setB (1, 0, +1); setC (0, 1, -1); 00241 break; 00242 case 'A': 00243 setVoltageSources (1); 00244 allocMatrixMNA (); 00245 setB (1, 0, -1); setC (0, 0, -1); 00246 break; 00247 case 'T': 00248 setVoltageSources (2); 00249 allocMatrixMNA (); 00250 setB (0, 0, +1); setB (1, 1, +1); 00251 setC (0, 0, -1); setC (1, 0, -1); 00252 break; 00253 } 00254 } 00255 00256 // Calculates MNA representation depending on parameter type. 00257 void rfedd::calcMNA (nr_double_t frequency) { 00258 const char * const type = getPropertyString ("Type"); 00259 int r, c, ports = getSize (); 00260 matrix p = calcMatrix (frequency); 00261 switch (type[0]) { 00262 case 'Y': 00263 setMatrixY (p); 00264 break; 00265 case 'Z': 00266 for (r = 0; r < ports; r++) 00267 for (c = 0; c < ports; c++) 00268 setD (r, c, p (r, c)); 00269 break; 00270 case 'S': 00271 for (r = 0; r < ports; r++) 00272 for (c = 0; c < ports; c++) { 00273 if (r == c) { 00274 setC (r, c, p (r, c) - 1.0); 00275 setD (r, c, z0 * (p (r, c) + 1.0)); 00276 } 00277 else { 00278 setC (r, c, p (r, c)); 00279 setD (r, c, z0 * p (r, c)); 00280 } 00281 } 00282 break; 00283 case 'H': 00284 setY (1, 1, p (1, 1)); setB (1, 0, p (1, 0)); 00285 setC (0, 1, p (0, 1)); setD (0, 0, p (0, 0)); 00286 break; 00287 case 'G': 00288 setY (0, 0, p (0, 0)); setB (0, 0, p (0, 1)); 00289 setC (0, 0, p (1, 0)); setD (0, 0, p (1, 1)); 00290 break; 00291 case 'A': 00292 setY (0, 1, p (1, 0)); setB (0, 0, p (1, 1)); 00293 setC (0, 1, p (0, 0)); setD (0, 0, p (0, 1)); 00294 break; 00295 case 'T': 00296 setC (0, 1, p (0, 1) + p (0, 0)); 00297 setC (1, 1, p (1, 1) + p (1, 0)); 00298 setD (0, 0, -z0); 00299 setD (1, 0, +z0); 00300 setD (0, 1, z0 * (p (0, 1) - p (0, 0))); 00301 setD (1, 1, z0 * (p (1, 1) - p (1, 0))); 00302 break; 00303 } 00304 } 00305 00306 // Callback for initializing the AC analysis. 00307 void rfedd::initAC (void) { 00308 initMNA (); 00309 prepareModel (); 00310 } 00311 00312 // Callback for AC analysis. 00313 void rfedd::calcAC (nr_double_t frequency) { 00314 calcMNA (frequency); 00315 } 00316 00317 // Computes parameter matrix. 00318 matrix rfedd::calcMatrix (nr_double_t frequency) { 00319 int i, j, k, ports = getSize (); 00320 matrix p (ports); 00321 00322 // update local equations 00323 updateLocals (frequency); 00324 00325 // calculate parameters and put into Jacobian 00326 for (k = 0, i = 0; i < ports; i++) { 00327 for (j = 0; j < ports; j++, k++) { 00328 p (i, j) = getResult (peqn[k]); 00329 } 00330 } 00331 00332 return p; 00333 } 00334 00335 // Callback for initializing the TR analysis. 00336 void rfedd::initTR (void) { 00337 initDC (); 00338 } 00339 00340 // Callback for the TR analysis. 00341 void rfedd::calcTR (nr_double_t) { 00342 calcDC (); 00343 } 00344 00345 // Callback for initializing the S-parameter analysis. 00346 void rfedd::initSP (void) { 00347 allocMatrixS (); 00348 prepareModel (); 00349 } 00350 00351 // Callback for S-parameter analysis. 00352 void rfedd::calcSP (nr_double_t frequency) { 00353 const char * const type = getPropertyString ("Type"); 00354 matrix p = calcMatrix (frequency); 00355 switch (type[0]) { 00356 case 'Y': 00357 setMatrixS (ytos (p)); 00358 break; 00359 case 'Z': 00360 setMatrixS (ztos (p)); 00361 break; 00362 case 'S': 00363 setMatrixS (p); 00364 break; 00365 case 'H': 00366 setMatrixS (twoport (p, 'H', 'S')); 00367 break; 00368 case 'G': 00369 setMatrixS (twoport (p, 'G', 'S')); 00370 break; 00371 case 'A': 00372 setMatrixS (twoport (p, 'A', 'S')); 00373 break; 00374 case 'T': 00375 setMatrixS (twoport (p, 'T', 'S')); 00376 break; 00377 } 00378 } 00379 00380 // properties 00381 PROP_REQ [] = { 00382 { "Type", PROP_STR, { PROP_NO_VAL, "Y" }, 00383 PROP_RNG_STR7 ("Y", "Z", "S", "H", "G", "A", "T") }, 00384 { "duringDC", PROP_STR, { PROP_NO_VAL, "open" }, 00385 PROP_RNG_STR4 ("open", "short", "unspecified", "zerofrequency") }, 00386 { "P11", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00387 PROP_NO_PROP }; 00388 PROP_OPT [] = { 00389 { "P12", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00390 { "P13", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00391 { "P14", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00392 { "P15", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00393 { "P16", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00394 { "P17", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00395 { "P18", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00396 { "P21", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00397 { "P22", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00398 { "P23", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00399 { "P24", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00400 { "P25", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00401 { "P26", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00402 { "P27", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00403 { "P28", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00404 { "P31", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00405 { "P32", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00406 { "P33", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00407 { "P34", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00408 { "P35", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00409 { "P36", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00410 { "P37", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00411 { "P38", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00412 { "P41", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00413 { "P42", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00414 { "P43", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00415 { "P44", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00416 { "P45", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00417 { "P46", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00418 { "P47", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00419 { "P48", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00420 { "P51", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00421 { "P52", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00422 { "P53", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00423 { "P54", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00424 { "P55", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00425 { "P56", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00426 { "P57", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00427 { "P58", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00428 { "P61", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00429 { "P62", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00430 { "P63", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00431 { "P64", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00432 { "P65", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00433 { "P66", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00434 { "P67", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00435 { "P68", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00436 { "P71", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00437 { "P72", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00438 { "P73", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00439 { "P74", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00440 { "P75", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00441 { "P76", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00442 { "P77", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00443 { "P78", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00444 { "P81", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00445 { "P82", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00446 { "P83", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00447 { "P84", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00448 { "P85", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00449 { "P86", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00450 { "P87", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00451 { "P88", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00452 PROP_NO_PROP }; 00453 struct define_t rfedd::cirdef = 00454 { "RFEDD", 00455 PROP_NODES, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };