Qucs-core  0.0.19
rfedd.cpp
Go to the documentation of this file.
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 };