LCOV - code coverage report
Current view: top level - src - spsolver.cpp (source / functions) Hit Total Coverage
Test: qucs-core-0.0.19 Code Coverage Lines: 463 500 92.6 %
Date: 2015-01-05 16:01:02 Functions: 27 35 77.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 533 964 55.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * spsolver.cpp - S-parameter solver class implementation
       3                 :            :  *
       4                 :            :  * Copyright (C) 2003-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                 :            : 
      33                 :            : #include "logging.h"
      34                 :            : #include "complex.h"
      35                 :            : #include "object.h"
      36                 :            : #include "node.h"
      37                 :            : #include "circuit.h"
      38                 :            : #include "strlist.h"
      39                 :            : #include "vector.h"
      40                 :            : #include "matvec.h"
      41                 :            : #include "dataset.h"
      42                 :            : #include "net.h"
      43                 :            : #include "analysis.h"
      44                 :            : #include "sweep.h"
      45                 :            : #include "nodelist.h"
      46                 :            : #include "netdefs.h"
      47                 :            : #include "characteristic.h"
      48                 :            : #include "spsolver.h"
      49                 :            : #include "constants.h"
      50                 :            : #include "components/component_id.h"
      51                 :            : #include "components/tee.h"
      52                 :            : #include "components/open.h"
      53                 :            : #include "components/itrafo.h"
      54                 :            : #include "components/cross.h"
      55                 :            : #include "components/ground.h"
      56                 :            : 
      57                 :            : /* Evolved optimization flags. */
      58                 :            : #define USE_GROUNDS 1   // use extra grounds ?
      59                 :            : #define USE_CROSSES 1   // use additional cross connectors ?
      60                 :            : #define SORTED_LIST 1   // use sorted node list?
      61                 :            : 
      62                 :            : #define TINYS (NR_TINY * 1.235) // 'tiny' value for singularities
      63                 :            : 
      64                 :            : namespace qucs {
      65                 :            : 
      66                 :            : // Constructor creates an unnamed instance of the spsolver class.
      67                 :         18 : spsolver::spsolver () : analysis () {
      68                 :         18 :   type = ANALYSIS_SPARAMETER;
      69                 :         18 :   swp = NULL;
      70                 :         18 :   saveCVs = 0;
      71                 :         18 :   noise = 0;
      72                 :         18 :   nlist = NULL;
      73                 :         18 :   tees = crosses = opens = grounds = 0;
      74                 :         18 :   gnd = NULL;
      75                 :         18 : }
      76                 :            : 
      77                 :            : // Constructor creates a named instance of the spsolver class.
      78                 :          0 : spsolver::spsolver (char * n) : analysis (n) {
      79                 :          0 :   type = ANALYSIS_SPARAMETER;
      80                 :          0 :   swp = NULL;
      81                 :          0 :   saveCVs = 0;
      82                 :          0 :   noise = 0;
      83                 :          0 :   nlist = NULL;
      84                 :          0 :   tees = crosses = opens = grounds = 0;
      85                 :          0 :   gnd = NULL;
      86                 :          0 : }
      87                 :            : 
      88                 :            : // Destructor deletes the spsolver class object.
      89                 :         18 : spsolver::~spsolver () {
      90 [ +  - ][ +  - ]:         18 :   if (swp) delete swp;
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
      91 [ -  + ][ #  # ]:         18 :   if (nlist) delete nlist;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      92 [ -  + ][ #  # ]:         36 : }
      93                 :            : 
      94                 :            : /* The copy constructor creates a new instance of the spsolver class
      95                 :            :    based on the given spsolver object. */
      96                 :          0 : spsolver::spsolver (spsolver & n) : analysis (n) {
      97                 :          0 :   tees = n.tees;
      98                 :          0 :   crosses = n.crosses;
      99                 :          0 :   opens = n.opens;
     100                 :          0 :   grounds = n.grounds;
     101                 :          0 :   noise = n.noise;
     102                 :          0 :   saveCVs = n.saveCVs;
     103 [ #  # ][ #  # ]:          0 :   swp = n.swp ? new sweep (*n.swp) : NULL;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     104 [ #  # ][ #  # ]:          0 :   nlist = n.nlist ? new nodelist (*n.nlist) : NULL;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     105                 :          0 :   gnd = n.gnd;
     106                 :          0 : }
     107                 :            : 
     108                 :            : /* This function joins two nodes of a single circuit (interconnected
     109                 :            :    nodes) and returns the resulting circuit. */
     110                 :      13105 : circuit * spsolver::interconnectJoin (node * n1, node * n2) {
     111                 :            : 
     112                 :      13105 :   circuit * s = n1->getCircuit ();
     113 [ +  - ][ +  - ]:      13105 :   circuit * result = new circuit (s->getSize () - 2);
     114                 :      13105 :   nr_complex_t p;
     115                 :            : 
     116                 :            :   // allocate S-parameter and noise corellation matrices
     117 [ +  - ][ +  + ]:      13105 :   result->initSP (); if (noise) result->initNoiseSP ();
                 [ +  - ]
     118                 :            : 
     119                 :            :   // interconnected port numbers
     120                 :      13105 :   int k = n1->getPort (), l = n2->getPort ();
     121                 :            : 
     122                 :            :   // denominator needs to be calculated only once
     123 [ +  - ][ +  - ]:      13105 :   nr_complex_t d = (1.0 - s->getS (k, l)) * (1.0 - s->getS (l, k)) -
     124 [ +  - ][ +  - ]:      26210 :     s->getS (k, k) * s->getS (l, l);
           [ +  -  +  - ]
                 [ +  - ]
     125                 :            : 
     126                 :            :   // avoid singularity when two full reflective ports are interconnected
     127 [ +  - ][ -  + ]:      13105 :   nr_double_t tiny1 = (d == 0) ? 1.0 - TINYS : 1.0;
     128                 :      13105 :   nr_double_t tiny2 = tiny1 * tiny1;
     129                 :      13105 :   nr_double_t tiny3 = tiny1 * tiny2;
     130 [ +  - ][ +  - ]:      13105 :   d = (1.0 - s->getS (k, l) * tiny1) * (1.0 - s->getS (l, k) * tiny1) -
     131 [ +  - ][ +  - ]:      26210 :     s->getS (k, k) * s->getS (l, l) * tiny2;
         [ +  - ][ +  - ]
                 [ +  - ]
     132                 :            : 
     133                 :            :   int j2; // column index for resulting matrix
     134                 :            :   int i2; // row index for resulting matrix
     135                 :            :   int j1; // column index for S matrix
     136                 :            :   int i1; // row index for S matrix
     137                 :            : 
     138                 :            :   // handle single S block only
     139                 :      13105 :   i2 = j2 = 0;
     140         [ +  + ]:      80405 :   for (j1 = 0; j1 < s->getSize (); j1++) {
     141                 :            : 
     142                 :            :     // skip connected node
     143 [ +  + ][ +  + ]:      67300 :     if (j1 == k || j1 == l) continue;
     144                 :            : 
     145                 :            :     // assign node name of resulting circuit
     146 [ +  - ][ +  - ]:      41090 :     result->setNode (j2, s->getNode(j1)->getName ());
     147                 :            : 
     148                 :            :     // inside S only
     149         [ +  + ]:     272722 :     for (i1 = 0; i1 < s->getSize (); i1++) {
     150                 :            : 
     151                 :            :       // skip connected node
     152 [ +  + ][ +  + ]:     231632 :       if (i1 == k || i1 == l) continue;
     153                 :            : 
     154                 :            :       // compute S'ij
     155         [ +  - ]:     149452 :       p = s->getS (i1, j1);
     156                 :            :       p +=
     157 [ +  - ][ +  - ]:     149452 :         (s->getS (k, j1) * s->getS (i1, l) * (1.0 - s->getS (l, k)) * tiny3 +
         [ +  - ][ +  - ]
                 [ +  - ]
     158 [ +  - ][ +  - ]:     298904 :          s->getS (l, j1) * s->getS (i1, k) * (1.0 - s->getS (k, l)) * tiny3 +
         [ +  - ][ +  - ]
                 [ +  - ]
     159 [ +  - ][ +  - ]:     298904 :          s->getS (k, j1) * s->getS (l, l) * s->getS (i1, k) * tiny3 +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     160 [ +  - ][ +  - ]:     298904 :          s->getS (l, j1) * s->getS (k, k) * s->getS (i1, l) * tiny3) / d;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     161         [ +  - ]:     149452 :       result->setS (i2++, j2, p);
     162                 :            :     }
     163                 :            : 
     164                 :            :     // next column
     165                 :      41090 :     j2++; i2 = 0;
     166                 :            :   }
     167                 :      13105 :   return result;
     168                 :            : }
     169                 :            : 
     170                 :            : /* This function joins two nodes of two different circuits (connected
     171                 :            :    nodes) and returns the resulting circuit. */
     172                 :     111570 : circuit * spsolver::connectedJoin (node * n1, node * n2) {
     173                 :            : 
     174                 :     111570 :   circuit * s = n1->getCircuit ();
     175                 :     111570 :   circuit * t = n2->getCircuit ();
     176 [ +  - ][ +  - ]:     111570 :   circuit * result = new circuit (s->getSize () + t->getSize () - 2);
     177                 :     111570 :   nr_complex_t p;
     178                 :            : 
     179                 :            :   // allocate S-parameter and noise corellation matrices
     180 [ +  - ][ +  + ]:     111570 :   result->initSP (); if (noise) result->initNoiseSP ();
                 [ +  - ]
     181                 :            : 
     182                 :            :   // connected port numbers
     183                 :     111570 :   int k = n1->getPort (), l = n2->getPort ();
     184                 :            : 
     185                 :            :   // denominator needs to be calculated only once
     186 [ +  - ][ +  - ]:     111570 :   nr_complex_t d = 1.0 - s->getS (k, k) * t->getS (l, l);
                 [ +  - ]
     187                 :            : 
     188                 :            :   // avoid singularity when two full reflective ports are connected
     189 [ +  - ][ -  + ]:     111570 :   nr_double_t tiny1 = (d == 0) ? 1.0 - TINYS : 1.0;
     190                 :     111570 :   nr_double_t tiny2 = tiny1 * tiny1;
     191                 :     111570 :   nr_double_t tiny3 = tiny1 * tiny2;
     192 [ +  - ][ +  - ]:     111570 :   d = 1.0 - s->getS (k, k) * t->getS (l, l) * tiny2;
                 [ +  - ]
     193                 :            : 
     194                 :            :   int j2; // column index for resulting matrix
     195                 :            :   int i2; // row index for resulting matrix
     196                 :            :   int j1; // column index for S matrix
     197                 :            :   int i1; // row index for S matrix
     198                 :            : 
     199                 :            :   // handle S block
     200                 :     111570 :   i2 = j2 = 0;
     201         [ +  + ]:     374868 :   for (j1 = 0; j1 < s->getSize (); j1++) {
     202                 :            : 
     203                 :            :     // skip connected node
     204         [ +  + ]:     263298 :     if (j1 == k) continue;
     205                 :            : 
     206                 :            :     // assign node name of resulting circuit
     207 [ +  - ][ +  - ]:     151728 :     result->setNode (j2, s->getNode(j1)->getName());
     208                 :            : 
     209                 :            :     // inside S
     210         [ +  + ]:     620110 :     for (i1 = 0; i1 < s->getSize (); i1++) {
     211                 :            : 
     212                 :            :       // skip connected node
     213         [ +  + ]:     468382 :       if (i1 == k) continue;
     214                 :            : 
     215                 :            :       // compute S'ij
     216         [ +  - ]:     316654 :       p  = s->getS (i1, j1);
     217 [ +  - ][ +  - ]:     316654 :       p += s->getS (k, j1) * t->getS (l, l) * s->getS (i1, k) * tiny3 / d;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     218         [ +  - ]:     316654 :       result->setS (i2++, j2, p);
     219                 :            :     }
     220                 :            : 
     221                 :            :     // across S and T
     222         [ +  + ]:     475805 :     for (i1 = 0; i1 < t->getSize (); i1++) {
     223                 :            : 
     224                 :            :       // skip connected node
     225         [ +  + ]:     324077 :       if (i1 == l) continue;
     226                 :            : 
     227                 :            :       // compute S'mj
     228 [ +  - ][ +  - ]:     172349 :       p = s->getS (k, j1) * t->getS (i1, l) * tiny2 / d;
         [ +  - ][ +  - ]
     229         [ +  - ]:     172349 :       result->setS (i2++, j2, p);
     230                 :            :     }
     231                 :            :     // next column
     232                 :     151728 :     j2++; i2 = 0;
     233                 :            :   }
     234                 :            : 
     235                 :            :   // handle T block
     236         [ +  + ]:     375936 :   for (j1 = 0; j1 < t->getSize (); j1++) {
     237                 :            : 
     238                 :            :     // skip connected node
     239         [ +  + ]:     264366 :     if (j1 == l) continue;
     240                 :            : 
     241                 :            :     // assign node name of resulting circuit
     242 [ +  - ][ +  - ]:     152796 :     result->setNode (j2, t->getNode(j1)->getName ());
     243                 :            : 
     244                 :            :     // across T and S
     245         [ +  + ]:     477941 :     for (i1 = 0; i1 < s->getSize (); i1++) {
     246                 :            : 
     247                 :            :       // skip connected node
     248         [ +  + ]:     325145 :       if (i1 == k) continue;
     249                 :            : 
     250                 :            :       // compute S'mj
     251 [ +  - ][ +  - ]:     172349 :       p = t->getS (l, j1) * s->getS (i1, k) * tiny2 / d;
         [ +  - ][ +  - ]
     252         [ +  - ]:     172349 :       result->setS (i2++, j2, p);
     253                 :            :     }
     254                 :            : 
     255                 :            :     // inside T
     256         [ +  + ]:     671972 :     for (i1 = 0; i1 < t->getSize (); i1++) {
     257                 :            : 
     258                 :            :       // skip connected node
     259         [ +  + ]:     519176 :       if (i1 == l) continue;
     260                 :            : 
     261                 :            :       // compute S'ij
     262         [ +  - ]:     366380 :       p  = t->getS (i1, j1);
     263 [ +  - ][ +  - ]:     366380 :       p += t->getS (l, j1) * s->getS (k, k) * t->getS (i1, l) * tiny3 / d;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     264         [ +  - ]:     366380 :       result->setS (i2++, j2, p);
     265                 :            :     }
     266                 :            : 
     267                 :            :     // next column
     268                 :     152796 :     j2++; i2 = 0;
     269                 :            :   }
     270                 :            : 
     271                 :     111570 :   return result;
     272                 :            : }
     273                 :            : 
     274                 :            : /* This function joins the two given nodes of a single circuit
     275                 :            :    (interconnected nodes) and modifies the resulting circuit
     276                 :            :    appropriately. */
     277                 :       1173 : void spsolver::noiseInterconnect (circuit * result, node * n1, node * n2) {
     278                 :            : 
     279                 :       1173 :   circuit * c = n1->getCircuit ();
     280                 :       1173 :   nr_complex_t p, k1, k2, k3, k4;
     281                 :            : 
     282                 :            :   // interconnected port numbers
     283                 :       1173 :   int k = n1->getPort (), l = n2->getPort ();
     284                 :            : 
     285                 :            :   // denominator needs to be calculated only once
     286 [ +  - ][ +  - ]:       1173 :   nr_complex_t t = (1.0 - c->getS (k, l)) * (1.0 - c->getS (l, k)) -
     287 [ +  - ][ +  - ]:       2346 :     c->getS (k, k) * c->getS (l, l);
           [ +  -  +  - ]
                 [ +  - ]
     288                 :            : 
     289                 :            :   // avoid singularity when two full reflective ports are interconnected
     290 [ +  - ][ -  + ]:       1173 :   nr_double_t tiny1 = (t == 0) ? 1.0 - TINYS : 1.0;
     291                 :       1173 :   nr_double_t tiny2 = tiny1 * tiny1;
     292 [ +  - ][ +  - ]:       1173 :   t = (1.0 - c->getS (k, l) * tiny1) * (1.0 - c->getS (l, k) * tiny1) -
     293 [ +  - ][ +  - ]:       2346 :     c->getS (k, k) * c->getS (l, l) * tiny2;
         [ +  - ][ +  - ]
                 [ +  - ]
     294                 :            : 
     295                 :            :   int j2; // column index for resulting matrix
     296                 :            :   int i2; // row index for resulting matrix
     297                 :            :   int j1; // column index for S matrix
     298                 :            :   int i1; // row index for S matrix
     299                 :            : 
     300                 :            :   // handle single C block only
     301                 :       1173 :   i2 = j2 = 0;
     302         [ +  + ]:      10017 :   for (j1 = 0; j1 < c->getSize (); j1++) {
     303                 :            : 
     304                 :            :     // skip connected node
     305 [ +  + ][ +  + ]:       8844 :     if (j1 == k || j1 == l) continue;
     306                 :            : 
     307                 :            :     // inside C only
     308         [ +  - ]:      31594 :     for (i1 = 0; i1 < c->getSize (); i1++) {
     309                 :            : 
     310                 :            :       // skip connected node
     311 [ +  + ][ +  + ]:      31594 :       if (i1 == k || i1 == l) continue;
     312                 :            : 
     313 [ +  - ][ +  - ]:      24780 :       k1 = (c->getS (i1, l) * (1.0 - c->getS (l, k)) +
     314 [ +  - ][ +  - ]:      49560 :             c->getS (l, l) * c->getS (i1, k)) * tiny2 / t;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     315 [ +  - ][ +  - ]:      24780 :       k2 = (c->getS (i1, k) * (1.0 - c->getS (k, l)) +
     316 [ +  - ][ +  - ]:      49560 :             c->getS (k, k) * c->getS (i1, l)) * tiny2 / t;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     317 [ +  - ][ +  - ]:      24780 :       k3 = (c->getS (j1, l) * (1.0 - c->getS (l, k)) +
     318 [ +  - ][ +  - ]:      49560 :             c->getS (l, l) * c->getS (j1, k)) * tiny2 / t;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     319 [ +  - ][ +  - ]:      24780 :       k4 = (c->getS (j1, k) * (1.0 - c->getS (k, l)) +
     320 [ +  - ][ +  - ]:      49560 :             c->getS (k, k) * c->getS (j1, l)) * tiny2 / t;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     321                 :            : 
     322                 :            :       p =
     323 [ +  - ][ +  - ]:      24780 :         c->getN (i1, j1) + c->getN (k, j1) * k1 + c->getN (l, j1) * k2 +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     324 [ +  - ][ +  - ]:      24780 :         conj (k3) * (c->getN (i1, k) + c->getN (k, k) * k1 +
                 [ +  - ]
     325 [ +  - ][ +  - ]:      74340 :                      c->getN (l, k) * k2) +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     326 [ +  - ][ +  - ]:      24780 :         conj (k4) * (c->getN (i1, l) + c->getN (k, l) * k1 +
                 [ +  - ]
     327 [ +  - ][ +  - ]:      74340 :                      c->getN (l, l) * k2);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     328         [ +  - ]:      24780 :       result->setN (i2, j2, p);
     329                 :            : 
     330         [ +  + ]:      24780 :       if (i2 >= j2) break; // the other half need not be computed
     331         [ +  - ]:      18282 :       result->setN (j2, i2, conj (p));
     332                 :      18282 :       i2++;
     333                 :            :     }
     334                 :            : 
     335                 :            :     // next column
     336                 :       6498 :     j2++; i2 = 0;
     337                 :            :   }
     338                 :       1173 : }
     339                 :            : 
     340                 :            : 
     341                 :            : /* The following function joins two nodes of two different circuits
     342                 :            :    and saves the noise wave correlation matrix in the resulting
     343                 :            :    circuit. */
     344                 :       7898 : void spsolver::noiseConnect (circuit * result, node * n1, node * n2) {
     345                 :       7898 :   circuit * c = n1->getCircuit ();
     346                 :       7898 :   circuit * d = n2->getCircuit ();
     347                 :       7898 :   nr_complex_t p;
     348                 :            : 
     349                 :            :   // connected port numbers
     350                 :       7898 :   int k = n1->getPort (), l = n2->getPort ();
     351                 :            : 
     352                 :            :   // denominator needs to be calculated only once
     353 [ +  - ][ +  - ]:       7898 :   nr_complex_t t = 1.0 - c->getS (k, k) * d->getS (l, l);
                 [ +  - ]
     354                 :            : 
     355                 :            :   // avoid singularity when two full reflective ports are connected
     356 [ +  - ][ -  + ]:       7898 :   nr_double_t tiny1 = (t == 0) ? 1.0 - TINYS : 1.0;
     357                 :       7898 :   nr_double_t tiny2 = tiny1 * tiny1;
     358                 :       7898 :   nr_double_t tiny3 = tiny1 * tiny2;
     359                 :       7898 :   nr_double_t tiny4 = tiny1 * tiny3;
     360 [ +  - ][ +  - ]:       7898 :   t = 1.0 - c->getS (k, k) * d->getS (l, l) * tiny2;
                 [ +  - ]
     361                 :            : 
     362                 :            :   int j2; // column index for resulting matrix
     363                 :            :   int i2; // row index for resulting matrix
     364                 :            :   int j1; // column index for S matrix
     365                 :            :   int i1; // row index for S matrix
     366                 :            : 
     367                 :            :   // handle C block
     368                 :       7898 :   i2 = j2 = 0;
     369         [ +  + ]:      27925 :   for (j1 = 0; j1 < c->getSize (); j1++) {
     370                 :            : 
     371                 :            :     // skip connected node
     372         [ +  + ]:      20027 :     if (j1 == k) continue;
     373                 :            : 
     374                 :            :     // inside C
     375         [ +  - ]:      27274 :     for (i1 = 0; i1 < c->getSize (); i1++) {
     376                 :            : 
     377                 :            :       // skip connected node
     378         [ +  + ]:      27274 :       if (i1 == k) continue;
     379                 :            : 
     380                 :            :       // compute C'ij
     381                 :            :       p = c->getN (i1, j1) +
     382 [ +  - ][ +  - ]:      21432 :         c->getN (k, j1) * d->getS (l, l) * c->getS (i1, k) * tiny2 / t +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     383 [ +  - ][ +  - ]:      42864 :         c->getN (i1, k) * conj (d->getS (l, l) * c->getS (j1, k) * tiny2 / t) +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     384 [ +  - ][ +  - ]:      21432 :         (c->getN (k, k) * norm (d->getS (l, l)) + d->getN (l, l)) *
         [ +  - ][ +  - ]
     385 [ +  - ][ +  - ]:      64296 :         c->getS (i1, k) * conj (c->getS (j1, k)) * tiny4 / norm (t);
           [ +  -  +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     386                 :            : 
     387         [ +  - ]:      21432 :       result->setN (i2, j2, p);
     388         [ +  + ]:      21432 :       if (i2 >= j2) break; // the other half need not be computed
     389         [ +  - ]:       9303 :       result->setN (j2, i2, conj (p));
     390                 :       9303 :       i2++;
     391                 :            :     }
     392                 :            : 
     393                 :            :     /* The formulas "across C and D" are calculated elsewhere by the
     394                 :            :        other half of the matrix (conjugate complex).  Therefore, they
     395                 :            :        are missing here. */
     396                 :            : 
     397                 :            :     // next column
     398                 :      12129 :     j2++; i2 = 0;
     399                 :            :   }
     400                 :            : 
     401                 :            :   // handle D block
     402         [ +  + ]:      29559 :   for (j1 = 0; j1 < d->getSize (); j1++) {
     403                 :            : 
     404                 :            :     // skip connected node
     405         [ +  + ]:      21661 :     if (j1 == l) continue;
     406                 :            : 
     407                 :            :     // across D and C
     408         [ +  + ]:      49896 :     for (i1 = 0; i1 < c->getSize (); i1++) {
     409                 :            : 
     410                 :            :       // skip connected node
     411         [ +  + ]:      36133 :       if (i1 == k) continue;
     412                 :            : 
     413                 :            :       // compute C'ij
     414 [ +  - ][ +  - ]:      22370 :       p = (c->getN (k, k) * d->getS (l, l) +
     415 [ +  - ][ +  - ]:      44740 :            d->getN (l, l) * conj (c->getS (k, k))) *
         [ +  - ][ +  - ]
     416 [ +  - ][ +  - ]:      44740 :         c->getS (i1, k) * conj (d->getS (j1, l)) * tiny3 / norm (t) +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     417 [ +  - ][ +  - ]:      44740 :         d->getN (l, j1) * c->getS (i1, k) * tiny1 / t +
         [ +  - ][ +  - ]
     418 [ +  - ][ +  - ]:      44740 :         c->getN (i1, k) * conj (d->getS (j1, l) * tiny1 / t);
                 [ +  - ]
           [ +  -  +  - ]
                 [ +  - ]
     419         [ +  - ]:      22370 :       result->setN (i2, j2, p);
     420         [ +  - ]:      22370 :       result->setN (j2, i2, conj (p));
     421                 :      22370 :       i2++;
     422                 :            :     }
     423                 :            : 
     424                 :            :     // inside D
     425         [ +  - ]:      32720 :     for (i1 = 0; i1 < d->getSize (); i1++) {
     426                 :            : 
     427                 :            :       // skip connected node
     428         [ +  + ]:      32720 :       if (i1 == l) continue;
     429                 :            : 
     430                 :            :       // compute C'ij
     431                 :            :       p = d->getN (i1, j1) +
     432 [ +  - ][ +  - ]:      30481 :         (d->getN (l, l) * norm (c->getS (k, k)) + c->getN (k, k)) *
         [ +  - ][ +  - ]
     433 [ +  - ][ +  - ]:      60962 :         d->getS (i1, l) * conj (d->getS (j1, l)) * tiny4 / norm (t) +
           [ +  -  +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     434 [ +  - ][ +  - ]:      60962 :         d->getN (i1, l) * conj (c->getS (k, k) * d->getS (j1, l) * tiny2 / t) +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     435 [ +  - ][ +  - ]:      60962 :         d->getN (l, j1) * c->getS (k, k) * d->getS (i1, l) * tiny2 / t;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     436         [ +  - ]:      30481 :       result->setN (i2, j2, p);
     437         [ +  + ]:      30481 :       if (i2 >= j2) break; // the other half need not be computed
     438         [ +  - ]:      16718 :       result->setN (j2, i2, conj (p));
     439                 :      16718 :       i2++;
     440                 :            :     }
     441                 :            : 
     442                 :            :     // next column
     443                 :      13763 :     j2++; i2 = 0;
     444                 :            :   }
     445                 :       7898 : }
     446                 :            : 
     447                 :            : /* Goes through the list of circuit objects and runs its frequency
     448                 :            :    dependent calcSP() function. */
     449                 :       5783 : void spsolver::calc (nr_double_t freq) {
     450                 :       5783 :   circuit * root = subnet->getRoot ();
     451         [ +  + ]:     135144 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     452                 :     129361 :     c->calcSP (freq);
     453         [ +  + ]:     129361 :     if (noise) c->calcNoiseSP (freq);
     454                 :            :   }
     455                 :       5783 : }
     456                 :            : 
     457                 :            : /* Go through each registered circuit object in the list and find the
     458                 :            :    connection which results in a new subnetwork with the smallest
     459                 :            :    number of s-parameters to calculate. */
     460                 :     124675 : void spsolver::reduce (void) {
     461                 :            : 
     462                 :            : #if SORTED_LIST
     463                 :            :   node * n1, * n2;
     464                 :            :   circuit * result, * cand1, * cand2;
     465                 :            : 
     466         [ +  - ]:     124675 :   nlist->sortedNodes (&n1, &n2);
     467                 :     124675 :   cand1 = n1->getCircuit ();
     468                 :     124675 :   cand2 = n2->getCircuit ();
     469                 :            : #else /* !SORTED_LIST */
     470                 :            :   node * n1, * n2, * cand;
     471                 :            :   circuit * result, * c1, * c2, * cand1, * cand2;
     472                 :            :   int ports;
     473                 :            :   circuit * root = subnet->getRoot ();
     474                 :            : 
     475                 :            :   // initialize local variables
     476                 :            :   result = c1 = c2 = cand1 = cand2 = NULL;
     477                 :            :   n1 = n2 = cand = NULL;
     478                 :            :   ports = 10000; // huge
     479                 :            : 
     480                 :            :   // go through the circuit list
     481                 :            :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     482                 :            : 
     483                 :            :     // skip signal ports
     484                 :            :     if (c->getPort ()) continue;
     485                 :            : 
     486                 :            :     // and each node in the circuit
     487                 :            :     for (int i = 0; i < c->getSize (); i++) {
     488                 :            : 
     489                 :            :       // find duplicate node
     490                 :            :       if ((cand = subnet->findConnectedCircuitNode (c->getNode (i))) != NULL) {
     491                 :            : 
     492                 :            :         // save both candidates
     493                 :            :         c1 = c; c2 = cand->getCircuit ();
     494                 :            :         // connected
     495                 :            :         if (c1 != c2) {
     496                 :            :           if (c1->getSize () + c2->getSize () - 2 < ports) {
     497                 :            :             ports = c1->getSize () + c2->getSize () - 2;
     498                 :            :             cand1 = c1; cand2 = c2; n1 = c1->getNode (i); n2 = cand;
     499                 :            :           }
     500                 :            :         }
     501                 :            :         // interconnect
     502                 :            :         else {
     503                 :            :           if (c1->getSize () - 2 < ports) {
     504                 :            :             ports = c1->getSize () - 2;
     505                 :            :             cand1 = c1; cand2 = c2; n1 = c1->getNode (i); n2 = cand;
     506                 :            :           }
     507                 :            :         }
     508                 :            :       }
     509                 :            :     }
     510                 :            :   }
     511                 :            : #endif /* !SORTED_LIST */
     512                 :            : 
     513                 :            :   // found a connection ?
     514 [ +  - ][ +  - ]:     124675 :   if (cand1 != NULL && cand2 != NULL) {
     515                 :            :     // connected
     516         [ +  + ]:     124675 :     if (cand1 != cand2) {
     517                 :            : #if DEBUG && 0
     518                 :            :       logprint (LOG_STATUS, "DEBUG: connected node (%s): %s - %s\n",
     519                 :            :                 n1->getName (), cand1->getName (), cand2->getName ());
     520                 :            : #endif /* DEBUG */
     521         [ +  - ]:     111570 :       result = connectedJoin (n1, n2);
     522 [ +  + ][ +  - ]:     111570 :       if (noise) noiseConnect (result, n1, n2);
     523         [ +  - ]:     111570 :       subnet->reducedCircuit (result);
     524                 :            : #if SORTED_LIST
     525         [ +  - ]:     111570 :       nlist->remove (cand1);
     526         [ +  - ]:     111570 :       nlist->remove (cand2);
     527         [ +  - ]:     111570 :       nlist->insert (result);
     528                 :            : #endif /* SORTED_LIST */
     529         [ +  - ]:     111570 :       subnet->removeCircuit (cand1);
     530         [ +  - ]:     111570 :       subnet->removeCircuit (cand2);
     531         [ +  - ]:     111570 :       subnet->insertCircuit (result);
     532                 :     111570 :       result->setOriginal (0);
     533                 :            :     }
     534                 :            :     // interconnect
     535                 :            :     else {
     536                 :            : #if DEBUG && 0
     537                 :            :       logprint (LOG_STATUS, "DEBUG: interconnected node (%s): %s\n",
     538                 :            :                 n1->getName (), cand1->getName ());
     539                 :            : #endif
     540         [ +  - ]:      13105 :       result = interconnectJoin (n1, n2);
     541 [ +  + ][ +  - ]:      13105 :       if (noise) noiseInterconnect (result, n1, n2);
     542         [ +  - ]:      13105 :       subnet->reducedCircuit (result);
     543                 :            : #if SORTED_LIST
     544         [ +  - ]:      13105 :       nlist->remove (cand1);
     545         [ +  - ]:      13105 :       nlist->insert (result);
     546                 :            : #endif /* SORTED_LIST */
     547         [ +  - ]:      13105 :       subnet->removeCircuit (cand1);
     548         [ +  - ]:      13105 :       subnet->insertCircuit (result);
     549                 :      13105 :       result->setOriginal (0);
     550                 :            :     }
     551                 :            :   }
     552                 :     124675 : }
     553                 :            : 
     554                 :            : /* Goes through the list of circuit objects and runs initializing
     555                 :            :    functions if necessary. */
     556                 :         18 : void spsolver::init (void) {
     557                 :         18 :   circuit * root = subnet->getRoot ();
     558         [ +  + ]:        233 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     559         [ +  + ]:        215 :     if (c->isNonLinear ()) c->calcOperatingPoints ();
     560                 :        215 :     c->initSP ();
     561         [ +  + ]:        215 :     if (noise) c->initNoiseSP ();
     562                 :            :   }
     563                 :         18 : }
     564                 :            : 
     565                 :            : /* This is the netlist solver.  It prepares the circuit list for each
     566                 :            :    requested frequency and solves it then. */
     567                 :         18 : int spsolver::solve (void) {
     568                 :            :   nr_double_t freq;
     569                 :            :   int ports;
     570                 :         18 :   runs++;
     571                 :            : 
     572                 :            :   // fetch simulation properties
     573         [ -  + ]:         18 :   saveCVs |= !strcmp (getPropertyString ("saveCVs"), "yes") ? SAVE_CVS : 0;
     574         [ -  + ]:         18 :   saveCVs |= !strcmp (getPropertyString ("saveAll"), "yes") ? SAVE_ALL : 0;
     575                 :            : 
     576                 :            :   // run additional noise analysis ?
     577         [ +  + ]:         18 :   noise = !strcmp (getPropertyString ("Noise"), "yes") ? 1 : 0;
     578                 :            : 
     579                 :            :   // create frequency sweep if necessary
     580         [ +  - ]:         18 :   if (swp == NULL) {
     581                 :         18 :     swp = createSweep ("frequency");
     582                 :            :   }
     583                 :            : 
     584                 :         18 :   init ();
     585                 :         18 :   insertConnections ();
     586                 :            : 
     587                 :            : #if SORTED_LIST
     588                 :            : #if DEBUG
     589                 :            :   logprint (LOG_STATUS, "NOTIFY: %s: creating sorted nodelist for "
     590                 :         18 :             "SP analysis\n", getName ());
     591                 :            : #endif
     592         [ +  - ]:         18 :   nlist = new nodelist (subnet);
     593                 :         18 :   nlist->sort ();
     594                 :            : #endif /* SORTED_LIST */
     595                 :            : 
     596                 :            : #if DEBUG
     597                 :         18 :   logprint (LOG_STATUS, "NOTIFY: %s: solving SP netlist\n", getName ());
     598                 :            : #endif
     599                 :            : 
     600                 :         18 :   swp->reset ();
     601         [ +  + ]:       5801 :   for (int i = 0; i < swp->getSize (); i++) {
     602                 :       5783 :     freq = swp->next ();
     603         [ +  - ]:       5783 :     if (progress) logprogressbar (i, swp->getSize (), 40);
     604                 :            : 
     605                 :       5783 :     ports = subnet->countNodes ();
     606                 :       5783 :     subnet->setReduced (0);
     607                 :       5783 :     calc (freq);
     608                 :            : 
     609                 :            : #if DEBUG && 0
     610                 :            :     logprint (LOG_STATUS, "NOTIFY: %s: solving netlist for f = %e\n",
     611                 :            :               getName (), (double) freq);
     612                 :            : #endif
     613                 :            : 
     614         [ +  + ]:     130458 :     while (ports > subnet->getPorts ()) {
     615                 :     124675 :       reduce ();
     616                 :     124675 :       ports -= 2;
     617                 :            :     }
     618                 :            : 
     619                 :       5783 :     saveResults (freq);
     620                 :       5783 :     subnet->getDroppedCircuits (nlist);
     621                 :       5783 :     subnet->deleteUnusedCircuits (nlist);
     622         [ -  + ]:       5783 :     if (saveCVs & SAVE_CVS) saveCharacteristics (freq);
     623                 :            :   }
     624         [ +  - ]:         18 :   if (progress) logprogressclear (40);
     625                 :         18 :   dropConnections ();
     626                 :            : #if SORTED_LIST
     627         [ +  - ]:         18 :   delete nlist; nlist = NULL;
     628                 :            : #endif
     629                 :         18 :   return 0;
     630                 :            : }
     631                 :            : 
     632                 :            : /* The function goes through the list of circuit objects and creates
     633                 :            :    tee and cross circuits if necessary.  It looks for nodes in the
     634                 :            :    circuit list connected to the given node. */
     635                 :        440 : void spsolver::insertConnectors (node * n) {
     636                 :            : 
     637                 :        440 :   int count = 0;
     638                 :            :   node * nodes[4], * _node;
     639                 :        440 :   char * _name = n->getName ();
     640                 :        440 :   circuit * root = subnet->getRoot ();
     641                 :            : 
     642                 :            : #if USE_GROUNDS
     643         [ +  + ]:        880 :   if (!strcmp (_name, "gnd")) return;
     644                 :            : #endif /* USE_GROUNDS */
     645                 :            : 
     646                 :        350 :   nodes[0] = n;
     647                 :            : 
     648                 :            :   // go through list of circuit objects
     649         [ +  + ]:       6472 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     650                 :            :     // and each node in a circuit
     651         [ +  + ]:      20935 :     for (int i = 0; i < c->getSize (); i++) {
     652         [ +  - ]:      14813 :       _node = c->getNode (i);
     653         [ +  + ]:      14813 :       if (!strcmp (_node->getName (), _name)) {
     654         [ +  + ]:        780 :         if (_node != n) {
     655                 :            : 
     656                 :            :           // found a connected node
     657                 :        430 :           nodes[++count] = _node;
     658                 :            : #if USE_CROSSES
     659         [ +  + ]:        430 :           if (count == 3) {
     660                 :            :             // create an additional cross and assign its nodes
     661         [ +  - ]:         18 :             insertCross (nodes, _name);
     662                 :         18 :             count = 1;
     663                 :            :           }
     664                 :            : #else /* !USE_CROSSES */
     665                 :            :           if (count == 2) {
     666                 :            :             // create an additional tee and assign its nodes
     667                 :            :             insertTee (nodes, _name);
     668                 :            :             count = 1;
     669                 :            :           }
     670                 :            : #endif /* !USE_CROSSES */
     671                 :            :         }
     672                 :            :       }
     673                 :            :     }
     674                 :            :   }
     675                 :            : #if USE_CROSSES
     676                 :            :   /* if using crosses there can be a tee left here */
     677         [ +  + ]:        350 :   if (count == 2) {
     678         [ +  - ]:        440 :     insertTee (nodes, _name);
     679                 :            :   }
     680                 :            : #endif /* USE_CROSSES */
     681                 :            : }
     682                 :            : 
     683                 :            : /* The following function creates a tee circuit with the given nodes
     684                 :            :    and the node name.  The tee's node names are adjusted to be
     685                 :            :    internal nodes. */
     686                 :         50 : void spsolver::insertTee (node ** nodes, char * name) {
     687                 :            :   circuit * result;
     688                 :            :   // create a tee and assign its node names
     689         [ +  - ]:         50 :   result = new tee ();
     690                 :         50 :   subnet->insertedCircuit (result);
     691                 :         50 :   result->setNode (0, name);
     692                 :         50 :   subnet->insertedNode (result->getNode (1));
     693                 :         50 :   subnet->insertedNode (result->getNode (2));
     694                 :            :   // rename the nodes connected to the tee
     695                 :         50 :   nodes[1]->setName (result->getNode(1)->getName ());
     696                 :         50 :   nodes[2]->setName (result->getNode(2)->getName ());
     697                 :            :   // complete the nodes of the tee
     698                 :         50 :   result->getNode(1)->setCircuit (result);
     699                 :         50 :   result->getNode(2)->setCircuit (result);
     700                 :         50 :   result->getNode(1)->setPort (1);
     701                 :         50 :   result->getNode(2)->setPort (2);
     702                 :            :   // put the tee into the circuit list and initialize it
     703                 :         50 :   subnet->insertCircuit (result);
     704         [ +  + ]:         50 :   result->initSP (); if (noise) result->initNoiseSP ();
     705                 :            :   // put the tee's first node into the node collection
     706                 :         50 :   nodes[1] = result->getNode (0);
     707                 :         50 :   tees++;
     708                 :         50 : }
     709                 :            : 
     710                 :            : /* The following function creates a cross circuit with the given nodes
     711                 :            :    and the node name.  The cross's node names are adjusted to be
     712                 :            :    internal nodes. */
     713                 :         18 : void spsolver::insertCross (node ** nodes, char * name) {
     714                 :            :   circuit * result;
     715                 :            :   // create a cross and assign its node names
     716         [ +  - ]:         18 :   result = new cross ();
     717                 :         18 :   subnet->insertedCircuit (result);
     718                 :         18 :   result->setNode (0, name);
     719                 :         18 :   subnet->insertedNode (result->getNode (1));
     720                 :         18 :   subnet->insertedNode (result->getNode (2));
     721                 :         18 :   subnet->insertedNode (result->getNode (3));
     722                 :            :   // rename the nodes connected to the cross
     723                 :         18 :   nodes[1]->setName (result->getNode(1)->getName ());
     724                 :         18 :   nodes[2]->setName (result->getNode(2)->getName ());
     725                 :         18 :   nodes[3]->setName (result->getNode(3)->getName ());
     726                 :            :   // complete the nodes of the cross
     727                 :         18 :   result->getNode(1)->setCircuit (result);
     728                 :         18 :   result->getNode(2)->setCircuit (result);
     729                 :         18 :   result->getNode(3)->setCircuit (result);
     730                 :         18 :   result->getNode(1)->setPort (1);
     731                 :         18 :   result->getNode(2)->setPort (2);
     732                 :         18 :   result->getNode(3)->setPort (3);
     733                 :            :   // put the cross into the circuit list and initialize it
     734                 :         18 :   subnet->insertCircuit (result);
     735         [ +  + ]:         18 :   result->initSP (); if (noise) result->initNoiseSP ();
     736                 :            :   // put the cross's first node into the node collection
     737                 :         18 :   nodes[1] = result->getNode (0);
     738                 :         18 :   crosses++;
     739                 :         18 : }
     740                 :            : 
     741                 :            : /* This function removes an inserted tee from the netlist and restores
     742                 :            :    the original node names. */
     743                 :         50 : void spsolver::dropTee (circuit * c) {
     744                 :            :   node * n;
     745         [ +  - ]:         50 :   if (c->getType () == CIR_TEE) {
     746                 :         50 :     char * name = c->getNode(0)->getName ();
     747                 :         50 :     n = subnet->findConnectedNode (c->getNode (1)); n->setName (name);
     748                 :         50 :     n = subnet->findConnectedNode (c->getNode (2)); n->setName (name);
     749                 :         50 :     c->setOriginal (0);
     750                 :         50 :     subnet->removeCircuit (c);
     751                 :            :   }
     752                 :         50 : }
     753                 :            : 
     754                 :            : /* This function removes an inserted cross from the netlist and restores
     755                 :            :    the original node names. */
     756                 :         18 : void spsolver::dropCross (circuit * c) {
     757                 :            :   node * n;
     758         [ +  - ]:         18 :   if (c->getType () == CIR_CROSS) {
     759                 :         18 :     char * name = c->getNode(0)->getName ();
     760                 :         18 :     n = subnet->findConnectedNode (c->getNode (1)); n->setName (name);
     761                 :         18 :     n = subnet->findConnectedNode (c->getNode (2)); n->setName (name);
     762                 :         18 :     n = subnet->findConnectedNode (c->getNode (3)); n->setName (name);
     763                 :         18 :     c->setOriginal (0);
     764                 :         18 :     subnet->removeCircuit (c);
     765                 :            :   }
     766                 :         18 : }
     767                 :            : 
     768                 :            : /* The function adds an open to the circuit list if the given node is
     769                 :            :    unconnected. */
     770                 :        440 : void spsolver::insertOpen (node * n) {
     771   [ +  +  +  + ]:        790 :   if (strcmp (n->getName (), "gnd") &&
                 [ +  + ]
     772                 :        350 :       subnet->findConnectedNode (n) == NULL) {
     773         [ +  - ]:          6 :     circuit * result = new open ();
     774                 :          6 :     subnet->insertedCircuit (result);
     775                 :          6 :     result->setNode (0, n->getName ());
     776                 :          6 :     subnet->insertCircuit (result);
     777         [ +  - ]:          6 :     result->initSP (); if (noise) result->initNoiseSP ();
     778                 :          6 :     opens++;
     779                 :            :   }
     780                 :        440 : }
     781                 :            : 
     782                 :            : // This function removes an inserted open from the netlist.
     783                 :          6 : void spsolver::dropOpen (circuit * c) {
     784         [ +  - ]:          6 :   if (c->getType () == CIR_OPEN) {
     785                 :          6 :     c->setOriginal (0);
     786                 :          6 :     subnet->removeCircuit (c);
     787                 :            :   }
     788                 :          6 : }
     789                 :            : 
     790                 :            : /* The function adds a ground circuit to the circuit list if the given
     791                 :            :    node is a ground connection. */
     792                 :        788 : void spsolver::insertGround (node * n) {
     793         [ +  + ]:        878 :   if (!strcmp (n->getName (), "gnd") && !n->getCircuit()->getPort () &&
           [ +  -  +  - ]
                 [ +  + ]
     794                 :         90 :       n->getCircuit()->getType () != CIR_GROUND) {
     795         [ +  - ]:         90 :     circuit * result = new ground ();
     796                 :         90 :     subnet->insertedCircuit (result);
     797                 :         90 :     subnet->insertedNode (result->getNode (0));
     798                 :         90 :     result->getNode(0)->setCircuit (result);
     799                 :         90 :     result->getNode(0)->setPort (0);
     800                 :         90 :     n->setName (result->getNode(0)->getName ());
     801                 :         90 :     subnet->insertCircuit (result);
     802         [ +  + ]:         90 :     result->initSP (); if (noise) result->initNoiseSP ();
     803                 :         90 :     grounds++;
     804                 :            :   }
     805                 :        788 : }
     806                 :            : 
     807                 :            : // This function removes an inserted ground from the netlist.
     808                 :         90 : void spsolver::dropGround (circuit * c) {
     809         [ +  - ]:         90 :   if (c->getType () == CIR_GROUND) {
     810                 :         90 :     node * n = subnet->findConnectedNode (c->getNode (0));
     811                 :         90 :     n->setName ("gnd");
     812                 :         90 :     c->setOriginal (0);
     813                 :         90 :     subnet->removeCircuit (c);
     814                 :            :   }
     815                 :         90 : }
     816                 :            : 
     817                 :            : /* This function prepares the circuit list by adding Ts and opens to
     818                 :            :    the circuit list.  With this adjustments the solver is able to
     819                 :            :    solve the circuit. */
     820                 :         18 : void spsolver::insertConnections (void) {
     821                 :            : 
     822                 :            :   circuit * root, * c;
     823                 :            : #if DEBUG
     824                 :            :   logprint (LOG_STATUS, "NOTIFY: %s: preparing circuit for analysis\n",
     825                 :         18 :             getName ());
     826                 :            : #endif /* DEBUG */
     827                 :            : 
     828                 :            : #if USE_GROUNDS
     829                 :            :   // remove original ground circuit from netlist
     830                 :         18 :   root = subnet->getRoot ();
     831         [ +  - ]:         21 :   for (c = root; c != NULL; c = (circuit *) c->getNext ()) {
     832         [ +  + ]:         21 :     if (c->getType () == CIR_GROUND) {
     833                 :         18 :       gnd = c;
     834                 :         18 :       subnet->removeCircuit (c, 0);
     835                 :         18 :       break;
     836                 :            :     }
     837                 :            :   }
     838                 :            : #endif /* USE_GROUNDS */
     839                 :            : 
     840                 :            :   // insert opens, tee and crosses where necessary
     841                 :         18 :   tees = crosses = opens = grounds = 0;
     842                 :         18 :   root = subnet->getRoot ();
     843         [ +  + ]:        218 :   for (c = root; c != NULL; c = (circuit *) c->getNext ()) {
     844         [ +  + ]:        640 :     for (int i = 0; i < c->getSize (); i++) {
     845                 :        440 :       insertConnectors (c->getNode (i));
     846                 :        440 :       insertOpen (c->getNode (i));
     847                 :            :     }
     848                 :            :   }
     849                 :            : 
     850                 :            :   // insert S-parameter port transformers
     851                 :         18 :   insertDifferentialPorts ();
     852                 :            : 
     853                 :            : #if USE_GROUNDS
     854                 :            :   // insert grounds where necessary
     855                 :         18 :   root = subnet->getRoot ();
     856         [ +  + ]:        332 :   for (c = root; c != NULL; c = (circuit *) c->getNext ()) {
     857         [ +  + ]:       1102 :     for (int i = 0; i < c->getSize (); i++) {
     858                 :        788 :       insertGround (c->getNode (i));
     859                 :            :     }
     860                 :            :   }
     861                 :            : #endif /* USE_GROUNDS */
     862                 :            : 
     863                 :            : #if DEBUG
     864                 :            :   logprint (LOG_STATUS, "NOTIFY: %s: inserted %d tees, %d crosses, %d opens "
     865                 :            :             "and %d grounds\n",
     866                 :         18 :             getName (), tees, crosses, opens, grounds);
     867                 :            : #endif /* DEBUG */
     868                 :         18 : }
     869                 :            : 
     870                 :            : /* The function is the counterpart of insertConnections().  It removes
     871                 :            :    all additional circuits from the netlist which were necessary to
     872                 :            :    run the analysis algorithm. */
     873                 :        222 : void spsolver::dropConnections (void) {
     874                 :            :   circuit * next, * cand;
     875                 :            :   int inserted;
     876                 :            : 
     877                 :            :   // drop all additional inserted circuits in correct order
     878         [ +  + ]:        222 :   do {
     879                 :            :     // find last inserted circuit
     880                 :        222 :     inserted = -1;
     881                 :        222 :     cand = NULL;
     882         [ +  + ]:       4202 :     for (circuit * c = subnet->getRoot (); c != NULL; c = next) {
     883                 :       3980 :       next = (circuit *) c->getNext ();
     884         [ +  + ]:       3980 :       if (c->getInserted () > inserted) {
     885                 :        458 :         inserted = c->getInserted ();
     886                 :        458 :         cand = c;
     887                 :            :       }
     888                 :            :     }
     889                 :            :     // if found, then drop that circuit
     890         [ +  + ]:        222 :     if (cand != NULL) {
     891   [ +  +  +  +  :        204 :       switch (cand->getType ()) {
                   +  - ]
     892                 :            :       case CIR_OPEN:
     893                 :          6 :         dropOpen (cand);
     894                 :          6 :         break;
     895                 :            :       case CIR_TEE:
     896                 :         50 :         dropTee (cand);
     897                 :         50 :         break;
     898                 :            :       case CIR_CROSS:
     899                 :         18 :         dropCross (cand);
     900                 :         18 :         break;
     901                 :            :       case CIR_GROUND:
     902                 :         90 :         dropGround (cand);
     903                 :         90 :         break;
     904                 :            :       case CIR_ITRAFO:
     905                 :         40 :         dropDifferentialPort (cand);
     906                 :        204 :         break;
     907                 :            :       }
     908                 :            :     }
     909                 :            :   } while (cand != NULL);
     910                 :            : 
     911                 :            : #if USE_GROUNDS
     912                 :            :   // attach the original ground to the netlist
     913                 :         18 :   subnet->insertCircuit (gnd);
     914                 :            : #endif /* USE_GROUNDS */
     915                 :         18 : }
     916                 :            : 
     917                 :            : /* This function inserts an ideal transformer before an AC power
     918                 :            :    source in order to allow differential S parameter ports.  */
     919                 :         18 : void spsolver::insertDifferentialPorts (void) {
     920                 :         18 :   circuit * root = subnet->getRoot ();
     921         [ +  + ]:        292 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     922         [ +  + ]:        274 :     if (c->getPort ()) {
     923                 :            : 
     924                 :            :       // create an ideal transformer and assign its node names
     925         [ +  - ]:         40 :       circuit * result = new itrafo ();
     926                 :         40 :       subnet->insertedCircuit (result);
     927                 :         40 :       subnet->insertedNode (result->getNode (0));
     928                 :         40 :       result->setNode (1, c->getNode(0)->getName ());
     929                 :         40 :       result->setNode (2, c->getNode(1)->getName ());
     930                 :            : 
     931                 :            :       // rename the nodes connected to the trafo
     932                 :         40 :       c->getNode(0)->setName (result->getNode(0)->getName ());
     933                 :         40 :       c->getNode(1)->setName ("PacGround");
     934                 :            : 
     935                 :            :       // complete the nodes of the trafo
     936                 :         40 :       result->getNode(0)->setCircuit (result);
     937                 :         40 :       result->getNode(0)->setPort (0);
     938                 :            : 
     939                 :            :       // pass the port impedance to the ideal trafo
     940                 :         40 :       result->addProperty ("Z", c->getPropertyDouble ("Z"));
     941                 :            : 
     942                 :            :       // put the trafo in the circuit list
     943                 :         40 :       subnet->insertCircuit (result);
     944                 :            : 
     945                 :            :       // allocate S-parameter and noise correlation matrices
     946         [ +  + ]:         40 :       result->initSP (); if (noise) result->initNoiseSP ();
     947                 :            :     }
     948                 :            :   }
     949                 :         18 : }
     950                 :            : 
     951                 :            : /* This function removes an ideal transformer which was necessary to
     952                 :            :    be placed in front of a s-parameter port in order to allow
     953                 :            :    differential s-parameters.  It also restores the original node
     954                 :            :    names. */
     955                 :         40 : void spsolver::dropDifferentialPort (circuit * c) {
     956                 :            :   circuit * pac;
     957                 :            :   node * n;
     958         [ +  - ]:         40 :   if (c->getType () == CIR_ITRAFO) {
     959                 :         40 :     n = subnet->findConnectedNode (c->getNode (0));
     960                 :         40 :     pac = n->getCircuit ();
     961                 :         40 :     pac->getNode(0)->setName (c->getNode(1)->getName ());
     962                 :         40 :     pac->getNode(1)->setName (c->getNode(2)->getName ());
     963                 :         40 :     c->setOriginal (0);
     964                 :         40 :     subnet->removeCircuit (c);
     965                 :            :   }
     966                 :         40 : }
     967                 :            : 
     968                 :            : /* This function saves the results of a single solve() functionality
     969                 :            :    (for the given frequency) into the output dataset. */
     970                 :       5783 : void spsolver::saveResults (nr_double_t freq) {
     971                 :            : 
     972                 :            :   vector * f;
     973                 :            :   node * sig_i, * sig_j;
     974                 :            :   char * n;
     975                 :            :   int res_i, res_j;
     976                 :       5783 :   circuit * root = subnet->getRoot ();
     977                 :            : 
     978                 :            :   // temporary noise matrices and input port impedance
     979 [ +  + ][ +  + ]:      52047 :   nr_complex_t noise_c[4], noise_s[4];
     980                 :       5783 :   nr_double_t z0 = circuit::z0;
     981                 :            : 
     982                 :            :   // add current frequency to the dependency of the output dataset
     983 [ +  - ][ +  + ]:       5783 :   if ((f = data->findDependency ("frequency")) == NULL) {
     984 [ +  - ][ +  - ]:         18 :     f = new vector ("frequency");
     985         [ +  - ]:         18 :     data->addDependency (f);
     986                 :            :   }
     987 [ +  - ][ +  - ]:       5783 :   if (runs == 1) f->add (freq);
     988                 :            : 
     989                 :            :   // go through the list of remaining circuits
     990         [ +  + ]:      23574 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
     991                 :            :     // skip signals
     992         [ +  + ]:      17791 :     if (!c->getPort ()) {
     993                 :            :       // handle each s-parameter
     994         [ +  + ]:      17791 :       for (int i = 0; i < c->getSize (); i++) {
     995         [ +  + ]:      36744 :         for (int j = 0; j < c->getSize (); j++) {
     996                 :            : 
     997                 :            :           // generate the appropriate variable name
     998 [ +  - ][ +  - ]:      24837 :           sig_i = subnet->findConnectedNode (c->getNode (i));
     999 [ +  - ][ +  - ]:      24837 :           sig_j = subnet->findConnectedNode (c->getNode (j));
    1000         [ +  - ]:      24837 :           res_i = sig_i->getCircuit()->getPropertyInteger ("Num");
    1001         [ +  - ]:      24837 :           res_j = sig_j->getCircuit()->getPropertyInteger ("Num");
    1002         [ +  - ]:      24837 :           n = createSP (res_i, res_j);
    1003                 :            : 
    1004                 :            :           // add variable data item to dataset
    1005 [ +  - ][ +  - ]:      24837 :           saveVariable (n, c->getS (i, j), f);
    1006                 :            : 
    1007                 :            :           // if noise analysis is requested
    1008         [ +  + ]:      24837 :           if (noise) {
    1009                 :            :             int ro, co;
    1010         [ +  - ]:       1036 :             int ni = getPropertyInteger ("NoiseIP");
    1011         [ +  - ]:       1036 :             int no = getPropertyInteger ("NoiseOP");
    1012 [ +  + ][ +  - ]:       1036 :             if ((res_i == ni || res_i == no) && (res_j == ni || res_j == no)) {
         [ +  + ][ +  - ]
    1013         [ +  + ]:       1036 :               if (ni == res_i) {
    1014                 :            :                 // assign input port impedance
    1015         [ +  - ]:        518 :                 z0 = sig_i->getCircuit()->getPropertyDouble ("Z");
    1016                 :            :               }
    1017                 :       1036 :               ro = (res_i == ni) ? 0 : 1;
    1018                 :       1036 :               co = (res_j == ni) ? 0 : 1;
    1019                 :            :               // save results in temporary data items
    1020         [ +  - ]:       1036 :               noise_c[co + ro * 2] = c->getN (i, j);
    1021         [ +  - ]:       1036 :               noise_s[co + ro * 2] = c->getS (i, j);
    1022                 :            :             }
    1023                 :            :           }
    1024                 :            :         }
    1025                 :            :       }
    1026                 :            :     }
    1027                 :            :   }
    1028                 :            : 
    1029                 :            :   // finally compute and save noise parameters
    1030         [ +  + ]:       5783 :   if (noise) {
    1031         [ +  - ]:        259 :     saveNoiseResults (noise_s, noise_c, z0, f);
    1032                 :            :   }
    1033                 :       5783 : }
    1034                 :            : 
    1035                 :            : /* This function takes the s-parameter matrix and noise wave
    1036                 :            :    correlation matrix and computes the noise parameters based upon
    1037                 :            :    these values.  Then it save the results into the dataset. */
    1038                 :        259 : void spsolver::saveNoiseResults (nr_complex_t s[4], nr_complex_t c[4],
    1039                 :            :                                  nr_double_t z0, vector * f) {
    1040                 :        259 :   nr_complex_t c22 = c[3], c11 = c[0], c12 = c[1];
    1041                 :        259 :   nr_complex_t s11 = s[0], s21 = s[2];
    1042                 :        259 :   nr_complex_t n1, n2, F, Sopt, Fmin, Rn;
    1043                 :            : 
    1044                 :            :   // linear noise figure
    1045         [ +  - ]:        259 :   F    = real (1.0 + c22 / norm (s21));
    1046                 :            :   n1   =
    1047 [ +  - ][ +  - ]:        259 :     c11 * norm (s21) - 2.0 * real (c12 * s21 * conj (s11)) +
                 [ +  - ]
    1048 [ +  - ][ +  - ]:        518 :     c22 * norm (s11);
    1049 [ +  - ][ +  - ]:        259 :   n2   = 2.0 * (c22 * s11 - c12 * s21) / (c22 + n1);
         [ +  - ][ +  - ]
                 [ +  - ]
    1050                 :            : 
    1051                 :            :   // optimal source reflection coefficient
    1052         [ +  - ]:        259 :   Sopt = 1.0 - norm (n2);
    1053         [ -  + ]:        259 :   if (real (Sopt) < 0.0)
    1054 [ #  # ][ #  # ]:          0 :     Sopt = (1.0 + sqrt (Sopt)) / n2;  // avoid a negative radicant
    1055                 :            :   else
    1056 [ +  - ][ +  - ]:        259 :     Sopt = (1.0 - sqrt (Sopt)) / n2;
    1057                 :            : 
    1058                 :            :   // minimum noise figure
    1059         [ +  - ]:        259 :   Fmin = real (1.0 + (c22 - n1 * norm (Sopt)) /
    1060         [ +  - ]:        518 :                norm (s21) / (1.0 + norm (Sopt)));
           [ +  -  +  - ]
    1061                 :            : 
    1062                 :            :   // equivalent noise resistance
    1063 [ +  - ][ +  - ]:        259 :   Rn   = real ((c11 - 2.0 * real (c12 * conj ((1.0 + s11) / s21)) +
    1064 [ +  - ][ +  - ]:        518 :                 c22 * norm ((1.0 + s11) / s21)) / 4.0);
                 [ +  - ]
    1065                 :        259 :   Rn   = Rn * z0;
    1066                 :            : 
    1067                 :            :   // add variable data items to dataset
    1068         [ +  - ]:        259 :   saveVariable ("F", F, f);
    1069         [ +  - ]:        259 :   saveVariable ("Sopt", Sopt, f);
    1070         [ +  - ]:        259 :   saveVariable ("Fmin", Fmin, f);
    1071         [ +  - ]:        259 :   saveVariable ("Rn", Rn, f);
    1072                 :        259 : }
    1073                 :            : 
    1074                 :            : // Create an appropriate variable name.
    1075                 :      24837 : char * spsolver::createSP (int i, int j) {
    1076                 :      24837 :   return matvec::createMatrixString ("S", i - 1, j - 1);
    1077                 :            : }
    1078                 :            : 
    1079                 :            : /* Create an appropriate variable name for characteristic values.  The
    1080                 :            :    caller is responsible to free() the returned string. */
    1081                 :          0 : const char * spsolver::createCV (const std::string &c, const std::string &n) {
    1082         [ #  # ]:          0 :   return (c+"."+n).c_str();
    1083                 :            : }
    1084                 :            : 
    1085                 :            : /* Goes through the list of circuit objects and runs its
    1086                 :            :    saveCharacteristics() function.  Then puts these values into the
    1087                 :            :    dataset. */
    1088                 :          0 : void spsolver::saveCharacteristics (nr_double_t freq) {
    1089                 :          0 :   circuit * root = subnet->getRoot ();
    1090                 :            :   const char * n;
    1091                 :          0 :   vector * f = data->findDependency ("frequency");
    1092         [ #  # ]:          0 :   for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) {
    1093         [ #  # ]:          0 :     c->saveCharacteristics (freq);
    1094 [ #  # ][ #  # ]:          0 :     if (c->getSubcircuit () && !(saveCVs & SAVE_ALL)) continue;
                 [ #  # ]
    1095         [ #  # ]:          0 :     c->calcCharacteristics (freq);
    1096         [ #  # ]:          0 :     valuelistiterator<characteristic> it (c->getCharacteristics ());
    1097 [ #  # ][ #  # ]:          0 :     for (; *it; ++it) {
    1098                 :          0 :       characteristic * p = it.currentVal ();
    1099 [ #  # ][ #  # ]:          0 :       n = createCV (c->getName (), p->getName ());
                 [ #  # ]
    1100         [ #  # ]:          0 :       saveVariable (n, p->getValue (), f);
    1101                 :            :     }
    1102                 :          0 :   }
    1103                 :          0 : }
    1104                 :            : 
    1105                 :            : // properties
    1106                 :            : PROP_REQ [] = {
    1107                 :            :   { "Type", PROP_STR, { PROP_NO_VAL, "lin" }, PROP_RNG_TYP },
    1108                 :            :   PROP_NO_PROP };
    1109                 :            : PROP_OPT [] = {
    1110                 :            :   { "Noise", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
    1111                 :            :   { "NoiseIP", PROP_INT, { 1, PROP_NO_STR }, PROP_RNGII (1, MAX_PORTS) },
    1112                 :            :   { "NoiseOP", PROP_INT, { 2, PROP_NO_STR }, PROP_RNGII (1, MAX_PORTS) },
    1113                 :            :   { "Start", PROP_REAL, { 1e9, PROP_NO_STR }, PROP_POS_RANGE },
    1114                 :            :   { "Stop", PROP_REAL, { 10e9, PROP_NO_STR }, PROP_POS_RANGE },
    1115                 :            :   { "Points", PROP_INT, { 10, PROP_NO_STR }, PROP_MIN_VAL (2) },
    1116                 :            :   { "Values", PROP_LIST, { 10, PROP_NO_STR }, PROP_POS_RANGE },
    1117                 :            :   { "saveCVs", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
    1118                 :            :   { "saveAll", PROP_STR, { PROP_NO_VAL, "no" }, PROP_RNG_YESNO },
    1119                 :            :   PROP_NO_PROP };
    1120                 :            : struct define_t spsolver::anadef =
    1121                 :            :   { "SP", 0, PROP_ACTION, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };
    1122                 :            : 
    1123                 :            : } // namespace qucs

Generated by: LCOV version 1.11