Qucs-core  0.0.19
circuit.cpp
Go to the documentation of this file.
00001 /*
00002  * circuit.cpp - circuit class implementation
00003  *
00004  * Copyright (C) 2003, 2004, 2005, 2006, 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 <stdlib.h>
00031 #include <string.h>
00032 #include <assert.h>
00033 
00034 #include "logging.h"
00035 #include "complex.h"
00036 #include "object.h"
00037 #include "matrix.h"
00038 #include "node.h"
00039 #include "property.h"
00040 #include "valuelist.h"
00041 #include "tvector.h"
00042 #include "history.h"
00043 #include "circuit.h"
00044 #include "microstrip/substrate.h"
00045 #include "operatingpoint.h"
00046 #include "characteristic.h"
00047 #include "component_id.h"
00048 
00049 namespace qucs {
00050 
00051 // normalising impedance
00052 const nr_double_t circuit::z0 = 50.0;
00053 
00054 // Constructor creates an unnamed instance of the circuit class.
00055 circuit::circuit () : object (), integrator () {
00056   next = prev = NULL;
00057   size = 0;
00058   MatrixN = MatrixS = MatrixY = NULL;
00059   MatrixB = MatrixC = MatrixD = NULL;
00060   VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
00061   MatrixQV = NULL;
00062   VectorCV = VectorGV = NULL;
00063   nodes = NULL;
00064   pacport = 0;
00065   pol = 1;
00066   flag = CIRCUIT_ORIGINAL | CIRCUIT_LINEAR;
00067   subst = NULL;
00068   vsource = -1;
00069   vsources = 0;
00070   nsources = 0;
00071   inserted = -1;
00072   subcircuit = std::string();
00073   subnet = NULL;
00074   deltas = NULL;
00075   histories = NULL;
00076   nHistories = 0;
00077   type = CIR_UNKNOWN;
00078 }
00079 
00080 /* Constructor creates an unnamed instance of the circuit class with a
00081    certain number of ports. */
00082 circuit::circuit (int s) : object (), integrator () {
00083   next = prev = NULL;
00084   assert (s >= 0);
00085   size = s;
00086   if (size > 0) nodes = new node[s];
00087   MatrixN = MatrixS = MatrixY = NULL;
00088   MatrixB = MatrixC = MatrixD = NULL;
00089   VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
00090   MatrixQV = NULL;
00091   VectorCV = VectorGV = NULL;
00092   pacport = 0;
00093   pol = 1;
00094   flag = CIRCUIT_ORIGINAL | CIRCUIT_LINEAR;
00095   subst = NULL;
00096   vsource = -1;
00097   vsources = 0;
00098   nsources = 0;
00099   inserted = -1;
00100   subcircuit = std::string();
00101   subnet = NULL;
00102   deltas = NULL;
00103   histories = NULL;
00104   nHistories = 0;
00105   type = CIR_UNKNOWN;
00106 }
00107 
00108 /* The copy constructor creates a new instance based on the given
00109    circuit object. */
00110 circuit::circuit (const circuit & c) : object (c), integrator (c) {
00111   next = c.next;
00112   prev = c.prev;
00113   size = c.size;
00114   pol = c.pol;
00115   pacport = c.pacport;
00116   flag = c.flag;
00117   type = c.type;
00118   subst = c.subst;
00119   vsource = c.vsource;
00120   vsources = c.vsources;
00121   nsources = c.nsources;
00122   inserted = c.inserted;
00123   subnet = c.subnet;
00124   deltas = c.deltas;
00125   nHistories = c.nHistories;
00126   histories = NULL;
00127   subcircuit = c.subcircuit;
00128 
00129   if (size > 0) {
00130     // copy each node and set its circuit to the current circuit object
00131     nodes = new node[size];
00132     for (int i = 0; i < size; i++) {
00133       nodes[i] = node (c.nodes[i]);;
00134       nodes[i].setCircuit (this);
00135     }
00136     // copy each s-parameter
00137     if (c.MatrixS) {
00138       allocMatrixS ();
00139       memcpy (MatrixS, c.MatrixS, size * size * sizeof (nr_complex_t));
00140     }
00141     // copy each noise-correlation parameter
00142     if (c.MatrixN) {
00143       allocMatrixN (nsources);
00144       int i = size + nsources;
00145       memcpy (MatrixN, c.MatrixN, i * i * sizeof (nr_complex_t));
00146     }
00147     // copy each HB-matrix entry
00148     if (c.MatrixQV) {
00149       allocMatrixHB ();
00150       memcpy (MatrixQV, c.MatrixQV, size * size * sizeof (nr_complex_t));
00151       memcpy (VectorGV, c.VectorGV, size * sizeof (nr_complex_t));
00152       memcpy (VectorCV, c.VectorCV, size * sizeof (nr_complex_t));
00153       memcpy (VectorQ, c.VectorQ, size * sizeof (nr_complex_t));
00154     }
00155     // copy each G-MNA matrix entry
00156     if (c.MatrixY) {
00157       allocMatrixMNA ();
00158       memcpy (MatrixY, c.MatrixY, size * size * sizeof (nr_complex_t));
00159       memcpy (VectorI, c.VectorI, size * sizeof (nr_complex_t));
00160       memcpy (VectorV, c.VectorV, size * sizeof (nr_complex_t));
00161       if (vsources > 0) {
00162         memcpy (MatrixB, c.MatrixB, vsources * size * sizeof (nr_complex_t));
00163         memcpy (MatrixC, c.MatrixC, vsources * size * sizeof (nr_complex_t));
00164         memcpy (MatrixD, c.MatrixD, vsources * vsources * sizeof (nr_complex_t));
00165         memcpy (VectorE, c.VectorE, vsources * sizeof (nr_complex_t));
00166         memcpy (VectorJ, c.VectorJ, vsources * sizeof (nr_complex_t));
00167       }
00168     }
00169   }
00170   else {
00171     nodes = NULL;
00172     MatrixS = MatrixN = MatrixY = NULL;
00173     MatrixB = MatrixC = MatrixD = NULL;
00174     VectorQ = VectorE = VectorI = VectorV = VectorJ = NULL;
00175     MatrixQV = NULL;
00176     VectorCV = VectorGV = NULL;
00177   }
00178 
00179   // copy operating points
00180   oper = valuelist<operatingpoint> (c.oper);
00181 }
00182 
00183 // Destructor deletes a circuit object.
00184 circuit::~circuit () {
00185   if (size > 0) {
00186     delete[] MatrixS;
00187     delete[] MatrixN;
00188     freeMatrixMNA ();
00189     freeMatrixHB ();
00190     delete[] nodes;
00191   }
00192   deleteHistory ();
00193 }
00194 
00195 /* With this function the number of ports of the circuit object can be
00196    changed.  Previously stored node and matrix information gets
00197    completely lost except the current size equals the given size. */
00198 void circuit::setSize (int s) {
00199   // nothing to do here
00200   if (size == s) return;
00201   assert (s >= 0);
00202 
00203   if (size > 0) {
00204     // destroy any matrix and node information
00205     delete[] MatrixS;
00206     delete[] MatrixN;
00207     MatrixS = MatrixN = NULL;
00208     freeMatrixMNA ();
00209     delete[] nodes; nodes = NULL;
00210   }
00211 
00212   if ((size = s) > 0) {
00213     // re-create matrix and node information space
00214     nodes = new node[size];
00215     allocMatrixS ();
00216     allocMatrixN (nsources);
00217     allocMatrixMNA ();
00218   }
00219 }
00220 
00221 /* Destroys the HB-matrix memory. */
00222 void circuit::freeMatrixHB (void) {
00223   if (VectorQ) { delete[] VectorQ; VectorQ = NULL; }
00224   if (MatrixQV) { delete[] MatrixQV; MatrixQV = NULL; }
00225   if (VectorCV) { delete[] VectorCV; VectorCV = NULL; }
00226   if (VectorGV) { delete[] VectorGV; VectorGV = NULL; }
00227 }
00228 
00229 /* Allocates the HB-matrix memory. */
00230 void circuit::allocMatrixHB (void) {
00231   if (VectorQ) {
00232     memset (VectorQ, 0, size * sizeof (nr_complex_t));
00233   } else {
00234     VectorQ = new nr_complex_t[size];
00235   }
00236   if (MatrixQV) {
00237     memset (MatrixQV, 0, size * size * sizeof (nr_complex_t));
00238   } else {
00239     MatrixQV = new nr_complex_t[size * size];
00240   }
00241   if (VectorCV) {
00242     memset (VectorCV, 0, size * sizeof (nr_complex_t));
00243   } else {
00244     VectorCV = new nr_complex_t[size];
00245   }
00246   if (VectorGV) {
00247     memset (VectorGV, 0, size * sizeof (nr_complex_t));
00248   } else {
00249     VectorGV = new nr_complex_t[size];
00250   }
00251 }
00252 
00253 /* Allocates the S-parameter matrix memory. */
00254 void circuit::allocMatrixS (void) {
00255   if (MatrixS) {
00256     memset (MatrixS, 0, size * size * sizeof (nr_complex_t));
00257   } else {
00258     MatrixS = new nr_complex_t[size * size];
00259   }
00260 }
00261 
00262 /* Allocates the noise correlation matrix memory. */
00263 void circuit::allocMatrixN (int sources) {
00264   nsources = sources;
00265   delete[] MatrixN;
00266   MatrixN = new nr_complex_t[(size + sources) * (size + sources)];
00267 }
00268 
00269 /* Allocates the matrix memory for the MNA matrices. */
00270 void circuit::allocMatrixMNA (void) {
00271   freeMatrixMNA ();
00272   if (size > 0) {
00273     MatrixY = new nr_complex_t[size * size];
00274     VectorI = new nr_complex_t[size];
00275     VectorV = new nr_complex_t[size];
00276     if (vsources > 0) {
00277       MatrixB = new nr_complex_t[vsources * size];
00278       MatrixC = new nr_complex_t[vsources * size];
00279       MatrixD = new nr_complex_t[vsources * vsources];
00280       VectorE = new nr_complex_t[vsources];
00281       VectorJ = new nr_complex_t[vsources];
00282     }
00283   }
00284 }
00285 
00286 /* Free()'s all memory used by the MNA matrices. */
00287 void circuit::freeMatrixMNA (void) {
00288   if (MatrixY) { delete[] MatrixY; MatrixY = NULL; }
00289   if (MatrixB) { delete[] MatrixB; MatrixB = NULL; }
00290   if (MatrixC) { delete[] MatrixC; MatrixC = NULL; }
00291   if (MatrixD) { delete[] MatrixD; MatrixD = NULL; }
00292   if (VectorE) { delete[] VectorE; VectorE = NULL; }
00293   if (VectorI) { delete[] VectorI; VectorI = NULL; }
00294   if (VectorV) { delete[] VectorV; VectorV = NULL; }
00295   if (VectorJ) { delete[] VectorJ; VectorJ = NULL; }
00296 }
00297 
00298 /* This function sets the name and port number of one of the circuit's
00299    nodes.  It also tells the appropriate node about the circuit it
00300    belongs to.  The optional 'intern' argument is used to mark a node
00301    to be for internal use only. */
00302 void circuit::setNode (int i, const std::string &n, int intern) {
00303   nodes[i].setName (n);
00304   nodes[i].setCircuit (this);
00305   nodes[i].setPort (i);
00306   nodes[i].setInternal (intern);
00307 }
00308 
00309 // Returns one of the circuit's nodes.
00310 node * circuit::getNode (int i) {
00311   return &nodes[i];
00312 }
00313 
00314 // Sets the subcircuit reference for the circuit object.
00315 void circuit::setSubcircuit (const std::string &n) {
00316   subcircuit = n;
00317 }
00318 
00319 #if DEBUG
00320 // DEBUG function:  Prints the S parameters of this circuit object.
00321 void circuit::print (void) {
00322   for (int i = 0; i < getSize (); i++) {
00323     for (int j = 0; j < getSize (); j++) {
00324       logprint (LOG_STATUS, "%s S%d%d(%+.3e,%+.3e) ", getName (), i, j,
00325                 (double) real (getS (i, j)), (double) imag (getS (i, j)));
00326     }
00327     logprint (LOG_STATUS, "\n");
00328   }
00329 }
00330 #endif /* DEBUG */
00331 
00332 /* Returns the current substrate of the circuit object.  Used for
00333    microstrip components only. */
00334 substrate * circuit::getSubstrate (void) {
00335   return subst;
00336 }
00337 
00338 // Sets the substrate of the circuit object.
00339 void circuit::setSubstrate (substrate * s) {
00340   subst = s;
00341 }
00342 
00343 /* Returns the circuits B-MNA matrix value of the given voltage source
00344    built in the circuit depending on the port number. */
00345 nr_complex_t circuit::getB (int port, int nr) {
00346   return MatrixB[(nr - vsource) * size + port];
00347 }
00348 
00349 /* Sets the circuits B-MNA matrix value of the given voltage source
00350    built in the circuit depending on the port number. */
00351 void circuit::setB (int port, int nr, nr_complex_t z) {
00352   MatrixB[nr * size + port] = z;
00353 }
00354 
00355 /* Returns the circuits C-MNA matrix value of the given voltage source
00356    built in the circuit depending on the port number. */
00357 nr_complex_t circuit::getC (int nr, int port) {
00358   return MatrixC[(nr - vsource) * size + port];
00359 }
00360 
00361 /* Sets the circuits C-MNA matrix value of the given voltage source
00362    built in the circuit depending on the port number. */
00363 void circuit::setC (int nr, int port, nr_complex_t z) {
00364   MatrixC[nr * size + port] = z;
00365 }
00366 
00367 /* Returns the circuits D-MNA matrix value of the given voltage source
00368    built in the circuit. */
00369 nr_complex_t circuit::getD (int r, int c) {
00370   return MatrixD[(r - vsource) * vsources + c - vsource];
00371 }
00372 
00373 /* Sets the circuits D-MNA matrix value of the given voltage source
00374    built in the circuit. */
00375 void circuit::setD (int r, int c, nr_complex_t z) {
00376   MatrixD[r * vsources + c] = z;
00377 }
00378 
00379 /* Returns the circuits E-MNA matrix value of the given voltage source
00380    built in the circuit. */
00381 nr_complex_t circuit::getE (int nr) {
00382   return VectorE[nr - vsource];
00383 }
00384 
00385 /* Sets the circuits E-MNA matrix value of the given voltage source
00386    built in the circuit. */
00387 void circuit::setE (int nr, nr_complex_t z) {
00388   VectorE[nr] = z;
00389 }
00390 
00391 /* Returns the circuits I-MNA matrix value of the current source built
00392    in the circuit. */
00393 nr_complex_t circuit::getI (int port) {
00394   return VectorI[port];
00395 }
00396 
00397 /* Sets the circuits I-MNA matrix value of the current source built in
00398    the circuit depending on the port number. */
00399 void circuit::setI (int port, nr_complex_t z) {
00400   VectorI[port] = z;
00401 }
00402 
00403 /* Modifies the circuits I-MNA matrix value of the current source
00404    built in the circuit depending on the port number. */
00405 void circuit::addI (int port, nr_complex_t i) {
00406   VectorI[port] += i;
00407 }
00408 
00409 /* Same as above with different argument type. */
00410 void circuit::addI (int port, nr_double_t i) {
00411   VectorI[port] += i;
00412 }
00413 
00414 /* Returns the circuits Q-HB vector value. */
00415 nr_complex_t circuit::getQ (int port) {
00416   return VectorQ[port];
00417 }
00418 
00419 /* Sets the circuits Q-HB vector value. */
00420 void circuit::setQ (int port, nr_complex_t q) {
00421   VectorQ[port] = q;
00422 }
00423 
00424 /* Returns the circuits J-MNA matrix value of the given voltage source
00425    built in the circuit. */
00426 nr_complex_t circuit::getJ (int nr) {
00427   return VectorJ[nr];
00428 }
00429 
00430 /* Sets the circuits J-MNA matrix value of the given voltage source
00431    built in the circuit. */
00432 void circuit::setJ (int nr, nr_complex_t z) {
00433   VectorJ[nr - vsource] = z;
00434 }
00435 
00436 // Returns the circuits voltage value at the given port.
00437 nr_complex_t circuit::getV (int port) {
00438   return VectorV[port];
00439 }
00440 
00441 // Sets the circuits voltage value at the given port.
00442 void circuit::setV (int port, nr_complex_t z) {
00443   VectorV[port] = z;
00444 }
00445 
00446 /* Returns the circuits G-MNA matrix value depending on the port
00447    numbers. */
00448 nr_complex_t circuit::getY (int r, int c) {
00449   return MatrixY[r * size + c];
00450 }
00451 
00452 /* Sets the circuits G-MNA matrix value depending on the port
00453    numbers. */
00454 void circuit::setY (int r, int c, nr_complex_t y) {
00455   MatrixY[r * size + c] = y;
00456 }
00457 
00458 /* Modifies the circuits G-MNA matrix value depending on the port
00459    numbers. */
00460 void circuit::addY (int r, int c, nr_complex_t y) {
00461   MatrixY[r * size + c] += y;
00462 }
00463 
00464 /* Same as above with different argument type. */
00465 void circuit::addY (int r, int c, nr_double_t y) {
00466   MatrixY[r * size + c] += y;
00467 }
00468 
00469 /* Returns the circuits G-MNA matrix value depending on the port
00470    numbers. */
00471 nr_double_t circuit::getG (int r, int c) {
00472   return real (MatrixY[r * size + c]);
00473 }
00474 
00475 /* Sets the circuits G-MNA matrix value depending on the port
00476    numbers. */
00477 void circuit::setG (int r, int c, nr_double_t y) {
00478   MatrixY[r * size + c] = y;
00479 }
00480 
00481 /* Returns the circuits C-HB matrix value depending on the port
00482    numbers. */
00483 nr_complex_t circuit::getQV (int r, int c) {
00484   return MatrixQV[r * size + c];
00485 }
00486 
00487 /* Sets the circuits C-HB matrix value depending on the port
00488    numbers. */
00489 void circuit::setQV (int r, int c, nr_complex_t qv) {
00490   MatrixQV[r * size + c] = qv;
00491 }
00492 
00493 /* Returns the circuits GV-HB vector value depending on the port
00494    number. */
00495 nr_complex_t circuit::getGV (int port) {
00496   return VectorGV[port];
00497 }
00498 
00499 /* Sets the circuits GV-HB matrix value depending on the port
00500    number. */
00501 void circuit::setGV (int port, nr_complex_t gv) {
00502   VectorGV[port] = gv;
00503 }
00504 
00505 /* Returns the circuits CV-HB vector value depending on the port
00506    number. */
00507 nr_complex_t circuit::getCV (int port) {
00508   return VectorCV[port];
00509 }
00510 
00511 /* Sets the circuits CV-HB matrix value depending on the port
00512    number. */
00513 void circuit::setCV (int port, nr_complex_t cv) {
00514   VectorCV[port] = cv;
00515 }
00516 
00517 /* This function adds a operating point consisting of a key and a
00518    value to the circuit. */
00519 void circuit::addOperatingPoint (const std::string &n, nr_double_t val) {
00520   operatingpoint p(n, val);
00521   oper.insert ({{n,p}});
00522 }
00523 
00524 /* Returns the requested operating point value which has been
00525    previously added as its double representation.  If there is no such
00526    operating point the function returns zero. */
00527 nr_double_t circuit::getOperatingPoint (const std::string &n) {
00528   const auto it = oper.find(n);
00529   if (it != oper.end())
00530     return (*it).second.getValue();
00531   return 0.0;
00532 }
00533 
00534 /* This function sets the operating point specified by the given name
00535    to the value passed to the function. */
00536 void circuit::setOperatingPoint (const std::string& n, nr_double_t val) {
00537   auto it = oper.find(n);
00538   if (it != oper.end())
00539     (*it).second.setValue (val);
00540   else
00541     addOperatingPoint (n, val);
00542 }
00543 
00544 /* The function checks whether the circuit has got a certain operating
00545    point value.  If so it returns non-zero, otherwise it returns
00546    zero. */
00547 int circuit::hasOperatingPoint (const std::string& n) {
00548   return oper.find(n) != oper.end();
00549 }
00550 
00551 /* This function adds a characteristic point consisting of a key and a
00552    value to the circuit. */
00553 void circuit::addCharacteristic (const std::string &n, nr_double_t val) {
00554   characteristic p(n, val);
00555   charac.insert({{n, p}});
00556 }
00557 
00558 /* Returns the requested characteristic value which has been
00559    previously added as its double representation.  If there is no such
00560    characteristic value the function returns zero. */
00561 nr_double_t circuit::getCharacteristic (const std::string &n) {
00562   const auto it = charac.find(n);
00563   if (it != charac.end())
00564     return (*it).second.getValue ();
00565   return 0.0;
00566 }
00567 
00568 /* This function sets the characteristic value specified by the given
00569    name to the value passed to the function. */
00570 void circuit::setCharacteristic (const std::string &n, nr_double_t val) {
00571   auto it = charac.find(n);
00572   if (it != charac.end())
00573     (*it).second.setValue (val);
00574   else
00575     addCharacteristic (n, val);
00576 }
00577 
00578 /* The function checks whether the circuit has got a certain
00579    characteristic value.  If so it returns non-zero, otherwise it
00580    returns zero. */
00581 int circuit::hasCharacteristic (const std::string & n) {
00582   return charac.find (n) != charac.end();
00583 }
00584 
00585 // Returns the S-parameter at the given matrix position.
00586 nr_complex_t circuit::getS (int x, int y) {
00587   return MatrixS[y + x * size];
00588 }
00589 
00590 // Sets the S-parameter at the given matrix position.
00591 void circuit::setS (int x, int y, nr_complex_t z) {
00592   MatrixS[y + x * size] = z;
00593 }
00594 
00595 // Returns the noise-correlation-parameter at the given matrix position.
00596 nr_complex_t circuit::getN (int r, int c) {
00597   return MatrixN[c + r * (size + nsources)];
00598 }
00599 
00600 // Sets the noise-correlation-parameter at the given matrix position.
00601 void circuit::setN (int r, int c, nr_complex_t z) {
00602   MatrixN[c + r * (size + nsources)] = z;
00603 }
00604 
00605 // Returns the number of internal voltage sources for DC analysis.
00606 int circuit::getVoltageSources (void) {
00607   return vsources;
00608 }
00609 
00610 // Sets the number of internal voltage sources for DC analysis.
00611 void circuit::setVoltageSources (int s) {
00612   assert (s >= 0);
00613   vsources = s;
00614 }
00615 
00616 // Returns the number of internal noise sources for AC analysis.
00617 int circuit::getNoiseSources (void) {
00618   return nsources;
00619 }
00620 
00621 // Sets the number of internal noise voltage sources for AC analysis.
00622 void circuit::setNoiseSources (int s) {
00623   assert (s >= 0);
00624   nsources = s;
00625 }
00626 
00627 /* The function returns an internal node or circuit name with the
00628    given prefix and based on the given circuits name.  The caller is
00629    responsible to free() the returned string. */
00630 std::string circuit::createInternal (const std::string &prefix, const std::string &obj) {
00631   return "_"+prefix+"#"+obj;
00632 }
00633 
00634 /* Creates an internal node given the node number as well as the name
00635    suffix.  An appropriate node name is constructed from the circuits
00636    name and the suffix. */
00637 void circuit::setInternalNode (int node, const std::string &suffix) {
00638   const std::string &n = createInternal (getName (), suffix);
00639   setNode (node, n, 1);
00640 }
00641 
00642 /* This function copies the matrix elements inside the given matrix to
00643    the internal S-parameter matrix of the circuit. */
00644 void circuit::setMatrixS (matrix s) {
00645   int r = s.getRows ();
00646   int c = s.getCols ();
00647   // copy matrix elements
00648   if (r > 0 && c > 0 && r * c == size * size) {
00649     memcpy (MatrixS, s.getData (), sizeof (nr_complex_t) * r * c);
00650   }
00651 }
00652 
00653 /* The function return a matrix containing the S-parameters of the
00654    circuit. */
00655 matrix circuit::getMatrixS (void) {
00656   matrix res (size);
00657   for(unsigned int i=0; i < size; ++i)
00658     for(unsigned int j=0; j < size; ++j)
00659       res(i,j) = MatrixS[i*size + j];
00660   return res;
00661 }
00662 
00663 /* This function copies the matrix elements inside the given matrix to
00664    the internal noise correlation matrix of the circuit. */
00665 void circuit::setMatrixN (matrix n) {
00666   int r = n.getRows ();
00667   int c = n.getCols ();
00668   // copy matrix elements
00669   if (r > 0 && c > 0 && r * c == size * size) {
00670     memcpy (MatrixN, n.getData (), sizeof (nr_complex_t) * r * c);
00671   }
00672 }
00673 
00674 /* The function return a matrix containing the noise correlation
00675    matrix of the circuit. */
00676 matrix circuit::getMatrixN (void) {
00677   matrix res (size);
00678   for(unsigned int i=0; i < size; ++i)
00679     for(unsigned int j=0; j < size; ++j)
00680       res(i,j) = MatrixN[i*size + j];
00681   return res;
00682 }
00683 
00684 /* This function copies the matrix elements inside the given matrix to
00685    the internal G-MNA matrix of the circuit. */
00686 void circuit::setMatrixY (matrix y) {
00687   int r = y.getRows ();
00688   int c = y.getCols ();
00689   // copy matrix elements
00690   if (r > 0 && c > 0 && r * c == size * size) {
00691     memcpy (MatrixY, y.getData (), sizeof (nr_complex_t) * r * c);
00692   }
00693 }
00694 
00695 /* The function return a matrix containing the G-MNA matrix of the
00696    circuit. */
00697 matrix circuit::getMatrixY (void) {
00698   matrix res (size);
00699   for(unsigned int i=0; i < size; ++i)
00700     for(unsigned int j=0; j < size; ++j)
00701       res(i,j) = MatrixY[i*size + j];
00702   return res;
00703 }
00704 
00705 // The function cleans up the B-MNA matrix entries.
00706 void circuit::clearB (void) {
00707   memset (MatrixB, 0, sizeof (nr_complex_t) * size * vsources);
00708 }
00709 
00710 // The function cleans up the C-MNA matrix entries.
00711 void circuit::clearC (void) {
00712   memset (MatrixC, 0, sizeof (nr_complex_t) * size * vsources);
00713 }
00714 
00715 // The function cleans up the D-MNA matrix entries.
00716 void circuit::clearD (void) {
00717   memset (MatrixD, 0, sizeof (nr_complex_t) * vsources * vsources);
00718 }
00719 
00720 // The function cleans up the E-MNA matrix entries.
00721 void circuit::clearE (void) {
00722   memset (VectorE, 0, sizeof (nr_complex_t) * vsources);
00723 }
00724 
00725 // The function cleans up the J-MNA matrix entries.
00726 void circuit::clearJ (void) {
00727   memset (VectorJ, 0, sizeof (nr_complex_t) * vsources);
00728 }
00729 
00730 // The function cleans up the I-MNA matrix entries.
00731 void circuit::clearI (void) {
00732   memset (VectorI, 0, sizeof (nr_complex_t) * size);
00733 }
00734 
00735 // The function cleans up the V-MNA matrix entries.
00736 void circuit::clearV (void) {
00737   memset (VectorV, 0, sizeof (nr_complex_t) * size);
00738 }
00739 
00740 // The function cleans up the G-MNA matrix entries.
00741 void circuit::clearY (void) {
00742   memset (MatrixY, 0, sizeof (nr_complex_t) * size * size);
00743 }
00744 
00745 /* This function can be used by several components in order to place
00746    the n-th voltage source between node 'pos' and node 'neg' with the
00747    given value.  Remember to indicate this voltage source using the
00748    function setVoltageSources(). */
00749 void circuit::voltageSource (int n, int pos, int neg, nr_double_t value) {
00750   setC (n, pos, +1.0); setC (n, neg, -1.0);
00751   setB (pos, n, +1.0); setB (neg, n, -1.0);
00752   setD (n, n, 0.0);
00753   setE (n, value);
00754 }
00755 
00756 /* The function runs the necessary calculation in order to perform a
00757    single integration step of a voltage controlled capacitance placed
00758    in between the given nodes.  It is assumed that the appropiate
00759    charge only depends on the voltage between these nodes. */
00760 void circuit::transientCapacitance (int qstate, int pos, int neg,
00761                                     nr_double_t cap, nr_double_t voltage,
00762                                     nr_double_t charge) {
00763   nr_double_t g, i;
00764   int cstate = qstate + 1;
00765   setState (qstate, charge);
00766   integrate (qstate, cap, g, i);
00767   addY (pos, pos, +g); addY (neg, neg, +g);
00768   addY (pos, neg, -g); addY (neg, pos, -g);
00769   i = pol * (getState (cstate) - g * voltage);
00770   addI (pos , -i);
00771   addI (neg , +i);
00772 }
00773 
00774 /* This is the one-node variant of the above function.  It performs
00775    the same steps for a single node related to ground. */
00776 void circuit::transientCapacitance (int qstate, int node, nr_double_t cap,
00777                                     nr_double_t voltage, nr_double_t charge) {
00778   nr_double_t g, i;
00779   int cstate = qstate + 1;
00780   setState (qstate, charge);
00781   integrate (qstate, cap, g, i);
00782   addY (node, node, +g);
00783   i = pol * (getState (cstate) - g * voltage);
00784   addI (node , -i);
00785 }
00786 
00787 /* The function performs a single integration step of the given charge
00788    located between the given nodes.  It saves the current
00789    contributions of the charge itself and considers the polarity of
00790    the circuit. */
00791 void circuit::transientCapacitanceQ (int qstate, int qpos, int qneg,
00792                                      nr_double_t charge) {
00793   nr_double_t unused, i;
00794   int cstate = qstate + 1;
00795   setState (qstate, charge);
00796   integrate (qstate, 0, unused, unused);
00797   i = pol * getState (cstate);
00798   addI (qpos , -i);
00799   addI (qneg , +i);
00800 }
00801 
00802 /* This is the one-node variant of the above function.  It performs
00803    the same steps for a single node related to ground. */
00804 void circuit::transientCapacitanceQ (int qstate, int qpos,
00805                                      nr_double_t charge) {
00806   nr_double_t unused, i;
00807   int cstate = qstate + 1;
00808   setState (qstate, charge);
00809   integrate (qstate, 0, unused, unused);
00810   i = pol * getState (cstate);
00811   addI (qpos , -i);
00812 }
00813 
00814 /* This function stores the Jacobian entries due to the C = dQ/dV
00815    value.  The nodes where the charge is located as well as those of
00816    the voltage dependency, the appropiate capacitance value and the
00817    voltage across the the controlling branch must be given.  It also
00818    saves the current contributions which are necessary for the NR
00819    iteration and considers the polarity of the circuit. */
00820 void circuit::transientCapacitanceC (int qpos, int qneg, int vpos, int vneg,
00821                                      nr_double_t cap, nr_double_t voltage) {
00822   nr_double_t g, i;
00823   conductor (cap, g);
00824   addY (qpos, vpos, +g); addY (qneg, vneg, +g);
00825   addY (qpos, vneg, -g); addY (qneg, vpos, -g);
00826   i = pol * (g * voltage);
00827   addI (qpos , +i);
00828   addI (qneg , -i);
00829 }
00830 
00831 /* This is the one-node variant of the transientCapacitanceC()
00832    function.  It performs the same steps for a single charge node
00833    related to ground. */
00834 void circuit::transientCapacitanceC2V (int qpos, int vpos, int vneg,
00835                                        nr_double_t cap, nr_double_t voltage) {
00836   nr_double_t g, i;
00837   conductor (cap, g);
00838   addY (qpos, vpos, +g);
00839   addY (qpos, vneg, -g);
00840   i = pol * (g * voltage);
00841   addI (qpos , +i);
00842 }
00843 
00844 /* This is the one-node variant of the transientCapacitanceC()
00845    function.  It performs the same steps for a single voltage node
00846    related to ground. */
00847 void circuit::transientCapacitanceC2Q (int qpos, int qneg, int vpos,
00848                                        nr_double_t cap, nr_double_t voltage) {
00849   nr_double_t g, i;
00850   conductor (cap, g);
00851   addY (qpos, vpos, +g); addY (qneg, vpos, -g);
00852   i = pol * (g * voltage);
00853   addI (qpos , +i);
00854   addI (qneg , -i);
00855 }
00856 
00857 /* This is the one-node variant of the transientCapacitanceC()
00858    function.  It performs the same steps for a single voltage node and
00859    charge node related to ground. */
00860 void circuit::transientCapacitanceC (int qpos, int vpos,
00861                                      nr_double_t cap, nr_double_t voltage) {
00862   nr_double_t g, i;
00863   conductor (cap, g);
00864   addY (qpos, vpos, +g);
00865   i = pol * (g * voltage);
00866   addI (qpos , +i);
00867 }
00868 
00869 // The function initializes the histories of a circuit having the given age.
00870 void circuit::initHistory (nr_double_t age) {
00871   nHistories = getSize () + getVoltageSources ();
00872   histories = new history[nHistories];
00873   setHistoryAge (age);
00874 }
00875 
00876 // Sets the age of all circuit histories
00877 void circuit::setHistoryAge (nr_double_t age) {
00878   for (int i = 0; i < nHistories; i++)
00879   {
00880     histories[i].setAge (age);
00881   }
00882 }
00883 
00884 
00885 
00886 // The function deletes the histories for the transient analysis.
00887 void circuit::deleteHistory (void) {
00888   if (histories != NULL) {
00889     delete[] histories;
00890     histories = NULL;
00891   }
00892   setHistory (false);
00893 }
00894 
00895 // Truncates the transient analysis history (i.e. removes values newer
00896 // newer than time tcut).
00897 void circuit::truncateHistory (nr_double_t tcut) {
00898   if (histories != NULL) {
00899     for (int i = 0; i < nHistories; i++)
00900     {
00901       histories[i].truncate (tcut);
00902     }
00903   }
00904 }
00905 
00906 // Appends a history value.
00907 void circuit::appendHistory (int n, nr_double_t val) {
00908   histories[n].push_back (val);
00909 }
00910 
00911 // Returns the required age of the history.
00912 nr_double_t circuit::getHistoryAge (void) {
00913   if (histories) return histories[0].getAge ();
00914   return 0.0;
00915 }
00916 
00917 // Returns size of the history
00918 int circuit::getHistorySize (void) {
00919   return histories[0].size ();
00920 }
00921 
00922 // Returns the time with the specified index
00923 nr_double_t circuit::getHistoryTFromIndex (int idx)
00924 {
00925   return histories[0].getTfromidx (idx);
00926 }
00927 
00928 /* This function should be used to apply the time vector history to
00929    the value histories of a circuit. */
00930 void circuit::applyHistory (history * h) {
00931   for (int i = 0; i < nHistories; i++)
00932   {
00933     histories[i].apply(*h);
00934   }
00935 
00936 }
00937 
00938 // Returns voltage at the given time for the given node.
00939 nr_double_t circuit::getV (int port, nr_double_t t) {
00940   return histories[port].nearest (t);
00941 }
00942 
00943 // Returns voltage at the given index from the history for the given node.
00944 nr_double_t circuit::getV (int port, int idx) {
00945   return histories[port].getValfromidx (idx);
00946 }
00947 
00948 // Returns current at the given time for the given voltage source.
00949 nr_double_t circuit::getJ (int nr, nr_double_t t) {
00950   return histories[nr + getSize ()].nearest (t);
00951 }
00952 
00953 } // namespace qucs