Branch data Line data Source code
1 : : /*
2 : : * acsolver.cpp - AC solver class implementation
3 : : *
4 : : * Copyright (C) 2004, 2005, 2007, 2008 Stefan Jahn <stefan@lkcc.org>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : #if HAVE_CONFIG_H
26 : : # include <config.h>
27 : : #endif
28 : :
29 : : #include <stdio.h>
30 : : #include <cmath>
31 : :
32 : : #include "object.h"
33 : : #include "complex.h"
34 : : #include "circuit.h"
35 : : #include "sweep.h"
36 : : #include "net.h"
37 : : #include "netdefs.h"
38 : : #include "analysis.h"
39 : : #include "nasolver.h"
40 : : #include "acsolver.h"
41 : :
42 : : namespace qucs {
43 : :
44 : : // Constructor creates an unnamed instance of the acsolver class.
45 : 18 : acsolver::acsolver () : nasolver<nr_complex_t> () {
46 : 18 : swp = NULL;
47 : 18 : type = ANALYSIS_AC;
48 : 18 : setDescription ("AC");
49 : 18 : xn = NULL;
50 : 18 : noise = 0;
51 : 18 : }
52 : :
53 : : // Constructor creates a named instance of the acsolver class.
54 : 0 : acsolver::acsolver (char * n) : nasolver<nr_complex_t> (n) {
55 : 0 : swp = NULL;
56 : 0 : type = ANALYSIS_AC;
57 : 0 : setDescription ("AC");
58 : 0 : xn = NULL;
59 : 0 : noise = 0;
60 : 0 : }
61 : :
62 : : // Destructor deletes the acsolver class object.
63 : 18 : acsolver::~acsolver () {
64 [ + - ][ + - ]: 18 : if (swp) delete swp;
[ + - ][ # # ]
[ # # ][ # # ]
65 [ + + ][ + - ]: 18 : if (xn) delete xn;
[ # # ][ # # ]
66 [ - + ][ # # ]: 36 : }
67 : :
68 : : /* The copy constructor creates a new instance of the acsolver class
69 : : based on the given acsolver object. */
70 : 0 : acsolver::acsolver (acsolver & o) : nasolver<nr_complex_t> (o) {
71 [ # # ][ # # ]: 0 : swp = o.swp ? new sweep (*(o.swp)) : NULL;
[ # # ][ # # ]
[ # # ][ # # ]
72 [ # # ][ # # ]: 0 : xn = o.xn ? new tvector<nr_double_t> (*(o.xn)) : NULL;
[ # # ][ # # ]
[ # # ][ # # ]
73 : 0 : noise = o.noise;
74 : 0 : }
75 : :
76 : : /* This is the AC netlist solver. It prepares the circuit list for
77 : : each requested frequency and solves it then. */
78 : 149 : int acsolver::solve (void) {
79 : 149 : runs++;
80 : :
81 : : // run additional noise analysis ?
82 [ + + ]: 149 : noise = !strcmp (getPropertyString ("Noise"), "yes") ? 1 : 0;
83 : :
84 : : // create frequency sweep if necessary
85 [ + + ]: 149 : if (swp == NULL) {
86 : 18 : swp = createSweep ("acfrequency");
87 : : }
88 : :
89 : : // initialize node voltages, first guess for non-linear circuits and
90 : : // generate extra circuits if necessary
91 : 149 : init ();
92 : 149 : setCalculation ((calculate_func_t) &calc);
93 : 149 : solve_pre ();
94 : :
95 : 149 : swp->reset ();
96 [ + + ]: 6811 : for (int i = 0; i < swp->getSize (); i++) {
97 : 6662 : freq = swp->next ();
98 [ + + ]: 6662 : if (progress) logprogressbar (i, swp->getSize (), 40);
99 : :
100 : : #if DEBUG && 0
101 : : logprint (LOG_STATUS, "NOTIFY: %s: solving netlist for f = %e\n",
102 : : getName (), (double) freq);
103 : : #endif
104 : :
105 : : // start the linear solver
106 : 6662 : eqnAlgo = ALGO_LU_DECOMPOSITION;
107 : 6662 : solve_linear ();
108 : :
109 : : // compute noise if requested
110 [ + + ]: 6662 : if (noise) solve_noise ();
111 : :
112 : : // save results
113 : 6662 : saveAllResults (freq);
114 : : }
115 : 149 : solve_post ();
116 [ + + ]: 149 : if (progress) logprogressclear (40);
117 : 149 : return 0;
118 : : }
119 : :
120 : : /* Goes through the list of circuit objects and runs its calcAC()
121 : : function. */
122 : 6662 : void acsolver::calc (acsolver * self) {
123 : 6662 : circuit * root = self->getNet()->getRoot ();
124 [ + + ]: 75905 : for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
125 : 69243 : c->calcAC (self->freq);
126 [ + + ]: 69243 : if (self->noise) c->calcNoiseAC (self->freq);
127 : : }
128 : 6662 : }
129 : :
130 : : /* Goes through the list of circuit objects and runs its initAC()
131 : : function. */
132 : 149 : void acsolver::init (void) {
133 : 149 : circuit * root = subnet->getRoot ();
134 [ + + ]: 1402 : for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
135 [ + + ]: 1253 : if (c->isNonLinear ()) c->calcOperatingPoints ();
136 : 1253 : c->initAC ();
137 [ + + ]: 1253 : if (noise) c->initNoiseAC ();
138 : : }
139 : 149 : }
140 : :
141 : : /* This function saves the results of a single solve() functionality
142 : : (for the given frequency) into the output dataset. */
143 : 6662 : void acsolver::saveAllResults (nr_double_t freq) {
144 : : qucs::vector * f;
145 : : // add current frequency to the dependency of the output dataset
146 [ + + ]: 6662 : if ((f = data->findDependency ("acfrequency")) == NULL) {
147 [ + - ]: 18 : f = new qucs::vector ("acfrequency");
148 : 18 : data->addDependency (f);
149 : : }
150 [ + + ][ + - ]: 6662 : if (runs == 1) f->add (freq);
151 : 6662 : saveResults ("v", "i", 0, f);
152 : :
153 : : // additionally save noise results if requested
154 [ + + ]: 6662 : if (noise) {
155 : 3003 : saveNoiseResults (f);
156 : : }
157 : 6662 : }
158 : :
159 : : /* The function computes the final noise results and puts them into
160 : : the output dataset. */
161 : 3003 : void acsolver::saveNoiseResults (qucs::vector * f) {
162 : 3003 : int N = countNodes ();
163 : 3003 : int M = countVoltageSources ();
164 [ + + ]: 28665 : for (int r = 0; r < N + M; r++) {
165 : : // renormalise the results
166 [ + - ]: 25662 : x->set (r, fabs (xn->get (r) * sqrt (kB * T0)));
167 : : }
168 : :
169 : : // apply probe data
170 : 3003 : circuit * root = subnet->getRoot ();
171 [ + + ]: 28665 : for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
172 [ + + ]: 25662 : if (!c->isProbe ()) continue;
173 : : int np, nn;
174 : : nr_double_t vp, vn;
175 : 2730 : np = getNodeNr (c->getNode (NODE_1)->getName ());
176 [ + - ]: 2730 : vp = np > 0 ? xn->get (np - 1) : 0.0;
177 : 2730 : nn = getNodeNr (c->getNode (NODE_2)->getName ());
178 [ - + ]: 2730 : vn = nn > 0 ? xn->get (nn - 1) : 0.0;
179 : 2730 : c->setOperatingPoint ("Vr", fabs ((vp - vn) * sqrt (kB * T0)));
180 : 2730 : c->setOperatingPoint ("Vi", 0.0);
181 : : }
182 : :
183 : 3003 : saveResults ("vn", "in", 0, f);
184 : 3003 : }
185 : :
186 : : /* This function runs the AC noise analysis. It saves its results in
187 : : the 'xn' vector. */
188 : 3003 : void acsolver::solve_noise (void) {
189 [ + - ]: 3003 : int N = countNodes ();
190 : 3003 : int M = countVoltageSources ();
191 : :
192 : : // save usual AC results
193 [ + - ]: 3003 : tvector<nr_complex_t> xsave = *x;
194 : :
195 : : // create the Cy matrix
196 [ + - ]: 3003 : createNoiseMatrix ();
197 : : // create noise result vector if necessary
198 [ + + ][ + - ]: 3003 : if (xn == NULL) xn = new tvector<nr_double_t> (N + M);
[ + - ]
199 : :
200 : : // temporary result vector for transimpedances
201 [ + - ]: 3003 : tvector<nr_complex_t> zn = tvector<nr_complex_t> (N + M);
202 : :
203 : : // create the MNA matrix once again and LU decompose the adjoint matrix
204 [ + - ]: 3003 : createMatrix ();
205 [ + - ]: 3003 : A->transpose ();
206 : 3003 : eqnAlgo = ALGO_LU_FACTORIZATION_CROUT;
207 [ + - ]: 3003 : runMNA ();
208 : :
209 : : // ensure skipping LU decomposition
210 : 3003 : updateMatrix = 0;
211 : 3003 : convHelper = CONV_None;
212 : 3003 : eqnAlgo = ALGO_LU_SUBSTITUTION_CROUT;
213 : :
214 : : // compute noise voltage for each node (and voltage source)
215 [ + + ]: 28665 : for (int i = 0; i < N + M; i++) {
216 [ + - ]: 25662 : z->set (0); z->set (i, -1); // modify right hand side appropriately
217 [ + - ]: 25662 : runMNA (); // solve
218 [ + - ]: 25662 : zn = *x; // save transimpedance vector
219 : :
220 : : // compute actual noise voltage
221 [ + - ][ + - ]: 25662 : xn->set (i, sqrt (real (scalar (zn * (*C), conj (zn)))));
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
222 : : }
223 : :
224 : : // restore usual AC results
225 [ + - ]: 3003 : *x = xsave;
226 : 3003 : }
227 : :
228 : : // properties
229 : : PROP_REQ [] = {
230 : : { "Type", PROP_STR, { PROP_NO_VAL, "lin" }, PROP_RNG_TYP },
231 : : PROP_NO_PROP };
232 : : PROP_OPT [] = {
233 : : { "Noise", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
234 : : { "Start", PROP_REAL, { 1e9, PROP_NO_STR }, PROP_POS_RANGE },
235 : : { "Stop", PROP_REAL, { 10e9, PROP_NO_STR }, PROP_POS_RANGE },
236 : : { "Points", PROP_INT, { 10, PROP_NO_STR }, PROP_MIN_VAL (2) },
237 : : { "Values", PROP_LIST, { 10, PROP_NO_STR }, PROP_POS_RANGE },
238 : : PROP_NO_PROP };
239 : : struct define_t acsolver::anadef =
240 : : { "AC", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };
241 : :
242 : : } // namespace qucs
|