Branch data Line data Source code
1 : : /*
2 : : * circuit.cpp - circuit class implementation
3 : : *
4 : : * Copyright (C) 2003, 2004, 2005, 2006, 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 <stdlib.h>
31 : : #include <string.h>
32 : : #include <assert.h>
33 : :
34 : : #include "logging.h"
35 : : #include "complex.h"
36 : : #include "object.h"
37 : : #include "matrix.h"
38 : : #include "node.h"
39 : : #include "property.h"
40 : : #include "valuelist.h"
41 : : #include "tvector.h"
42 : : #include "history.h"
43 : : #include "circuit.h"
44 : : #include "microstrip/substrate.h"
45 : : #include "operatingpoint.h"
46 : : #include "characteristic.h"
47 : : #include "component_id.h"
48 : :
49 : : namespace qucs {
50 : :
51 : : // normalising impedance
52 : : const nr_double_t circuit::z0 = 50.0;
53 : :
54 : : // Constructor creates an unnamed instance of the circuit class.
55 [ # # ][ # # ]: 0 : circuit::circuit () : object (), integrator () {
56 : 0 : size = 0;
57 : 0 : MatrixN = MatrixS = MatrixY = NULL;
58 : 0 : MatrixB = MatrixC = MatrixD = NULL;
59 : 0 : VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
60 : 0 : MatrixQV = NULL;
61 : 0 : VectorCV = VectorGV = NULL;
62 : 0 : nodes = NULL;
63 : 0 : pacport = 0;
64 : 0 : pol = 1;
65 : 0 : flag = CIRCUIT_ORIGINAL | CIRCUIT_LINEAR;
66 : 0 : subst = NULL;
67 : 0 : vsource = -1;
68 : 0 : vsources = 0;
69 : 0 : nsources = 0;
70 : 0 : inserted = -1;
71 : 0 : subcircuit = NULL;
72 : 0 : subnet = NULL;
73 : 0 : deltas = NULL;
74 : 0 : histories = NULL;
75 : 0 : nHistories = 0;
76 : 0 : type = CIR_UNKNOWN;
77 : 0 : }
78 : :
79 : : /* Constructor creates an unnamed instance of the circuit class with a
80 : : certain number of ports. */
81 [ + - ][ + - ]: 125988 : circuit::circuit (int s) : object (), integrator () {
82 [ - + ][ - + ]: 125988 : assert (s >= 0);
83 : 125988 : size = s;
84 [ + - ][ + - ]: 474473 : if (size > 0) nodes = new node[s];
[ + - ][ + + ]
[ # # # # ]
[ + - ][ + - ]
[ + - ][ + + ]
[ # # # # ]
85 : 125988 : MatrixN = MatrixS = MatrixY = NULL;
86 : 125988 : MatrixB = MatrixC = MatrixD = NULL;
87 : 125988 : VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
88 : 125988 : MatrixQV = NULL;
89 : 125988 : VectorCV = VectorGV = NULL;
90 : 125988 : pacport = 0;
91 : 125988 : pol = 1;
92 : 125988 : flag = CIRCUIT_ORIGINAL | CIRCUIT_LINEAR;
93 : 125988 : subst = NULL;
94 : 125988 : vsource = -1;
95 : 125988 : vsources = 0;
96 : 125988 : nsources = 0;
97 : 125988 : inserted = -1;
98 : 125988 : subcircuit = NULL;
99 : 125988 : subnet = NULL;
100 : 125988 : deltas = NULL;
101 : 125988 : histories = NULL;
102 : 125988 : nHistories = 0;
103 : 125988 : type = CIR_UNKNOWN;
104 : 125988 : }
105 : :
106 : : /* The copy constructor creates a new instance based on the given
107 : : circuit object. */
108 [ # # ][ # # ]: 0 : circuit::circuit (const circuit & c) : object (c), integrator (c) {
109 : 0 : size = c.size;
110 : 0 : pol = c.pol;
111 : 0 : pacport = c.pacport;
112 : 0 : flag = c.flag;
113 : 0 : type = c.type;
114 : 0 : subst = c.subst;
115 : 0 : vsource = c.vsource;
116 : 0 : vsources = c.vsources;
117 : 0 : nsources = c.nsources;
118 : 0 : inserted = c.inserted;
119 : 0 : subnet = c.subnet;
120 : 0 : deltas = c.deltas;
121 : 0 : nHistories = c.nHistories;
122 : 0 : histories = NULL;
123 [ # # ][ # # ]: 0 : subcircuit = c.subcircuit ? strdup (c.subcircuit) : NULL;
[ # # ][ # # ]
124 : :
125 [ # # ][ # # ]: 0 : if (size > 0) {
126 : : // copy each node and set its circuit to the current circuit object
127 [ # # ][ # # ]: 0 : nodes = new node[size];
[ # # # #
# # ][ # # ]
[ # # ][ # #
# # # # ]
128 [ # # ][ # # ]: 0 : for (int i = 0; i < size; i++) {
129 [ # # ][ # # ]: 0 : nodes[i] = node (c.nodes[i]);;
[ # # ][ # # ]
130 : 0 : nodes[i].setCircuit (this);
131 : : }
132 : : // copy each s-parameter
133 [ # # ][ # # ]: 0 : if (c.MatrixS) {
134 [ # # ][ # # ]: 0 : allocMatrixS ();
135 : 0 : memcpy (MatrixS, c.MatrixS, size * size * sizeof (nr_complex_t));
136 : : }
137 : : // copy each noise-correlation parameter
138 [ # # ][ # # ]: 0 : if (c.MatrixN) {
139 [ # # ][ # # ]: 0 : allocMatrixN (nsources);
140 : 0 : int i = size + nsources;
141 : 0 : memcpy (MatrixN, c.MatrixN, i * i * sizeof (nr_complex_t));
142 : : }
143 : : // copy each HB-matrix entry
144 [ # # ][ # # ]: 0 : if (c.MatrixQV) {
145 [ # # ][ # # ]: 0 : allocMatrixHB ();
146 : 0 : memcpy (MatrixQV, c.MatrixQV, size * size * sizeof (nr_complex_t));
147 : 0 : memcpy (VectorGV, c.VectorGV, size * sizeof (nr_complex_t));
148 : 0 : memcpy (VectorCV, c.VectorCV, size * sizeof (nr_complex_t));
149 : 0 : memcpy (VectorQ, c.VectorQ, size * sizeof (nr_complex_t));
150 : : }
151 : : // copy each G-MNA matrix entry
152 [ # # ][ # # ]: 0 : if (c.MatrixY) {
153 [ # # ][ # # ]: 0 : allocMatrixMNA ();
154 : 0 : memcpy (MatrixY, c.MatrixY, size * size * sizeof (nr_complex_t));
155 : 0 : memcpy (VectorI, c.VectorI, size * sizeof (nr_complex_t));
156 : 0 : memcpy (VectorV, c.VectorV, size * sizeof (nr_complex_t));
157 [ # # ][ # # ]: 0 : if (vsources > 0) {
158 : 0 : memcpy (MatrixB, c.MatrixB, vsources * size * sizeof (nr_complex_t));
159 : 0 : memcpy (MatrixC, c.MatrixC, vsources * size * sizeof (nr_complex_t));
160 : 0 : memcpy (MatrixD, c.MatrixD, vsources * vsources * sizeof (nr_complex_t));
161 : 0 : memcpy (VectorE, c.VectorE, vsources * sizeof (nr_complex_t));
162 : 0 : memcpy (VectorJ, c.VectorJ, vsources * sizeof (nr_complex_t));
163 : : }
164 : : }
165 : : }
166 : : else {
167 : 0 : nodes = NULL;
168 : 0 : MatrixS = MatrixN = MatrixY = NULL;
169 : 0 : MatrixB = MatrixC = MatrixD = NULL;
170 : 0 : VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
171 : 0 : MatrixQV = NULL;
172 : 0 : VectorCV = VectorGV = NULL;
173 : : }
174 : :
175 : : // copy operating points
176 [ # # ][ # # ]: 0 : oper = valuelist<operatingpoint> (c.oper);
[ # # ][ # # ]
177 : 0 : }
178 : :
179 : : // Destructor deletes a circuit object.
180 [ + - ][ + - ]: 125988 : circuit::~circuit () {
[ + - ][ + - ]
[ + - ][ + - ]
181 [ + - ][ + - ]: 125988 : if (size > 0) {
182 [ + - ][ + - ]: 125988 : if (MatrixS) delete[] MatrixS;
[ + + ][ + - ]
183 [ + + ][ + - ]: 125988 : if (MatrixN) delete[] MatrixN;
[ + + ][ + - ]
184 : 125988 : freeMatrixMNA ();
185 : 125988 : freeMatrixHB ();
186 [ + - ][ + + ]: 474473 : delete[] nodes;
[ + - ][ + - ]
[ + + ][ + - ]
187 : : }
188 [ - + ][ + + ]: 125988 : if (subcircuit) free (subcircuit);
189 : 125988 : deleteHistory ();
190 [ - + ][ - + ]: 250663 : }
191 : :
192 : : /* With this function the number of ports of the circuit object can be
193 : : changed. Previously stored node and matrix information gets
194 : : completely lost except the current size equals the given size. */
195 : 0 : void circuit::setSize (int s) {
196 : : // nothing to do here
197 [ # # ]: 0 : if (size == s) return;
198 [ # # ]: 0 : assert (s >= 0);
199 : :
200 [ # # ]: 0 : if (size > 0) {
201 : : // destroy any matrix and node information
202 [ # # ][ # # ]: 0 : if (MatrixS) delete[] MatrixS;
203 [ # # ][ # # ]: 0 : if (MatrixN) delete[] MatrixN;
204 : 0 : MatrixS = MatrixN = NULL;
205 : 0 : freeMatrixMNA ();
206 [ # # ][ # # ]: 0 : delete[] nodes; nodes = NULL;
207 : : }
208 : :
209 [ # # ]: 0 : if ((size = s) > 0) {
210 : : // re-create matrix and node information space
211 [ # # ][ # # : 0 : nodes = new node[size];
# # # # ]
212 : 0 : allocMatrixS ();
213 : 0 : allocMatrixN (nsources);
214 : 0 : allocMatrixMNA ();
215 : : }
216 : : }
217 : :
218 : : /* Destroys the HB-matrix memory. */
219 : 125988 : void circuit::freeMatrixHB (void) {
220 [ + + ][ + - ]: 125988 : if (VectorQ) { delete[] VectorQ; VectorQ = NULL; }
221 [ + + ][ + - ]: 125988 : if (MatrixQV) { delete[] MatrixQV; MatrixQV = NULL; }
222 [ + + ][ + - ]: 125988 : if (VectorCV) { delete[] VectorCV; VectorCV = NULL; }
223 [ + + ][ + - ]: 125988 : if (VectorGV) { delete[] VectorGV; VectorGV = NULL; }
224 : 125988 : }
225 : :
226 : : /* Allocates the HB-matrix memory. */
227 : 1 : void circuit::allocMatrixHB (void) {
228 [ - + ]: 1 : if (VectorQ) {
229 : 0 : memset (VectorQ, 0, size * sizeof (nr_complex_t));
230 : : } else {
231 [ + + ]: 3 : VectorQ = new nr_complex_t[size];
232 : : }
233 [ - + ]: 1 : if (MatrixQV) {
234 : 0 : memset (MatrixQV, 0, size * size * sizeof (nr_complex_t));
235 : : } else {
236 [ + + ]: 5 : MatrixQV = new nr_complex_t[size * size];
237 : : }
238 [ - + ]: 1 : if (VectorCV) {
239 : 0 : memset (VectorCV, 0, size * sizeof (nr_complex_t));
240 : : } else {
241 [ + + ]: 3 : VectorCV = new nr_complex_t[size];
242 : : }
243 [ - + ]: 1 : if (VectorGV) {
244 : 0 : memset (VectorGV, 0, size * sizeof (nr_complex_t));
245 : : } else {
246 [ + + ]: 3 : VectorGV = new nr_complex_t[size];
247 : : }
248 : 1 : }
249 : :
250 : : /* Allocates the S-parameter matrix memory. */
251 : 125097 : void circuit::allocMatrixS (void) {
252 [ - + ]: 125097 : if (MatrixS) {
253 : 0 : memset (MatrixS, 0, size * size * sizeof (nr_complex_t));
254 : : } else {
255 [ + + ]: 1304639 : MatrixS = new nr_complex_t[size * size];
256 : : }
257 : 125097 : }
258 : :
259 : : /* Allocates the noise correlation matrix memory. */
260 : 9452 : void circuit::allocMatrixN (int sources) {
261 : 9452 : nsources = sources;
262 [ + + ][ + - ]: 9452 : if (MatrixN) delete[] MatrixN;
263 [ + + ]: 178148 : MatrixN = new nr_complex_t[(size + sources) * (size + sources)];
264 : 9452 : }
265 : :
266 : : /* Allocates the matrix memory for the MNA matrices. */
267 : 126752 : void circuit::allocMatrixMNA (void) {
268 : 126752 : freeMatrixMNA ();
269 [ + - ]: 126752 : if (size > 0) {
270 [ + + ]: 1116571 : MatrixY = new nr_complex_t[size * size];
271 [ + + ]: 407347 : VectorI = new nr_complex_t[size];
272 [ + + ]: 407347 : VectorV = new nr_complex_t[size];
273 [ + + ]: 126752 : if (vsources > 0) {
274 [ + + ]: 94285 : MatrixB = new nr_complex_t[vsources * size];
275 [ + + ]: 94285 : MatrixC = new nr_complex_t[vsources * size];
276 [ + + ]: 62400 : MatrixD = new nr_complex_t[vsources * vsources];
277 [ + + ]: 62098 : VectorE = new nr_complex_t[vsources];
278 [ + + ]: 62098 : VectorJ = new nr_complex_t[vsources];
279 : : }
280 : : }
281 : 126752 : }
282 : :
283 : : /* Free()'s all memory used by the MNA matrices. */
284 : 252740 : void circuit::freeMatrixMNA (void) {
285 [ + + ][ + - ]: 252740 : if (MatrixY) { delete[] MatrixY; MatrixY = NULL; }
286 [ + + ][ + - ]: 252740 : if (MatrixB) { delete[] MatrixB; MatrixB = NULL; }
287 [ + + ][ + - ]: 252740 : if (MatrixC) { delete[] MatrixC; MatrixC = NULL; }
288 [ + + ][ + - ]: 252740 : if (MatrixD) { delete[] MatrixD; MatrixD = NULL; }
289 [ + + ][ + - ]: 252740 : if (VectorE) { delete[] VectorE; VectorE = NULL; }
290 [ + + ][ + - ]: 252740 : if (VectorI) { delete[] VectorI; VectorI = NULL; }
291 [ + + ][ + - ]: 252740 : if (VectorV) { delete[] VectorV; VectorV = NULL; }
292 [ + + ][ + - ]: 252740 : if (VectorJ) { delete[] VectorJ; VectorJ = NULL; }
293 : 252740 : }
294 : :
295 : : /* This function sets the name and port number of one of the circuit's
296 : : nodes. It also tells the appropriate node about the circuit it
297 : : belongs to. The optional 'intern' argument is used to mark a node
298 : : to be for internal use only. */
299 : 384274 : void circuit::setNode (int i, const char * n, int intern) {
300 : 384274 : nodes[i].setName (n);
301 : 384274 : nodes[i].setCircuit (this);
302 : 384274 : nodes[i].setPort (i);
303 : 384274 : nodes[i].setInternal (intern);
304 : 384274 : }
305 : :
306 : : // Returns one of the circuit's nodes.
307 : 6970665 : node * circuit::getNode (int i) {
308 : 6970665 : return &nodes[i];
309 : : }
310 : :
311 : : // Sets the subcircuit reference for the circuit object.
312 : 933 : void circuit::setSubcircuit (char * n) {
313 [ - + ]: 933 : if (subcircuit) free (subcircuit);
314 [ + + ]: 933 : subcircuit = n ? strdup (n) : NULL;
315 : 933 : }
316 : :
317 : : #if DEBUG
318 : : // DEBUG function: Prints the S parameters of this circuit object.
319 : 0 : void circuit::print (void) {
320 [ # # ]: 0 : for (int i = 0; i < getSize (); i++) {
321 [ # # ]: 0 : for (int j = 0; j < getSize (); j++) {
322 : : logprint (LOG_STATUS, "%s S%d%d(%+.3e,%+.3e) ", getName (), i, j,
323 [ # # ]: 0 : (double) real (getS (i, j)), (double) imag (getS (i, j)));
324 : : }
325 : 0 : logprint (LOG_STATUS, "\n");
326 : : }
327 : 0 : }
328 : : #endif /* DEBUG */
329 : :
330 : : /* Returns the current substrate of the circuit object. Used for
331 : : microstrip components only. */
332 : 3344 : substrate * circuit::getSubstrate (void) {
333 : 3344 : return subst;
334 : : }
335 : :
336 : : // Sets the substrate of the circuit object.
337 : 27 : void circuit::setSubstrate (substrate * s) {
338 : 27 : subst = s;
339 : 27 : }
340 : :
341 : : /* Returns the circuits B-MNA matrix value of the given voltage source
342 : : built in the circuit depending on the port number. */
343 : 3726572 : nr_complex_t circuit::getB (int port, int nr) {
344 : 3726572 : return MatrixB[(nr - vsource) * size + port];
345 : : }
346 : :
347 : : /* Sets the circuits B-MNA matrix value of the given voltage source
348 : : built in the circuit depending on the port number. */
349 : 63182 : void circuit::setB (int port, int nr, nr_complex_t z) {
350 : 63182 : MatrixB[nr * size + port] = z;
351 : 63182 : }
352 : :
353 : : /* Returns the circuits C-MNA matrix value of the given voltage source
354 : : built in the circuit depending on the port number. */
355 : 3726572 : nr_complex_t circuit::getC (int nr, int port) {
356 : 3726572 : return MatrixC[(nr - vsource) * size + port];
357 : : }
358 : :
359 : : /* Sets the circuits C-MNA matrix value of the given voltage source
360 : : built in the circuit depending on the port number. */
361 : 223692 : void circuit::setC (int nr, int port, nr_complex_t z) {
362 : 223692 : MatrixC[nr * size + port] = z;
363 : 223692 : }
364 : :
365 : : /* Returns the circuits D-MNA matrix value of the given voltage source
366 : : built in the circuit. */
367 : 2433343 : nr_complex_t circuit::getD (int r, int c) {
368 : 2433343 : return MatrixD[(r - vsource) * vsources + c - vsource];
369 : : }
370 : :
371 : : /* Sets the circuits D-MNA matrix value of the given voltage source
372 : : built in the circuit. */
373 : 376201 : void circuit::setD (int r, int c, nr_complex_t z) {
374 : 376201 : MatrixD[r * vsources + c] = z;
375 : 376201 : }
376 : :
377 : : /* Returns the circuits E-MNA matrix value of the given voltage source
378 : : built in the circuit. */
379 : 2049654 : nr_complex_t circuit::getE (int nr) {
380 : 2049654 : return VectorE[nr - vsource];
381 : : }
382 : :
383 : : /* Sets the circuits E-MNA matrix value of the given voltage source
384 : : built in the circuit. */
385 : 880080 : void circuit::setE (int nr, nr_complex_t z) {
386 : 880080 : VectorE[nr] = z;
387 : 880080 : }
388 : :
389 : : /* Returns the circuits I-MNA matrix value of the current source built
390 : : in the circuit. */
391 : 3202101 : nr_complex_t circuit::getI (int port) {
392 : 3202101 : return VectorI[port];
393 : : }
394 : :
395 : : /* Sets the circuits I-MNA matrix value of the current source built in
396 : : the circuit depending on the port number. */
397 : 2869379 : void circuit::setI (int port, nr_complex_t z) {
398 : 2869379 : VectorI[port] = z;
399 : 2869379 : }
400 : :
401 : : /* Modifies the circuits I-MNA matrix value of the current source
402 : : built in the circuit depending on the port number. */
403 : 0 : void circuit::addI (int port, nr_complex_t i) {
404 : 0 : VectorI[port] += i;
405 : 0 : }
406 : :
407 : : /* Same as above with different argument type. */
408 : 1967746 : void circuit::addI (int port, nr_double_t i) {
409 : 1967746 : VectorI[port] += i;
410 : 1967746 : }
411 : :
412 : : /* Returns the circuits Q-HB vector value. */
413 : 352 : nr_complex_t circuit::getQ (int port) {
414 : 352 : return VectorQ[port];
415 : : }
416 : :
417 : : /* Sets the circuits Q-HB vector value. */
418 : 352 : void circuit::setQ (int port, nr_complex_t q) {
419 : 352 : VectorQ[port] = q;
420 : 352 : }
421 : :
422 : : /* Returns the circuits J-MNA matrix value of the given voltage source
423 : : built in the circuit. */
424 : 208702 : nr_complex_t circuit::getJ (int nr) {
425 : 208702 : return VectorJ[nr];
426 : : }
427 : :
428 : : /* Sets the circuits J-MNA matrix value of the given voltage source
429 : : built in the circuit. */
430 : 2864758 : void circuit::setJ (int nr, nr_complex_t z) {
431 : 2864758 : VectorJ[nr - vsource] = z;
432 : 2864758 : }
433 : :
434 : : // Returns the circuits voltage value at the given port.
435 : 7406742 : nr_complex_t circuit::getV (int port) {
436 : 7406742 : return VectorV[port];
437 : : }
438 : :
439 : : // Sets the circuits voltage value at the given port.
440 : 16448388 : void circuit::setV (int port, nr_complex_t z) {
441 : 16448388 : VectorV[port] = z;
442 : 16448388 : }
443 : :
444 : : /* Returns the circuits G-MNA matrix value depending on the port
445 : : numbers. */
446 : 18419856 : nr_complex_t circuit::getY (int r, int c) {
447 : 18419856 : return MatrixY[r * size + c];
448 : : }
449 : :
450 : : /* Sets the circuits G-MNA matrix value depending on the port
451 : : numbers. */
452 : 15761029 : void circuit::setY (int r, int c, nr_complex_t y) {
453 : 15761029 : MatrixY[r * size + c] = y;
454 : 15761029 : }
455 : :
456 : : /* Modifies the circuits G-MNA matrix value depending on the port
457 : : numbers. */
458 : 0 : void circuit::addY (int r, int c, nr_complex_t y) {
459 : 0 : MatrixY[r * size + c] += y;
460 : 0 : }
461 : :
462 : : /* Same as above with different argument type. */
463 : 3935492 : void circuit::addY (int r, int c, nr_double_t y) {
464 : 3935492 : MatrixY[r * size + c] += y;
465 : 3935492 : }
466 : :
467 : : /* Returns the circuits G-MNA matrix value depending on the port
468 : : numbers. */
469 : 0 : nr_double_t circuit::getG (int r, int c) {
470 : 0 : return real (MatrixY[r * size + c]);
471 : : }
472 : :
473 : : /* Sets the circuits G-MNA matrix value depending on the port
474 : : numbers. */
475 : 0 : void circuit::setG (int r, int c, nr_double_t y) {
476 : 0 : MatrixY[r * size + c] = y;
477 : 0 : }
478 : :
479 : : /* Returns the circuits C-HB matrix value depending on the port
480 : : numbers. */
481 : 176 : nr_complex_t circuit::getQV (int r, int c) {
482 : 176 : return MatrixQV[r * size + c];
483 : : }
484 : :
485 : : /* Sets the circuits C-HB matrix value depending on the port
486 : : numbers. */
487 : 704 : void circuit::setQV (int r, int c, nr_complex_t qv) {
488 : 704 : MatrixQV[r * size + c] = qv;
489 : 704 : }
490 : :
491 : : /* Returns the circuits GV-HB vector value depending on the port
492 : : number. */
493 : 176 : nr_complex_t circuit::getGV (int port) {
494 : 176 : return VectorGV[port];
495 : : }
496 : :
497 : : /* Sets the circuits GV-HB matrix value depending on the port
498 : : number. */
499 : 352 : void circuit::setGV (int port, nr_complex_t gv) {
500 : 352 : VectorGV[port] = gv;
501 : 352 : }
502 : :
503 : : /* Returns the circuits CV-HB vector value depending on the port
504 : : number. */
505 : 176 : nr_complex_t circuit::getCV (int port) {
506 : 176 : return VectorCV[port];
507 : : }
508 : :
509 : : /* Sets the circuits CV-HB matrix value depending on the port
510 : : number. */
511 : 352 : void circuit::setCV (int port, nr_complex_t cv) {
512 : 352 : VectorCV[port] = cv;
513 : 352 : }
514 : :
515 : : /* This function adds a operating point consisting of a key and a
516 : : value to the circuit. */
517 : 1216 : void circuit::addOperatingPoint (const char * n, nr_double_t val) {
518 [ + - ]: 1216 : operatingpoint * p = new operatingpoint (n, val);
519 : 1216 : oper.add (n, p);
520 : 1216 : }
521 : :
522 : : /* Returns the requested operating point value which has been
523 : : previously added as its double representation. If there is no such
524 : : operating point the function returns zero. */
525 : 2154262 : nr_double_t circuit::getOperatingPoint (const char * n) {
526 : 2154262 : operatingpoint * p = oper.get (n);
527 [ + - ]: 2154262 : if (p != NULL) return p->getValue ();
528 : 2154262 : return 0.0;
529 : : }
530 : :
531 : : /* This function sets the operating point specified by the given name
532 : : to the value passed to the function. */
533 : 4187551 : void circuit::setOperatingPoint (const char * n, nr_double_t val) {
534 : 4187551 : operatingpoint * p = oper.get (n);
535 [ + + ]: 4187551 : if (p != NULL)
536 : 4186335 : p->setValue (val);
537 : : else
538 : 1216 : addOperatingPoint (n, val);
539 : 4187551 : }
540 : :
541 : : /* The function checks whether the circuit has got a certain operating
542 : : point value. If so it returns non-zero, otherwise it returns
543 : : zero. */
544 : 0 : int circuit::hasOperatingPoint (char * n) {
545 [ # # ]: 0 : return (oper.get (n)) ? 1 : 0;
546 : : }
547 : :
548 : : /* This function adds a characteristic point consisting of a key and a
549 : : value to the circuit. */
550 : 0 : void circuit::addCharacteristic (const char * n, nr_double_t val) {
551 [ # # ]: 0 : characteristic * p = new characteristic (n, val);
552 : 0 : charac.add (n, p);
553 : 0 : }
554 : :
555 : : /* Returns the requested characteristic value which has been
556 : : previously added as its double representation. If there is no such
557 : : characteristic value the function returns zero. */
558 : 0 : nr_double_t circuit::getCharacteristic (char * n) {
559 : 0 : characteristic * p = charac.get (n);
560 [ # # ]: 0 : if (p != NULL) return p->getValue ();
561 : 0 : return 0.0;
562 : : }
563 : :
564 : : /* This function sets the characteristic value specified by the given
565 : : name to the value passed to the function. */
566 : 0 : void circuit::setCharacteristic (const char * n, nr_double_t val) {
567 : 0 : characteristic * p = charac.get (n);
568 [ # # ]: 0 : if (p != NULL)
569 : 0 : p->setValue (val);
570 : : else
571 : 0 : addCharacteristic (n, val);
572 : 0 : }
573 : :
574 : : /* The function checks whether the circuit has got a certain
575 : : characteristic value. If so it returns non-zero, otherwise it
576 : : returns zero. */
577 : 0 : int circuit::hasCharacteristic (char * n) {
578 [ # # ]: 0 : return (charac.get (n)) ? 1 : 0;
579 : : }
580 : :
581 : : // Returns the S-parameter at the given matrix position.
582 : 6876468 : nr_complex_t circuit::getS (int x, int y) {
583 : 6876468 : return MatrixS[y + x * size];
584 : : }
585 : :
586 : : // Sets the S-parameter at the given matrix position.
587 : 1395118 : void circuit::setS (int x, int y, nr_complex_t z) {
588 : 1395118 : MatrixS[y + x * size] = z;
589 : 1395118 : }
590 : :
591 : : // Returns the noise-correlation-parameter at the given matrix position.
592 : 718337 : nr_complex_t circuit::getN (int r, int c) {
593 : 718337 : return MatrixN[c + r * (size + nsources)];
594 : : }
595 : :
596 : : // Sets the noise-correlation-parameter at the given matrix position.
597 : 216516 : void circuit::setN (int r, int c, nr_complex_t z) {
598 : 216516 : MatrixN[c + r * (size + nsources)] = z;
599 : 216516 : }
600 : :
601 : : // Returns the number of internal voltage sources for DC analysis.
602 : 156041497 : int circuit::getVoltageSources (void) {
603 : 156041497 : return vsources;
604 : : }
605 : :
606 : : // Sets the number of internal voltage sources for DC analysis.
607 : 35488 : void circuit::setVoltageSources (int s) {
608 [ - + ]: 35488 : assert (s >= 0);
609 : 35488 : vsources = s;
610 : 35488 : }
611 : :
612 : : // Returns the number of internal noise sources for AC analysis.
613 : 0 : int circuit::getNoiseSources (void) {
614 : 0 : return nsources;
615 : : }
616 : :
617 : : // Sets the number of internal noise voltage sources for AC analysis.
618 : 0 : void circuit::setNoiseSources (int s) {
619 [ # # ]: 0 : assert (s >= 0);
620 : 0 : nsources = s;
621 : 0 : }
622 : :
623 : : /* The function returns an internal node or circuit name with the
624 : : given prefix and based on the given circuits name. The caller is
625 : : responsible to free() the returned string. */
626 : 28151 : char * circuit::createInternal (const char * prefix, const char * obj) {
627 : 28151 : char * n = (char *) malloc (strlen (prefix) + strlen (obj) + 3);
628 : 28151 : sprintf (n, "_%s#%s", prefix, obj);
629 : 28151 : return n;
630 : : }
631 : :
632 : : /* Creates an internal node given the node number as well as the name
633 : : suffix. An appropriate node name is constructed from the circuits
634 : : name and the suffix. */
635 : 28005 : void circuit::setInternalNode (int node, const char * suffix) {
636 : 28005 : char * n = createInternal (getName (), suffix);
637 : 28005 : setNode (node, n, 1);
638 : 28005 : free (n);
639 : 28005 : }
640 : :
641 : : /* This function copies the matrix elements inside the given matrix to
642 : : the internal S-parameter matrix of the circuit. */
643 : 1070 : void circuit::setMatrixS (matrix s) {
644 : 1070 : int r = s.getRows ();
645 : 1070 : int c = s.getCols ();
646 : : // copy matrix elements
647 [ + - ][ + - ]: 1070 : if (r > 0 && c > 0 && r * c == size * size) {
[ + - ]
648 : 1070 : memcpy (MatrixS, s.getData (), sizeof (nr_complex_t) * r * c);
649 : : }
650 : 1070 : }
651 : :
652 : : /* The function return a matrix containing the S-parameters of the
653 : : circuit. */
654 : 70 : matrix circuit::getMatrixS (void) {
655 : 70 : matrix res (size);
656 [ + + ]: 770 : for(unsigned int i=0; i < size; ++i)
657 [ + + ]: 7700 : for(unsigned int j=0; j < size; ++j)
658 : 7000 : res(i,j) = MatrixS[i*size + j];
659 : 70 : return res;
660 : : }
661 : :
662 : : /* This function copies the matrix elements inside the given matrix to
663 : : the internal noise correlation matrix of the circuit. */
664 : 70 : void circuit::setMatrixN (matrix n) {
665 : 70 : int r = n.getRows ();
666 : 70 : int c = n.getCols ();
667 : : // copy matrix elements
668 [ + - ][ + - ]: 70 : if (r > 0 && c > 0 && r * c == size * size) {
[ + - ]
669 : 70 : memcpy (MatrixN, n.getData (), sizeof (nr_complex_t) * r * c);
670 : : }
671 : 70 : }
672 : :
673 : : /* The function return a matrix containing the noise correlation
674 : : matrix of the circuit. */
675 : 0 : matrix circuit::getMatrixN (void) {
676 : 0 : matrix res (size);
677 [ # # ]: 0 : for(unsigned int i=0; i < size; ++i)
678 [ # # ]: 0 : for(unsigned int j=0; j < size; ++j)
679 : 0 : res(i,j) = MatrixN[i*size + j];
680 : 0 : return res;
681 : : }
682 : :
683 : : /* This function copies the matrix elements inside the given matrix to
684 : : the internal G-MNA matrix of the circuit. */
685 : 2600 : void circuit::setMatrixY (matrix y) {
686 : 2600 : int r = y.getRows ();
687 : 2600 : int c = y.getCols ();
688 : : // copy matrix elements
689 [ + - ][ + - ]: 2600 : if (r > 0 && c > 0 && r * c == size * size) {
[ + - ]
690 : 2600 : memcpy (MatrixY, y.getData (), sizeof (nr_complex_t) * r * c);
691 : : }
692 : 2600 : }
693 : :
694 : : /* The function return a matrix containing the G-MNA matrix of the
695 : : circuit. */
696 : 0 : matrix circuit::getMatrixY (void) {
697 : 0 : matrix res (size);
698 [ # # ]: 0 : for(unsigned int i=0; i < size; ++i)
699 [ # # ]: 0 : for(unsigned int j=0; j < size; ++j)
700 : 0 : res(i,j) = MatrixY[i*size + j];
701 : 0 : return res;
702 : : }
703 : :
704 : : // The function cleans up the B-MNA matrix entries.
705 : 2 : void circuit::clearB (void) {
706 : 2 : memset (MatrixB, 0, sizeof (nr_complex_t) * size * vsources);
707 : 2 : }
708 : :
709 : : // The function cleans up the C-MNA matrix entries.
710 : 2 : void circuit::clearC (void) {
711 : 2 : memset (MatrixC, 0, sizeof (nr_complex_t) * size * vsources);
712 : 2 : }
713 : :
714 : : // The function cleans up the D-MNA matrix entries.
715 : 0 : void circuit::clearD (void) {
716 : 0 : memset (MatrixD, 0, sizeof (nr_complex_t) * vsources * vsources);
717 : 0 : }
718 : :
719 : : // The function cleans up the E-MNA matrix entries.
720 : 0 : void circuit::clearE (void) {
721 : 0 : memset (VectorE, 0, sizeof (nr_complex_t) * vsources);
722 : 0 : }
723 : :
724 : : // The function cleans up the J-MNA matrix entries.
725 : 0 : void circuit::clearJ (void) {
726 : 0 : memset (VectorJ, 0, sizeof (nr_complex_t) * vsources);
727 : 0 : }
728 : :
729 : : // The function cleans up the I-MNA matrix entries.
730 : 258 : void circuit::clearI (void) {
731 : 258 : memset (VectorI, 0, sizeof (nr_complex_t) * size);
732 : 258 : }
733 : :
734 : : // The function cleans up the V-MNA matrix entries.
735 : 0 : void circuit::clearV (void) {
736 : 0 : memset (VectorV, 0, sizeof (nr_complex_t) * size);
737 : 0 : }
738 : :
739 : : // The function cleans up the G-MNA matrix entries.
740 : 5156 : void circuit::clearY (void) {
741 : 5156 : memset (MatrixY, 0, sizeof (nr_complex_t) * size * size);
742 : 5156 : }
743 : :
744 : : /* This function can be used by several components in order to place
745 : : the n-th voltage source between node 'pos' and node 'neg' with the
746 : : given value. Remember to indicate this voltage source using the
747 : : function setVoltageSources(). */
748 : 30649 : void circuit::voltageSource (int n, int pos, int neg, nr_double_t value) {
749 : 30649 : setC (n, pos, +1.0); setC (n, neg, -1.0);
750 : 30649 : setB (pos, n, +1.0); setB (neg, n, -1.0);
751 : 30649 : setD (n, n, 0.0);
752 : 30649 : setE (n, value);
753 : 30649 : }
754 : :
755 : : /* The function runs the necessary calculation in order to perform a
756 : : single integration step of a voltage controlled capacitance placed
757 : : in between the given nodes. It is assumed that the appropiate
758 : : charge only depends on the voltage between these nodes. */
759 : 911023 : void circuit::transientCapacitance (int qstate, int pos, int neg,
760 : : nr_double_t cap, nr_double_t voltage,
761 : : nr_double_t charge) {
762 : : nr_double_t g, i;
763 : 911023 : int cstate = qstate + 1;
764 : 911023 : setState (qstate, charge);
765 [ + - ]: 911023 : integrate (qstate, cap, g, i);
766 : 911023 : addY (pos, pos, +g); addY (neg, neg, +g);
767 : 911023 : addY (pos, neg, -g); addY (neg, pos, -g);
768 : 911023 : i = pol * (getState (cstate) - g * voltage);
769 : 911023 : addI (pos , -i);
770 : 911023 : addI (neg , +i);
771 : 911023 : }
772 : :
773 : : /* This is the one-node variant of the above function. It performs
774 : : the same steps for a single node related to ground. */
775 : 0 : void circuit::transientCapacitance (int qstate, int node, nr_double_t cap,
776 : : nr_double_t voltage, nr_double_t charge) {
777 : : nr_double_t g, i;
778 : 0 : int cstate = qstate + 1;
779 : 0 : setState (qstate, charge);
780 [ # # ]: 0 : integrate (qstate, cap, g, i);
781 : 0 : addY (node, node, +g);
782 : 0 : i = pol * (getState (cstate) - g * voltage);
783 : 0 : addI (node , -i);
784 : 0 : }
785 : :
786 : : /* The function performs a single integration step of the given charge
787 : : located between the given nodes. It saves the current
788 : : contributions of the charge itself and considers the polarity of
789 : : the circuit. */
790 : 0 : void circuit::transientCapacitanceQ (int qstate, int qpos, int qneg,
791 : : nr_double_t charge) {
792 : : nr_double_t unused, i;
793 : 0 : int cstate = qstate + 1;
794 : 0 : setState (qstate, charge);
795 [ # # ]: 0 : integrate (qstate, 0, unused, unused);
796 : 0 : i = pol * getState (cstate);
797 : 0 : addI (qpos , -i);
798 : 0 : addI (qneg , +i);
799 : 0 : }
800 : :
801 : : /* This is the one-node variant of the above function. It performs
802 : : the same steps for a single node related to ground. */
803 : 0 : void circuit::transientCapacitanceQ (int qstate, int qpos,
804 : : nr_double_t charge) {
805 : : nr_double_t unused, i;
806 : 0 : int cstate = qstate + 1;
807 : 0 : setState (qstate, charge);
808 [ # # ]: 0 : integrate (qstate, 0, unused, unused);
809 : 0 : i = pol * getState (cstate);
810 : 0 : addI (qpos , -i);
811 : 0 : }
812 : :
813 : : /* This function stores the Jacobian entries due to the C = dQ/dV
814 : : value. The nodes where the charge is located as well as those of
815 : : the voltage dependency, the appropiate capacitance value and the
816 : : voltage across the the controlling branch must be given. It also
817 : : saves the current contributions which are necessary for the NR
818 : : iteration and considers the polarity of the circuit. */
819 : 72850 : void circuit::transientCapacitanceC (int qpos, int qneg, int vpos, int vneg,
820 : : nr_double_t cap, nr_double_t voltage) {
821 : : nr_double_t g, i;
822 [ + - ]: 72850 : conductor (cap, g);
823 : 72850 : addY (qpos, vpos, +g); addY (qneg, vneg, +g);
824 : 72850 : addY (qpos, vneg, -g); addY (qneg, vpos, -g);
825 : 72850 : i = pol * (g * voltage);
826 : 72850 : addI (qpos , +i);
827 : 72850 : addI (qneg , -i);
828 : 72850 : }
829 : :
830 : : /* This is the one-node variant of the transientCapacitanceC()
831 : : function. It performs the same steps for a single charge node
832 : : related to ground. */
833 : 0 : void circuit::transientCapacitanceC2V (int qpos, int vpos, int vneg,
834 : : nr_double_t cap, nr_double_t voltage) {
835 : : nr_double_t g, i;
836 [ # # ]: 0 : conductor (cap, g);
837 : 0 : addY (qpos, vpos, +g);
838 : 0 : addY (qpos, vneg, -g);
839 : 0 : i = pol * (g * voltage);
840 : 0 : addI (qpos , +i);
841 : 0 : }
842 : :
843 : : /* This is the one-node variant of the transientCapacitanceC()
844 : : function. It performs the same steps for a single voltage node
845 : : related to ground. */
846 : 0 : void circuit::transientCapacitanceC2Q (int qpos, int qneg, int vpos,
847 : : nr_double_t cap, nr_double_t voltage) {
848 : : nr_double_t g, i;
849 [ # # ]: 0 : conductor (cap, g);
850 : 0 : addY (qpos, vpos, +g); addY (qneg, vpos, -g);
851 : 0 : i = pol * (g * voltage);
852 : 0 : addI (qpos , +i);
853 : 0 : addI (qneg , -i);
854 : 0 : }
855 : :
856 : : /* This is the one-node variant of the transientCapacitanceC()
857 : : function. It performs the same steps for a single voltage node and
858 : : charge node related to ground. */
859 : 0 : void circuit::transientCapacitanceC (int qpos, int vpos,
860 : : nr_double_t cap, nr_double_t voltage) {
861 : : nr_double_t g, i;
862 [ # # ]: 0 : conductor (cap, g);
863 : 0 : addY (qpos, vpos, +g);
864 : 0 : i = pol * (g * voltage);
865 : 0 : addI (qpos , +i);
866 : 0 : }
867 : :
868 : : // The function initializes the histories of a circuit having the given age.
869 : 0 : void circuit::initHistory (nr_double_t age) {
870 : 0 : nHistories = getSize () + getVoltageSources ();
871 [ # # ][ # # : 0 : histories = new history[nHistories];
# # # # ]
872 : 0 : setHistoryAge (age);
873 : 0 : }
874 : :
875 : : // Sets the age of all circuit histories
876 : 0 : void circuit::setHistoryAge (nr_double_t age) {
877 [ # # ]: 0 : for (int i = 0; i < nHistories; i++)
878 : : {
879 : 0 : histories[i].setAge (age);
880 : : }
881 : 0 : }
882 : :
883 : :
884 : :
885 : : // The function deletes the histories for the transient analysis.
886 : 126018 : void circuit::deleteHistory (void) {
887 [ - + ]: 126018 : if (histories != NULL) {
888 [ # # ][ # # ]: 0 : delete[] histories;
889 : 0 : histories = NULL;
890 : : }
891 : 126018 : setHistory (false);
892 : 126018 : }
893 : :
894 : : // Truncates the transient analysis history (i.e. removes values newer
895 : : // newer than time tcut).
896 : 0 : void circuit::truncateHistory (nr_double_t tcut) {
897 [ # # ]: 0 : if (histories != NULL) {
898 [ # # ]: 0 : for (int i = 0; i < nHistories; i++)
899 : : {
900 : 0 : histories[i].truncate (tcut);
901 : : }
902 : : }
903 : 0 : }
904 : :
905 : : // Appends a history value.
906 : 0 : void circuit::appendHistory (int n, nr_double_t val) {
907 : 0 : histories[n].append (val);
908 : 0 : }
909 : :
910 : : // Returns the required age of the history.
911 : 0 : nr_double_t circuit::getHistoryAge (void) {
912 [ # # ]: 0 : if (histories) return histories[0].getAge ();
913 : 0 : return 0.0;
914 : : }
915 : :
916 : : // Returns size of the history
917 : 0 : int circuit::getHistorySize (void) {
918 : 0 : return histories[0].getSize ();
919 : : }
920 : :
921 : : // Returns the time with the specified index
922 : 0 : nr_double_t circuit::getHistoryTFromIndex (int idx)
923 : : {
924 : 0 : return histories[0].getTfromidx (idx);
925 : : }
926 : :
927 : : /* This function should be used to apply the time vector history to
928 : : the value histories of a circuit. */
929 : 0 : void circuit::applyHistory (history * h) {
930 [ # # ]: 0 : for (int i = 0; i < nHistories; i++)
931 : : {
932 : 0 : histories[i].apply(*h);
933 : : }
934 : :
935 : 0 : }
936 : :
937 : : // Returns voltage at the given time for the given node.
938 : 0 : nr_double_t circuit::getV (int port, nr_double_t t) {
939 : 0 : return histories[port].nearest (t);
940 : : }
941 : :
942 : : // Returns voltage at the given index from the history for the given node.
943 : 0 : nr_double_t circuit::getV (int port, int idx) {
944 : 0 : return histories[port].getValfromidx (idx);
945 : : }
946 : :
947 : : // Returns current at the given time for the given voltage source.
948 : 0 : nr_double_t circuit::getJ (int nr, nr_double_t t) {
949 : 0 : return histories[nr + getSize ()].nearest (t);
950 : : }
951 : :
952 : : } // namespace qucs
|