Qucs-core  0.0.19
acsolver.cpp
Go to the documentation of this file.
00001 /*
00002  * acsolver.cpp - AC solver class implementation
00003  *
00004  * Copyright (C) 2004, 2005, 2007, 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 <stdio.h>
00030 #include <cmath>
00031 
00032 #include "object.h"
00033 #include "complex.h"
00034 #include "circuit.h"
00035 #include "sweep.h"
00036 #include "net.h"
00037 #include "netdefs.h"
00038 #include "analysis.h"
00039 #include "nasolver.h"
00040 #include "acsolver.h"
00041 
00042 namespace qucs {
00043 
00044 // Constructor creates an unnamed instance of the acsolver class.
00045 acsolver::acsolver () : nasolver<nr_complex_t> () {
00046   swp = NULL;
00047   type = ANALYSIS_AC;
00048   setDescription ("AC");
00049   xn = NULL;
00050   noise = 0;
00051 }
00052 
00053 // Constructor creates a named instance of the acsolver class.
00054 acsolver::acsolver (char * n) : nasolver<nr_complex_t> (n) {
00055   swp = NULL;
00056   type = ANALYSIS_AC;
00057   setDescription ("AC");
00058   xn = NULL;
00059   noise = 0;
00060 }
00061 
00062 // Destructor deletes the acsolver class object.
00063 acsolver::~acsolver () {
00064   delete swp;
00065   delete xn;
00066 }
00067 
00068 /* The copy constructor creates a new instance of the acsolver class
00069    based on the given acsolver object. */
00070 acsolver::acsolver (acsolver & o) : nasolver<nr_complex_t> (o) {
00071   swp = o.swp ? new sweep (*(o.swp)) : NULL;
00072   xn = o.xn ? new tvector<nr_double_t> (*(o.xn)) : NULL;
00073   noise = o.noise;
00074 }
00075 
00076 /* This is the AC netlist solver.  It prepares the circuit list for
00077    each requested frequency and solves it then. */
00078 int acsolver::solve (void) {
00079   runs++;
00080 
00081   // run additional noise analysis ?
00082   noise = !strcmp (getPropertyString ("Noise"), "yes") ? 1 : 0;
00083 
00084   // create frequency sweep if necessary
00085   if (swp == NULL) {
00086     swp = createSweep ("acfrequency");
00087   }
00088 
00089   // initialize node voltages, first guess for non-linear circuits and
00090   // generate extra circuits if necessary
00091   init ();
00092   setCalculation ((calculate_func_t) &calc);
00093   solve_pre ();
00094 
00095   swp->reset ();
00096   for (int i = 0; i < swp->getSize (); i++) {
00097     freq = swp->next ();
00098     if (progress) logprogressbar (i, swp->getSize (), 40);
00099 
00100 #if DEBUG && 0
00101     logprint (LOG_STATUS, "NOTIFY: %s: solving netlist for f = %e\n",
00102               getName (), (double) freq);
00103 #endif
00104 
00105     // start the linear solver
00106     eqnAlgo = ALGO_LU_DECOMPOSITION;
00107     solve_linear ();
00108 
00109     // compute noise if requested
00110     if (noise) solve_noise ();
00111 
00112     // save results
00113     saveAllResults (freq);
00114   }
00115   solve_post ();
00116   if (progress) logprogressclear (40);
00117   return 0;
00118 }
00119 
00120 /* Goes through the list of circuit objects and runs its calcAC()
00121    function. */
00122 void acsolver::calc (acsolver * self) {
00123   circuit * root = self->getNet()->getRoot ();
00124   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00125     c->calcAC (self->freq);
00126     if (self->noise) c->calcNoiseAC (self->freq);
00127   }
00128 }
00129 
00130 /* Goes through the list of circuit objects and runs its initAC()
00131    function. */
00132 void acsolver::init (void) {
00133   circuit * root = subnet->getRoot ();
00134   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00135     if (c->isNonLinear ()) c->calcOperatingPoints ();
00136     c->initAC ();
00137     if (noise) c->initNoiseAC ();
00138   }
00139 }
00140 
00141 /* This function saves the results of a single solve() functionality
00142    (for the given frequency) into the output dataset. */
00143 void acsolver::saveAllResults (nr_double_t freq) {
00144   qucs::vector * f;
00145   // add current frequency to the dependency of the output dataset
00146   if ((f = data->findDependency ("acfrequency")) == NULL) {
00147     f = new qucs::vector ("acfrequency");
00148     data->addDependency (f);
00149   }
00150   if (runs == 1) f->add (freq);
00151   saveResults ("v", "i", 0, f);
00152 
00153   // additionally save noise results if requested
00154   if (noise) {
00155     saveNoiseResults (f);
00156   }
00157 }
00158 
00159 /* The function computes the final noise results and puts them into
00160    the output dataset. */
00161 void acsolver::saveNoiseResults (qucs::vector * f) {
00162   int N = countNodes ();
00163   int M = countVoltageSources ();
00164   for (int r = 0; r < N + M; r++) {
00165     // renormalise the results
00166     x->set (r, fabs (xn->get (r) * sqrt (kB * T0)));
00167   }
00168 
00169   // apply probe data
00170   circuit * root = subnet->getRoot ();
00171   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
00172     if (!c->isProbe ()) continue;
00173     int np, nn;
00174     nr_double_t vp, vn;
00175     np = getNodeNr (c->getNode (NODE_1)->getName ());
00176     vp = np > 0 ? xn->get (np - 1) : 0.0;
00177     nn = getNodeNr (c->getNode (NODE_2)->getName ());
00178     vn = nn > 0 ? xn->get (nn - 1) : 0.0;
00179     c->setOperatingPoint ("Vr", fabs ((vp - vn) * sqrt (kB * T0)));
00180     c->setOperatingPoint ("Vi", 0.0);
00181   }
00182 
00183   saveResults ("vn", "in", 0, f);
00184 }
00185 
00186 /* This function runs the AC noise analysis.  It saves its results in
00187    the 'xn' vector. */
00188 void acsolver::solve_noise (void) {
00189   int N = countNodes ();
00190   int M = countVoltageSources ();
00191 
00192   // save usual AC results
00193   tvector<nr_complex_t> xsave = *x;
00194 
00195   // create the Cy matrix
00196   createNoiseMatrix ();
00197   // create noise result vector if necessary
00198   if (xn == NULL) xn = new tvector<nr_double_t> (N + M);
00199 
00200   // temporary result vector for transimpedances
00201   tvector<nr_complex_t> zn = tvector<nr_complex_t> (N + M);
00202 
00203   // create the MNA matrix once again and LU decompose the adjoint matrix
00204   createMatrix ();
00205   A->transpose ();
00206   eqnAlgo = ALGO_LU_FACTORIZATION_CROUT;
00207   runMNA ();
00208 
00209   // ensure skipping LU decomposition
00210   updateMatrix = 0;
00211   convHelper = CONV_None;
00212   eqnAlgo = ALGO_LU_SUBSTITUTION_CROUT;
00213 
00214   // compute noise voltage for each node (and voltage source)
00215   for (int i = 0; i < N + M; i++) {
00216     z->set (0); z->set (i, -1); // modify right hand side appropriately
00217     runMNA ();                  // solve
00218     zn = *x;                    // save transimpedance vector
00219 
00220     // compute actual noise voltage
00221     xn->set (i, sqrt (real (scalar (zn * (*C), conj (zn)))));
00222   }
00223 
00224   // restore usual AC results
00225   *x = xsave;
00226 }
00227 
00228 // properties
00229 PROP_REQ [] = {
00230   { "Type", PROP_STR, { PROP_NO_VAL, "lin" }, PROP_RNG_TYP },
00231   PROP_NO_PROP };
00232 PROP_OPT [] = {
00233   { "Noise", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
00234   { "Start", PROP_REAL, { 1e9, PROP_NO_STR }, PROP_POS_RANGE },
00235   { "Stop", PROP_REAL, { 10e9, PROP_NO_STR }, PROP_POS_RANGE },
00236   { "Points", PROP_INT, { 10, PROP_NO_STR }, PROP_MIN_VAL (2) },
00237   { "Values", PROP_LIST, { 10, PROP_NO_STR }, PROP_POS_RANGE },
00238   PROP_NO_PROP };
00239 struct define_t acsolver::anadef =
00240   { "AC", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };
00241 
00242 } // namespace qucs