Qucs-core
0.0.19
|
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